//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ namespace System.Web.UI.WebControls.WebParts { using System; using System.Collections; using System.ComponentModel; using System.Drawing; using System.Globalization; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.Util; public abstract class EditorZoneBase : ToolZone { private EditorPartCollection _editorParts; private const int baseIndex = 0; private const int applyVerbIndex = 1; private const int cancelVerbIndex = 2; private const int okVerbIndex = 3; private const int viewStateArrayLength = 4; private WebPartVerb _applyVerb; private WebPartVerb _cancelVerb; private WebPartVerb _okVerb; private bool _applyError; private EditorPartChrome _editorPartChrome; private const string applyEventArgument = "apply"; private const string cancelEventArgument = "cancel"; private const string okEventArgument = "ok"; protected EditorZoneBase() : base(WebPartManager.EditDisplayMode) { } [ DefaultValue(null), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), NotifyParentProperty(true), PersistenceMode(PersistenceMode.InnerProperty), WebCategory("Verbs"), WebSysDescription(SR.EditorZoneBase_ApplyVerb), ] public virtual WebPartVerb ApplyVerb { get { if (_applyVerb == null) { _applyVerb = new WebPartEditorApplyVerb(); _applyVerb.EventArgument = applyEventArgument; if (IsTrackingViewState) { ((IStateManager)_applyVerb).TrackViewState(); } } return _applyVerb; } } [ DefaultValue(null), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), NotifyParentProperty(true), PersistenceMode(PersistenceMode.InnerProperty), WebCategory("Verbs"), WebSysDescription(SR.EditorZoneBase_CancelVerb), ] public virtual WebPartVerb CancelVerb { get { if (_cancelVerb == null) { _cancelVerb = new WebPartEditorCancelVerb(); _cancelVerb.EventArgument = cancelEventArgument; if (IsTrackingViewState) { ((IStateManager)_cancelVerb).TrackViewState(); } } return _cancelVerb; } } protected override bool Display { get { return (base.Display && WebPartToEdit != null); } } [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) ] public EditorPartChrome EditorPartChrome { get { if (_editorPartChrome == null) { _editorPartChrome = CreateEditorPartChrome(); } return _editorPartChrome; } } [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) ] public EditorPartCollection EditorParts { get { if (_editorParts == null) { WebPart webPartToEdit = WebPartToEdit; EditorPartCollection webPartEditorParts = null; if (webPartToEdit != null && webPartToEdit is IWebEditable) { webPartEditorParts = ((IWebEditable)webPartToEdit).CreateEditorParts(); } EditorPartCollection editorParts = new EditorPartCollection(webPartEditorParts, CreateEditorParts()); // Verify that each EditorPart has a nonempty ID. Don't throw an exception in the designer, // since we want only the offending control to render as an error block, not the whole CatalogZone. if (!DesignMode) { foreach (EditorPart editorPart in editorParts) { if (String.IsNullOrEmpty(editorPart.ID)) { throw new InvalidOperationException(SR.GetString(SR.EditorZoneBase_NoEditorPartID)); } } } _editorParts = editorParts; // Call EnsureChildControls to parent the EditorParts and set the WebPartToEdit, // WebPartManager, and Zone EnsureChildControls(); } return _editorParts; } } [ WebSysDefaultValue(SR.EditorZoneBase_DefaultEmptyZoneText) ] public override string EmptyZoneText { // Must look at viewstate directly instead of the property in the base class, // so we can distinguish between an unset property and a property set to String.Empty. get { string s = (string)ViewState["EmptyZoneText"]; return((s == null) ? SR.GetString(SR.EditorZoneBase_DefaultEmptyZoneText) : s); } set { ViewState["EmptyZoneText"] = value; } } [ Localizable(true), WebCategory("Behavior"), WebSysDefaultValue(SR.EditorZoneBase_DefaultErrorText), WebSysDescription(SR.EditorZoneBase_ErrorText), ] public virtual string ErrorText { get { string s = (string)ViewState["ErrorText"]; return((s == null) ? SR.GetString(SR.EditorZoneBase_DefaultErrorText) : s); } set { ViewState["ErrorText"] = value; } } [ WebSysDefaultValue(SR.EditorZoneBase_DefaultHeaderText) ] public override string HeaderText { get { string s = (string)ViewState["HeaderText"]; return((s == null) ? SR.GetString(SR.EditorZoneBase_DefaultHeaderText) : s); } set { ViewState["HeaderText"] = value; } } [ WebSysDefaultValue(SR.EditorZoneBase_DefaultInstructionText), ] public override string InstructionText { get { string s = (string)ViewState["InstructionText"]; return((s == null) ? SR.GetString(SR.EditorZoneBase_DefaultInstructionText) : s); } set { ViewState["InstructionText"] = value; } } [ DefaultValue(null), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), NotifyParentProperty(true), PersistenceMode(PersistenceMode.InnerProperty), WebCategory("Verbs"), WebSysDescription(SR.EditorZoneBase_OKVerb), ] public virtual WebPartVerb OKVerb { get { if (_okVerb == null) { _okVerb = new WebPartEditorOKVerb(); _okVerb.EventArgument = okEventArgument; if (IsTrackingViewState) { ((IStateManager)_okVerb).TrackViewState(); } } return _okVerb; } } protected WebPart WebPartToEdit { get { if (WebPartManager != null && WebPartManager.DisplayMode == WebPartManager.EditDisplayMode) { return WebPartManager.SelectedWebPart; } else { return null; } } } private void ApplyAndSyncChanges() { WebPart webPartToEdit = WebPartToEdit; Debug.Assert(webPartToEdit != null); if (webPartToEdit != null) { EditorPartCollection editorParts = EditorParts; foreach (EditorPart editorPart in editorParts) { if (editorPart.Display && editorPart.Visible && editorPart.ChromeState == PartChromeState.Normal) { if (!editorPart.ApplyChanges()) { _applyError = true; } } } if (!_applyError) { foreach (EditorPart editorPart in editorParts) { editorPart.SyncChanges(); } } } } /// /// Returns the Page to normal view. Does not call ApplyChanges to any EditorParts. /// protected override void Close() { if (WebPartManager != null) { WebPartManager.EndWebPartEditing(); } } /// protected internal override void CreateChildControls() { ControlCollection controls = Controls; controls.Clear(); WebPart webPartToEdit = WebPartToEdit; foreach (EditorPart editorPart in EditorParts) { // webPartToEdit will be null if WebPartManager is null if (webPartToEdit != null) { editorPart.SetWebPartToEdit(webPartToEdit); editorPart.SetWebPartManager(WebPartManager); } editorPart.SetZone(this); controls.Add(editorPart); } } protected virtual EditorPartChrome CreateEditorPartChrome() { return new EditorPartChrome(this); } protected abstract EditorPartCollection CreateEditorParts(); // Called by a derived class if the list of EditorParts changes, and they want CreateEditorParts() // to be called again. protected void InvalidateEditorParts() { _editorParts = null; ChildControlsCreated = false; } protected override void LoadViewState(object savedState) { if (savedState == null) { base.LoadViewState(null); } else { object[] myState = (object[]) savedState; if (myState.Length != viewStateArrayLength) { throw new ArgumentException(SR.GetString(SR.ViewState_InvalidViewState)); } base.LoadViewState(myState[baseIndex]); if (myState[applyVerbIndex] != null) { ((IStateManager) ApplyVerb).LoadViewState(myState[applyVerbIndex]); } if (myState[cancelVerbIndex] != null) { ((IStateManager) CancelVerb).LoadViewState(myState[cancelVerbIndex]); } if (myState[okVerbIndex] != null) { ((IStateManager) OKVerb).LoadViewState(myState[okVerbIndex]); } } } protected override void OnDisplayModeChanged(object sender, WebPartDisplayModeEventArgs e) { InvalidateEditorParts(); base.OnDisplayModeChanged(sender, e); } protected internal override void OnPreRender(EventArgs e) { base.OnPreRender(e); EditorPartChrome.PerformPreRender(); } protected override void OnSelectedWebPartChanged(object sender, WebPartEventArgs e) { if (WebPartManager != null && WebPartManager.DisplayMode == WebPartManager.EditDisplayMode) { InvalidateEditorParts(); // SelectedWebPartChanged is raised when a WebPart is entering or exiting Edit mode. // We only want to call SyncChanges when a WebPart is entering Edit mode // (e.WebPart will be non-null). if (e.WebPart != null) { foreach (EditorPart editorPart in EditorParts) { editorPart.SyncChanges(); } } } base.OnSelectedWebPartChanged(sender, e); } protected override void RaisePostBackEvent(string eventArgument) { if (String.Equals(eventArgument, applyEventArgument, StringComparison.OrdinalIgnoreCase)) { if (ApplyVerb.Visible && ApplyVerb.Enabled && WebPartToEdit != null) { ApplyAndSyncChanges(); } } else if (String.Equals(eventArgument, cancelEventArgument, StringComparison.OrdinalIgnoreCase)) { if (CancelVerb.Visible && CancelVerb.Enabled && WebPartToEdit != null) { Close(); } } else if (String.Equals(eventArgument, okEventArgument, StringComparison.OrdinalIgnoreCase)) { if (OKVerb.Visible && OKVerb.Enabled && WebPartToEdit != null) { ApplyAndSyncChanges(); if (!_applyError) { // Only close the EditorZone if there were no errors applying the EditorParts Close(); } } } else { base.RaisePostBackEvent(eventArgument); } } protected internal override void Render(HtmlTextWriter writer) { if (Page != null) { Page.VerifyRenderingInServerForm(this); } base.Render(writer); } protected override void RenderBody(HtmlTextWriter writer) { RenderBodyTableBeginTag(writer); if (DesignMode) { RenderDesignerRegionBeginTag(writer, Orientation.Vertical); } if (HasControls()) { bool firstCell = true; RenderInstructionText(writer, ref firstCell); if (_applyError) { RenderErrorText(writer, ref firstCell); } EditorPartChrome chrome = EditorPartChrome; foreach (EditorPart editorPart in EditorParts) { if ((!editorPart.Display) || (!editorPart.Visible)) { continue; } writer.RenderBeginTag(HtmlTextWriterTag.Tr); if (!firstCell) { writer.AddStyleAttribute(HtmlTextWriterStyle.PaddingTop, "0"); } else { firstCell = false; } writer.RenderBeginTag(HtmlTextWriterTag.Td); chrome.RenderEditorPart(writer, editorPart); writer.RenderEndTag(); // Td writer.RenderEndTag(); // Tr } writer.RenderBeginTag(HtmlTextWriterTag.Tr); // Mozilla renders padding on an empty TD without this attribute writer.AddStyleAttribute(HtmlTextWriterStyle.Padding, "0"); // Add an extra row with height of 100%, to [....] up any extra space // if the height of the zone is larger than its contents // Mac IE needs height=100% set on instead of writer.AddStyleAttribute(HtmlTextWriterStyle.Height, "100%"); writer.RenderBeginTag(HtmlTextWriterTag.Td); writer.RenderEndTag(); // Td writer.RenderEndTag(); // Tr } else { RenderEmptyZoneText(writer); } if (DesignMode) { RenderDesignerRegionEndTag(writer); } RenderBodyTableEndTag(writer); } private void RenderEmptyZoneText(HtmlTextWriter writer) { string emptyZoneText = EmptyZoneText; if (!String.IsNullOrEmpty(emptyZoneText)) { writer.RenderBeginTag(HtmlTextWriterTag.Tr); writer.AddAttribute(HtmlTextWriterAttribute.Valign, "top"); Style emptyZoneTextStyle = EmptyZoneTextStyle; if (!emptyZoneTextStyle.IsEmpty) { emptyZoneTextStyle.AddAttributesToRender(writer, this); } writer.RenderBeginTag(HtmlTextWriterTag.Td); writer.Write(emptyZoneText); writer.RenderEndTag(); // Td writer.RenderEndTag(); // Tr } } private void RenderErrorText(HtmlTextWriter writer, ref bool firstCell) { string errorText = ErrorText; if (!String.IsNullOrEmpty(errorText)) { writer.RenderBeginTag(HtmlTextWriterTag.Tr); writer.RenderBeginTag(HtmlTextWriterTag.Td); firstCell = false; Label label = new Label(); label.Text = errorText; label.Page = Page; label.ApplyStyle(ErrorStyle); label.RenderControl(writer); writer.RenderEndTag(); // Td writer.RenderEndTag(); // Tr } } private void RenderInstructionText(HtmlTextWriter writer, ref bool firstCell) { string instructionText = InstructionText; if (!String.IsNullOrEmpty(instructionText)) { writer.RenderBeginTag(HtmlTextWriterTag.Tr); writer.RenderBeginTag(HtmlTextWriterTag.Td); firstCell = false; Label label = new Label(); label.Text = instructionText; label.Page = Page; label.ApplyStyle(InstructionTextStyle); label.RenderControl(writer); writer.RenderEndTag(); // Td writer.RenderEndTag(); // Tr } } protected override void RenderVerbs(HtmlTextWriter writer) { RenderVerbsInternal(writer, new WebPartVerb[] {OKVerb, CancelVerb, ApplyVerb}); } protected override object SaveViewState() { object[] myState = new object[viewStateArrayLength]; myState[baseIndex] = base.SaveViewState(); myState[applyVerbIndex] = (_applyVerb != null) ? ((IStateManager)_applyVerb).SaveViewState() : null; myState[cancelVerbIndex] = (_cancelVerb != null) ? ((IStateManager)_cancelVerb).SaveViewState() : null; myState[okVerbIndex] = (_okVerb != null) ? ((IStateManager)_okVerb).SaveViewState() : null; for (int i=0; i < viewStateArrayLength; i++) { if (myState[i] != null) { return myState; } } // More performant to return null than an array of null values return null; } protected override void TrackViewState() { base.TrackViewState(); if (_applyVerb != null) { ((IStateManager) _applyVerb).TrackViewState(); } if (_cancelVerb != null) { ((IStateManager) _cancelVerb).TrackViewState(); } if (_okVerb != null) { ((IStateManager) _okVerb).TrackViewState(); } } } }