Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Web / UI / WebParts / EditorZoneBase.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="EditorZoneBase.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6
7 namespace System.Web.UI.WebControls.WebParts {
8
9     using System;
10     using System.Collections;
11     using System.ComponentModel;
12     using System.Drawing;
13     using System.Globalization;
14     using System.Web.UI;
15     using System.Web.UI.WebControls;
16     using System.Web.Util;
17
18     public abstract class EditorZoneBase : ToolZone {
19
20         private EditorPartCollection _editorParts;
21
22         private const int baseIndex = 0;
23         private const int applyVerbIndex = 1;
24         private const int cancelVerbIndex = 2;
25         private const int okVerbIndex = 3;
26         private const int viewStateArrayLength = 4;
27
28         private WebPartVerb _applyVerb;
29         private WebPartVerb _cancelVerb;
30         private WebPartVerb _okVerb;
31
32         private bool _applyError;
33
34         private EditorPartChrome _editorPartChrome;
35
36         private const string applyEventArgument = "apply";
37         private const string cancelEventArgument = "cancel";
38         private const string okEventArgument = "ok";
39
40         protected EditorZoneBase() : base(WebPartManager.EditDisplayMode) {
41         }
42
43         [
44         DefaultValue(null),
45         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
46         NotifyParentProperty(true),
47         PersistenceMode(PersistenceMode.InnerProperty),
48         WebCategory("Verbs"),
49         WebSysDescription(SR.EditorZoneBase_ApplyVerb),
50         ]
51         public virtual WebPartVerb ApplyVerb {
52             get {
53                 if (_applyVerb == null) {
54                     _applyVerb = new WebPartEditorApplyVerb();
55                     _applyVerb.EventArgument = applyEventArgument;
56                     if (IsTrackingViewState) {
57                         ((IStateManager)_applyVerb).TrackViewState();
58                     }
59                 }
60                 return _applyVerb;
61             }
62         }
63
64         [
65         DefaultValue(null),
66         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
67         NotifyParentProperty(true),
68         PersistenceMode(PersistenceMode.InnerProperty),
69         WebCategory("Verbs"),
70         WebSysDescription(SR.EditorZoneBase_CancelVerb),
71         ]
72         public virtual WebPartVerb CancelVerb {
73             get {
74                 if (_cancelVerb == null) {
75                     _cancelVerb = new WebPartEditorCancelVerb();
76                     _cancelVerb.EventArgument = cancelEventArgument;
77                     if (IsTrackingViewState) {
78                         ((IStateManager)_cancelVerb).TrackViewState();
79                     }
80                 }
81
82                 return _cancelVerb;
83             }
84         }
85
86         protected override bool Display {
87             get {
88                 return (base.Display && WebPartToEdit != null);
89             }
90         }
91
92         [
93         Browsable(false),
94         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
95         ]
96         public EditorPartChrome EditorPartChrome {
97             get {
98                 if (_editorPartChrome == null) {
99                     _editorPartChrome = CreateEditorPartChrome();
100                 }
101                 return _editorPartChrome;
102             }
103         }
104
105         [
106         Browsable(false),
107         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
108         ]
109         public EditorPartCollection EditorParts {
110             get {
111                 if (_editorParts == null) {
112                     WebPart webPartToEdit = WebPartToEdit;
113                     EditorPartCollection webPartEditorParts = null;
114                     if (webPartToEdit != null && webPartToEdit is IWebEditable) {
115                         webPartEditorParts = ((IWebEditable)webPartToEdit).CreateEditorParts();
116                     }
117
118                     EditorPartCollection editorParts = new EditorPartCollection(webPartEditorParts, CreateEditorParts());
119
120                     // Verify that each EditorPart has a nonempty ID.  Don't throw an exception in the designer,
121                     // since we want only the offending control to render as an error block, not the whole CatalogZone.
122                     if (!DesignMode) {
123                         foreach (EditorPart editorPart in editorParts) {
124                             if (String.IsNullOrEmpty(editorPart.ID)) {
125                                 throw new InvalidOperationException(SR.GetString(SR.EditorZoneBase_NoEditorPartID));
126                             }
127                         }
128                     }
129
130                     _editorParts = editorParts;
131
132                     // Call EnsureChildControls to parent the EditorParts and set the WebPartToEdit,
133                     // WebPartManager, and Zone
134                     EnsureChildControls();
135                 }
136
137                 return _editorParts;
138             }
139         }
140
141         [
142         WebSysDefaultValue(SR.EditorZoneBase_DefaultEmptyZoneText)
143         ]
144         public override string EmptyZoneText {
145             // Must look at viewstate directly instead of the property in the base class,
146             // so we can distinguish between an unset property and a property set to String.Empty.
147             get {
148                 string s = (string)ViewState["EmptyZoneText"];
149                 return((s == null) ? SR.GetString(SR.EditorZoneBase_DefaultEmptyZoneText) : s);
150             }
151             set {
152                 ViewState["EmptyZoneText"] = value;
153             }
154         }
155
156         [
157         Localizable(true),
158         WebCategory("Behavior"),
159         WebSysDefaultValue(SR.EditorZoneBase_DefaultErrorText),
160         WebSysDescription(SR.EditorZoneBase_ErrorText),
161         ]
162         public virtual string ErrorText {
163             get {
164                 string s = (string)ViewState["ErrorText"];
165                 return((s == null) ? SR.GetString(SR.EditorZoneBase_DefaultErrorText) : s);
166             }
167             set {
168                 ViewState["ErrorText"] = value;
169             }
170         }
171
172         [
173         WebSysDefaultValue(SR.EditorZoneBase_DefaultHeaderText)
174         ]
175         public override string HeaderText {
176             get {
177                 string s = (string)ViewState["HeaderText"];
178                 return((s == null) ? SR.GetString(SR.EditorZoneBase_DefaultHeaderText) : s);
179             }
180             set {
181                 ViewState["HeaderText"] = value;
182             }
183         }
184
185         [
186         WebSysDefaultValue(SR.EditorZoneBase_DefaultInstructionText),
187         ]
188         public override string InstructionText {
189             get {
190                 string s = (string)ViewState["InstructionText"];
191                 return((s == null) ? SR.GetString(SR.EditorZoneBase_DefaultInstructionText) : s);
192             }
193             set {
194                 ViewState["InstructionText"] = value;
195             }
196         }
197
198         [
199         DefaultValue(null),
200         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
201         NotifyParentProperty(true),
202         PersistenceMode(PersistenceMode.InnerProperty),
203         WebCategory("Verbs"),
204         WebSysDescription(SR.EditorZoneBase_OKVerb),
205         ]
206         public virtual WebPartVerb OKVerb {
207             get {
208                 if (_okVerb == null) {
209                     _okVerb = new WebPartEditorOKVerb();
210                     _okVerb.EventArgument = okEventArgument;
211                     if (IsTrackingViewState) {
212                         ((IStateManager)_okVerb).TrackViewState();
213                     }
214                 }
215                 return _okVerb;
216             }
217         }
218
219         protected WebPart WebPartToEdit {
220             get {
221                 if (WebPartManager != null && WebPartManager.DisplayMode == WebPartManager.EditDisplayMode) {
222                     return WebPartManager.SelectedWebPart;
223                 }
224                 else {
225                     return null;
226                 }
227             }
228         }
229
230         private void ApplyAndSyncChanges() {
231             WebPart webPartToEdit = WebPartToEdit;
232             Debug.Assert(webPartToEdit != null);
233             if (webPartToEdit != null) {
234                 EditorPartCollection editorParts = EditorParts;
235                 foreach (EditorPart editorPart in editorParts) {
236                     if (editorPart.Display && editorPart.Visible && editorPart.ChromeState == PartChromeState.Normal) {
237                         if (!editorPart.ApplyChanges()) {
238                             _applyError = true;
239                         }
240                     }
241                 }
242                 if (!_applyError) {
243                     foreach (EditorPart editorPart in editorParts) {
244                         editorPart.SyncChanges();
245                     }
246                 }
247             }
248         }
249
250         /// <devdoc>
251         /// Returns the Page to normal view.  Does not call ApplyChanges to any EditorParts.
252         /// </devdoc>
253         protected override void Close() {
254             if (WebPartManager != null) {
255                 WebPartManager.EndWebPartEditing();
256             }
257         }
258
259         /// <internalonly/>
260         protected internal override void CreateChildControls() {
261             ControlCollection controls = Controls;
262             controls.Clear();
263
264             WebPart webPartToEdit = WebPartToEdit;
265             foreach (EditorPart editorPart in EditorParts) {
266                 // webPartToEdit will be null if WebPartManager is null
267                 if (webPartToEdit != null) {
268                     editorPart.SetWebPartToEdit(webPartToEdit);
269                     editorPart.SetWebPartManager(WebPartManager);
270                 }
271                 editorPart.SetZone(this);
272                 controls.Add(editorPart);
273             }
274         }
275
276         protected virtual EditorPartChrome CreateEditorPartChrome() {
277             return new EditorPartChrome(this);
278         }
279
280         protected abstract EditorPartCollection CreateEditorParts();
281
282         // Called by a derived class if the list of EditorParts changes, and they want CreateEditorParts()
283         // to be called again.
284         protected void InvalidateEditorParts() {
285             _editorParts = null;
286             ChildControlsCreated = false;
287         }
288
289         protected override void LoadViewState(object savedState) {
290             if (savedState == null) {
291                 base.LoadViewState(null);
292             }
293             else {
294                 object[] myState = (object[]) savedState;
295                 if (myState.Length != viewStateArrayLength) {
296                     throw new ArgumentException(SR.GetString(SR.ViewState_InvalidViewState));
297                 }
298
299                 base.LoadViewState(myState[baseIndex]);
300                 if (myState[applyVerbIndex] != null) {
301                     ((IStateManager) ApplyVerb).LoadViewState(myState[applyVerbIndex]);
302                 }
303                 if (myState[cancelVerbIndex] != null) {
304                     ((IStateManager) CancelVerb).LoadViewState(myState[cancelVerbIndex]);
305                 }
306                 if (myState[okVerbIndex] != null) {
307                     ((IStateManager) OKVerb).LoadViewState(myState[okVerbIndex]);
308                 }
309             }
310         }
311
312         protected override void OnDisplayModeChanged(object sender, WebPartDisplayModeEventArgs e) {
313             InvalidateEditorParts();
314             base.OnDisplayModeChanged(sender, e);
315         }
316
317         protected internal override void OnPreRender(EventArgs e) {
318             base.OnPreRender(e);
319
320             EditorPartChrome.PerformPreRender();
321         }
322
323         protected override void OnSelectedWebPartChanged(object sender, WebPartEventArgs e) {
324             if (WebPartManager != null && WebPartManager.DisplayMode == WebPartManager.EditDisplayMode) {
325                 InvalidateEditorParts();
326
327                 // SelectedWebPartChanged is raised when a WebPart is entering or exiting Edit mode.
328                 // We only want to call SyncChanges when a WebPart is entering Edit mode
329                 // (e.WebPart will be non-null).
330                 if (e.WebPart != null) {
331                     foreach (EditorPart editorPart in EditorParts) {
332                         editorPart.SyncChanges();
333                     }
334                 }
335             }
336
337             base.OnSelectedWebPartChanged(sender, e);
338         }
339
340         protected override void RaisePostBackEvent(string eventArgument) {
341             if (String.Equals(eventArgument, applyEventArgument, StringComparison.OrdinalIgnoreCase)) {
342                 if (ApplyVerb.Visible && ApplyVerb.Enabled && WebPartToEdit != null) {
343                     ApplyAndSyncChanges();
344                 }
345             }
346             else if (String.Equals(eventArgument, cancelEventArgument, StringComparison.OrdinalIgnoreCase)) {
347                 if (CancelVerb.Visible && CancelVerb.Enabled && WebPartToEdit != null) {
348                     Close();
349                 }
350             }
351             else if (String.Equals(eventArgument, okEventArgument, StringComparison.OrdinalIgnoreCase)) {
352                 if (OKVerb.Visible && OKVerb.Enabled && WebPartToEdit != null) {
353                     ApplyAndSyncChanges();
354                     if (!_applyError) {
355                         // Only close the EditorZone if there were no errors applying the EditorParts
356                         Close();
357                     }
358                 }
359             }
360             else {
361                 base.RaisePostBackEvent(eventArgument);
362             }
363         }
364
365         protected internal override void Render(HtmlTextWriter writer) {
366             if (Page != null) {
367                 Page.VerifyRenderingInServerForm(this);
368             }
369
370             base.Render(writer);
371         }
372
373         protected override void RenderBody(HtmlTextWriter writer) {
374             RenderBodyTableBeginTag(writer);
375             if (DesignMode) {
376                 RenderDesignerRegionBeginTag(writer, Orientation.Vertical);
377             }
378
379             if (HasControls()) {
380                 bool firstCell = true;
381
382                 RenderInstructionText(writer, ref firstCell);
383
384                 if (_applyError) {
385                     RenderErrorText(writer, ref firstCell);
386                 }
387
388                 EditorPartChrome chrome = EditorPartChrome;
389                 foreach (EditorPart editorPart in EditorParts) {
390                     if ((!editorPart.Display) || (!editorPart.Visible)) {
391                         continue;
392                     }
393
394                     writer.RenderBeginTag(HtmlTextWriterTag.Tr);
395
396                     if (!firstCell) {
397                         writer.AddStyleAttribute(HtmlTextWriterStyle.PaddingTop, "0");
398                     }
399                     else {
400                         firstCell = false;
401                     }
402                     writer.RenderBeginTag(HtmlTextWriterTag.Td);
403
404                     chrome.RenderEditorPart(writer, editorPart);
405
406                     writer.RenderEndTag();  // Td
407                     writer.RenderEndTag();  // Tr
408                 }
409
410                 writer.RenderBeginTag(HtmlTextWriterTag.Tr);
411
412                 // Mozilla renders padding on an empty TD without this attribute
413                 writer.AddStyleAttribute(HtmlTextWriterStyle.Padding, "0");
414
415                 // Add an extra row with height of 100%, to Microsoft up any extra space
416                 // if the height of the zone is larger than its contents
417                 // Mac IE needs height=100% set on <td> instead of <tr>
418                 writer.AddStyleAttribute(HtmlTextWriterStyle.Height, "100%");
419
420                 writer.RenderBeginTag(HtmlTextWriterTag.Td);
421                 writer.RenderEndTag(); // Td
422                 writer.RenderEndTag(); // Tr
423             }
424             else {
425                 RenderEmptyZoneText(writer);
426             }
427
428             if (DesignMode) {
429                 RenderDesignerRegionEndTag(writer);
430             }
431             RenderBodyTableEndTag(writer);
432         }
433
434         private void RenderEmptyZoneText(HtmlTextWriter writer) {
435             string emptyZoneText = EmptyZoneText;
436             if (!String.IsNullOrEmpty(emptyZoneText)) {
437                 writer.RenderBeginTag(HtmlTextWriterTag.Tr);
438
439                 writer.AddAttribute(HtmlTextWriterAttribute.Valign, "top");
440
441                 Style emptyZoneTextStyle = EmptyZoneTextStyle;
442                 if (!emptyZoneTextStyle.IsEmpty) {
443                     emptyZoneTextStyle.AddAttributesToRender(writer, this);
444                 }
445                 writer.RenderBeginTag(HtmlTextWriterTag.Td);
446
447                 writer.Write(emptyZoneText);
448
449                 writer.RenderEndTag();  // Td
450                 writer.RenderEndTag();  // Tr
451             }
452         }
453
454         private void RenderErrorText(HtmlTextWriter writer, ref bool firstCell) {
455             string errorText = ErrorText;
456             if (!String.IsNullOrEmpty(errorText)) {
457                 writer.RenderBeginTag(HtmlTextWriterTag.Tr);
458                 writer.RenderBeginTag(HtmlTextWriterTag.Td);
459                 firstCell = false;
460
461                 Label label = new Label();
462                 label.Text = errorText;
463                 label.Page = Page;
464                 label.ApplyStyle(ErrorStyle);
465                 label.RenderControl(writer);
466
467                 writer.RenderEndTag();  // Td
468                 writer.RenderEndTag();  // Tr
469             }
470         }
471
472         private void RenderInstructionText(HtmlTextWriter writer, ref bool firstCell) {
473             string instructionText = InstructionText;
474             if (!String.IsNullOrEmpty(instructionText)) {
475                 writer.RenderBeginTag(HtmlTextWriterTag.Tr);
476                 writer.RenderBeginTag(HtmlTextWriterTag.Td);
477                 firstCell = false;
478
479                 Label label = new Label();
480                 label.Text = instructionText;
481                 label.Page = Page;
482                 label.ApplyStyle(InstructionTextStyle);
483                 label.RenderControl(writer);
484
485                 writer.RenderEndTag();  // Td
486                 writer.RenderEndTag();  // Tr
487             }
488         }
489
490         protected override void RenderVerbs(HtmlTextWriter writer) {
491             RenderVerbsInternal(writer, new WebPartVerb[] {OKVerb, CancelVerb, ApplyVerb});
492         }
493
494         protected override object SaveViewState() {
495             object[] myState = new object[viewStateArrayLength];
496
497             myState[baseIndex] = base.SaveViewState();
498             myState[applyVerbIndex] = (_applyVerb != null) ? ((IStateManager)_applyVerb).SaveViewState() : null;
499             myState[cancelVerbIndex] = (_cancelVerb != null) ? ((IStateManager)_cancelVerb).SaveViewState() : null;
500             myState[okVerbIndex] = (_okVerb != null) ? ((IStateManager)_okVerb).SaveViewState() : null;
501
502             for (int i=0; i < viewStateArrayLength; i++) {
503                 if (myState[i] != null) {
504                     return myState;
505                 }
506             }
507
508             // More performant to return null than an array of null values
509             return null;
510         }
511
512         protected override void TrackViewState() {
513             base.TrackViewState();
514
515             if (_applyVerb != null) {
516                 ((IStateManager) _applyVerb).TrackViewState();
517             }
518             if (_cancelVerb != null) {
519                 ((IStateManager) _cancelVerb).TrackViewState();
520             }
521             if (_okVerb != null) {
522                 ((IStateManager) _okVerb).TrackViewState();
523             }
524         }
525     }
526 }
527