Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Web / UI / WebParts / WebPartManager.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="WebPartManager.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.Collections.Specialized;
12     using System.ComponentModel;
13     using System.Diagnostics.CodeAnalysis;
14     using System.Drawing;
15     using System.Globalization;
16     using System.IO;
17     using System.Reflection;
18     using System.Security;
19     using System.Security.Permissions;
20     using System.Text;
21     using System.Web;
22     using System.Web.Configuration;
23     using System.Web.UI;
24     using System.Web.UI.WebControls;
25     using System.Web.Util;
26     using System.Xml;
27
28     [
29     Bindable(false),
30     Designer("System.Web.UI.Design.WebControls.WebParts.WebPartManagerDesigner, " + AssemblyRef.SystemDesign),
31     NonVisualControl(),
32     ParseChildren(true),
33     PersistChildren(false),
34     ViewStateModeById(),
35     ]
36     public class WebPartManager : Control, INamingContainer, IPersonalizable {
37
38         public static readonly WebPartDisplayMode CatalogDisplayMode = new CatalogWebPartDisplayMode();
39         public static readonly WebPartDisplayMode ConnectDisplayMode = new ConnectWebPartDisplayMode();
40         public static readonly WebPartDisplayMode DesignDisplayMode = new DesignWebPartDisplayMode();
41         public static readonly WebPartDisplayMode EditDisplayMode = new EditWebPartDisplayMode();
42         public static readonly WebPartDisplayMode BrowseDisplayMode = new BrowseWebPartDisplayMode();
43
44         // Cache collections of ConnectionPoints for each object Type.  We store an array of
45         // 2 ConnectionPointCollections (consumer, provider) for each Type.  The Hashtable
46         // is synchronized so it is threadsafe with multiple writers.
47         private static Hashtable ConnectionPointsCache;
48
49         private static readonly object AuthorizeWebPartEvent = new object();
50         private static readonly object ConnectionsActivatedEvent = new object();
51         private static readonly object ConnectionsActivatingEvent = new object();
52         private static readonly object DisplayModeChangedEvent = new object();
53         private static readonly object DisplayModeChangingEvent = new object();
54         private static readonly object SelectedWebPartChangingEvent = new object();
55         private static readonly object SelectedWebPartChangedEvent = new object();
56         private static readonly object WebPartAddedEvent = new object();
57         private static readonly object WebPartAddingEvent = new object();
58         private static readonly object WebPartClosedEvent = new object();
59         private static readonly object WebPartClosingEvent = new object();
60         private static readonly object WebPartDeletedEvent = new object();
61         private static readonly object WebPartDeletingEvent = new object();
62         private static readonly object WebPartMovedEvent = new object();
63         private static readonly object WebPartMovingEvent = new object();
64         private static readonly object WebPartsConnectedEvent = new object();
65         private static readonly object WebPartsConnectingEvent = new object();
66         private static readonly object WebPartsDisconnectedEvent = new object();
67         private static readonly object WebPartsDisconnectingEvent = new object();
68
69         private PermissionSet _minimalPermissionSet;
70         private PermissionSet _mediumPermissionSet;
71         private bool? _usePermitOnly;
72
73         private const string DynamicConnectionIDPrefix = "c";
74         private const string DynamicWebPartIDPrefix = "wp";
75
76         private const int baseIndex = 0;
77         private const int selectedWebPartIndex = 1;
78         private const int displayModeIndex = 2;
79         private const int controlStateArrayLength = 3;
80
81         private WebPartPersonalization _personalization;
82         private WebPartDisplayMode _displayMode;
83         private WebPartDisplayModeCollection _displayModes;
84         private WebPartDisplayModeCollection _supportedDisplayModes;
85         private WebPartManagerInternals _internals;
86
87         private bool _allowCreateDisplayTitles;
88         private bool _pageInitComplete;
89
90         // When this flag is set to false, then cancelled events are ignored.  We will not actually
91         // cancel the action even though e.Cancel is true.  (VSWhidbey 516012)
92         private bool _allowEventCancellation;
93
94         private PersonalizationDictionary _personalizationState;
95         private bool _hasDataChanged;
96
97         private WebPartConnectionCollection _staticConnections;
98         private WebPartConnectionCollection _dynamicConnections;
99
100         private WebPartZoneCollection _webPartZones;
101         private TransformerTypeCollection _availableTransformers;
102
103         // Dictionary mapping a WebPart to its DisplayTitle.  Created and filled on demand when
104         // GetDisplayTitle() is called after PreRender.
105         private IDictionary _displayTitles;
106
107         // NOTE: We are no longer rendering the LRO or PDF characters (VSWhidbey 364897)
108         // LRO is the Unicode left-to-right override marker.  Effectively creates a "run break"
109         // so that contents in parentheses et. al. maintain correct reading order regardless
110         // of text direction (LTR or RTL).  PDF "pops" the formatting and allows ensuing text
111         // to lay out as it would w/o the markers.  The PDF is needed when constructing dialogs
112         // that use the web part titles.  We must use the Unicode characters instead of
113         // <span dir="ltr">, since the DisplayTitle is HTML Encoded before being rendered.
114         // (VSWhidbey 190501)
115         // private static string LRO = new String((char)0x202d, 1);  // left-to-right override
116         // private static string PDF = new String((char)0x202c, 1);  // pop directional formatting
117
118         // PERF: At compile-time, compute strings to append to DisplayTitle
119         // We chose to compute suffixes up to 20, since it is unlikely there will be more than
120         // 20 WebParts with the same title.
121         // The 0 element is currently not used, but is a placeholder so the index into the array
122         // matches the string.
123         private static string[] displayTitleSuffix = new string[] {
124             " [0]", " [1]", " [2]", " [3]", " [4]", " [5]", " [6]", " [7]", " [8]", " [9]", " [10]",
125             " [11]", " [12]", " [13]", " [14]", " [15]", " [16]", " [17]", " [18]", " [19]", " [20]" };
126
127         // Dictionary mapping a zone to the parts in the zone.  Used by GetAllWebPartsForZone
128         // to improve performance.
129         private IDictionary _partsForZone;
130
131         // Contains the IDs of WebParts and Child Controls already added.  WebParts and the child
132         // controls of GenericWebParts share the same namespace, meaning you cannot have a WebPart
133         // and a Child Control with the same ID. An exception is thrown if a WebPart or Child Control
134         // is added with a duplicate ID.
135         private IDictionary _partAndChildControlIDs;
136
137         // Contains the IDs of Zones already added.  An exception is thrown if a Zone is added with
138         // a duplicate ID.
139         private IDictionary _zoneIDs;
140
141         private WebPart _selectedWebPart;
142
143         private bool _renderClientScript;
144
145         private const string DragOverlayElementHtmlTemplate = @"
146 <div id=""{0}___Drag"" style=""display:none; position:absolute; z-index: 32000; filter:alpha(opacity=75)""></div>";
147         private const string ExportSensitiveDataWarningDeclaration = "ExportSensitiveDataWarningDeclaration";
148         private const string CloseProviderWarningDeclaration = "CloseProviderWarningDeclaration";
149         private const string DeleteWarningDeclaration = "DeleteWarningDeclaration";
150         private const string StartupScript = @"
151 <script type=""text/javascript"">
152
153 __wpm = new WebPartManager();
154 __wpm.overlayContainerElement = {0};
155 __wpm.personalizationScopeShared = {1};
156
157 var zoneElement;
158 var zoneObject;
159 {2}
160 </script>
161 ";
162         private const string ZoneScript = @"
163 zoneElement = document.getElementById('{0}');
164 if (zoneElement != null) {{
165     zoneObject = __wpm.AddZone(zoneElement, '{1}', {2}, {3}, '{4}');";
166
167         private const string ZonePartScript = @"
168     zoneObject.AddWebPart(document.getElementById('{0}'), {1}, {2});";
169
170         private const string ZoneEndScript = @"
171 }";
172
173         private const string AuthorizationFilterName = "AuthorizationFilter";
174         private const string ImportErrorMessageName = "ImportErrorMessage";
175         private const string ZoneIDName = "ZoneID";
176         private const string ZoneIndexName = "ZoneIndex";
177
178         internal const string ExportRootElement = "webParts";
179         internal const string ExportPartElement = "webPart";
180         internal const string ExportPartNamespaceAttribute = "xmlns";
181         internal const string ExportPartNamespaceValue = "http://schemas.microsoft.com/WebPart/v3";
182         internal const string ExportMetaDataElement = "metaData";
183         internal const string ExportTypeElement = "type";
184         internal const string ExportErrorMessageElement = "importErrorMessage";
185         internal const string ExportDataElement = "data";
186         internal const string ExportPropertiesElement = "properties";
187         internal const string ExportPropertyElement = "property";
188         internal const string ExportTypeNameAttribute = "name";
189         internal const string ExportUserControlSrcAttribute = "src";
190         internal const string ExportPropertyNameAttribute = "name";
191         internal const string ExportGenericPartPropertiesElement = "genericWebPartProperties";
192         internal const string ExportIPersonalizableElement = "ipersonalizable";
193         internal const string ExportPropertyTypeAttribute = "type";
194         internal const string ExportPropertyScopeAttribute = "scope";
195         internal const string ExportPropertyNullAttribute = "null";
196
197         private const string ExportTypeBool = "bool";
198         private const string ExportTypeInt = "int";
199         private const string ExportTypeChromeState = "chromestate";
200         private const string ExportTypeChromeType = "chrometype";
201         private const string ExportTypeColor = "color";
202         private const string ExportTypeDateTime = "datetime";
203         private const string ExportTypeDirection = "direction";
204         private const string ExportTypeDouble = "double";
205         private const string ExportTypeExportMode = "exportmode";
206         private const string ExportTypeFontSize = "fontsize";
207         private const string ExportTypeHelpMode = "helpmode";
208         private const string ExportTypeObject = "object";
209         private const string ExportTypeSingle = "single";
210         private const string ExportTypeString = "string";
211         private const string ExportTypeUnit = "unit";
212
213         /// <devdoc>
214         /// </devdoc>
215         public WebPartManager() {
216             _allowEventCancellation = true;
217             _displayMode = BrowseDisplayMode;
218             _webPartZones = new WebPartZoneCollection();
219             _partAndChildControlIDs = new HybridDictionary(true /* caseInsensitive */);
220             _zoneIDs = new HybridDictionary(true /* caseInsensitive */);
221         }
222
223         [
224         Browsable(false),
225         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
226         ]
227         public TransformerTypeCollection AvailableTransformers {
228             get {
229                 if (_availableTransformers == null) {
230                     _availableTransformers = CreateAvailableTransformers();
231                 }
232                 return _availableTransformers;
233             }
234         }
235
236         [
237         WebCategory("Behavior"),
238         WebSysDefaultValue(SR.WebPartManager_DefaultCloseProviderWarning),
239         WebSysDescription(SR.WebPartManager_CloseProviderWarning)
240         ]
241         public virtual string CloseProviderWarning {
242             get {
243                 object o = ViewState["CloseProviderWarning"];
244                 return (o != null) ? (string)o : SR.GetString(SR.WebPartManager_DefaultCloseProviderWarning);
245             }
246             set {
247                 ViewState["CloseProviderWarning"] = value;
248             }
249         }
250
251         [
252         Browsable(false),
253         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
254         ]
255         public WebPartConnectionCollection Connections {
256             get {
257                 WebPartConnectionCollection connections = new WebPartConnectionCollection(this);
258                 if (_staticConnections != null) {
259                     foreach (WebPartConnection connection in _staticConnections) {
260                         if (!Internals.ConnectionDeleted(connection)) {
261                             connections.Add(connection);
262                         }
263                     }
264                 }
265                 if (_dynamicConnections != null) {
266                     foreach (WebPartConnection connection in _dynamicConnections) {
267                         if (!Internals.ConnectionDeleted(connection)) {
268                             connections.Add(connection);
269                         }
270                     }
271                 }
272                 connections.SetReadOnly(SR.WebPartManager_ConnectionsReadOnly);
273                 return connections;
274             }
275         }
276
277         // Hide the Controls property from IntelliSense.  The developer should use the
278         // WebParts property instead.
279         [
280         EditorBrowsable(EditorBrowsableState.Never),
281         ]
282         public override ControlCollection Controls {
283             get {
284                 return base.Controls;
285             }
286         }
287
288         [
289         WebCategory("Behavior"),
290         WebSysDefaultValue(SR.WebPartManager_DefaultDeleteWarning),
291         WebSysDescription(SR.WebPartManager_DeleteWarning)
292         ]
293         public virtual string DeleteWarning {
294             get {
295                 object o = ViewState["DeleteWarning"];
296                 return (o != null) ? (string)o : SR.GetString(SR.WebPartManager_DefaultDeleteWarning);
297             }
298             set {
299                 ViewState["DeleteWarning"] = value;
300             }
301         }
302
303         [
304         Browsable(false),
305         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
306         ]
307         public virtual WebPartDisplayMode DisplayMode {
308             get {
309                 return _displayMode;
310             }
311             set {
312                 if (value == null) {
313                     throw new ArgumentNullException("value");
314                 }
315
316                 if (DisplayMode == value) {
317                     return;
318                 }
319
320                 if (SupportedDisplayModes.Contains(value) == false) {
321                     throw new ArgumentException(SR.GetString(SR.WebPartManager_InvalidDisplayMode), "value");
322                 }
323
324                 if (!value.IsEnabled(this)) {
325                     throw new ArgumentException(SR.GetString(SR.WebPartManager_DisabledDisplayMode), "value");
326                 }
327
328                 WebPartDisplayModeCancelEventArgs dmce = new WebPartDisplayModeCancelEventArgs(value);
329                 OnDisplayModeChanging(dmce);
330
331                 if (_allowEventCancellation && dmce.Cancel) {
332                     return;
333                 }
334
335                 // Custom display modes can take actions like this in the OnDisplayModeChanging method.
336                 // For example:
337                 // public override void OnDisplayModeChanging(WebPartDisplayModeCancelEventArgs e) {
338                 //     base.OnDisplayModeChanging(e);
339                 //     if (e.Cancel) return;
340                 //     if (DisplayMode == CustomDisplayMode) {
341                 //         // Take some actions and set e.Cancel=true if appropriate
342                 //     }
343                 // }
344
345                 // End web part connecting if necessary
346                 if ((DisplayMode == ConnectDisplayMode) && (SelectedWebPart != null)) {
347                     EndWebPartConnecting();
348                     if (SelectedWebPart != null) {
349                         // WebPartConnectModeChanging event was cancelled
350                         return;
351                     }
352                 }
353
354                 // End web part editing if necessary
355                 if ((DisplayMode == EditDisplayMode) && (SelectedWebPart != null)) {
356                     EndWebPartEditing();
357                     if (SelectedWebPart != null) {
358                         // WebPartEditModeChanging event was cancelled
359                         return;
360                     }
361                 }
362
363                 WebPartDisplayModeEventArgs dme = new WebPartDisplayModeEventArgs(DisplayMode);
364                 _displayMode = value;
365                 OnDisplayModeChanged(dme);
366             }
367         }
368
369         [
370         Browsable(false),
371         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
372         ]
373         public WebPartDisplayModeCollection DisplayModes {
374             get {
375                 if (_displayModes == null) {
376                     _displayModes = CreateDisplayModes();
377                     _displayModes.SetReadOnly(SR.WebPartManager_DisplayModesReadOnly);
378                 }
379
380                 return _displayModes;
381             }
382         }
383
384         protected internal WebPartConnectionCollection DynamicConnections {
385             get {
386                 if (_dynamicConnections == null) {
387                     _dynamicConnections = new WebPartConnectionCollection(this);
388                 }
389                 return _dynamicConnections;
390             }
391         }
392
393         [
394         DefaultValue(true),
395         WebCategory("Behavior"),
396         WebSysDescription(SR.WebPartManager_EnableClientScript)
397         ]
398         public virtual bool EnableClientScript {
399             get {
400                 object o = ViewState["EnableClientScript"];
401                 return (o != null) ? (bool)o : true;
402             }
403             set {
404                 ViewState["EnableClientScript"] = value;
405             }
406         }
407
408         // Theming must be enabled, so the WebPart child controls have theming enabled
409         [
410         Browsable(false),
411         DefaultValue(true),
412         EditorBrowsable(EditorBrowsableState.Never),
413         ]
414         public override bool EnableTheming {
415             get {
416                 return true;
417             }
418             set {
419                 throw new NotSupportedException(SR.GetString(SR.WebPartManager_CantSetEnableTheming));
420             }
421         }
422
423         [
424         WebCategory("Behavior"),
425         WebSysDefaultValue(SR.WebPartChrome_ConfirmExportSensitive),
426         WebSysDescription(SR.WebPartManager_ExportSensitiveDataWarning)
427         ]
428         public virtual string ExportSensitiveDataWarning {
429             get {
430                 object o = ViewState["ExportSensitiveDataWarning"];
431                 return (o != null) ? (string)o : SR.GetString(SR.WebPartChrome_ConfirmExportSensitive);
432             }
433             set {
434                 ViewState["ExportSensitiveDataWarning"] = value;
435             }
436         }
437
438         [
439         EditorBrowsable(EditorBrowsableState.Never),
440         ]
441         protected WebPartManagerInternals Internals {
442             get {
443                 if (_internals == null) {
444                     _internals = new WebPartManagerInternals(this);
445                 }
446                 return _internals;
447             }
448         }
449
450         /// <devdoc>
451         /// </devdoc>
452         protected virtual bool IsCustomPersonalizationStateDirty {
453             get {
454                 return _hasDataChanged;
455             }
456         }
457
458         // PermissionSet that allows only Execution and AspNetHostingPermissionLevel.Medium.
459         // AspNetHostingPermissionLevel.Medium is needed to call BuildManager.GetType().
460         // Used for during Import for type deserialization.
461         protected virtual PermissionSet MediumPermissionSet {
462             get {
463                 if (_mediumPermissionSet == null) {
464                     _mediumPermissionSet = new PermissionSet(PermissionState.None);
465                     _mediumPermissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
466                     _mediumPermissionSet.AddPermission(new AspNetHostingPermission(AspNetHostingPermissionLevel.Medium));
467                 }
468                 return _mediumPermissionSet;
469             }
470         }
471
472         // PermissionSet that allows only Execution and AspNetHostingPermissionLevel.Minimal.
473         // Used for during Import for everything except type deserialization.
474         protected virtual PermissionSet MinimalPermissionSet {
475             get {
476                 if (_minimalPermissionSet == null) {
477                     _minimalPermissionSet = new PermissionSet(PermissionState.None);
478                     _minimalPermissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
479                     _minimalPermissionSet.AddPermission(new AspNetHostingPermission(AspNetHostingPermissionLevel.Minimal));
480                 }
481                 return _minimalPermissionSet;
482             }
483         }
484
485         /// <devdoc>
486         /// </devdoc>
487         [
488         DefaultValue(null),
489         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
490         NotifyParentProperty(true),
491         PersistenceMode(PersistenceMode.InnerProperty),
492         WebCategory("Behavior"),
493         WebSysDescription(SR.WebPartManager_Personalization)
494         ]
495         public WebPartPersonalization Personalization {
496             get {
497                 if (_personalization == null) {
498                     _personalization = CreatePersonalization();
499                 }
500
501                 return _personalization;
502             }
503         }
504
505         internal bool RenderClientScript {
506             get {
507                 return _renderClientScript;
508             }
509         }
510
511         [
512         Browsable(false),
513         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
514         ]
515         public WebPart SelectedWebPart {
516             get {
517                 return _selectedWebPart;
518             }
519         }
520
521         [
522         Browsable(false),
523         DefaultValue(""),
524         EditorBrowsable(EditorBrowsableState.Never),
525         ]
526         public override string SkinID {
527             get {
528                 return String.Empty;
529             }
530             set {
531                 throw new NotSupportedException(SR.GetString(SR.NoThemingSupport, this.GetType().Name));
532             }
533         }
534
535         [
536         DefaultValue(null),
537         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
538         MergableProperty(false),
539         PersistenceMode(PersistenceMode.InnerProperty),
540         WebCategory("Behavior"),
541         WebSysDescription(SR.WebPartManager_StaticConnections),
542         ]
543         public WebPartConnectionCollection StaticConnections {
544             get {
545                 if (_staticConnections == null) {
546                     _staticConnections = new WebPartConnectionCollection(this);
547                 }
548                 return _staticConnections;
549             }
550         }
551
552         [
553         Browsable(false),
554         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
555         ]
556         public WebPartDisplayModeCollection SupportedDisplayModes {
557             get {
558                 if (_supportedDisplayModes == null) {
559                     _supportedDisplayModes = new WebPartDisplayModeCollection();
560
561                     foreach (WebPartDisplayMode mode in DisplayModes) {
562                         if (mode.AssociatedWithToolZone == false) {
563                             _supportedDisplayModes.Add(mode);
564                         }
565                     }
566
567                     _supportedDisplayModes.SetReadOnly(SR.WebPartManager_DisplayModesReadOnly);
568                 }
569                 return _supportedDisplayModes;
570             }
571         }
572
573         // Only call PermitOnly() in legacy CAS mode.  In the v4 CAS model, calling PermitOnly() would prevent us from calling
574         // Activator.CreateInstance() on types in App_Code (assuming it is non-APTCA). (Dev10 Bug 807117)
575         private bool UsePermitOnly {
576             get {
577                 if (!_usePermitOnly.HasValue) {
578                     _usePermitOnly =  RuntimeConfig.GetAppConfig().Trust.LegacyCasModel;
579                 }
580                 return _usePermitOnly.Value;
581             }
582         }
583
584         [
585         Bindable(false),
586         Browsable(false),
587         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
588         EditorBrowsable(EditorBrowsableState.Never),
589         ]
590         public override bool Visible {
591             get {
592                 // Even though we are a non-visual control, this returns true, because we want our
593                 // child controls (the WebParts) to be Visible.
594                 return true;
595             }
596             set {
597                 throw new NotSupportedException(SR.GetString(SR.ControlNonVisual, this.GetType().Name));
598             }
599         }
600
601         /// <devdoc>
602         /// All the WebParts on the page.
603         /// </devdoc>
604         [
605         Browsable(false),
606         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
607         ]
608         public WebPartCollection WebParts {
609             get {
610                 // PERF: Consider changing WebPartCollection so it just wraps the ControlCollection,
611                 // instead of copying the controls to a new collection.
612                 if (HasControls()) {
613                     return new WebPartCollection(Controls);
614                 }
615                 else {
616                     return new WebPartCollection();
617                 }
618             }
619         }
620
621         [
622         Browsable(false),
623         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
624         ]
625         public WebPartZoneCollection Zones {
626             get {
627                 return _webPartZones;
628             }
629         }
630
631         [
632         WebCategory("Action"),
633         WebSysDescription(SR.WebPartManager_AuthorizeWebPart)
634         ]
635         public event WebPartAuthorizationEventHandler AuthorizeWebPart {
636             add {
637                 Events.AddHandler(AuthorizeWebPartEvent, value);
638             }
639             remove {
640                 Events.RemoveHandler(AuthorizeWebPartEvent, value);
641             }
642         }
643
644         [
645         WebCategory("Action"),
646         WebSysDescription(SR.WebPartManager_ConnectionsActivated)
647         ]
648         public event EventHandler ConnectionsActivated {
649             add {
650                 Events.AddHandler(ConnectionsActivatedEvent, value);
651             }
652             remove {
653                 Events.RemoveHandler(ConnectionsActivatedEvent, value);
654             }
655         }
656
657         [
658         WebCategory("Action"),
659         WebSysDescription(SR.WebPartManager_ConnectionsActivating)
660         ]
661         public event EventHandler ConnectionsActivating {
662             add {
663                 Events.AddHandler(ConnectionsActivatingEvent, value);
664             }
665             remove {
666                 Events.RemoveHandler(ConnectionsActivatingEvent, value);
667             }
668         }
669
670         [
671         WebCategory("Action"),
672         WebSysDescription(SR.WebPartManager_DisplayModeChanged)
673         ]
674         public event WebPartDisplayModeEventHandler DisplayModeChanged {
675             add {
676                 Events.AddHandler(DisplayModeChangedEvent, value);
677             }
678             remove {
679                 Events.RemoveHandler(DisplayModeChangedEvent, value);
680             }
681         }
682
683         [
684         WebCategory("Action"),
685         WebSysDescription(SR.WebPartManager_DisplayModeChanging)
686         ]
687         public event WebPartDisplayModeCancelEventHandler DisplayModeChanging {
688             add {
689                 Events.AddHandler(DisplayModeChangingEvent, value);
690             }
691             remove {
692                 Events.RemoveHandler(DisplayModeChangingEvent, value);
693             }
694         }
695
696         [
697         WebCategory("Action"),
698         WebSysDescription(SR.WebPartManager_SelectedWebPartChanged)
699         ]
700         public event WebPartEventHandler SelectedWebPartChanged {
701             add {
702                 Events.AddHandler(SelectedWebPartChangedEvent, value);
703             }
704             remove {
705                 Events.RemoveHandler(SelectedWebPartChangedEvent, value);
706             }
707         }
708
709         [
710         WebCategory("Action"),
711         WebSysDescription(SR.WebPartManager_SelectedWebPartChanging)
712         ]
713         public event WebPartCancelEventHandler SelectedWebPartChanging {
714             add {
715                 Events.AddHandler(SelectedWebPartChangingEvent, value);
716             }
717             remove {
718                 Events.RemoveHandler(SelectedWebPartChangingEvent, value);
719             }
720         }
721
722         [
723         WebCategory("Action"),
724         WebSysDescription(SR.WebPartManager_WebPartAdded)
725         ]
726         public event WebPartEventHandler WebPartAdded {
727             add {
728                 Events.AddHandler(WebPartAddedEvent, value);
729             }
730             remove {
731                 Events.RemoveHandler(WebPartAddedEvent, value);
732             }
733         }
734
735         [
736         WebCategory("Action"),
737         WebSysDescription(SR.WebPartManager_WebPartAdding)
738         ]
739         public event WebPartAddingEventHandler WebPartAdding {
740             add {
741                 Events.AddHandler(WebPartAddingEvent, value);
742             }
743             remove {
744                 Events.RemoveHandler(WebPartAddingEvent, value);
745             }
746         }
747
748         [
749         WebCategory("Action"),
750         WebSysDescription(SR.WebPartManager_WebPartClosed)
751         ]
752         public event WebPartEventHandler WebPartClosed {
753             add {
754                 Events.AddHandler(WebPartClosedEvent, value);
755             }
756             remove {
757                 Events.RemoveHandler(WebPartClosedEvent, value);
758             }
759         }
760
761         [
762         WebCategory("Action"),
763         WebSysDescription(SR.WebPartManager_WebPartClosing)
764         ]
765         public event WebPartCancelEventHandler WebPartClosing {
766             add {
767                 Events.AddHandler(WebPartClosingEvent, value);
768             }
769             remove {
770                 Events.RemoveHandler(WebPartClosingEvent, value);
771             }
772         }
773
774         [
775         WebCategory("Action"),
776         WebSysDescription(SR.WebPartManager_WebPartDeleted)
777         ]
778         public event WebPartEventHandler WebPartDeleted {
779             add {
780                 Events.AddHandler(WebPartDeletedEvent, value);
781             }
782             remove {
783                 Events.RemoveHandler(WebPartDeletedEvent, value);
784             }
785         }
786
787         [
788         WebCategory("Action"),
789         WebSysDescription(SR.WebPartManager_WebPartDeleting)
790         ]
791         public event WebPartCancelEventHandler WebPartDeleting {
792             add {
793                 Events.AddHandler(WebPartDeletingEvent, value);
794             }
795             remove {
796                 Events.RemoveHandler(WebPartDeletingEvent, value);
797             }
798         }
799
800         [
801         WebCategory("Action"),
802         WebSysDescription(SR.WebPartManager_WebPartMoved)
803         ]
804         public event WebPartEventHandler WebPartMoved {
805             add {
806                 Events.AddHandler(WebPartMovedEvent, value);
807             }
808             remove {
809                 Events.RemoveHandler(WebPartMovedEvent, value);
810             }
811         }
812
813         [
814         WebCategory("Action"),
815         WebSysDescription(SR.WebPartManager_WebPartMoving)
816         ]
817         public event WebPartMovingEventHandler WebPartMoving {
818             add {
819                 Events.AddHandler(WebPartMovingEvent, value);
820             }
821             remove {
822                 Events.RemoveHandler(WebPartMovingEvent, value);
823             }
824         }
825
826         [
827         WebCategory("Action"),
828         WebSysDescription(SR.WebPartManager_WebPartsConnected)
829         ]
830         public event WebPartConnectionsEventHandler WebPartsConnected {
831             add {
832                 Events.AddHandler(WebPartsConnectedEvent, value);
833             }
834             remove {
835                 Events.RemoveHandler(WebPartsConnectedEvent, value);
836             }
837         }
838
839         [
840         WebCategory("Action"),
841         WebSysDescription(SR.WebPartManager_WebPartsConnecting)
842         ]
843         public event WebPartConnectionsCancelEventHandler WebPartsConnecting {
844             add {
845                 Events.AddHandler(WebPartsConnectingEvent, value);
846             }
847             remove {
848                 Events.RemoveHandler(WebPartsConnectingEvent, value);
849             }
850         }
851
852         [
853         WebCategory("Action"),
854         WebSysDescription(SR.WebPartManager_WebPartsDisconnected)
855         ]
856         public event WebPartConnectionsEventHandler WebPartsDisconnected {
857             add {
858                 Events.AddHandler(WebPartsDisconnectedEvent, value);
859             }
860             remove {
861                 Events.RemoveHandler(WebPartsDisconnectedEvent, value);
862             }
863         }
864
865         [
866         WebCategory("Action"),
867         WebSysDescription(SR.WebPartManager_WebPartsDisconnecting)
868         ]
869         public event WebPartConnectionsCancelEventHandler WebPartsDisconnecting {
870             add {
871                 Events.AddHandler(WebPartsDisconnectingEvent, value);
872             }
873             remove {
874                 Events.RemoveHandler(WebPartsDisconnectingEvent, value);
875             }
876         }
877
878         protected virtual void ActivateConnections() {
879             try {
880                 // ActivateConnections() is called as a result of no user action, so the events
881                 // should not be cancellable. (VSWhidbey 516012)
882                 _allowEventCancellation = false;
883                 foreach (WebPartConnection connection in ConnectionsToActivate()) {
884                     connection.Activate();
885                 }
886             }
887             finally {
888                 _allowEventCancellation = true;
889             }
890         }
891
892         // Called by WebPartManagerInternals
893         internal void AddWebPart(WebPart webPart) {
894             ((WebPartManagerControlCollection)Controls).AddWebPart(webPart);
895         }
896
897         private WebPart AddDynamicWebPartToZone(WebPart webPart, WebPartZoneBase zone, int zoneIndex) {
898             Debug.Assert(Personalization.IsModifiable);
899
900             // Zone should not be set on a dynamic web part being added to the page for the first time
901             Debug.Assert(webPart.Zone == null);
902
903             // Only add WebPart if IsAuthorized(webPart) == true
904             if (!IsAuthorized(webPart)) {
905                 return null;
906             }
907
908             WebPart newWebPart = CopyWebPart(webPart);
909             Internals.SetIsStatic(newWebPart, false);
910             Internals.SetIsShared(newWebPart, Personalization.Scope == PersonalizationScope.Shared);
911
912             AddWebPartToZone(newWebPart, zone, zoneIndex);
913             Internals.AddWebPart(newWebPart);
914
915             // We set the personalized properties on the added WebPart AFTER it has been added to the
916             // control tree, since we want to exactly recreate the process the WebPart will go through
917             // when it is added from Personalization.
918             Personalization.CopyPersonalizationState(webPart, newWebPart);
919
920             // Raise event at very end of Add method
921             OnWebPartAdded(new WebPartEventArgs(newWebPart));
922
923             return newWebPart;
924         }
925
926         // Returns the WebPart that was actually added.  For an existing Closed WebPart, this is a reference
927         // to the webPart parameter.  For a new DynamicWebPart, this will be a copy of the webPart parameter.
928         public WebPart AddWebPart(WebPart webPart, WebPartZoneBase zone, int zoneIndex) {
929             Personalization.EnsureEnabled(/* ensureModifiable */ true);
930
931             if (webPart == null) {
932                 throw new ArgumentNullException("webPart");
933             }
934             // Do not check that Controls.Contains(webPart), since this will be called on a WebPart
935             // before it is added to the Controls collection.
936             if (zone == null) {
937                 throw new ArgumentNullException("zone");
938             }
939             if (_webPartZones.Contains(zone) == false) {
940                 throw new ArgumentException(SR.GetString(SR.WebPartManager_MustRegister), "zone");
941             }
942             if (zoneIndex < 0) {
943                 throw new ArgumentOutOfRangeException("zoneIndex");
944             }
945             if (webPart.Zone != null && !webPart.IsClosed) {
946                 throw new ArgumentException(SR.GetString(SR.WebPartManager_AlreadyInZone), "webPart");
947             }
948
949             WebPartAddingEventArgs e = new WebPartAddingEventArgs(webPart, zone, zoneIndex);
950             OnWebPartAdding(e);
951             if (_allowEventCancellation && e.Cancel) {
952                 return null;
953             }
954
955             WebPart addedWebPart;
956
957             // If a part is already in the controls collection, dynamic or static, just make it
958             // not closed and add it to the specified zone
959             if (Controls.Contains(webPart)) {
960                 addedWebPart = webPart;
961                 AddWebPartToZone(webPart, zone, zoneIndex);
962                 OnWebPartAdded(new WebPartEventArgs(addedWebPart));
963             } else {
964                 addedWebPart = AddDynamicWebPartToZone(webPart, zone, zoneIndex);
965                 // OnWebPartAdded() is called by AddDynamicWebPartToZone
966             }
967
968 #if DEBUG
969             CheckPartZoneIndexes(zone);
970 #endif
971
972             return addedWebPart;
973         }
974
975         /// <devdoc>
976         /// Adds the part to the dictionary mapping zones to parts.
977         /// </devdoc>
978         private void AddWebPartToDictionary(WebPart webPart) {
979             if (_partsForZone != null) {
980                 string zoneID = Internals.GetZoneID(webPart);
981                 if (!String.IsNullOrEmpty(zoneID)) {
982                     SortedList partsForZone = (SortedList)(_partsForZone[zoneID]);
983                     if (partsForZone == null) {
984                         partsForZone = new SortedList(new WebPart.ZoneIndexComparer());
985                         _partsForZone[zoneID] = partsForZone;
986                     }
987                     partsForZone.Add(webPart, null);
988                 }
989             }
990         }
991
992         /// <devdoc>
993         /// Adds a web part to a zone at the specified zoneIndex, and renumbers all the parts in the zone
994         /// sequentially.
995         /// </devdoc>
996         private void AddWebPartToZone(WebPart webPart, WebPartZoneBase zone, int zoneIndex) {
997             Debug.Assert(webPart.Zone == null || webPart.IsClosed);
998
999             // All the parts for the zone
1000             IList allParts = GetAllWebPartsForZone(zone);
1001
1002             // The parts for the zone that were actually rendered
1003             WebPartCollection renderedParts = GetWebPartsForZone(zone);
1004
1005             // The zoneIndex parameter is the desired index in the renderedParts collection.
1006             // Calculate the destination index into the allParts collection. (VSWhidbey 77719)
1007             int allPartsDestinationIndex;
1008             if (zoneIndex < renderedParts.Count) {
1009                 WebPart successor = renderedParts[zoneIndex];
1010                 Debug.Assert(allParts.Contains(successor));
1011                 allPartsDestinationIndex = allParts.IndexOf(successor);
1012             }
1013             else {
1014                 allPartsDestinationIndex = allParts.Count;
1015             }
1016
1017             // Renumber all parts in the zone, leaving room for the added part
1018             for (int i = 0; i < allPartsDestinationIndex; i++) {
1019                 WebPart part = ((WebPart)allParts[i]);
1020                 Internals.SetZoneIndex(part, i);
1021             }
1022             for (int i = allPartsDestinationIndex; i < allParts.Count; i++) {
1023                 WebPart part = ((WebPart)allParts[i]);
1024                 Internals.SetZoneIndex(part, i + 1);
1025             }
1026
1027             // Set the part index and add to destination zone
1028             Internals.SetZoneIndex(webPart, allPartsDestinationIndex);
1029             Internals.SetZoneID(webPart, zone.ID);
1030             Internals.SetIsClosed(webPart, false);
1031
1032             _hasDataChanged = true;
1033
1034             AddWebPartToDictionary(webPart);
1035         }
1036
1037         public virtual void BeginWebPartConnecting(WebPart webPart) {
1038             Personalization.EnsureEnabled(/* ensureModifiable */ true);
1039
1040             if (webPart == null) {
1041                 throw new ArgumentNullException("webPart");
1042             }
1043
1044             if (webPart.IsClosed) {
1045                 throw new ArgumentException(SR.GetString(SR.WebPartManager_CantBeginConnectingClosed), "webPart");
1046             }
1047
1048             if (!Controls.Contains(webPart)) {
1049                 throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "webPart");
1050             }
1051
1052             if (DisplayMode != ConnectDisplayMode) {
1053                 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_MustBeInConnect));
1054             }
1055
1056             if (webPart == SelectedWebPart) {
1057                 throw new ArgumentException(SR.GetString(SR.WebPartManager_AlreadyInConnect), "webPart");
1058             }
1059
1060             WebPartCancelEventArgs ce = new WebPartCancelEventArgs(webPart);
1061             OnSelectedWebPartChanging(ce);
1062             if (_allowEventCancellation && ce.Cancel) {
1063                 return;
1064             }
1065
1066             if (SelectedWebPart != null) {
1067                 EndWebPartConnecting();
1068                 if (SelectedWebPart != null) {
1069                     // The ConnectModeChange was cancelled
1070                     return;
1071                 }
1072             }
1073
1074             SetSelectedWebPart(webPart);
1075
1076             Internals.CallOnConnectModeChanged(webPart);
1077
1078             OnSelectedWebPartChanged(new WebPartEventArgs(webPart));
1079         }
1080
1081         public virtual void BeginWebPartEditing(WebPart webPart) {
1082             Personalization.EnsureEnabled(/* ensureModifiable */ true);
1083
1084             if (webPart == null) {
1085                 throw new ArgumentNullException("webPart");
1086             }
1087
1088             if (webPart.IsClosed) {
1089                 throw new ArgumentException(SR.GetString(SR.WebPartManager_CantBeginEditingClosed), "webPart");
1090             }
1091
1092             if (!Controls.Contains(webPart)) {
1093                 throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "webPart");
1094             }
1095
1096             if (DisplayMode != EditDisplayMode) {
1097                 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_MustBeInEdit));
1098             }
1099
1100             if (webPart == SelectedWebPart) {
1101                 throw new ArgumentException(SR.GetString(SR.WebPartManager_AlreadyInEdit), "webPart");
1102             }
1103
1104             WebPartCancelEventArgs ce = new WebPartCancelEventArgs(webPart);
1105             OnSelectedWebPartChanging(ce);
1106             if (_allowEventCancellation && ce.Cancel) {
1107                 return;
1108             }
1109
1110             if (SelectedWebPart != null) {
1111                 EndWebPartEditing();
1112                 if (SelectedWebPart != null) {
1113                     // The EditModeChange was cancelled
1114                     return;
1115                 }
1116             }
1117
1118             SetSelectedWebPart(webPart);
1119
1120             Internals.CallOnEditModeChanged(webPart);
1121
1122             OnSelectedWebPartChanged(new WebPartEventArgs(webPart));
1123         }
1124
1125 #if DEBUG
1126         /// <devdoc>
1127         /// Checks that the web parts in a zone are numbered sequentially.  This invariant
1128         /// should hold at the exit of AddWebPart, CloseWebPart, DeleteWebPart, MoveWebPart, and RegisterZone.
1129         /// </devdoc>
1130         private void CheckPartZoneIndexes(WebPartZoneBase zone) {
1131             ICollection parts = GetAllWebPartsForZone(zone);
1132             int index = 0;
1133             foreach (WebPart part in parts) {
1134                 if (part.ZoneIndex != index) {
1135                     System.Text.StringBuilder builder = new System.Text.StringBuilder();
1136                     builder.Append("Title\tZone\tZoneIndex");
1137                     foreach (WebPart part2 in Controls) {
1138                         string zoneTitle = (part2.Zone == null) ? "null" : part2.Zone.DisplayTitle;
1139                         builder.Append(part2.DisplayTitle + "\t" + zoneTitle + "\t" + part2.ZoneIndex);
1140                     }
1141                     Debug.Assert(false, builder.ToString());
1142                     return;
1143                 }
1144                 index++;
1145             }
1146         }
1147 #endif // DEBUG
1148
1149         protected virtual bool CheckRenderClientScript() {
1150             bool renderClientScript = false;
1151
1152             if (EnableClientScript && Page != null) {
1153                 HttpBrowserCapabilities browserCaps = Page.Request.Browser;
1154
1155                 // Win32 IE5.5+ and JScript 5.5+
1156                 if (browserCaps.Win32 && (browserCaps.MSDomVersion.CompareTo(new Version(5, 5)) >= 0)) {
1157                     renderClientScript = true;
1158                 }
1159             }
1160
1161             return renderClientScript;
1162         }
1163
1164         // When a Zone is deleted, any web parts in that zone should move to the page catalog.
1165         // VSWhidbey 77708
1166         private void CloseOrphanedParts() {
1167             // PERF: Use Controls instead of WebParts property, to avoid creating another collection
1168             if (HasControls()) {
1169                 try {
1170                     // CloseOrphanedParts() is called as a result of no user action, so the events
1171                     // should not be cancellable. (VSWhidbey 516012)
1172                     _allowEventCancellation = false;
1173                     foreach (WebPart part in Controls) {
1174                         if (part.IsOrphaned) {
1175                             CloseWebPart(part);
1176                         }
1177                     }
1178                 }
1179                 finally {
1180                     _allowEventCancellation = true;
1181                 }
1182             }
1183         }
1184
1185         public bool CanConnectWebParts(WebPart provider, ProviderConnectionPoint providerConnectionPoint,
1186                                        WebPart consumer, ConsumerConnectionPoint consumerConnectionPoint) {
1187             return CanConnectWebParts(provider, providerConnectionPoint, consumer, consumerConnectionPoint, null);
1188         }
1189
1190         public virtual bool CanConnectWebParts(WebPart provider, ProviderConnectionPoint providerConnectionPoint,
1191                                                WebPart consumer, ConsumerConnectionPoint consumerConnectionPoint,
1192                                                WebPartTransformer transformer) {
1193             return CanConnectWebPartsCore(provider, providerConnectionPoint, consumer, consumerConnectionPoint,
1194                                           transformer, false);
1195         }
1196
1197         private bool CanConnectWebPartsCore(WebPart provider, ProviderConnectionPoint providerConnectionPoint,
1198                                             WebPart consumer, ConsumerConnectionPoint consumerConnectionPoint,
1199                                             WebPartTransformer transformer, bool throwOnError) {
1200             if (!Personalization.IsModifiable) {
1201                 if (throwOnError) {
1202                     // Will throw appropriate exception
1203                     Personalization.EnsureEnabled(/* ensureModifiable */ true);
1204                 }
1205                 else {
1206                     return false;
1207                 }
1208             }
1209
1210             if (provider == null) {
1211                 throw new ArgumentNullException("provider");
1212             }
1213             if (!Controls.Contains(provider)) {
1214                 throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "provider");
1215             }
1216
1217             if (consumer == null) {
1218                 throw new ArgumentNullException("consumer");
1219             }
1220             if (!Controls.Contains(consumer)) {
1221                 throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "consumer");
1222             }
1223
1224             if (providerConnectionPoint == null) {
1225                 throw new ArgumentNullException("providerConnectionPoint");
1226             }
1227             if (consumerConnectionPoint == null) {
1228                 throw new ArgumentNullException("consumerConnectionPoint");
1229             }
1230
1231             Control providerControl = provider.ToControl();
1232             Control consumerControl = consumer.ToControl();
1233
1234             if (providerConnectionPoint.ControlType != providerControl.GetType()) {
1235                 throw new ArgumentException(SR.GetString(SR.WebPartManager_InvalidConnectionPoint), "providerConnectionPoint");
1236             }
1237             if (consumerConnectionPoint.ControlType != consumerControl.GetType()) {
1238                 throw new ArgumentException(SR.GetString(SR.WebPartManager_InvalidConnectionPoint), "consumerConnectionPoint");
1239             }
1240
1241             if (provider == consumer) {
1242                 if (throwOnError) {
1243                     throw new InvalidOperationException(SR.GetString(SR.WebPartManager_CantConnectToSelf));
1244                 }
1245                 else {
1246                     return false;
1247                 }
1248             }
1249
1250             if (provider.IsClosed) {
1251                 if (throwOnError) {
1252                     throw new InvalidOperationException(SR.GetString(SR.WebPartManager_CantConnectClosed, provider.ID));
1253                 }
1254                 else {
1255                     return false;
1256                 }
1257             }
1258
1259             if (consumer.IsClosed) {
1260                 if (throwOnError) {
1261                     throw new InvalidOperationException(SR.GetString(SR.WebPartManager_CantConnectClosed, consumer.ID));
1262                 }
1263                 else {
1264                     return false;
1265                 }
1266             }
1267
1268             if (!providerConnectionPoint.GetEnabled(providerControl)) {
1269                 if (throwOnError) {
1270                     throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_DisabledConnectionPoint, providerConnectionPoint.ID, provider.ID));
1271                 }
1272                 else {
1273                     return false;
1274                 }
1275             }
1276
1277             if (!consumerConnectionPoint.GetEnabled(consumerControl)) {
1278                 if (throwOnError) {
1279                     throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_DisabledConnectionPoint, consumerConnectionPoint.ID, consumer.ID));
1280                 }
1281                 else {
1282                     return false;
1283                 }
1284             }
1285
1286             // Check AllowsMultipleConnections on each ConnectionPoint
1287             if (!providerConnectionPoint.AllowsMultipleConnections) {
1288                 foreach (WebPartConnection c in Connections) {
1289                     if (c.Provider == provider && c.ProviderConnectionPoint == providerConnectionPoint) {
1290                         if (throwOnError) {
1291                             throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_Duplicate, providerConnectionPoint.ID, provider.ID));
1292                         }
1293                         else {
1294                             return false;
1295                         }
1296                     }
1297                 }
1298             }
1299
1300             if (!consumerConnectionPoint.AllowsMultipleConnections) {
1301                 foreach (WebPartConnection c in Connections) {
1302                     if (c.Consumer == consumer && c.ConsumerConnectionPoint == consumerConnectionPoint) {
1303                         if (throwOnError) {
1304                             throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_Duplicate, consumerConnectionPoint.ID, consumer.ID));
1305                         }
1306                         else {
1307                             return false;
1308                         }
1309                     }
1310                 }
1311             }
1312
1313             if (transformer == null) {
1314                 if (providerConnectionPoint.InterfaceType != consumerConnectionPoint.InterfaceType) {
1315                     if (throwOnError) {
1316                         throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_NoCommonInterface,
1317                             new string[] {providerConnectionPoint.DisplayName, provider.ID,
1318                                 consumerConnectionPoint.DisplayName, consumer.ID}));
1319                     }
1320                     else {
1321                         return false;
1322                     }
1323                 }
1324
1325                 ConnectionInterfaceCollection secondaryInterfaces = providerConnectionPoint.GetSecondaryInterfaces(providerControl);
1326                 if (!consumerConnectionPoint.SupportsConnection(consumerControl, secondaryInterfaces)) {
1327                     if (throwOnError) {
1328                         throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_IncompatibleSecondaryInterfaces, new string[] {
1329                                 consumerConnectionPoint.DisplayName, consumer.ID,
1330                                 providerConnectionPoint.DisplayName, provider.ID}));
1331                     }
1332                     else {
1333                         return false;
1334                     }
1335                 }
1336             }
1337             else {
1338                 Type transformerType = transformer.GetType();
1339
1340                 if (!AvailableTransformers.Contains(transformerType)) {
1341                     throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_TransformerNotAvailable, transformerType.FullName));
1342                 }
1343
1344                 // Check matching interfaces on connection points and transformer attribute.
1345                 // Note that we require the connection interfaces to match exactly.  We do not match
1346                 // a derived interface type.  This is because we want to simplify the interface matching
1347                 // algorithm when transformers are involved.  If we allowed derived interfaces to match,
1348                 // then we would to take into account the "closest" match if multiple transformers
1349                 // have compatible interfaces.
1350                 Type transformerConsumerType = WebPartTransformerAttribute.GetConsumerType(transformerType);
1351                 Type transformerProviderType = WebPartTransformerAttribute.GetProviderType(transformerType);
1352                 if (providerConnectionPoint.InterfaceType != transformerConsumerType) {
1353                     if (throwOnError) {
1354                         throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_IncompatibleProviderTransformer,
1355                             providerConnectionPoint.DisplayName, provider.ID, transformerType.FullName));
1356                     }
1357                     else {
1358                         return false;
1359                     }
1360                 }
1361                 if (transformerProviderType != consumerConnectionPoint.InterfaceType) {
1362                     if (throwOnError) {
1363                         throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_IncompatibleConsumerTransformer,
1364                             transformerType.FullName, consumerConnectionPoint.DisplayName, consumer.ID));
1365                     }
1366                     else {
1367                         return false;
1368                     }
1369                 }
1370
1371                 // A transformer never provides any secondary interfaces
1372                 if (!consumerConnectionPoint.SupportsConnection(consumerControl, ConnectionInterfaceCollection.Empty)) {
1373                     if (throwOnError) {
1374                         throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_ConsumerRequiresSecondaryInterfaces,
1375                             consumerConnectionPoint.DisplayName, consumer.ID));
1376                     }
1377                     else {
1378                         return false;
1379                     }
1380                 }
1381
1382             }
1383
1384             return true;
1385         }
1386
1387         public void CloseWebPart(WebPart webPart) {
1388             CloseOrDeleteWebPart(webPart, /* delete */ false);
1389         }
1390
1391         private void CloseOrDeleteWebPart(WebPart webPart, bool delete) {
1392             Personalization.EnsureEnabled(/* ensureModifiable */ true);
1393
1394             if (webPart == null) {
1395                 throw new ArgumentNullException("webPart");
1396             }
1397             if (!Controls.Contains(webPart)) {
1398                 throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "webPart");
1399             }
1400
1401             if (!delete && webPart.IsClosed) {
1402                 // Throw an exception instead of just returning.  If the shared user and per user close
1403                 // a WebPart at the same time, then the WebPartZoneBase should not call CloseWebPart
1404                 // if the WebPart is now closed.
1405                 throw new ArgumentException(SR.GetString(SR.WebPartManager_AlreadyClosed), "webPart");
1406             }
1407
1408             if (delete) {
1409                 if (webPart.IsStatic) {
1410                     // Can't delete static parts
1411                     throw new ArgumentException(SR.GetString(SR.WebPartManager_CantDeleteStatic), "webPart");
1412                 }
1413                 else if (webPart.IsShared && (Personalization.Scope == PersonalizationScope.User)) {
1414                     // Can't delete shared part in user scope
1415                     throw new ArgumentException(SR.GetString(SR.WebPartManager_CantDeleteSharedInUserScope), "webPart");
1416                 }
1417             }
1418
1419             WebPartCancelEventArgs ce = new WebPartCancelEventArgs(webPart);
1420             if (delete) {
1421                 OnWebPartDeleting(ce);
1422             }
1423             else {
1424                 OnWebPartClosing(ce);
1425             }
1426             if (_allowEventCancellation && ce.Cancel) {
1427                 return;
1428             }
1429
1430             if ((DisplayMode == ConnectDisplayMode) && (webPart == SelectedWebPart)) {
1431                 EndWebPartConnecting();
1432                 if (SelectedWebPart != null) {
1433                     // The ConnectModeChange was cancelled
1434                     return;
1435                 }
1436             }
1437
1438             // VSWhidbey 77768
1439             if ((DisplayMode == EditDisplayMode) && (webPart == SelectedWebPart)) {
1440                 EndWebPartEditing();
1441                 if (SelectedWebPart != null) {
1442                     // The EditModeChange was cancelled
1443                     return;
1444                 }
1445             }
1446
1447             if (delete) {
1448                 Internals.CallOnDeleting(webPart);
1449             }
1450             else {
1451                 Internals.CallOnClosing(webPart);
1452             }
1453
1454 #if DEBUG
1455             WebPartZoneBase zone = webPart.Zone;
1456 #endif
1457
1458             // If we are deleting a closed WebPart, it has already been removed from
1459             // its Zone, so there is no need to do it again.
1460             if (!webPart.IsClosed) {
1461                 RemoveWebPartFromZone(webPart);
1462             }
1463
1464             DisconnectWebPart(webPart);
1465
1466             if (delete) {
1467                 Internals.RemoveWebPart(webPart);
1468
1469                 // Raise the WebPartDeleted event after changing the WebPart properties
1470                 // The WebPartDeleting event is raised before changing the WebPart properties
1471                 OnWebPartDeleted(new WebPartEventArgs(webPart));
1472             }
1473             else {
1474                 // Raise the WebPartClosed event after changing the WebPart properties
1475                 // The WebPartClosing event is raised before changing the WebPart properties
1476                 OnWebPartClosed(new WebPartEventArgs(webPart));
1477             }
1478
1479 #if DEBUG
1480             if (zone != null) {
1481                 CheckPartZoneIndexes(zone);
1482             }
1483 #endif
1484         }
1485
1486         private WebPartConnection[] ConnectionsToActivate() {
1487             // PERF: We could implement this with a sorted list to simplify the code
1488
1489             ArrayList connectionsToActivate = new ArrayList();
1490
1491             // Contains the connection IDs we have already seen
1492             HybridDictionary connectionIDs = new HybridDictionary(true /* caseInsensitive */);
1493
1494             WebPartConnection[] connections = new WebPartConnection[StaticConnections.Count + DynamicConnections.Count];
1495             StaticConnections.CopyTo(connections, 0);
1496             DynamicConnections.CopyTo(connections, StaticConnections.Count);
1497             foreach (WebPartConnection connection in connections) {
1498                 ConnectionsToActivateHelper(connection, connectionIDs, connectionsToActivate);
1499             }
1500
1501             // Check unshared connections for conflicts with shared connections
1502             // Maybe this should only be done in user scope
1503             WebPartConnection[] connectionsToActivateArray = (WebPartConnection[])connectionsToActivate.ToArray(typeof(WebPartConnection));
1504             foreach (WebPartConnection connection in connectionsToActivateArray) {
1505                 if (connection.IsShared) {
1506                     continue;
1507                 }
1508
1509                 ArrayList connectionsToDelete = new ArrayList();
1510                 foreach (WebPartConnection otherConnection in connectionsToActivate) {
1511                     if (connection == otherConnection) {
1512                         continue;
1513                     }
1514
1515                     if (otherConnection.IsShared && connection.ConflictsWith(otherConnection)) {
1516                         // Delete shared connection.
1517                         connectionsToDelete.Add(otherConnection);
1518                     }
1519                 }
1520
1521                 foreach (WebPartConnection connectionToDelete in connectionsToDelete) {
1522                     DisconnectWebParts(connectionToDelete);
1523                     connectionsToActivate.Remove(connectionToDelete);
1524                 }
1525             }
1526
1527             // Check shared, nonstatic connections for conflicts with static connections
1528             connectionsToActivateArray = (WebPartConnection[])connectionsToActivate.ToArray(typeof(WebPartConnection));
1529             foreach (WebPartConnection connection in connectionsToActivateArray) {
1530                 if (!connection.IsShared || connection.IsStatic) {
1531                     continue;
1532                 }
1533
1534                 ArrayList connectionsToDelete = new ArrayList();
1535                 foreach (WebPartConnection otherConnection in connectionsToActivate) {
1536                     if (connection == otherConnection) {
1537                         continue;
1538                     }
1539
1540                     if (otherConnection.IsStatic && connection.ConflictsWith(otherConnection)) {
1541                         // Delete static connection.
1542                         connectionsToDelete.Add(otherConnection);
1543                     }
1544                 }
1545
1546                 foreach (WebPartConnection connectionToDelete in connectionsToDelete) {
1547                     DisconnectWebParts(connectionToDelete);
1548                     connectionsToActivate.Remove(connectionToDelete);
1549                 }
1550             }
1551
1552             // Check all remaining connections for conflicts.  Any conflicts at this stage will
1553             // cause an error to be rendered in the consumer WebPart, and the conflicting connections
1554             // will not be activated.
1555             ArrayList finalConnectionsToActivate = new ArrayList();
1556             foreach (WebPartConnection connection in connectionsToActivate) {
1557                 bool hasConflict = false;
1558
1559                 foreach (WebPartConnection otherConnection in connectionsToActivate) {
1560                     if (connection == otherConnection) {
1561                         continue;
1562                     }
1563
1564                     if (connection.ConflictsWithConsumer(otherConnection)) {
1565                         connection.Consumer.SetConnectErrorMessage(SR.GetString(SR.WebPartConnection_Duplicate, connection.ConsumerConnectionPoint.DisplayName,
1566                                 connection.Consumer.DisplayTitle));
1567                         hasConflict = true;
1568                     }
1569
1570                     if (connection.ConflictsWithProvider(otherConnection)) {
1571                         connection.Consumer.SetConnectErrorMessage(SR.GetString(SR.WebPartConnection_Duplicate, connection.ProviderConnectionPoint.DisplayName,
1572                                 connection.Provider.DisplayTitle));
1573                         hasConflict = true;
1574                     }
1575                 }
1576
1577                 if (!hasConflict) {
1578                     finalConnectionsToActivate.Add(connection);
1579                 }
1580             }
1581
1582             // Don't allow the user to modify the StaticConnections collection after its connections have
1583             // been activated.  Use property instead of field to force creation of collection.
1584             StaticConnections.SetReadOnly(SR.WebPartManager_StaticConnectionsReadOnly);
1585
1586             // The user can't directly change the DynamicConnections property since it is internal.
1587             // Make it read-only in case we have a bug and try to change it after activation.
1588             // We check the read-only status of this collection in ConnectWebParts() and DisconnectWebParts().
1589             DynamicConnections.SetReadOnly(SR.WebPartManager_DynamicConnectionsReadOnly);
1590
1591             return (WebPartConnection[])finalConnectionsToActivate.ToArray(typeof(WebPartConnection));
1592         }
1593
1594         // If we think we should activate the connection, adds it to the dictionary under the key
1595         // for its provider and consumer connection points.
1596         private void ConnectionsToActivateHelper(WebPartConnection connection, IDictionary connectionIDs,
1597                                                  ArrayList connectionsToActivate) {
1598             string connectionID = connection.ID;
1599
1600             if (String.IsNullOrEmpty(connectionID)) {
1601                 throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_NoID));
1602             }
1603
1604             if (connectionIDs.Contains(connectionID)) {
1605                 throw new InvalidOperationException(
1606                     SR.GetString(SR.WebPartManager_DuplicateConnectionID, connectionID));
1607             }
1608             connectionIDs.Add(connectionID, null);
1609
1610             if (connection.Deleted) {
1611                 return;
1612             }
1613
1614             WebPart providerWebPart = connection.Provider;
1615             if (providerWebPart == null) {
1616                 if (connection.IsStatic) {
1617                     // throw an exception, to alert the developer that his static connection is invalid
1618                     throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_NoProvider, connection.ProviderID));
1619                 }
1620                 else {
1621                     // Silently delete the connection, since this is a valid runtime scenario.
1622                     // A connected web part may have been deleted.
1623                     DisconnectWebParts(connection);
1624                     return;
1625                 }
1626             }
1627
1628             WebPart consumerWebPart = connection.Consumer;
1629             if (consumerWebPart == null) {
1630                 if (connection.IsStatic) {
1631                     // throw an exception, to alert the developer that his static connection is invalid
1632                     throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_NoConsumer, connection.ConsumerID));
1633                 }
1634                 else {
1635                     // Silently delete the connection, since this is a valid runtime scenario.
1636                     // A connected web part may have been deleted.
1637                     DisconnectWebParts(connection);
1638                     return;
1639                 }
1640             }
1641
1642             // Do not activate connections involving ProxyWebParts
1643             if (providerWebPart is ProxyWebPart || consumerWebPart is ProxyWebPart) {
1644                 return;
1645             }
1646
1647             Control providerControl = providerWebPart.ToControl();
1648             Control consumerControl = consumerWebPart.ToControl();
1649
1650             // Cannot connect a WebPart to itself
1651             if (providerControl == consumerControl) {
1652                 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_CantConnectToSelf));
1653             }
1654
1655             ProviderConnectionPoint providerConnectionPoint = connection.ProviderConnectionPoint;
1656             if (providerConnectionPoint == null) {
1657                 consumerWebPart.SetConnectErrorMessage(SR.GetString(SR.WebPartConnection_NoProviderConnectionPoint, connection.ProviderConnectionPointID,
1658                     providerWebPart.DisplayTitle));
1659                 return;
1660             }
1661             // Don't need to check that providerConnectionPoint is enabled, since this will be checked
1662             // in WebPartConnection.Activate().
1663
1664             ConsumerConnectionPoint consumerConnectionPoint = connection.ConsumerConnectionPoint;
1665             if (consumerConnectionPoint == null) {
1666                 consumerWebPart.SetConnectErrorMessage(SR.GetString(SR.WebPartConnection_NoConsumerConnectionPoint, connection.ConsumerConnectionPointID,
1667                     consumerWebPart.DisplayTitle));
1668                 return;
1669             }
1670             // Don't need to check that consumer ConnectionPoint is enabled, since this will be checked
1671             // in WebPartConnection.Activate().
1672
1673             connectionsToActivate.Add(connection);
1674         }
1675
1676         public WebPartConnection ConnectWebParts(WebPart provider, ProviderConnectionPoint providerConnectionPoint,
1677                                                  WebPart consumer, ConsumerConnectionPoint consumerConnectionPoint) {
1678             return ConnectWebParts(provider, providerConnectionPoint, consumer, consumerConnectionPoint, null);
1679         }
1680
1681         public virtual WebPartConnection ConnectWebParts(WebPart provider, ProviderConnectionPoint providerConnectionPoint,
1682                                                          WebPart consumer, ConsumerConnectionPoint consumerConnectionPoint,
1683                                                          WebPartTransformer transformer) {
1684             CanConnectWebPartsCore(provider, providerConnectionPoint, consumer, consumerConnectionPoint,
1685                                    transformer, /*throwOnError*/ true);
1686
1687             if (DynamicConnections.IsReadOnly) {
1688                 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_ConnectTooLate));
1689             }
1690
1691             WebPartConnectionsCancelEventArgs ce = new WebPartConnectionsCancelEventArgs(
1692                 provider, providerConnectionPoint, consumer, consumerConnectionPoint);
1693             OnWebPartsConnecting(ce);
1694             if (_allowEventCancellation && ce.Cancel) {
1695                 return null;
1696             }
1697
1698             Control providerControl = provider.ToControl();
1699             Control consumerControl = consumer.ToControl();
1700
1701             WebPartConnection connection = new WebPartConnection();
1702             connection.ID = CreateDynamicConnectionID();
1703             connection.ProviderID = providerControl.ID;
1704             connection.ConsumerID = consumerControl.ID;
1705             connection.ProviderConnectionPointID = providerConnectionPoint.ID;
1706             connection.ConsumerConnectionPointID = consumerConnectionPoint.ID;
1707
1708             if (transformer != null) {
1709                 Internals.SetTransformer(connection, transformer);
1710             }
1711
1712             Internals.SetIsShared(connection, Personalization.Scope == PersonalizationScope.Shared);
1713             Internals.SetIsStatic(connection, false);
1714
1715             DynamicConnections.Add(connection);
1716             _hasDataChanged = true;
1717
1718             OnWebPartsConnected(new WebPartConnectionsEventArgs(provider, providerConnectionPoint,
1719                                                                 consumer, consumerConnectionPoint, connection));
1720
1721             return connection;
1722         }
1723
1724         // Returns a copy of the WebPart, with all the properties reset to their default value.
1725         // If the WebPart is a GenericWebPart, returns a copy of the GenericWebPart and a copy of the
1726         // ChildControl inside the GenericWebPart.  The ID of the new WebPart and ChildControl should
1727         // be set to a value obtained from CreateDynamicWebPartID.
1728         // Virtual because a derived WebPartManager will deserialize a WebPart from XML in this method.
1729         protected virtual WebPart CopyWebPart(WebPart webPart) {
1730             WebPart newWebPart;
1731
1732             GenericWebPart genericWebPart = webPart as GenericWebPart;
1733             if (genericWebPart != null) {
1734                 Control childControl = genericWebPart.ChildControl;
1735                 VerifyType(childControl);
1736                 Type childControlType = childControl.GetType();
1737                 Control newChildControl = (Control)Internals.CreateObjectFromType(childControlType);
1738                 newChildControl.ID = CreateDynamicWebPartID(childControlType);
1739
1740                 newWebPart = CreateWebPart(newChildControl);
1741             }
1742             else {
1743                 VerifyType(webPart);
1744                 newWebPart = (WebPart)Internals.CreateObjectFromType(webPart.GetType());
1745             }
1746
1747             newWebPart.ID = CreateDynamicWebPartID(webPart.GetType());
1748
1749             return newWebPart;
1750         }
1751
1752         protected virtual TransformerTypeCollection CreateAvailableTransformers() {
1753             TransformerTypeCollection availableTransformers = new TransformerTypeCollection();
1754
1755             WebPartsSection configSection = RuntimeConfig.GetConfig().WebParts;
1756
1757             IDictionary transformers = configSection.Transformers.GetTransformerEntries();
1758
1759             foreach (Type type in transformers.Values) {
1760                 availableTransformers.Add(type);
1761             }
1762
1763             return availableTransformers;
1764         }
1765
1766         // Returns an array of ICollection objects.  The first is the ConsumerConnectionPoints, the
1767         // second is the ProviderConnectionPoints.
1768         private static ICollection[] CreateConnectionPoints(Type type) {
1769             ArrayList consumerConnectionPoints = new ArrayList();
1770             ArrayList providerConnectionPoints = new ArrayList();
1771
1772             MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
1773             foreach (MethodInfo method in methods) {
1774
1775                 // Create consumer connection points
1776                 object[] consumerAttributes = method.GetCustomAttributes(typeof(ConnectionConsumerAttribute), true);
1777                 // ConnectionConsumerAttribute.AllowMultiple is false
1778                 Debug.Assert(consumerAttributes.Length == 0 || consumerAttributes.Length == 1);
1779                 if (consumerAttributes.Length == 1) {
1780                     // Consumer signature: method is public, return type is void, takes one parameter
1781                     ParameterInfo[] parameters = method.GetParameters();
1782                     Type parameterType = null;
1783                     if (parameters.Length == 1) {
1784                         parameterType = parameters[0].ParameterType;
1785                     }
1786
1787                     if (method.IsPublic && method.ReturnType == typeof(void) && parameterType != null) {
1788                         ConnectionConsumerAttribute attribute = consumerAttributes[0] as ConnectionConsumerAttribute;
1789                         String displayName = attribute.DisplayName;
1790                         String id = attribute.ID;
1791                         Type connectionPointType = attribute.ConnectionPointType;
1792                         bool allowsMultipleConnections = attribute.AllowsMultipleConnections;
1793                         ConsumerConnectionPoint connectionPoint;
1794                         if (connectionPointType == null) {
1795                             connectionPoint = new ConsumerConnectionPoint(method, parameterType, type,
1796                                                                           displayName, id, allowsMultipleConnections);
1797                         }
1798                         else {
1799                             // The ConnectionPointType is validated in the attribute property getter
1800                             Object[] args = new Object[] { method, parameterType, type, displayName, id, allowsMultipleConnections };
1801                             connectionPoint = (ConsumerConnectionPoint)Activator.CreateInstance(connectionPointType, args);
1802                         }
1803                         consumerConnectionPoints.Add(connectionPoint);
1804                     }
1805                     else {
1806                         throw new InvalidOperationException(SR.GetString(SR.WebPartManager_InvalidConsumerSignature, method.Name, type.FullName));
1807                     }
1808                 }
1809
1810                 // Create provider connection points
1811                 object[] providerAttributes = method.GetCustomAttributes(typeof(ConnectionProviderAttribute), true);
1812                 // ConnectionProviderAttribute.AllowMultiple is false
1813                 Debug.Assert(providerAttributes.Length == 0 || providerAttributes.Length == 1);
1814                 if (providerAttributes.Length == 1) {
1815                     // Provider signature: method is public, return type is an object, and takes no parameters
1816                     Type returnType = method.ReturnType;
1817                     if (method.IsPublic && returnType != typeof(void) && method.GetParameters().Length == 0) {
1818                         ConnectionProviderAttribute attribute = providerAttributes[0] as ConnectionProviderAttribute;
1819                         String displayName = attribute.DisplayName;
1820                         String id = attribute.ID;
1821                         Type connectionPointType = attribute.ConnectionPointType;
1822                         bool allowsMultipleConnections = attribute.AllowsMultipleConnections;
1823                         ProviderConnectionPoint connectionPoint;
1824                         if (connectionPointType == null) {
1825                             connectionPoint = new ProviderConnectionPoint(method, returnType, type,
1826                                                                           displayName, id, allowsMultipleConnections);
1827                         }
1828                         else {
1829                             // The ConnectionPointType is validated in the attribute property getter
1830                             Object[] args = new Object[] { method, returnType, type, displayName, id, allowsMultipleConnections };
1831                             connectionPoint = (ProviderConnectionPoint)Activator.CreateInstance(connectionPointType, args);
1832                         }
1833                         providerConnectionPoints.Add(connectionPoint);
1834                     }
1835                     else {
1836                         throw new InvalidOperationException(SR.GetString(SR.WebPartManager_InvalidProviderSignature, method.Name, type.FullName));
1837                     }
1838                 }
1839             }
1840
1841             return new ICollection[] { new ConsumerConnectionPointCollection(consumerConnectionPoints),
1842                 new ProviderConnectionPointCollection(providerConnectionPoints) };
1843         }
1844
1845         protected sealed override ControlCollection CreateControlCollection() {
1846             return new WebPartManagerControlCollection(this);
1847         }
1848
1849         /// <devdoc>
1850         /// Can be overridden by derived types, to add additional display modes.  Display modes
1851         /// should be added in the order they are to appear in the page menu.
1852         /// </devdoc>
1853         protected virtual WebPartDisplayModeCollection CreateDisplayModes() {
1854             WebPartDisplayModeCollection displayModes = new WebPartDisplayModeCollection();
1855
1856             displayModes.Add(BrowseDisplayMode);
1857             displayModes.Add(CatalogDisplayMode);
1858             displayModes.Add(DesignDisplayMode);
1859             displayModes.Add(EditDisplayMode);
1860             displayModes.Add(ConnectDisplayMode);
1861
1862             return displayModes;
1863         }
1864
1865         private string CreateDisplayTitle(string title, WebPart webPart, int count) {
1866             string displayTitle = title;
1867
1868             if (webPart.Hidden) {
1869                 displayTitle = SR.GetString(SR.WebPart_HiddenFormatString, displayTitle);
1870             }
1871
1872             if (webPart is ErrorWebPart) {
1873                 displayTitle = SR.GetString(SR.WebPart_ErrorFormatString, displayTitle);
1874             }
1875
1876             if (count != 0) {
1877                 if (count < displayTitleSuffix.Length) {
1878                     displayTitle += displayTitleSuffix[count];
1879                 }
1880                 else {
1881                     displayTitle += " [" + count.ToString(CultureInfo.CurrentCulture) + "]";
1882                 }
1883             }
1884
1885             return displayTitle;
1886         }
1887
1888         private IDictionary CreateDisplayTitles() {
1889             Hashtable displayTitles = new Hashtable();
1890
1891             Hashtable titles = new Hashtable();
1892             foreach (WebPart part in Controls) {
1893                 string title = part.Title;
1894                 if (String.IsNullOrEmpty(title)) {
1895                     title = SR.GetString(SR.Part_Untitled);
1896                 }
1897
1898                 if (part is UnauthorizedWebPart) {
1899                     displayTitles[part] = title;
1900                     continue;
1901                 }
1902
1903                 ArrayList parts = (ArrayList)titles[title];
1904                 if (parts == null) {
1905                     parts = new ArrayList();
1906                     titles[title] = parts;
1907                     displayTitles[part] = CreateDisplayTitle(title, part, 0);
1908                 }
1909                 else {
1910                     int count = parts.Count;
1911                     if (count == 1) {
1912                         WebPart firstPart = (WebPart)parts[0];
1913                         displayTitles[firstPart] = CreateDisplayTitle(title, firstPart, 1);
1914                     }
1915                     displayTitles[part] = CreateDisplayTitle(title, part, count + 1);
1916                 }
1917
1918                 parts.Add(part);
1919             }
1920
1921             return displayTitles;
1922         }
1923
1924         protected virtual string CreateDynamicConnectionID() {
1925             Debug.Assert(Personalization.IsModifiable);
1926             // 
1927             int guidHash = Math.Abs(Guid.NewGuid().GetHashCode());
1928             return DynamicConnectionIDPrefix + guidHash.ToString(CultureInfo.InvariantCulture);
1929         }
1930
1931         protected virtual string CreateDynamicWebPartID(Type webPartType) {
1932             if (webPartType == null) {
1933                 throw new ArgumentNullException("webPartType");
1934             }
1935
1936             Debug.Assert(Personalization.IsModifiable);
1937
1938             // 
1939
1940             int guidHash = Math.Abs(Guid.NewGuid().GetHashCode());
1941             string id = DynamicWebPartIDPrefix + guidHash.ToString(CultureInfo.InvariantCulture);
1942
1943             if (Page != null && Page.Trace.IsEnabled) {
1944                 id += webPartType.Name;
1945             }
1946
1947             return id;
1948         }
1949
1950         protected virtual ErrorWebPart CreateErrorWebPart(string originalID, string originalTypeName,
1951                                                           string originalPath, string genericWebPartID,
1952                                                           string errorMessage) {
1953             ErrorWebPart errorWebPart = new ErrorWebPart(originalID, originalTypeName, originalPath, genericWebPartID);
1954             errorWebPart.ErrorMessage = errorMessage;
1955             return errorWebPart;
1956         }
1957
1958         /// <devdoc>
1959         /// </devdoc>
1960         protected virtual WebPartPersonalization CreatePersonalization() {
1961             return new WebPartPersonalization(this);
1962         }
1963
1964         /// <devdoc>
1965         /// Wraps the control in a GenericWebPart, and returns the GenericWebPart.  Virtual so it can be
1966         /// overridden to use a derived type of GenericWebPart instead.  Needs to be public so it can
1967         /// be called by the page developer.
1968         /// </devdoc>
1969         public virtual GenericWebPart CreateWebPart(Control control) {
1970             return CreateWebPartStatic(control);
1971         }
1972
1973         // Called by other WebParts classes to create a GenericWebPart, if they do not have
1974         // a reference to a WebPartManager (i.e. at design time).  This method centralizes
1975         // the creation of GenericWebParts.
1976         internal static GenericWebPart CreateWebPartStatic(Control control) {
1977             GenericWebPart genericWebPart = new GenericWebPart(control);
1978             
1979             // The ChildControl should be added to the GenericWebPart.Controls collection when CreateWebPart()
1980             // is called, instead of waiting until the GenericWebPart.Controls collection is accessed.
1981             // This is necessary since the caller has a direct reference to the ChildControl, and may
1982             // perform operations on the ChildControl that assume the ChildControl is parented.
1983             // (VSWhidbey 498039)
1984             genericWebPart.CreateChildControls();
1985
1986             return genericWebPart;
1987         }
1988
1989         public void DeleteWebPart(WebPart webPart) {
1990             CloseOrDeleteWebPart(webPart, /* delete */ true);
1991         }
1992
1993         // Disconnects all connections involving the Web Part
1994         protected virtual void DisconnectWebPart(WebPart webPart) {
1995             try {
1996                 // We cannot allow any of the WebPartsDisconnecting events to be cancelled, since we may have already
1997                 // disconnected some connections before we hit the one that needs to be cancelled. (VSWhidbey 516012)
1998                 _allowEventCancellation = false;
1999                 foreach (WebPartConnection connection in Connections) {
2000                     if (connection.Provider == webPart || connection.Consumer == webPart) {
2001                         DisconnectWebParts(connection);
2002                     }
2003                 }
2004             }
2005             finally {
2006                 _allowEventCancellation = true;
2007             }
2008         }
2009
2010         public virtual void DisconnectWebParts(WebPartConnection connection) {
2011             Personalization.EnsureEnabled(/* ensureModifiable */ true);
2012
2013             if (connection == null) {
2014                 throw new ArgumentNullException("connection");
2015             }
2016
2017             Debug.Assert(!(StaticConnections.Contains(connection) && DynamicConnections.Contains(connection)));
2018
2019             WebPart provider = connection.Provider;
2020             ProviderConnectionPoint providerConnectionPoint = connection.ProviderConnectionPoint;
2021             WebPart consumer = connection.Consumer;
2022             ConsumerConnectionPoint consumerConnectionPoint = connection.ConsumerConnectionPoint;
2023
2024             WebPartConnectionsCancelEventArgs ce = new WebPartConnectionsCancelEventArgs(
2025                 provider, providerConnectionPoint, consumer, consumerConnectionPoint, connection);
2026             OnWebPartsDisconnecting(ce);
2027             if (_allowEventCancellation && ce.Cancel) {
2028                 return;
2029             }
2030
2031             WebPartConnectionsEventArgs eventArgs = new WebPartConnectionsEventArgs(
2032                 provider, providerConnectionPoint, consumer, consumerConnectionPoint);
2033
2034             if (StaticConnections.Contains(connection)) {
2035                 if (StaticConnections.IsReadOnly) {
2036                     throw new InvalidOperationException(SR.GetString(SR.WebPartManager_DisconnectTooLate));
2037                 }
2038                 if (Internals.ConnectionDeleted(connection)) {
2039                     throw new InvalidOperationException(SR.GetString(SR.WebPartManager_AlreadyDisconnected));
2040                 }
2041                 Internals.DeleteConnection(connection);
2042                 _hasDataChanged = true;
2043                 OnWebPartsDisconnected(eventArgs);
2044             }
2045             else if (DynamicConnections.Contains(connection)) {
2046                 if (DynamicConnections.IsReadOnly) {
2047                     throw new InvalidOperationException(SR.GetString(SR.WebPartManager_DisconnectTooLate));
2048                 }
2049
2050                 if (ShouldRemoveConnection(connection)) {
2051                     // Unshared dynamic connection should never be disabled
2052                     Debug.Assert(!Internals.ConnectionDeleted(connection));
2053                     DynamicConnections.Remove(connection);
2054                 }
2055                 else {
2056                     if (Internals.ConnectionDeleted(connection)) {
2057                         throw new InvalidOperationException(SR.GetString(SR.WebPartManager_AlreadyDisconnected));
2058                     }
2059                     Internals.DeleteConnection(connection);
2060                 }
2061                 _hasDataChanged = true;
2062                 OnWebPartsDisconnected(eventArgs);
2063             }
2064             else {
2065                 throw new ArgumentException(SR.GetString(SR.WebPartManager_UnknownConnection), "connection");
2066             }
2067         }
2068
2069         public virtual void EndWebPartConnecting() {
2070             Personalization.EnsureEnabled(/* ensureModifiable */ true);
2071
2072             WebPart selectedWebPart = SelectedWebPart;
2073
2074             if (selectedWebPart == null) {
2075                 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_NoSelectedWebPartConnect));
2076             }
2077
2078             WebPartCancelEventArgs ce = new WebPartCancelEventArgs(selectedWebPart);
2079             OnSelectedWebPartChanging(ce);
2080
2081             if (_allowEventCancellation && ce.Cancel) {
2082                 return;
2083             }
2084
2085             SetSelectedWebPart(null);
2086
2087             Internals.CallOnConnectModeChanged(selectedWebPart);
2088
2089             // The EventArg should always contain the new SelectedWebPart, so it should contain null
2090             // when we are ending connecting.
2091             OnSelectedWebPartChanged(new WebPartEventArgs(null));
2092         }
2093
2094         public virtual void EndWebPartEditing() {
2095             Personalization.EnsureEnabled(/* ensureModifiable */ true);
2096
2097             WebPart selectedWebPart = SelectedWebPart;
2098
2099             if (selectedWebPart == null) {
2100                 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_NoSelectedWebPartEdit));
2101             }
2102
2103             WebPartCancelEventArgs ce = new WebPartCancelEventArgs(selectedWebPart);
2104             OnSelectedWebPartChanging(ce);
2105
2106             if (_allowEventCancellation && ce.Cancel) {
2107                 return;
2108             }
2109
2110             SetSelectedWebPart(null);
2111
2112             Internals.CallOnEditModeChanged(selectedWebPart);
2113
2114             // The EventArg should always contain the new SelectedWebPart, so it should contain null
2115             // when we are ending editing.
2116             OnSelectedWebPartChanged(new WebPartEventArgs(null));
2117         }
2118
2119         public virtual void ExportWebPart(WebPart webPart, XmlWriter writer) {
2120 //            Personalization.EnsureEnabled(/* ensureModifiable */ false);
2121
2122             if (webPart == null) {
2123                 throw new ArgumentNullException("webPart");
2124             }
2125             if (!Controls.Contains(webPart)) {
2126                 throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "webPart");
2127             }
2128
2129             if (writer == null) {
2130                 throw new ArgumentNullException("writer");
2131             }
2132             if (webPart.ExportMode == WebPartExportMode.None) {
2133                 throw new ArgumentException(SR.GetString(SR.WebPartManager_PartNotExportable), "webPart");
2134             }
2135             bool excludeSensitive = (webPart.ExportMode == WebPartExportMode.NonSensitiveData &&
2136                 !(Personalization.Scope == PersonalizationScope.Shared));
2137
2138             // Write the root elements
2139             writer.WriteStartElement(ExportRootElement);
2140             writer.WriteStartElement(ExportPartElement);
2141             writer.WriteAttributeString(ExportPartNamespaceAttribute, ExportPartNamespaceValue);
2142             // Write metadata
2143             writer.WriteStartElement(ExportMetaDataElement);
2144             writer.WriteStartElement(ExportTypeElement);
2145             Control control = webPart.ToControl();
2146             UserControl userControl = control as UserControl;
2147             if (userControl != null) {
2148                 writer.WriteAttributeString(ExportUserControlSrcAttribute, userControl.AppRelativeVirtualPath);
2149             }
2150             else {
2151                 writer.WriteAttributeString(ExportTypeNameAttribute, WebPartUtil.SerializeType(control.GetType()));
2152             }
2153             writer.WriteEndElement(); //type
2154             writer.WriteElementString(ExportErrorMessageElement, webPart.ImportErrorMessage);
2155             writer.WriteEndElement(); //metadata
2156             // Write the data
2157             writer.WriteStartElement(ExportDataElement);
2158             // We get the personalization data for the current page personalization mode
2159             IDictionary propBag = PersonalizableAttribute.GetPersonalizablePropertyValues(webPart, PersonalizationScope.Shared, excludeSensitive);
2160
2161             writer.WriteStartElement(ExportPropertiesElement);
2162
2163             // Special case GenericWebPart
2164             GenericWebPart genericWebPart = webPart as GenericWebPart;
2165
2166             if (genericWebPart != null) {
2167
2168                 // Export IPersonalizable user control data first
2169                 ExportIPersonalizable(writer, control, excludeSensitive);
2170
2171                 IDictionary controlData = PersonalizableAttribute.GetPersonalizablePropertyValues(control,
2172                                                                                                   PersonalizationScope.Shared,
2173                                                                                                   excludeSensitive);
2174                 ExportToWriter(controlData, writer);
2175                 writer.WriteEndElement(); //properties
2176                 writer.WriteStartElement(ExportGenericPartPropertiesElement);
2177                 // Export IPersonalizable part data first
2178                 ExportIPersonalizable(writer, webPart, excludeSensitive);
2179                 ExportToWriter(propBag, writer);
2180             }
2181             else {
2182                 // Export IPersonalizable part data first
2183                 ExportIPersonalizable(writer, webPart, excludeSensitive);
2184                 ExportToWriter(propBag, writer);
2185             }
2186             writer.WriteEndElement(); //properties or genericWebPartProperties
2187             writer.WriteEndElement(); //data
2188             writer.WriteEndElement(); //webpart
2189             writer.WriteEndElement(); //webparts
2190         }
2191
2192         private void ExportIPersonalizable(XmlWriter writer, Control control, bool excludeSensitive) {
2193             IPersonalizable personalizableControl = control as IPersonalizable;
2194             if (personalizableControl != null) {
2195                 PersonalizationDictionary personalizableData = new PersonalizationDictionary();
2196                 personalizableControl.Save(personalizableData);
2197                 if (personalizableData.Count > 0) {
2198                     writer.WriteStartElement(ExportIPersonalizableElement);
2199                     ExportToWriter(personalizableData, writer, /* isIPersonalizable */ true, excludeSensitive);
2200                     writer.WriteEndElement(); // ipersonalizable
2201                 }
2202             }
2203         }
2204
2205         private static void ExportProperty(XmlWriter writer, string name, string value, Type type,
2206             PersonalizationScope scope, bool isIPersonalizable) {
2207
2208             writer.WriteStartElement(ExportPropertyElement);
2209             writer.WriteAttributeString(ExportPropertyNameAttribute, name);
2210             writer.WriteAttributeString(ExportPropertyTypeAttribute, GetExportName(type));
2211             if (isIPersonalizable) {
2212                 writer.WriteAttributeString(ExportPropertyScopeAttribute, scope.ToString());
2213             }
2214             if (value == null) {
2215                 writer.WriteAttributeString(ExportPropertyNullAttribute, "true");
2216             }
2217             else {
2218                 writer.WriteString(value);
2219             }
2220             writer.WriteEndElement(); //property
2221         }
2222
2223         private void ExportToWriter(IDictionary propBag, XmlWriter writer) {
2224             ExportToWriter(propBag, writer, false, false);
2225         }
2226
2227         private void ExportToWriter(IDictionary propBag,
2228                                     XmlWriter writer,
2229                                     bool isIPersonalizable,
2230                                     bool excludeSensitive) {
2231             // We only honor excludeSensitive if isIpersonalizable is true.
2232             Debug.Assert((!excludeSensitive) || isIPersonalizable);
2233
2234             // Work on each property in the persomalization data
2235             foreach(DictionaryEntry entry in propBag) {
2236                 string name = (string)entry.Key;
2237                 if (name == AuthorizationFilterName || name == ImportErrorMessageName) {
2238                     continue;
2239                 }
2240
2241                 PropertyInfo pi = null;
2242                 object val = null;
2243                 Pair data = entry.Value as Pair;
2244                 PersonalizationScope scope = PersonalizationScope.User;
2245                 // We expect a pair if not exporting types
2246                 // (which happens only for non-IPersonalizable data)
2247                 if (isIPersonalizable == false && data != null) {
2248                     pi = (PropertyInfo)data.First;
2249                     val = data.Second;
2250                 }
2251                 else if (isIPersonalizable) {
2252                     PersonalizationEntry personalizationEntry = entry.Value as PersonalizationEntry;
2253                     if (personalizationEntry != null &&
2254                         (Personalization.Scope == PersonalizationScope.Shared ||
2255                         personalizationEntry.Scope == PersonalizationScope.User)) {
2256
2257                         val = personalizationEntry.Value;
2258                         scope = personalizationEntry.Scope;
2259                     }
2260                     if (excludeSensitive && personalizationEntry.IsSensitive) {
2261                         continue;
2262                     }
2263                 }
2264                 // we get the type from the PropertyInfo if we have it, or from the value if it's not null, or we use object.
2265                 Type valType = ((pi != null) ? pi.PropertyType : ((val != null) ? val.GetType() : typeof(object)));
2266
2267                 string exportString;
2268                 if (ShouldExportProperty(pi, valType, val, out exportString)) {
2269                     ExportProperty(writer, name, exportString, valType, scope, isIPersonalizable);
2270                 }
2271             }
2272         }
2273
2274         [
2275         EditorBrowsable(EditorBrowsableState.Never),
2276         ]
2277         public override void Focus() {
2278             throw new NotSupportedException(SR.GetString(SR.NoFocusSupport, this.GetType().Name));
2279         }
2280
2281         /// <devdoc>
2282         /// Returns all the web parts in a zone, excluding closed web parts.
2283         /// Since this is only a private method, return an IList instead of a WebPartCollection
2284         /// for better performance.
2285         /// </devdoc>
2286         private IList GetAllWebPartsForZone(WebPartZoneBase zone) {
2287             if (_partsForZone == null) {
2288                 _partsForZone = new HybridDictionary(true /* caseInsensitive */);
2289                 foreach (WebPart part in Controls) {
2290                     if (!part.IsClosed) {
2291                         string zoneID = Internals.GetZoneID(part);
2292                         Debug.Assert(!String.IsNullOrEmpty(zoneID));
2293                         if (!String.IsNullOrEmpty(zoneID)) {
2294                             SortedList partsForZone = (SortedList)_partsForZone[zoneID];
2295                             if (partsForZone == null) {
2296                                 partsForZone = new SortedList(new WebPart.ZoneIndexComparer());
2297                                 _partsForZone[zoneID] = partsForZone;
2298                             }
2299                             partsForZone.Add(part, null);
2300                         }
2301                     }
2302                 }
2303             }
2304
2305             SortedList parts = (SortedList)_partsForZone[zone.ID];
2306             if (parts == null) {
2307                 parts = new SortedList();
2308             }
2309
2310             return parts.GetKeyList();
2311         }
2312
2313         private static ICollection[] GetConnectionPoints(Type type) {
2314             if (ConnectionPointsCache == null) {
2315                 // I don't think there is a race condition here.  Even if multiple threads enter this block
2316                 // at the same time, the worst thing that can happen is that the ConnectionPointsCache gets
2317                 // replaced by a new Hashtable(), and existing entries will need to be recomputed.
2318                 // There is no way for the ConnectionPointsCache to become null.
2319                 ConnectionPointsCache = Hashtable.Synchronized(new Hashtable());
2320             }
2321
2322             // DevDiv Bugs 38677: Cache by culture and type as it may vary by culture within this app
2323             ConnectionPointKey connectionPointKey = new ConnectionPointKey(type, CultureInfo.CurrentCulture, CultureInfo.CurrentUICulture);
2324
2325             ICollection[] connectionPoints = (ICollection[])ConnectionPointsCache[connectionPointKey];
2326             if (connectionPoints == null) {
2327                 connectionPoints = CreateConnectionPoints(type);
2328                 ConnectionPointsCache[connectionPointKey] = connectionPoints;
2329             }
2330
2331             return connectionPoints;
2332         }
2333
2334         internal ConsumerConnectionPoint GetConsumerConnectionPoint(WebPart webPart, string connectionPointID) {
2335             ConsumerConnectionPointCollection points = GetConsumerConnectionPoints(webPart);
2336             if (points != null && points.Count > 0) {
2337                 return points[connectionPointID];
2338             }
2339             else {
2340                 return null;
2341             }
2342         }
2343
2344         public virtual ConsumerConnectionPointCollection GetConsumerConnectionPoints(WebPart webPart) {
2345             if (webPart == null) {
2346                 throw new ArgumentNullException("webPart");
2347             }
2348             // Do not check that Controls.Contains(webPart), since this may be called on a WebPart
2349             // outside of a Zone.  Also, this method shouldn't really care whether the WebPart is
2350             // inside the WebPartManager.
2351
2352             return GetConsumerConnectionPoints(webPart.ToControl().GetType());
2353         }
2354
2355         private static ConsumerConnectionPointCollection GetConsumerConnectionPoints(Type type) {
2356             ICollection[] connectionPoints = GetConnectionPoints(type);
2357             return (ConsumerConnectionPointCollection)connectionPoints[0];
2358         }
2359
2360         public static WebPartManager GetCurrentWebPartManager(Page page) {
2361             if (page == null) {
2362                 throw new ArgumentNullException("page");
2363             }
2364
2365             return page.Items[typeof(WebPartManager)] as WebPartManager;
2366         }
2367
2368         // Before PreRender, return String.Empty.
2369         // On first call to this function after PreRender, compute DisplayTitle for all WebParts
2370         // and save it in a dictionary.  WebPart.DisplayTitle is nonvirtual and calls this method every time.
2371         // A derived WebPartManager can override this method to compute and store DisplayTitle any way it
2372         // sees fit.  It could compute the values sooner than PreRender.
2373         protected internal virtual string GetDisplayTitle(WebPart webPart) {
2374             if (webPart == null) {
2375                 throw new ArgumentNullException("webPart");
2376             }
2377             if (!Controls.Contains(webPart)) {
2378                 throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "webPart");
2379             }
2380
2381             if (!_allowCreateDisplayTitles) {
2382                 return String.Empty;
2383             }
2384
2385             if (_displayTitles == null) {
2386                 _displayTitles = CreateDisplayTitles();
2387             }
2388
2389             string displayTitle = (string)_displayTitles[webPart];
2390             Debug.Assert(!String.IsNullOrEmpty(displayTitle));
2391             return displayTitle;
2392         }
2393
2394         private static ICollection GetEnabledConnectionPoints(ICollection connectionPoints, WebPart webPart) {
2395             Control control = webPart.ToControl();
2396             ArrayList enabledPoints = new ArrayList();
2397             foreach (ConnectionPoint point in connectionPoints) {
2398                 if (point.GetEnabled(control)) {
2399                     enabledPoints.Add(point);
2400                 }
2401             }
2402             return enabledPoints;
2403         }
2404
2405         internal ConsumerConnectionPointCollection GetEnabledConsumerConnectionPoints(WebPart webPart) {
2406             ICollection enabledPoints = GetEnabledConnectionPoints(GetConsumerConnectionPoints(webPart), webPart);
2407             return new ConsumerConnectionPointCollection(enabledPoints);
2408         }
2409
2410         internal ProviderConnectionPointCollection GetEnabledProviderConnectionPoints(WebPart webPart) {
2411             ICollection enabledPoints = GetEnabledConnectionPoints(GetProviderConnectionPoints(webPart), webPart);
2412             return new ProviderConnectionPointCollection(enabledPoints);
2413         }
2414
2415         public string GetExportUrl(WebPart webPart) {
2416             string personalizationScope =
2417                 (Personalization.Scope == PersonalizationScope.Shared) ? "&scope=shared" : String.Empty;
2418             string queryString = Page.Request.QueryStringText;
2419
2420             return Page.Request.FilePath + "?" + Page.WebPartExportID + "=true&webPart=" +
2421                 HttpUtility.UrlEncode(webPart.ID) +
2422                 (!String.IsNullOrEmpty(queryString) ?
2423                     "&query=" + HttpUtility.UrlEncode(queryString) :
2424                     String.Empty) +
2425                 personalizationScope;
2426         }
2427
2428         private static Type GetExportType(string name) {
2429             switch (name) {
2430                 case ExportTypeString:
2431                     return typeof(string);
2432                 case ExportTypeInt:
2433                     return typeof(int);
2434                 case ExportTypeBool:
2435                     return typeof(bool);
2436                 case ExportTypeDouble:
2437                     return typeof(double);
2438                 case ExportTypeSingle:
2439                     return typeof(Single);
2440                 case ExportTypeDateTime:
2441                     return typeof(DateTime);
2442                 case ExportTypeColor:
2443                     return typeof(Color);
2444                 case ExportTypeUnit:
2445                     return typeof(Unit);
2446                 case ExportTypeFontSize:
2447                     return typeof(FontSize);
2448                 case ExportTypeDirection:
2449                     return typeof(ContentDirection);
2450                 case ExportTypeHelpMode:
2451                     return typeof(WebPartHelpMode);
2452                 case ExportTypeChromeState:
2453                     return typeof(PartChromeState);
2454                 case ExportTypeChromeType:
2455                     return typeof(PartChromeType);
2456                 case ExportTypeExportMode:
2457                     return typeof(WebPartExportMode);
2458                 case ExportTypeObject:
2459                     return typeof(object);
2460                 default:
2461                     return WebPartUtil.DeserializeType(name, false);
2462             }
2463         }
2464
2465         private static string GetExportName(Type type) {
2466             if (type == typeof(string)) {
2467                 return ExportTypeString;
2468             }
2469             else if (type == typeof(int)) {
2470                 return ExportTypeInt;
2471             }
2472             else if (type == typeof(bool)) {
2473                 return ExportTypeBool;
2474             }
2475             else if (type == typeof(double)) {
2476                 return ExportTypeDouble;
2477             }
2478             else if (type == typeof(Single)) {
2479                 return ExportTypeSingle;
2480             }
2481             else if (type == typeof(DateTime)) {
2482                 return ExportTypeDateTime;
2483             }
2484             else if (type == typeof(Color)) {
2485                 return ExportTypeColor;
2486             }
2487             else if (type == typeof(Unit)) {
2488                 return ExportTypeUnit;
2489             }
2490             else if (type == typeof(FontSize)) {
2491                 return ExportTypeFontSize;
2492             }
2493             else if (type == typeof(ContentDirection)) {
2494                 return ExportTypeDirection;
2495             }
2496             else if (type == typeof(WebPartHelpMode)) {
2497                 return ExportTypeHelpMode;
2498             }
2499             else if (type == typeof(PartChromeState)) {
2500                 return ExportTypeChromeState;
2501             }
2502             else if (type == typeof(PartChromeType)) {
2503                 return ExportTypeChromeType;
2504             }
2505             else if (type == typeof(WebPartExportMode)) {
2506                 return ExportTypeExportMode;
2507             }
2508             else if (type == typeof(object)) {
2509                 return ExportTypeObject;
2510             }
2511             else {
2512                 return type.AssemblyQualifiedName;
2513             }
2514         }
2515
2516         /// <devdoc>
2517         /// Used by the page developer to get a reference to the WebPart that contains a control
2518         /// placed in a WebPartZone.  Returns null if the control is not inside a WebPart.
2519         /// </devdoc>
2520         public GenericWebPart GetGenericWebPart(Control control) {
2521              if (control == null) {
2522                  throw new ArgumentNullException("control");
2523              }
2524
2525              // PERF: First check the parent of the control, before looping through all GenericWebParts
2526              Control parent = control.Parent;
2527              GenericWebPart genericParent = parent as GenericWebPart;
2528              if (genericParent != null && genericParent.ChildControl == control) {
2529                  return genericParent;
2530              }
2531              else {
2532                  foreach (WebPart part in Controls) {
2533                      GenericWebPart genericPart = part as GenericWebPart;
2534                      if (genericPart != null && genericPart.ChildControl == control) {
2535                          return genericPart;
2536                      }
2537                  }
2538              }
2539
2540              return null;
2541         }
2542
2543         internal ProviderConnectionPoint GetProviderConnectionPoint(WebPart webPart, string connectionPointID) {
2544             ProviderConnectionPointCollection points = GetProviderConnectionPoints(webPart);
2545             if (points != null && points.Count > 0) {
2546                 return points[connectionPointID];
2547             }
2548             else {
2549                 return null;
2550             }
2551         }
2552
2553         public virtual ProviderConnectionPointCollection GetProviderConnectionPoints(WebPart webPart) {
2554             if (webPart == null) {
2555                 throw new ArgumentNullException("webPart");
2556             }
2557             // Do not check that Controls.Contains(webPart), since this may be called on a WebPart
2558             // outside of a Zone.  Also, this method shouldn't really care whether the WebPart is
2559             // inside the WebPartManager.
2560
2561             return GetProviderConnectionPoints(webPart.ToControl().GetType());
2562         }
2563
2564         private static ProviderConnectionPointCollection GetProviderConnectionPoints(Type type) {
2565             ICollection[] connectionPoints = GetConnectionPoints(type);
2566             return (ProviderConnectionPointCollection)connectionPoints[1];
2567         }
2568
2569         /// <devdoc>
2570         /// Returns the web parts that should currently be rendered by the zone.  It is important that
2571         /// this method filter out any web parts that will not be rendered by the zone, otherwise
2572         /// the AddWebPart method will not work correctly (VSWhidbey 77719)
2573         /// </devdoc>
2574         internal WebPartCollection GetWebPartsForZone(WebPartZoneBase zone) {
2575             if (zone == null) {
2576                 throw new ArgumentNullException("zone");
2577             }
2578             if (_webPartZones.Contains(zone) == false) {
2579                 throw new ArgumentException(SR.GetString(SR.WebPartManager_MustRegister), "zone");
2580             }
2581
2582             IList allWebPartsForZone = GetAllWebPartsForZone(zone);
2583             WebPartCollection webParts = new WebPartCollection();
2584
2585             if (allWebPartsForZone.Count > 0) {
2586                 foreach (WebPart part in allWebPartsForZone) {
2587                     if (ShouldRenderWebPartInZone(part, zone)) {
2588                         webParts.Add(part);
2589                     }
2590                 }
2591             }
2592
2593             return webParts;
2594         }
2595
2596         /// <devdoc>
2597         /// If the WebPart is a consumer on the given connection point, returns the corresponding connection.
2598         /// Else, returns null.
2599         /// </devdoc>
2600         internal WebPartConnection GetConnectionForConsumer(WebPart consumer, ConsumerConnectionPoint connectionPoint) {
2601             ConsumerConnectionPoint actualConnectionPoint = connectionPoint;
2602             // 
2603             if (connectionPoint == null) {
2604                 actualConnectionPoint = GetConsumerConnectionPoint(consumer, null);
2605             }
2606
2607             // PERF: Use the StaticConnections and DynamicConnections collections separately, instead
2608             // of using the Connections property which is created on every call.
2609             foreach (WebPartConnection connection in StaticConnections) {
2610                 if (!Internals.ConnectionDeleted(connection) && connection.Consumer == consumer) {
2611                     ConsumerConnectionPoint c =
2612                         GetConsumerConnectionPoint(consumer, connection.ConsumerConnectionPointID);
2613                     if (c == actualConnectionPoint) {
2614                         return connection;
2615                     }
2616                 }
2617             }
2618
2619             foreach (WebPartConnection connection in DynamicConnections) {
2620                 if (!Internals.ConnectionDeleted(connection) && connection.Consumer == consumer) {
2621                     ConsumerConnectionPoint c =
2622                         GetConsumerConnectionPoint(consumer, connection.ConsumerConnectionPointID);
2623                     if (c == actualConnectionPoint) {
2624                         return connection;
2625                     }
2626                 }
2627             }
2628
2629             return null;
2630         }
2631
2632         /// <devdoc>
2633         /// If the WebPart is a provider on the given connection point, returns the corresponding connection.
2634         /// Else, returns null.
2635         /// </devdoc>
2636         internal WebPartConnection GetConnectionForProvider(WebPart provider, ProviderConnectionPoint connectionPoint) {
2637             ProviderConnectionPoint actualConnectionPoint = connectionPoint;
2638             if (connectionPoint == null) {
2639                 actualConnectionPoint = GetProviderConnectionPoint(provider, null);
2640             }
2641
2642             // PERF: Use the StaticConnections and DynamicConnections collections separately, instead
2643             // of using the Connections property which is created on every call.
2644             foreach (WebPartConnection connection in StaticConnections) {
2645                 if (!Internals.ConnectionDeleted(connection) && connection.Provider == provider) {
2646                     ProviderConnectionPoint c =
2647                         GetProviderConnectionPoint(provider, connection.ProviderConnectionPointID);
2648                     if (c == actualConnectionPoint) {
2649                         return connection;
2650                     }
2651                 }
2652             }
2653
2654             foreach (WebPartConnection connection in DynamicConnections) {
2655                 if (!Internals.ConnectionDeleted(connection) && connection.Provider == provider) {
2656                     ProviderConnectionPoint c =
2657                         GetProviderConnectionPoint(provider, connection.ProviderConnectionPointID);
2658                     if (c == actualConnectionPoint) {
2659                         return connection;
2660                     }
2661                 }
2662             }
2663
2664             return null;
2665         }
2666
2667         private static void ImportReadTo(XmlReader reader, string elementToFind) {
2668             while (reader.Name != elementToFind) {
2669                 if (!reader.Read()) {
2670                     throw new XmlException();
2671                 }
2672             }
2673         }
2674
2675         private static void ImportReadTo(XmlReader reader, string elementToFindA, string elementToFindB) {
2676             while (reader.Name != elementToFindA && reader.Name != elementToFindB) {
2677                 if (!reader.Read()) {
2678                     throw new XmlException();
2679                 }
2680             }
2681         }
2682
2683         private static void ImportSkipTo(XmlReader reader, string elementToFind) {
2684             while (reader.Name != elementToFind) {
2685                 reader.Skip();
2686                 if (reader.EOF) {
2687                     throw new XmlException();
2688                 }
2689             }
2690         }
2691
2692         /// <devdoc>
2693         /// Never throws except for null arguments. Returns an error message in the out parameter instead.
2694         /// [Microsoft] I investigated whether this could be refactored to share common code with
2695         ///           LoadDynamicWebPart(), but it seems the methods are too different.
2696         /// </devdoc>
2697         public virtual WebPart ImportWebPart(XmlReader reader, out string errorMessage) {
2698             Personalization.EnsureEnabled(/* ensureModifiable */ true);
2699
2700             if (reader == null) {
2701                 throw new ArgumentNullException("reader");
2702             }
2703
2704             bool permitOnly = false;
2705
2706             if (UsePermitOnly) {
2707                 MinimalPermissionSet.PermitOnly();
2708                 permitOnly = true;
2709             }
2710             string importErrorMessage = string.Empty;
2711             // Extra try-catch block to prevent elevation of privilege attack via exception filter
2712             try {
2713                 try {
2714                     // Get to the metadata
2715                     reader.MoveToContent();
2716                     reader.ReadStartElement(ExportRootElement);
2717                     ImportSkipTo(reader, ExportPartElement);
2718                     // Check the version on the webPart element
2719                     string version = reader.GetAttribute(ExportPartNamespaceAttribute);
2720                     if (String.IsNullOrEmpty(version)) {
2721                         errorMessage = SR.GetString(SR.WebPart_ImportErrorNoVersion);
2722                         return null;
2723                     }
2724                     if (!String.Equals(version, ExportPartNamespaceValue, StringComparison.OrdinalIgnoreCase)) {
2725                         errorMessage = SR.GetString(SR.WebPart_ImportErrorInvalidVersion);
2726                         return null;
2727                     }
2728                     ImportReadTo(reader, ExportMetaDataElement);
2729                     reader.ReadStartElement(ExportMetaDataElement);
2730                     // Get the type name
2731                     string partTypeName = null;
2732                     string userControlTypeName = null;
2733                     ImportSkipTo(reader, ExportTypeElement);
2734                     partTypeName = reader.GetAttribute(ExportTypeNameAttribute);
2735                     userControlTypeName = reader.GetAttribute(ExportUserControlSrcAttribute);
2736                     // Get the error message to display if unsuccessful to load the type
2737                     ImportSkipTo(reader, ExportErrorMessageElement);
2738                     importErrorMessage = reader.ReadElementString();
2739                     // Get a type object from the type name
2740                     Type partType;
2741                     WebPart part = null;
2742                     Control childControl = null;
2743
2744                     try {
2745                         // If we are in shared scope, we are importing a shared WebPart
2746                         bool isShared = (Personalization.Scope == PersonalizationScope.Shared);
2747
2748                         if (!String.IsNullOrEmpty(partTypeName)) {
2749
2750                             if (UsePermitOnly) {
2751                                 CodeAccessPermission.RevertPermitOnly();
2752                                 permitOnly = false;
2753                                 MediumPermissionSet.PermitOnly();
2754                                 permitOnly = true;
2755                             }
2756
2757                             partType = WebPartUtil.DeserializeType(partTypeName, true);
2758
2759                             if (UsePermitOnly) {
2760                                 CodeAccessPermission.RevertPermitOnly();
2761                                 permitOnly = false;
2762                                 MinimalPermissionSet.PermitOnly();
2763                                 permitOnly = true;
2764                             }
2765
2766                             // First check if the type is authorized
2767                             if (!IsAuthorized(partType, null, null, isShared)) {
2768                                 errorMessage = SR.GetString(SR.WebPartManager_ForbiddenType);
2769                                 return null;
2770                             }
2771                             // If the type is not a webpart, create a generic Web Part
2772                             if (!partType.IsSubclassOf(typeof(WebPart))) {
2773                                 if (!partType.IsSubclassOf(typeof(Control))) {
2774                                     // We only allow for Controls (VSWhidbey 428511)
2775                                     errorMessage = SR.GetString(SR.WebPartManager_TypeMustDeriveFromControl);
2776                                     return null;
2777                                 }
2778                                 // Create an instance of the object
2779                                 childControl = (Control)(Internals.CreateObjectFromType(partType));
2780                                 childControl.ID = CreateDynamicWebPartID(partType);
2781                                 part = CreateWebPart(childControl);
2782                             }
2783                             else {
2784                                 // Create an instance of the object
2785                                 part = (WebPart)(Internals.CreateObjectFromType(partType));
2786                             }
2787                         }
2788                         else {
2789                             // Instantiate a user control in a generic web part
2790
2791                             // Check if the path is authorized
2792                             if (!IsAuthorized(typeof(UserControl), userControlTypeName, null, isShared)) {
2793                                 errorMessage = SR.GetString(SR.WebPartManager_ForbiddenType);
2794                                 return null;
2795                             }
2796
2797                             if (UsePermitOnly) {
2798                                 CodeAccessPermission.RevertPermitOnly();
2799                                 permitOnly = false;
2800                             }
2801                             childControl = Page.LoadControl(userControlTypeName);
2802                             partType = childControl.GetType();
2803                             if (UsePermitOnly) {
2804                                 MinimalPermissionSet.PermitOnly();
2805                                 permitOnly = true;
2806                             }
2807                             childControl.ID = CreateDynamicWebPartID(partType);
2808                             part = CreateWebPart(childControl);
2809                         }
2810                     }
2811                     catch {
2812                         if (!String.IsNullOrEmpty(importErrorMessage)) {
2813                             errorMessage = importErrorMessage;
2814                         }
2815                         else {
2816                             errorMessage = SR.GetString(SR.WebPartManager_ErrorLoadingWebPartType);
2817                         }
2818                         return null;
2819                     }
2820
2821                     // Set default error message for all subsequent errors
2822                     if (String.IsNullOrEmpty(importErrorMessage)) {
2823                         importErrorMessage = SR.GetString(SR.WebPart_DefaultImportErrorMessage);
2824                     }
2825                     // Get to the data
2826                     ImportSkipTo(reader, ExportDataElement);
2827                     reader.ReadStartElement(ExportDataElement);
2828                     ImportSkipTo(reader, ExportPropertiesElement);
2829                     if (!reader.IsEmptyElement) {
2830                         reader.ReadStartElement(ExportPropertiesElement);
2831                         // Special-case IPersonalizable controls
2832                         // ImportFromReader will set the right permission set when appropriate, reverting before we call
2833                         if (UsePermitOnly) {
2834                             CodeAccessPermission.RevertPermitOnly();
2835                             permitOnly = false;
2836                         }
2837                         ImportIPersonalizable(reader, (childControl != null ? childControl : part));
2838                         if (UsePermitOnly) {
2839                             MinimalPermissionSet.PermitOnly();
2840                             permitOnly = true;
2841                         }
2842                     }
2843                     // Set property values from XML description
2844                     IDictionary personalizableProperties;
2845                     if (childControl != null) {
2846                         if (!reader.IsEmptyElement) {
2847                             // Get the collection of personalizable properties for the child control
2848                             personalizableProperties = PersonalizableAttribute.GetPersonalizablePropertyEntries(partType);
2849
2850                             // Copied from below.  We must also execute this code when parsing the ChildControl
2851                             // IPersonalizable and Personalizable properties.
2852                             while (reader.Name != ExportPropertyElement) {
2853                                 reader.Skip();
2854                                 if (reader.EOF) {
2855                                     errorMessage = null;
2856                                     return part;
2857                                 }
2858                             }                            
2859                             
2860                             // ImportFromReader will set the right permission set when appropriate, reverting before we call
2861                             if (UsePermitOnly) {
2862                                 CodeAccessPermission.RevertPermitOnly();
2863                                 permitOnly = false;
2864                             }
2865                             ImportFromReader(personalizableProperties, childControl, reader);
2866                             if (UsePermitOnly) {
2867                                 MinimalPermissionSet.PermitOnly();
2868                                 permitOnly = true;
2869                             }
2870                         }
2871                         // And then for the generic WebPart
2872                         ImportSkipTo(reader, ExportGenericPartPropertiesElement);
2873                         reader.ReadStartElement(ExportGenericPartPropertiesElement);
2874                         // ImportFromReader will set the right permission set when appropriate, reverting before we call
2875                         if (UsePermitOnly) {
2876                             CodeAccessPermission.RevertPermitOnly();
2877                             permitOnly = false;
2878                         }
2879                         ImportIPersonalizable(reader, part);
2880                         if (UsePermitOnly) {
2881                             MinimalPermissionSet.PermitOnly();
2882                             permitOnly = true;
2883                         }
2884                         personalizableProperties = PersonalizableAttribute.GetPersonalizablePropertyEntries(part.GetType());
2885                     }
2886                     else {
2887                         // Get the collection of personalizable properties
2888                         personalizableProperties = PersonalizableAttribute.GetPersonalizablePropertyEntries(partType);
2889                     }
2890
2891                     while (reader.Name != ExportPropertyElement) {
2892                         reader.Skip();
2893                         if (reader.EOF) {
2894                             errorMessage = null;
2895                             return part;
2896                         }
2897                     }
2898
2899                     // ImportFromReader will set the right permission set when appropriate, reverting before we call
2900                     if (UsePermitOnly) {
2901                         CodeAccessPermission.RevertPermitOnly();
2902                         permitOnly = false;
2903                     }
2904                     ImportFromReader(personalizableProperties, part, reader);
2905                     if (UsePermitOnly) {
2906                         MinimalPermissionSet.PermitOnly();
2907                         permitOnly = true;
2908                     }
2909                     errorMessage = null;
2910                     // Return imported part
2911                     return part;
2912                 }
2913                 catch (XmlException) {
2914                     errorMessage = SR.GetString(SR.WebPartManager_ImportInvalidFormat);
2915                     return null;
2916                 }
2917                 catch (Exception e) {
2918                     if ((Context != null) && (Context.IsCustomErrorEnabled)) {
2919                         errorMessage = (importErrorMessage.Length != 0) ?
2920                             importErrorMessage :
2921                             SR.GetString(SR.WebPart_DefaultImportErrorMessage);
2922                     }
2923                     else {
2924                         errorMessage = e.Message;
2925                     }
2926                     return null;
2927                 }
2928                 finally {
2929                     if (permitOnly) {
2930                         // revert if you're not just exiting the stack frame anyway
2931                         CodeAccessPermission.RevertPermitOnly();
2932                     }
2933                 }
2934             }
2935             catch {
2936                 throw;
2937             }
2938         }
2939
2940         private void ImportIPersonalizable(XmlReader reader, Control control) {
2941             if (control is IPersonalizable) {
2942                 // The control may implement IPersonalizable, but the .WebPart file may not contain
2943                 // an "ipersonalizable" element.  The WebPart may have returned no data from its
2944                 // IPersonalizable.Save() method, or the WebPart may have been recently changed to
2945                 // implement IPersonalizable.  This are valid scenarios, so we should not require
2946                 // the XML to contain the "ipersonalizable" element. (VSWhidbey 499016)
2947
2948                 // Read to the next element that is either "property" or "ipersonalizable".
2949                 ImportReadTo(reader, ExportIPersonalizableElement, ExportPropertyElement);
2950
2951                 // If the next element is "ipersonalizable", then we import the IPersonalizable data.
2952                 // Else, we do nothing, and the current "property" element will be imported as a standard
2953                 // personalizable property.
2954                 if (reader.Name == ExportIPersonalizableElement) {
2955                     // Create a dictionary from the XML description
2956                     reader.ReadStartElement(ExportIPersonalizableElement);
2957                     ImportFromReader(null, control, reader);
2958                 }
2959             }
2960         }
2961
2962         private void ImportFromReader(IDictionary personalizableProperties,
2963                                       Control target,
2964                                       XmlReader reader) {
2965
2966             Debug.Assert(target != null);
2967
2968             ImportReadTo(reader, ExportPropertyElement);
2969
2970             bool permitOnly = false;
2971
2972             if (UsePermitOnly) {
2973                 MinimalPermissionSet.PermitOnly();
2974                 permitOnly = true;
2975             }
2976
2977             try {
2978                 try {
2979                     IDictionary properties;
2980                     if (personalizableProperties != null) {
2981                         properties = new HybridDictionary();
2982                     }
2983                     else {
2984                         properties = new PersonalizationDictionary();
2985                     }
2986                     // Set properties from the xml document
2987                     while (reader.Name == ExportPropertyElement) {
2988                         // Get the name of the property
2989                         string propertyName = reader.GetAttribute(ExportPropertyNameAttribute);
2990                         string typeName = reader.GetAttribute(ExportPropertyTypeAttribute);
2991                         string scope = reader.GetAttribute(ExportPropertyScopeAttribute);
2992                         bool isNull = String.Equals(
2993                             reader.GetAttribute(ExportPropertyNullAttribute),
2994                             "true",
2995                             StringComparison.OrdinalIgnoreCase);
2996
2997                         // Do not import Zone information or AuthorizationFilter or custom data
2998                         if (propertyName == AuthorizationFilterName ||
2999                              propertyName == ZoneIDName ||
3000                              propertyName == ZoneIndexName) {
3001
3002                             reader.ReadElementString();
3003                             if (!reader.Read()) {
3004                                 throw new XmlException();
3005                             }
3006                         }
3007                         else {
3008                             string valString = reader.ReadElementString();
3009                             object val = null;
3010                             bool valueComputed = false;
3011                             PropertyInfo pi = null;
3012                             if (personalizableProperties != null) {
3013                                 // Get the relevant personalizable property on the target (no need to check the property is personalizable)
3014                                 PersonalizablePropertyEntry entry = (PersonalizablePropertyEntry)(personalizableProperties[propertyName]);
3015                                 if (entry != null) {
3016                                     pi = entry.PropertyInfo;
3017                                     Debug.Assert(pi != null);
3018                                     // If the property is a url, validate protocol (VSWhidbey 290418)
3019                                     UrlPropertyAttribute urlAttr = Attribute.GetCustomAttribute(pi, typeof(UrlPropertyAttribute), true) as UrlPropertyAttribute;
3020                                     if (urlAttr != null && CrossSiteScriptingValidation.IsDangerousUrl(valString)) {
3021                                         throw new InvalidDataException(SR.GetString(SR.WebPart_BadUrl, valString));
3022                                     }
3023                                 }
3024                             }
3025
3026                             Type type = null;
3027                             if (!String.IsNullOrEmpty(typeName)) {
3028                                 if (UsePermitOnly) {
3029                                     // Need medium trust to call BuildManager.GetType()
3030                                     CodeAccessPermission.RevertPermitOnly();
3031                                     permitOnly = false;
3032                                     MediumPermissionSet.PermitOnly();
3033                                     permitOnly = true;
3034                                 }
3035                                 type = GetExportType(typeName);
3036
3037                                 if (UsePermitOnly) {
3038                                     CodeAccessPermission.RevertPermitOnly();
3039                                     permitOnly = false;
3040                                     MinimalPermissionSet.PermitOnly();
3041                                     permitOnly = true;
3042                                 }
3043                             }
3044
3045                             if ((pi != null) && ((pi.PropertyType == type) || (type == null))) {
3046                                 // Look at the target property
3047                                 // See if the property itself has a type converter associated with it
3048                                 TypeConverterAttribute attr = Attribute.GetCustomAttribute(pi, typeof(TypeConverterAttribute), true) as TypeConverterAttribute;
3049                                 if (attr != null) {
3050                                     if (UsePermitOnly) {
3051                                         // Need medium trust to call BuildManager.GetType()
3052                                         CodeAccessPermission.RevertPermitOnly();
3053                                         permitOnly = false;
3054                                         MediumPermissionSet.PermitOnly();
3055                                         permitOnly = true;
3056                                     }
3057
3058                                     Type converterType = WebPartUtil.DeserializeType(attr.ConverterTypeName, false);
3059
3060                                     if (UsePermitOnly) {
3061                                         CodeAccessPermission.RevertPermitOnly();
3062                                         permitOnly = false;
3063                                         MinimalPermissionSet.PermitOnly();
3064                                         permitOnly = true;
3065                                     }
3066
3067                                     // SECURITY: Check that the type is a subclass of TypeConverter before instantiating.
3068                                     if (converterType != null && converterType.IsSubclassOf(typeof(TypeConverter))) {
3069                                         TypeConverter converter = (TypeConverter)(Internals.CreateObjectFromType(converterType));
3070                                         if (Util.CanConvertToFrom(converter, typeof(string))) {
3071                                             if (!isNull) {
3072                                                 val = converter.ConvertFromInvariantString(valString);
3073                                             }
3074                                             valueComputed = true;
3075                                         }
3076                                     }
3077                                 }
3078                                 // Then, look at the converters on the property type
3079                                 if (!valueComputed) {
3080                                     // Use the type converter associated with the type itself
3081                                     TypeConverter converter = TypeDescriptor.GetConverter(pi.PropertyType);
3082                                     if (Util.CanConvertToFrom(converter, typeof(string))) {
3083                                         if (!isNull) {
3084                                             val = converter.ConvertFromInvariantString(valString);
3085                                         }
3086                                         valueComputed = true;
3087                                         // Not importing anything else for security reasons
3088                                     }
3089                                 }
3090                             }
3091                             // finally, use the XML-specified type
3092                             if (!valueComputed && (type != null)) {
3093                                 // Look at the XML-declared type
3094                                 if (type == typeof(string)) {
3095                                     if (!isNull) {
3096                                         val = valString;
3097                                     }
3098                                     valueComputed = true;
3099                                 }
3100                                 else {
3101                                     TypeConverter typeConverter = TypeDescriptor.GetConverter(type);
3102                                     if (Util.CanConvertToFrom(typeConverter, typeof(string))) {
3103                                         if (!isNull) {
3104                                             val = typeConverter.ConvertFromInvariantString(valString);
3105                                         }
3106                                         valueComputed = true;
3107                                     }
3108                                 }
3109                             }
3110
3111                             // Always want to import a null IPersonalizable value, since we will never have a type
3112                             // converter for the value.  However, we should not import a null Personalizable value
3113                             // unless the PropertyInfo had a type converter, since the property may be a value type
3114                             // that cannot accept null as a value. (VSWhidbey 537895)
3115                             if (isNull && personalizableProperties == null) {
3116                                 valueComputed = true;
3117                             }
3118
3119                             // Now we should have a value (val)
3120                             if (valueComputed) {
3121                                 if (personalizableProperties != null) {
3122                                     properties.Add(propertyName, val);
3123                                 }
3124                                 else {
3125                                     // Determine scope:
3126                                     PersonalizationScope personalizationScope =
3127                                         String.Equals(scope, PersonalizationScope.Shared.ToString(), StringComparison.OrdinalIgnoreCase) ?
3128                                         PersonalizationScope.Shared : PersonalizationScope.User;
3129                                     properties.Add(propertyName, new PersonalizationEntry(val, personalizationScope));
3130                                 }
3131                             }
3132                             else {
3133                                 throw new HttpException(SR.GetString(SR.WebPartManager_ImportInvalidData, propertyName));
3134                             }
3135                         }
3136                         while (reader.Name != ExportPropertyElement) {
3137                             if (reader.EOF ||
3138                                 (reader.Name == ExportGenericPartPropertiesElement) ||
3139                                 (reader.Name == ExportPropertiesElement) ||
3140                                 ((reader.Name == ExportIPersonalizableElement) && (reader.NodeType == XmlNodeType.EndElement))) {
3141                                 goto EndOfData;
3142                             }
3143                             reader.Skip();
3144                         }
3145                     }
3146                     EndOfData:
3147                     if (personalizableProperties != null) {
3148                         IDictionary unused = BlobPersonalizationState.SetPersonalizedProperties(target, properties);
3149                         if ((unused != null) && (unused.Count > 0)) {
3150                             IVersioningPersonalizable versioningTarget = target as IVersioningPersonalizable;
3151                             if (versioningTarget != null) {
3152                                 versioningTarget.Load(unused);
3153                             }
3154                         }
3155                     }
3156                     else {
3157                         Debug.Assert(target is IPersonalizable);
3158                         ((IPersonalizable)target).Load((PersonalizationDictionary)properties);
3159                     }
3160                 }
3161                 finally {
3162                     if (permitOnly) {
3163                         // revert if you're not just exiting the stack frame anyway
3164                         CodeAccessPermission.RevertPermitOnly();
3165                     }
3166                 }
3167             }
3168             catch {
3169                 throw;
3170             }
3171         }
3172
3173         public virtual bool IsAuthorized(Type type, string path, string authorizationFilter, bool isShared) {
3174             if (type == null) {
3175                 throw new ArgumentNullException("type");
3176             }
3177
3178             if (type == typeof(UserControl)) {
3179                 if (String.IsNullOrEmpty(path)) {
3180                     throw new ArgumentException(SR.GetString(SR.WebPartManager_PathCannotBeEmpty));
3181                 }
3182             }
3183             else {
3184                 if (!String.IsNullOrEmpty(path)) {
3185                     throw new ArgumentException(SR.GetString(SR.WebPartManager_PathMustBeEmpty, path));
3186                 }
3187             }
3188
3189             WebPartAuthorizationEventArgs auth = new WebPartAuthorizationEventArgs(type, path, authorizationFilter, isShared);
3190             OnAuthorizeWebPart(auth);
3191             return auth.IsAuthorized;
3192         }
3193
3194         public bool IsAuthorized(WebPart webPart) {
3195             if (webPart == null) {
3196                 throw new ArgumentNullException("webPart");
3197             }
3198
3199             // Do not check that Controls.Contains(webPart), since this will be called on a WebPart
3200             // before it is added to the Controls collection.
3201
3202             // Calculate authorizationFilter from property value and personalization data
3203             string authorizationFilter = webPart.AuthorizationFilter;
3204
3205             // webPart.ID will be null for imported WebParts.  Also, a user may want to call
3206             // this method on a WebPart before it has an ID.
3207             string webPartID = webPart.ID;
3208             if (!String.IsNullOrEmpty(webPartID) && Personalization.IsEnabled) {
3209                 string personalizedAuthorizationFilter = Personalization.GetAuthorizationFilter(webPart.ID);
3210                 if (personalizedAuthorizationFilter != null) {
3211                     authorizationFilter = personalizedAuthorizationFilter;
3212                 }
3213             }
3214
3215             GenericWebPart genericWebPart = webPart as GenericWebPart;
3216             if (genericWebPart != null) {
3217                 Type childType = null;
3218                 string childPath = null;
3219
3220                 Control childControl = genericWebPart.ChildControl;
3221                 UserControl childUserControl = childControl as UserControl;
3222                 if (childUserControl != null) {
3223                     childType = typeof(UserControl);
3224                     childPath = childUserControl.AppRelativeVirtualPath;
3225                 }
3226                 else {
3227                     childType = childControl.GetType();
3228                 }
3229
3230                 // Only authorize the type/path of the child control
3231                 // Don't need to authorize the GenericWebPart as well
3232                 return IsAuthorized(childType, childPath, authorizationFilter, webPart.IsShared);
3233             }
3234             else {
3235                 return IsAuthorized(webPart.GetType(), null, authorizationFilter, webPart.IsShared);
3236             }
3237         }
3238
3239         internal bool IsConsumerConnected(WebPart consumer, ConsumerConnectionPoint connectionPoint) {
3240             return (GetConnectionForConsumer(consumer, connectionPoint) != null);
3241         }
3242
3243         internal bool IsProviderConnected(WebPart provider, ProviderConnectionPoint connectionPoint) {
3244             return (GetConnectionForProvider(provider, connectionPoint) != null);
3245         }
3246
3247         /// <devdoc>
3248         /// Loads the control state for those properties that should persist across postbacks
3249         /// even when EnableViewState=false.
3250         /// </devdoc>
3251         protected internal override void LoadControlState(object savedState) {
3252             if (savedState == null) {
3253                 base.LoadControlState(null);
3254             }
3255             else {
3256                 object[] myState = (object[])savedState;
3257                 if (myState.Length != controlStateArrayLength) {
3258                     throw new ArgumentException(SR.GetString(SR.Invalid_ControlState));
3259                 }
3260
3261                 base.LoadControlState(myState[baseIndex]);
3262
3263                 // 
3264
3265                 if (myState[selectedWebPartIndex] != null) {
3266                     // All dynamic parts must be loaded before this point, in case a dynamic part is the
3267                     // SelectedWebPart.
3268                     WebPart selectedWebPart = WebParts[(string)myState[selectedWebPartIndex]];
3269                     if (selectedWebPart == null || selectedWebPart.IsClosed) {
3270                         // The SelectedWebPart was either closed or deleted between requests.
3271                         // Raise the changed event, since the SelectedWebPart was not null on the previous request.
3272                         SetSelectedWebPart(null);
3273                         OnSelectedWebPartChanged(new WebPartEventArgs(null));
3274                     }
3275                     else {
3276                         SetSelectedWebPart(selectedWebPart);
3277                     }
3278                 }
3279                 if (myState[displayModeIndex] != null) {
3280                     string modeName = (string)myState[displayModeIndex];
3281
3282                     WebPartDisplayMode restoredDisplayMode = SupportedDisplayModes[modeName];
3283                     if (!restoredDisplayMode.IsEnabled(this)) {
3284                         // Throw
3285                     }
3286
3287                     if (restoredDisplayMode == null) {
3288                         _displayMode = BrowseDisplayMode;
3289                         OnDisplayModeChanged(new WebPartDisplayModeEventArgs(null));
3290                     }
3291                     else {
3292                         _displayMode = restoredDisplayMode;
3293                     }
3294                 }
3295             }
3296         }
3297
3298         protected virtual void LoadCustomPersonalizationState(PersonalizationDictionary state) {
3299             // The state must be loaded after the Static Connections and WebParts have been added
3300             // to the WebPartManager (after the WebPartZone's and ProxyWebPartManager's Init methods)
3301             _personalizationState = state;
3302         }
3303
3304         private void LoadDynamicConnections(PersonalizationEntry entry) {
3305             if (entry != null) {
3306                 object[] dynamicConnectionState = (object[])entry.Value;
3307                 if (dynamicConnectionState != null) {
3308                     Debug.Assert(dynamicConnectionState.Length % 7 == 0);
3309                     for (int i = 0; i < dynamicConnectionState.Length; i += 7) {
3310                         string ID = (string)dynamicConnectionState[i];
3311                         string consumerID = (string)dynamicConnectionState[i + 1];
3312                         string consumerConnectionPointID = (string)dynamicConnectionState[i + 2];
3313                         string providerID = (string)dynamicConnectionState[i + 3];
3314                         string providerConnectionPointID = (string)dynamicConnectionState[i + 4];
3315
3316                         // Add a new connection to the collection
3317                         WebPartConnection connection = new WebPartConnection();
3318                         connection.ID = ID;
3319                         connection.ConsumerID = consumerID;
3320                         connection.ConsumerConnectionPointID = consumerConnectionPointID;
3321                         connection.ProviderID = providerID;
3322                         connection.ProviderConnectionPointID = providerConnectionPointID;
3323                         Internals.SetIsShared(connection, (entry.Scope == PersonalizationScope.Shared));
3324                         Internals.SetIsStatic(connection, false);
3325
3326                         Type type = dynamicConnectionState[i + 5] as Type;
3327                         if (type != null) {
3328                             // SECURITY: Only instantiate type if it is a subclass of WebPartTransformer
3329                             if (type.IsSubclassOf(typeof(WebPartTransformer))) {
3330                                 object configuration = dynamicConnectionState[i + 6];
3331                                 WebPartTransformer transformer = (WebPartTransformer)Internals.CreateObjectFromType(type);
3332                                 Internals.LoadConfigurationState(transformer, configuration);
3333                                 Internals.SetTransformer(connection, transformer);
3334                             }
3335                             else {
3336                                 throw new InvalidOperationException(SR.GetString(SR.WebPartTransformerAttribute_NotTransformer, type.Name));
3337                             }
3338                         }
3339
3340                         DynamicConnections.Add(connection);
3341                     }
3342                 }
3343             }
3344         }
3345
3346         private void LoadDynamicWebPart(string id, string typeName, string path, string genericWebPartID, bool isShared) {
3347             WebPart dynamicWebPart = null;
3348             Type type = WebPartUtil.DeserializeType(typeName, false);
3349             if (type == null) {
3350                 string errorMessage;
3351                 if (Context != null && Context.IsCustomErrorEnabled) {
3352                     errorMessage = SR.GetString(SR.WebPartManager_ErrorLoadingWebPartType);
3353                 }
3354                 else {
3355                     errorMessage = SR.GetString(SR.Invalid_type, typeName);
3356                 }
3357                 dynamicWebPart = CreateErrorWebPart(id, typeName, path, genericWebPartID, errorMessage);
3358             }
3359             else if (type.IsSubclassOf(typeof(WebPart))) {
3360                 string authorizationFilter = Personalization.GetAuthorizationFilter(id);
3361                 if (IsAuthorized(type, null, authorizationFilter, isShared)) {
3362                     try {
3363                         dynamicWebPart = (WebPart)Internals.CreateObjectFromType(type);
3364                         dynamicWebPart.ID = id;
3365                     }
3366                     catch {
3367                         // If custom errors are enabled, we do not want to render the type name to the browser.
3368                         // (VSWhidbey 381646)
3369                         string errorMessage;
3370                         if (Context != null && Context.IsCustomErrorEnabled) {
3371                             errorMessage = SR.GetString(SR.WebPartManager_CantCreateInstance);
3372                         }
3373                         else {
3374                             errorMessage = SR.GetString(SR.WebPartManager_CantCreateInstanceWithType, typeName);
3375                         }
3376                         dynamicWebPart = CreateErrorWebPart(id, typeName, path, genericWebPartID, errorMessage);
3377                     }
3378                 }
3379                 else {
3380                     dynamicWebPart = new UnauthorizedWebPart(id, typeName, path, genericWebPartID);
3381                 }
3382             }
3383             else if (type.IsSubclassOf(typeof(Control))) {
3384                 string authorizationFilter = Personalization.GetAuthorizationFilter(genericWebPartID);
3385                 if (IsAuthorized(type, path, authorizationFilter, isShared)) {
3386                     Control childControl = null;
3387                     try {
3388                         if (!String.IsNullOrEmpty(path)) {
3389                             Debug.Assert(type == typeof(UserControl));
3390                             childControl = Page.LoadControl(path);
3391                         }
3392                         else {
3393                             childControl = (Control)Internals.CreateObjectFromType(type);
3394                         }
3395                         childControl.ID = id;
3396
3397                         dynamicWebPart = CreateWebPart(childControl);
3398                         dynamicWebPart.ID = genericWebPartID;
3399                     }
3400                     catch {
3401                         string errorMessage;
3402                         if (childControl == null && String.IsNullOrEmpty(path)) {
3403                             if (Context != null && Context.IsCustomErrorEnabled) {
3404                                 errorMessage = SR.GetString(SR.WebPartManager_CantCreateInstance);
3405                             }
3406                             else {
3407                                 errorMessage = SR.GetString(SR.WebPartManager_CantCreateInstanceWithType, typeName);
3408                             }
3409                         }
3410                         else if (childControl == null) {
3411                             if (Context != null && Context.IsCustomErrorEnabled) {
3412                                 errorMessage = SR.GetString(SR.WebPartManager_InvalidPath);
3413                             }
3414                             else {
3415                                 errorMessage = SR.GetString(SR.WebPartManager_InvalidPathWithPath, path);
3416                             }
3417                         }
3418                         else {
3419                             errorMessage = SR.GetString(SR.WebPartManager_CantCreateGeneric);
3420                         }
3421                         dynamicWebPart = CreateErrorWebPart(id, typeName, path, genericWebPartID, errorMessage);
3422                     }
3423                 }
3424                 else {
3425                     dynamicWebPart = new UnauthorizedWebPart(id, typeName, path, genericWebPartID);
3426                 }
3427             }
3428             else {
3429                 // Type is not a subclass of Control.  For security, do not even instantiate
3430                 // the type (VSWhidbey 428511).
3431                 string errorMessage;
3432                 if (Context != null && Context.IsCustomErrorEnabled) {
3433                     errorMessage = SR.GetString(SR.WebPartManager_TypeMustDeriveFromControl);
3434                 }
3435                 else {
3436                     errorMessage = SR.GetString(SR.WebPartManager_TypeMustDeriveFromControlWithType, typeName);
3437                 }
3438                 dynamicWebPart = CreateErrorWebPart(id, typeName, path, genericWebPartID, errorMessage);
3439             }
3440
3441             Debug.Assert(dynamicWebPart != null);
3442             Internals.SetIsStatic(dynamicWebPart, false);
3443             Internals.SetIsShared(dynamicWebPart, isShared);
3444             Internals.AddWebPart(dynamicWebPart);
3445         }
3446
3447         private void LoadDynamicWebParts(PersonalizationEntry entry) {
3448             if (entry != null) {
3449                 object[] dynamicWebPartState = (object[])entry.Value;
3450                 if (dynamicWebPartState != null) {
3451                     Debug.Assert(dynamicWebPartState.Length % 4 == 0);
3452                     bool isShared = (entry.Scope == PersonalizationScope.Shared);
3453
3454                     // 
3455                     for (int i = 0; i < dynamicWebPartState.Length; i += 4) {
3456                         string id = (string)dynamicWebPartState[i];
3457                         string typeName = (string)dynamicWebPartState[i + 1];
3458                         string path = (string)dynamicWebPartState[i + 2];
3459                         string genericWebPartID = (string)dynamicWebPartState[i + 3];
3460
3461                         LoadDynamicWebPart(id, typeName, path, genericWebPartID, isShared);
3462                     }
3463                 }
3464             }
3465         }
3466
3467         private void LoadDeletedConnectionState(PersonalizationEntry entry) {
3468             if (entry != null) {
3469                 string[] deletedConnections = (string[])entry.Value;
3470                 if (deletedConnections != null) {
3471                     for (int i=0; i < deletedConnections.Length; i++) {
3472                         string idToDelete = deletedConnections[i];
3473                         WebPartConnection connectionToDelete = null;
3474
3475                         foreach (WebPartConnection connection in StaticConnections) {
3476                             if (String.Equals(connection.ID, idToDelete, StringComparison.OrdinalIgnoreCase)) {
3477                                 connectionToDelete = connection;
3478                                 break;
3479                             }
3480                         }
3481                         if (connectionToDelete == null) {
3482                             foreach (WebPartConnection connection in DynamicConnections) {
3483                                 if (String.Equals(connection.ID, idToDelete, StringComparison.OrdinalIgnoreCase)) {
3484                                     connectionToDelete = connection;
3485                                     break;
3486                                 }
3487                             }
3488                         }
3489
3490                         if (connectionToDelete != null) {
3491                             // Only shared connections can be deleted
3492                             Debug.Assert(connectionToDelete.IsShared);
3493
3494                             // In shared scope, only static connections should be deleted
3495                             // In user scope, static and dynamic connections can be deleted
3496                             Debug.Assert(connectionToDelete.IsStatic || entry.Scope == PersonalizationScope.User);
3497
3498                             Internals.DeleteConnection(connectionToDelete);
3499                         }
3500                         else {
3501                             // Some of the personalization data is invalid, so we should mark ourselves
3502                             // as dirty so the data will be re-saved, and the invalid data will be removed.
3503                             _hasDataChanged = true;
3504                         }
3505                     }
3506                 }
3507             }
3508         }
3509
3510         /// <devdoc>
3511         /// Sets the ZoneID, ZoneIndex, and IsClosed properties on the WebParts.  The state
3512         /// was loaded from personalization.
3513         /// </devdoc>
3514         private void LoadWebPartState(PersonalizationEntry entry) {
3515             if (entry != null) {
3516                 object[] webPartState = (object[])entry.Value;
3517                 if (webPartState != null) {
3518                     Debug.Assert(webPartState.Length % 4 == 0);
3519                     for (int i=0; i < webPartState.Length; i += 4) {
3520                         string id = (string)webPartState[i];
3521                         string zoneID = (string)webPartState[i + 1];
3522                         int zoneIndex = (int)webPartState[i + 2];
3523                         bool isClosed = (bool)webPartState[i + 3];
3524
3525                         WebPart part = (WebPart)FindControl(id);
3526                         if (part != null) {
3527                             Internals.SetZoneID(part, zoneID);
3528                             Internals.SetZoneIndex(part, zoneIndex);
3529                             // 
3530
3531                             Internals.SetIsClosed(part, isClosed);
3532                         }
3533                         else {
3534                             // Some of the personalization data is invalid, so we should mark ourselves
3535                             // as dirty so the data will be re-saved, and the invalid data will be removed.
3536                             _hasDataChanged = true;
3537                         }
3538                     }
3539                 }
3540             }
3541         }
3542
3543         /// <devdoc>
3544         /// </devdoc>
3545         public virtual void MoveWebPart(WebPart webPart, WebPartZoneBase zone, int zoneIndex) {
3546             Personalization.EnsureEnabled(/* ensureModifiable */ true);
3547
3548             if (webPart == null) {
3549                 throw new ArgumentNullException("webPart");
3550             }
3551             if (!Controls.Contains(webPart)) {
3552                 throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "webPart");
3553             }
3554             if (zone == null) {
3555                 throw new ArgumentNullException("zone");
3556             }
3557             if (_webPartZones.Contains(zone) == false) {
3558                 throw new ArgumentException(SR.GetString(SR.WebPartManager_MustRegister), "zone");
3559             }
3560             if (zoneIndex < 0) {
3561                 throw new ArgumentOutOfRangeException("zoneIndex");
3562             }
3563             if (webPart.Zone == null || webPart.IsClosed) {
3564                 throw new ArgumentException(SR.GetString(SR.WebPartManager_MustBeInZone), "webPart");
3565             }
3566
3567             // Return immediately if moving part to its current location
3568             if ((webPart.Zone == zone) && (webPart.ZoneIndex == zoneIndex)) {
3569                 return;
3570             }
3571
3572             WebPartMovingEventArgs e = new WebPartMovingEventArgs(webPart, zone, zoneIndex);
3573             OnWebPartMoving(e);
3574             if (_allowEventCancellation && e.Cancel) {
3575                 return;
3576             }
3577
3578             RemoveWebPartFromZone(webPart);
3579             AddWebPartToZone(webPart, zone, zoneIndex);
3580
3581             // Raise event at very end of Move method
3582             OnWebPartMoved(new WebPartEventArgs(webPart));
3583
3584 #if DEBUG
3585             CheckPartZoneIndexes(webPart.Zone);
3586             CheckPartZoneIndexes(zone);
3587 #endif
3588         }
3589
3590         protected virtual void OnAuthorizeWebPart(WebPartAuthorizationEventArgs e) {
3591             WebPartAuthorizationEventHandler handler = (WebPartAuthorizationEventHandler)Events[AuthorizeWebPartEvent];
3592             if (handler != null) {
3593                 handler(this, e);
3594             }
3595         }
3596
3597         protected virtual void OnConnectionsActivated(EventArgs e) {
3598             EventHandler handler = (EventHandler)Events[ConnectionsActivatedEvent];
3599             if (handler != null) {
3600                 handler(this, e);
3601             }
3602         }
3603
3604         protected virtual void OnConnectionsActivating(EventArgs e) {
3605             EventHandler handler = (EventHandler)Events[ConnectionsActivatingEvent];
3606             if (handler != null) {
3607                 handler(this, e);
3608             }
3609         }
3610
3611         protected virtual void OnDisplayModeChanged(WebPartDisplayModeEventArgs e) {
3612             WebPartDisplayModeEventHandler handler = (WebPartDisplayModeEventHandler)Events[DisplayModeChangedEvent];
3613             if (handler != null) {
3614                 handler(this, e);
3615             }
3616         }
3617
3618         protected virtual void OnDisplayModeChanging(WebPartDisplayModeCancelEventArgs e) {
3619             WebPartDisplayModeCancelEventHandler handler = (WebPartDisplayModeCancelEventHandler)Events[DisplayModeChangingEvent];
3620             if (handler != null) {
3621                 handler(this, e);
3622             }
3623         }
3624
3625         /// <devdoc>
3626         /// </devdoc>
3627         protected internal override void OnInit(EventArgs e) {
3628             base.OnInit(e);
3629
3630             if (!DesignMode) {
3631                 Page page = Page;
3632                 if (page != null) {
3633                     WebPartManager existingInstance = (WebPartManager)page.Items[typeof(WebPartManager)];
3634
3635                     if (existingInstance != null) {
3636                         Debug.Assert(existingInstance != this);
3637                         throw new InvalidOperationException(SR.GetString(SR.WebPartManager_OnlyOneInstance));
3638                     }
3639
3640                     page.Items[typeof(WebPartManager)] = this;
3641
3642                     page.InitComplete += new EventHandler(this.OnPageInitComplete);
3643                     page.LoadComplete += new EventHandler(this.OnPageLoadComplete);
3644                     page.SaveStateComplete += new EventHandler(this.OnPageSaveStateComplete);
3645                     page.RegisterRequiresControlState(this);
3646
3647                     Personalization.LoadInternal();
3648                 }
3649             }
3650         }
3651
3652         /// <devdoc>
3653         /// </devdoc>
3654         protected internal override void OnUnload(EventArgs e) {
3655             base.OnUnload(e);
3656
3657             if (!DesignMode) {
3658                 Page page = Page;
3659
3660                 Debug.Assert(page != null);
3661                 if (page != null) {
3662                     page.Items.Remove(typeof(WebPartManager));
3663                 }
3664             }
3665         }
3666
3667         private void OnPageInitComplete(object sender, EventArgs e) {
3668             if (_personalizationState != null) {
3669                 // These must be loaded after the Static Connections have been added to the WebPartManager
3670                 // (after the ProxyWebPartManager's Init methods)
3671                 LoadDynamicConnections(_personalizationState["DynamicConnectionsShared"]);
3672                 LoadDynamicConnections(_personalizationState["DynamicConnectionsUser"]);
3673                 LoadDeletedConnectionState(_personalizationState["DeletedConnectionsShared"]);
3674                 LoadDeletedConnectionState(_personalizationState["DeletedConnectionsUser"]);
3675
3676                 // These must be loaded after the Static WebParts have been added to the WebPartManager
3677                 // (after the WebPartZone's Init methods)
3678                 LoadDynamicWebParts(_personalizationState["DynamicWebPartsShared"]);
3679                 LoadDynamicWebParts(_personalizationState["DynamicWebPartsUser"]);
3680                 LoadWebPartState(_personalizationState["WebPartStateShared"]);
3681                 LoadWebPartState(_personalizationState["WebPartStateUser"]);
3682             }
3683
3684             _pageInitComplete = true;
3685         }
3686
3687         private void OnPageLoadComplete(object sender, EventArgs e) {
3688             // VSWhidbey 77708
3689             CloseOrphanedParts();
3690
3691             _allowCreateDisplayTitles = true;
3692
3693             // Raise events outside of ActivateConnections() method, since the method is virtual
3694             OnConnectionsActivating(EventArgs.Empty);
3695             // Activate connections in Page.LoadComplete instead of WebPartManager.PreRender.
3696             // Additional connection types can be activated here, so this improves our compatibility. (VSWhidbey 266995)
3697             ActivateConnections();
3698             OnConnectionsActivated(EventArgs.Empty);
3699         }
3700
3701         private void OnPageSaveStateComplete(object sender, EventArgs e) {
3702             // NOTE: Ideally this would be done by overriding SaveViewState in
3703             //       WebPartManager and WebPart to be symmetric with Personalization
3704             //       loading which happens in TrackViewState.
3705             //       However SaveViewState is not called when view state is disabled. Also,
3706             //       we don't want to have everything register for the SaveStateComplete event,
3707             //       because that creates more management issues for the event handler list.
3708             //       We don't want to change how the Apply works either, because we'd have
3709             //       to set up listeners for the Init event on every webpart.
3710             Personalization.ExtractPersonalizationState();
3711             foreach (WebPart webPart in Controls) {
3712                 Personalization.ExtractPersonalizationState(webPart);
3713             }
3714
3715             Personalization.SaveInternal();
3716         }
3717
3718         protected internal override void OnPreRender(EventArgs e) {
3719             base.OnPreRender(e);
3720
3721             if (Page != null) {
3722                 Page.ClientScript.RegisterStartupScript(
3723                     this,
3724                     typeof(WebPartManager),
3725                     ExportSensitiveDataWarningDeclaration,
3726                     "var __wpmExportWarning='" + Util.QuoteJScriptString(ExportSensitiveDataWarning) + "';",
3727                     true);
3728
3729                 Page.ClientScript.RegisterStartupScript(
3730                     this,
3731                     typeof(WebPartManager),
3732                     CloseProviderWarningDeclaration,
3733                     "var __wpmCloseProviderWarning='" + Util.QuoteJScriptString(CloseProviderWarning) + "';",
3734                     true);
3735
3736                 Page.ClientScript.RegisterStartupScript(
3737                     this,
3738                     typeof(WebPartManager),
3739                     DeleteWarningDeclaration,
3740                     "var __wpmDeleteWarning='" + Util.QuoteJScriptString(DeleteWarning) + "';",
3741                     true);
3742
3743                 _renderClientScript = CheckRenderClientScript();
3744                 if (_renderClientScript) {
3745                     // 
3746
3747                     Page.RegisterPostBackScript();
3748
3749                     RegisterClientScript();
3750                 }
3751             }
3752         }
3753
3754         protected virtual void OnSelectedWebPartChanged(WebPartEventArgs e) {
3755             WebPartEventHandler handler = (WebPartEventHandler)Events[SelectedWebPartChangedEvent];
3756             if (handler != null) {
3757                 handler(this, e);
3758             }
3759         }
3760
3761         protected virtual void OnSelectedWebPartChanging(WebPartCancelEventArgs e) {
3762             WebPartCancelEventHandler handler = (WebPartCancelEventHandler)Events[SelectedWebPartChangingEvent];
3763             if (handler != null) {
3764                 handler(this, e);
3765             }
3766         }
3767
3768         protected virtual void OnWebPartAdded(WebPartEventArgs e) {
3769             WebPartEventHandler handler = (WebPartEventHandler)Events[WebPartAddedEvent];
3770             if (handler != null) {
3771                 handler(this, e);
3772             }
3773         }
3774
3775         protected virtual void OnWebPartAdding(WebPartAddingEventArgs e) {
3776             WebPartAddingEventHandler handler = (WebPartAddingEventHandler)Events[WebPartAddingEvent];
3777             if (handler != null) {
3778                 handler(this, e);
3779             }
3780         }
3781
3782         protected virtual void OnWebPartClosed(WebPartEventArgs e) {
3783             WebPartEventHandler handler = (WebPartEventHandler)Events[WebPartClosedEvent];
3784             if (handler != null) {
3785                 handler(this, e);
3786             }
3787         }
3788
3789         protected virtual void OnWebPartClosing(WebPartCancelEventArgs e) {
3790             WebPartCancelEventHandler handler = (WebPartCancelEventHandler)Events[WebPartClosingEvent];
3791             if (handler != null) {
3792                 handler(this, e);
3793             }
3794
3795         }
3796
3797         protected virtual void OnWebPartDeleted(WebPartEventArgs e) {
3798             WebPartEventHandler handler = (WebPartEventHandler)Events[WebPartDeletedEvent];
3799             if (handler != null) {
3800                 handler(this, e);
3801             }
3802         }
3803
3804         protected virtual void OnWebPartDeleting(WebPartCancelEventArgs e) {
3805             WebPartCancelEventHandler handler = (WebPartCancelEventHandler)Events[WebPartDeletingEvent];
3806             if (handler != null) {
3807                 handler(this, e);
3808             }
3809         }
3810
3811         protected virtual void OnWebPartMoved(WebPartEventArgs e) {
3812             WebPartEventHandler handler = (WebPartEventHandler)Events[WebPartMovedEvent];
3813             if (handler != null) {
3814                 handler(this, e);
3815             }
3816         }
3817
3818         protected virtual void OnWebPartMoving(WebPartMovingEventArgs e) {
3819             WebPartMovingEventHandler handler = (WebPartMovingEventHandler)Events[WebPartMovingEvent];
3820             if (handler != null) {
3821                 handler(this, e);
3822             }
3823         }
3824
3825         protected virtual void OnWebPartsConnected(WebPartConnectionsEventArgs e) {
3826             WebPartConnectionsEventHandler handler = (WebPartConnectionsEventHandler)Events[WebPartsConnectedEvent];
3827             if (handler != null) {
3828                 handler(this, e);
3829             }
3830         }
3831
3832         protected virtual void OnWebPartsConnecting(WebPartConnectionsCancelEventArgs e) {
3833             WebPartConnectionsCancelEventHandler handler = (WebPartConnectionsCancelEventHandler)Events[WebPartsConnectingEvent];
3834             if (handler != null) {
3835                 handler(this, e);
3836             }
3837         }
3838
3839         protected virtual void OnWebPartsDisconnected(WebPartConnectionsEventArgs e) {
3840             WebPartConnectionsEventHandler handler = (WebPartConnectionsEventHandler)Events[WebPartsDisconnectedEvent];
3841             if (handler != null) {
3842                 handler(this, e);
3843             }
3844         }
3845
3846         protected virtual void OnWebPartsDisconnecting(WebPartConnectionsCancelEventArgs e) {
3847             WebPartConnectionsCancelEventHandler handler = (WebPartConnectionsCancelEventHandler)Events[WebPartsDisconnectingEvent];
3848             if (handler != null) {
3849                 handler(this, e);
3850             }
3851         }
3852
3853         protected virtual void RegisterClientScript() {
3854             Page.ClientScript.RegisterClientScriptResource(this, typeof(WebPartManager), "WebParts.js");
3855
3856             bool allowPageDesign = DisplayMode.AllowPageDesign;
3857
3858             string dragOverlayElementReference = "null";
3859             if (allowPageDesign) {
3860                 dragOverlayElementReference = "document.getElementById('" + ClientID + "___Drag')";
3861             }
3862
3863             StringBuilder zoneCode = new StringBuilder(1024);
3864             foreach (WebPartZoneBase zone in _webPartZones) {
3865                 string isVertical = (zone.LayoutOrientation == Orientation.Vertical) ? "true" : "false";
3866
3867                 string allowLayoutChange = "false";
3868                 string dragHighlightColor = "black";
3869                 if (allowPageDesign && zone.AllowLayoutChange) {
3870                     allowLayoutChange = "true";
3871                     dragHighlightColor = ColorTranslator.ToHtml(zone.DragHighlightColor);
3872                 }
3873
3874                 zoneCode.AppendFormat(CultureInfo.InvariantCulture, ZoneScript, zone.ClientID, zone.UniqueID, isVertical,
3875                                       allowLayoutChange, dragHighlightColor);
3876
3877                 WebPartCollection webParts = GetWebPartsForZone(zone);
3878                 foreach (WebPart webPart in webParts) {
3879                     string titleBarElementReference = "null";
3880                     string allowMove = "false";
3881                     if (allowPageDesign) {
3882                         titleBarElementReference = "document.getElementById('" + webPart.TitleBarID + "')";
3883                         if (webPart.AllowZoneChange) {
3884                             allowMove = "true";
3885                         }
3886                     }
3887                     zoneCode.AppendFormat(ZonePartScript, webPart.WholePartID, titleBarElementReference, allowMove);
3888                 }
3889
3890                 zoneCode.Append(ZoneEndScript);
3891             }
3892
3893             string startupScript = String.Format(CultureInfo.InvariantCulture,
3894                                                  StartupScript,
3895                                                  dragOverlayElementReference,
3896                                                  (Personalization.Scope == PersonalizationScope.Shared ? "true" : "false"),
3897                                                  zoneCode.ToString());
3898             Page.ClientScript.RegisterStartupScript(this, typeof(WebPartManager), String.Empty, startupScript, false);
3899
3900             IScriptManager scriptManager = Page.ScriptManager;
3901             if ((scriptManager != null) && scriptManager.SupportsPartialRendering) {
3902                 scriptManager.RegisterDispose(this, "WebPartManager_Dispose();");
3903             }
3904         }
3905
3906         internal void RegisterZone(WebZone zone) {
3907             Debug.Assert(zone != null);
3908
3909             if (_pageInitComplete) {
3910                 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_RegisterTooLate));
3911             }
3912
3913             string zoneID = zone.ID;
3914             if (String.IsNullOrEmpty(zoneID)) {
3915                 throw new ArgumentException(SR.GetString(SR.WebPartManager_NoZoneID), "zone");
3916             }
3917             if (_zoneIDs.Contains(zoneID)) {
3918                 throw new ArgumentException(SR.GetString(SR.WebPartManager_DuplicateZoneID, zoneID));
3919             }
3920             _zoneIDs.Add(zoneID, zone);
3921
3922             WebPartZoneBase webPartZone = zone as WebPartZoneBase;
3923             if (webPartZone != null) {
3924                 if (_webPartZones.Contains(webPartZone)) {
3925                     throw new ArgumentException(SR.GetString(SR.WebPartManager_AlreadyRegistered), "zone");
3926                 }
3927
3928                 _webPartZones.Add(webPartZone);
3929
3930                 WebPartCollection initialWebParts = webPartZone.GetInitialWebParts();
3931                 ((WebPartManagerControlCollection)Controls).AddWebPartsFromZone(webPartZone, initialWebParts);
3932             }
3933             else {
3934                 Debug.Assert(zone is ToolZone);
3935                 ToolZone toolZone = (ToolZone)zone;
3936
3937                 WebPartDisplayModeCollection allDisplayModes = DisplayModes;
3938                 WebPartDisplayModeCollection supportedDisplayModes = SupportedDisplayModes;
3939                 foreach (WebPartDisplayMode displayMode in toolZone.AssociatedDisplayModes) {
3940                     if (allDisplayModes.Contains(displayMode) && !supportedDisplayModes.Contains(displayMode)) {
3941                         supportedDisplayModes.AddInternal(displayMode);
3942                     }
3943                 }
3944             }
3945         }
3946
3947         /// <devdoc>
3948         /// Deletes the part from the dictionary mapping zones to parts.
3949         /// </devdoc>
3950         private void RemoveWebPartFromDictionary(WebPart webPart) {
3951             if (_partsForZone != null) {
3952                 string zoneID = Internals.GetZoneID(webPart);
3953                 if (!String.IsNullOrEmpty(zoneID)) {
3954                     SortedList partsForZone = (SortedList)(_partsForZone[zoneID]);
3955                     if (partsForZone != null) {
3956                         partsForZone.Remove(webPart);
3957                     }
3958                 }
3959             }
3960         }
3961
3962         // Called by WebPartManagerInternals
3963         internal void RemoveWebPart(WebPart webPart) {
3964             ((WebPartManagerControlCollection)Controls).RemoveWebPart(webPart);
3965         }
3966
3967         /// <devdoc>
3968         /// Removes a web part from its zone, and renumbers all the remaining parts sequentially.
3969         /// </devdoc>
3970         private void RemoveWebPartFromZone(WebPart webPart) {
3971             Debug.Assert(!webPart.IsClosed);
3972
3973             WebPartZoneBase zone = webPart.Zone;
3974             Internals.SetIsClosed(webPart, true);
3975             _hasDataChanged = true;
3976
3977             RemoveWebPartFromDictionary(webPart);
3978
3979             // 
3980
3981             if (zone != null) {
3982                 IList parts = GetAllWebPartsForZone(zone);
3983                 for (int i = 0; i < parts.Count; i++) {
3984                     WebPart part = ((WebPart)parts[i]);
3985                     Internals.SetZoneIndex(part, i);
3986                 }
3987             }
3988         }
3989
3990         protected internal override void Render(HtmlTextWriter writer) {
3991             if (DisplayMode.AllowPageDesign) {
3992                 string dragOverlayElementHtml = String.Format(CultureInfo.InvariantCulture, DragOverlayElementHtmlTemplate, ClientID);
3993                 writer.WriteLine(dragOverlayElementHtml);
3994             }
3995         }
3996
3997         /// <devdoc>
3998         /// Saves the control state for those properties that should persist across postbacks
3999         /// even when EnableViewState=false.
4000         /// </devdoc>
4001         protected internal override object SaveControlState() {
4002             object[] myState = new object[controlStateArrayLength];
4003
4004             myState[baseIndex] = base.SaveControlState();
4005             if (SelectedWebPart != null) {
4006                 myState[selectedWebPartIndex] = SelectedWebPart.ID;
4007             }
4008             if (_displayMode != BrowseDisplayMode) {
4009                 myState[displayModeIndex] = _displayMode.Name;
4010             }
4011
4012             for (int i=0; i < controlStateArrayLength; i++) {
4013                 if (myState[i] != null) {
4014                     return myState;
4015                 }
4016             }
4017
4018             // More performant to return null than an array of null values
4019             return null;
4020         }
4021
4022         protected virtual void SaveCustomPersonalizationState(PersonalizationDictionary state) {
4023             PersonalizationScope scope = Personalization.Scope;
4024
4025             int webPartsCount = Controls.Count;
4026             if (webPartsCount > 0) {
4027                 object[] webPartState = new object[webPartsCount * 4];
4028                 for (int i=0; i < webPartsCount; i++) {
4029                     WebPart webPart = (WebPart)Controls[i];
4030                     webPartState[4*i] = webPart.ID;
4031                     webPartState[4*i + 1] = Internals.GetZoneID(webPart);
4032                     webPartState[4*i + 2] = webPart.ZoneIndex;
4033                     webPartState[4*i + 3] = webPart.IsClosed;
4034                 }
4035                 if (scope == PersonalizationScope.Shared) {
4036                     state["WebPartStateShared"] =
4037                         new PersonalizationEntry(webPartState, PersonalizationScope.Shared);
4038                 }
4039                 else {
4040                     state["WebPartStateUser"] =
4041                         new PersonalizationEntry(webPartState, PersonalizationScope.User);
4042                 }
4043             }
4044
4045             // Select only the dynamic WebParts that should be saved for this mode
4046             ArrayList dynamicWebParts = new ArrayList();
4047             foreach (WebPart webPart in Controls) {
4048                 if (!webPart.IsStatic &&
4049                     ((scope == PersonalizationScope.User && !webPart.IsShared) ||
4050                      (scope == PersonalizationScope.Shared && webPart.IsShared))) {
4051                     dynamicWebParts.Add(webPart);
4052                 }
4053             }
4054
4055             int dynamicWebPartsCount = dynamicWebParts.Count;
4056             if (dynamicWebPartsCount > 0) {
4057                 // Use a 1-dimensional array for smallest storage space
4058                 object[] dynamicWebPartState = new object[dynamicWebPartsCount * 4];
4059                 for (int i = 0; i < dynamicWebPartsCount; i++) {
4060                     WebPart webPart = (WebPart)dynamicWebParts[i];
4061
4062                     string id;
4063                     string typeName;
4064                     string path = null;
4065                     string genericWebPartID = null;
4066                     ProxyWebPart proxyWebPart = webPart as ProxyWebPart;
4067                     if (proxyWebPart != null) {
4068                         id = proxyWebPart.OriginalID;
4069                         typeName = proxyWebPart.OriginalTypeName;
4070                         path = proxyWebPart.OriginalPath;
4071                         genericWebPartID = proxyWebPart.GenericWebPartID;
4072                     }
4073                     else {
4074                         GenericWebPart genericWebPart = webPart as GenericWebPart;
4075                         if (genericWebPart != null) {
4076                             Control childControl = genericWebPart.ChildControl;
4077                             UserControl userControl = childControl as UserControl;
4078
4079                             id = childControl.ID;
4080                             if (userControl != null) {
4081                                 typeName = WebPartUtil.SerializeType(typeof(UserControl));
4082                                 path = userControl.AppRelativeVirtualPath;
4083                             }
4084                             else {
4085                                 typeName = WebPartUtil.SerializeType(childControl.GetType());
4086                             }
4087                             genericWebPartID = genericWebPart.ID;
4088                         }
4089                         else {
4090                             id = webPart.ID;
4091                             typeName = WebPartUtil.SerializeType(webPart.GetType());
4092                         }
4093                     }
4094
4095                     dynamicWebPartState[4*i] = id;
4096                     dynamicWebPartState[4*i + 1] = typeName;
4097                     if (!String.IsNullOrEmpty(path)) {
4098                         dynamicWebPartState[4*i + 2] = path;
4099                     }
4100                     if (!String.IsNullOrEmpty(genericWebPartID)) {
4101                         dynamicWebPartState[4*i + 3] = genericWebPartID;
4102                     }
4103                 }
4104                 if (scope == PersonalizationScope.Shared) {
4105                     state["DynamicWebPartsShared"] =
4106                         new PersonalizationEntry(dynamicWebPartState, PersonalizationScope.Shared);
4107                 }
4108                 else {
4109                     state["DynamicWebPartsUser"] =
4110                         new PersonalizationEntry(dynamicWebPartState, PersonalizationScope.User);
4111                 }
4112             }
4113
4114             // Save deleted connections
4115             // 
4116
4117             ArrayList deletedConnections = new ArrayList();
4118             // PERF: Use the StaticConnections and DynamicConnections collections separately, instead
4119             // of using the Connections property which is created on every call.
4120             foreach (WebPartConnection connection in StaticConnections) {
4121                 if (Internals.ConnectionDeleted(connection)) {
4122                     deletedConnections.Add(connection);
4123                 }
4124             }
4125             foreach (WebPartConnection connection in DynamicConnections) {
4126                 if (Internals.ConnectionDeleted(connection)) {
4127                     deletedConnections.Add(connection);
4128                 }
4129             }
4130
4131             int deletedConnectionsCount = deletedConnections.Count;
4132             if (deletedConnections.Count > 0) {
4133                 string[] deletedConnectionsState = new string[deletedConnectionsCount];
4134                 for (int i=0; i < deletedConnectionsCount; i++) {
4135                     WebPartConnection deletedConnection = (WebPartConnection)deletedConnections[i];
4136                     // Only shared connections can be deleted
4137                     Debug.Assert(deletedConnection.IsShared);
4138                     // In shared scope, only static connections should be deleted
4139                     // In user scope, static and dynamic connections can be deleted
4140                     Debug.Assert(deletedConnection.IsStatic || scope == PersonalizationScope.User);
4141                     deletedConnectionsState[i] = deletedConnection.ID;
4142                 }
4143                 if (scope == PersonalizationScope.Shared) {
4144                     state["DeletedConnectionsShared"] =
4145                         new PersonalizationEntry(deletedConnectionsState, PersonalizationScope.Shared);
4146                 }
4147                 else {
4148                     state["DeletedConnectionsUser"] =
4149                         new PersonalizationEntry(deletedConnectionsState, PersonalizationScope.User);
4150                 }
4151             }
4152
4153             // Select only the dynamic Connections that should be saved for this mode
4154             ArrayList dynamicConnections = new ArrayList();
4155             foreach (WebPartConnection connection in DynamicConnections) {
4156                 if (((scope == PersonalizationScope.User) && (!connection.IsShared)) ||
4157                     ((scope == PersonalizationScope.Shared) && (connection.IsShared))) {
4158                     dynamicConnections.Add(connection);
4159                 }
4160             }
4161
4162             int dynamicConnectionsCount = dynamicConnections.Count;
4163             if (dynamicConnectionsCount > 0) {
4164                 // Use a 1-dimensional array for smallest storage space
4165                 object[] dynamicConnectionState = new object[dynamicConnectionsCount * 7];
4166                 for (int i = 0; i < dynamicConnectionsCount; i++) {
4167                     WebPartConnection connection = (WebPartConnection)dynamicConnections[i];
4168                     WebPartTransformer transformer = connection.Transformer;
4169
4170                     // We should never be saving a deleted dynamic connection.  If the User has deleted a
4171                     // a shared connection, the connection will be saved in the Shared data, not here.
4172                     Debug.Assert(!Internals.ConnectionDeleted(connection));
4173
4174                     dynamicConnectionState[7*i] = connection.ID;
4175                     dynamicConnectionState[7*i + 1] = connection.ConsumerID;
4176                     dynamicConnectionState[7*i + 2] = connection.ConsumerConnectionPointID;
4177                     dynamicConnectionState[7*i + 3] = connection.ProviderID;
4178                     dynamicConnectionState[7*i + 4] = connection.ProviderConnectionPointID;
4179                     if (transformer != null) {
4180                         dynamicConnectionState[7*i + 5] = transformer.GetType();
4181                         dynamicConnectionState[7*i + 6] = Internals.SaveConfigurationState(transformer);
4182                     }
4183                 }
4184
4185                 if (scope == PersonalizationScope.Shared) {
4186                     state["DynamicConnectionsShared"] =
4187                         new PersonalizationEntry(dynamicConnectionState, PersonalizationScope.Shared);
4188                 }
4189                 else {
4190                     state["DynamicConnectionsUser"] =
4191                         new PersonalizationEntry(dynamicConnectionState, PersonalizationScope.User);
4192                 }
4193             }
4194         }
4195
4196         // Can be called by a derived WebPartManager to mark itself as dirty
4197         protected void SetPersonalizationDirty() {
4198             Personalization.SetDirty();
4199         }
4200
4201         // Returns true if the WebPart should currently be rendered in the Zone.  Determines
4202         // which WebParts are returned by GetWebPartsForZone.
4203         private bool ShouldRenderWebPartInZone(WebPart part, WebPartZoneBase zone) {
4204             Debug.Assert(part.Zone == zone);
4205
4206             // Never render UnauthorizedWebParts
4207             if (part is UnauthorizedWebPart) {
4208                 return false;
4209             }
4210
4211             return true;
4212         }
4213
4214         protected void SetSelectedWebPart(WebPart webPart) {
4215             _selectedWebPart = webPart;
4216         }
4217
4218         // PropertyInfo will be null for an IPersonalizable property, since there is no associated PropertyInfo
4219         private bool ShouldExportProperty(PropertyInfo propertyInfo, Type propertyValueType,
4220                                           object propertyValue, out string exportString) {
4221             string propertyValueAsString = propertyValue as string;
4222             if (propertyValueAsString != null) {
4223                 exportString = propertyValueAsString;
4224                 return true;
4225             }
4226             else {
4227                 TypeConverter converter = null;
4228
4229                 if (propertyInfo != null) {
4230                     // See if the property itself has a type converter associated with it
4231                     TypeConverterAttribute attr =
4232                         Attribute.GetCustomAttribute(propertyInfo, typeof(TypeConverterAttribute), true) as TypeConverterAttribute;
4233                     if (attr != null) {
4234                         // Get the type using DeserializeType(), which calls BuildManager.GetType(),
4235                         // since we want this to work with a non-assembly qualified typename
4236                         // in the Code directory.
4237                         Type converterType = WebPartUtil.DeserializeType(attr.ConverterTypeName, false);
4238                         // SECURITY: Check that the type is a subclass of TypeConverter before instantiating.
4239                         if (converterType != null && converterType.IsSubclassOf(typeof(TypeConverter))) {
4240                             TypeConverter tempConverter = (TypeConverter)(Internals.CreateObjectFromType(converterType));
4241                             if (Util.CanConvertToFrom(tempConverter, typeof(string))) {
4242                                 converter = tempConverter;
4243                             }
4244                         }
4245                     }
4246                 }
4247
4248                 if (converter == null) {
4249                     // If there was no valid type converter on the property info, look on the type of the value
4250                     TypeConverter tempConverter = TypeDescriptor.GetConverter(propertyValueType);
4251                     if (Util.CanConvertToFrom(tempConverter, typeof(string))) {
4252                         converter = tempConverter;
4253                     }
4254                 }
4255
4256                 // Only export property if we found a valid type converter (VSWhidbey 496495)
4257                 if (converter != null) {
4258                     if (propertyValue != null) {
4259                         exportString = converter.ConvertToInvariantString(propertyValue);
4260                         return true;
4261                     }
4262                     else {
4263                         // Special-case null value
4264                         exportString = null;
4265                         return true;
4266                     }
4267                 }
4268                 else {
4269                     exportString = null;
4270                     if (propertyInfo == null && propertyValue == null) {
4271                         // Always want to export a null IPersonalizable value, since we will never have a type
4272                         // converter for the value.  However, we should not export a null Personalizable value
4273                         // unless the propertyInfo had a type converter, since we may not be able to import a
4274                         // null value, since the property may be a value type that cannot accept null as a value.
4275                         // (VSWhidbey 537895)
4276                         return true;
4277                     }
4278                     else {
4279                         return false;
4280                     }
4281                 }
4282             }
4283         }
4284
4285         /// <devdoc>
4286         /// Returns true if the connection should be removed from the dynamic connection
4287         /// collection when deleted.
4288         /// </devdoc>
4289         private bool ShouldRemoveConnection(WebPartConnection connection) {
4290             Debug.Assert(Personalization.IsModifiable);
4291
4292             if (connection.IsShared && (Personalization.Scope == PersonalizationScope.User)) {
4293                 // Can't remove shared connection in user mode
4294                 return false;
4295             }
4296             else {
4297                 return true;
4298             }
4299         }
4300
4301         /// <internalonly />
4302         protected override void TrackViewState() {
4303             Personalization.ApplyPersonalizationState();
4304             base.TrackViewState();
4305         }
4306
4307         // Throw if the type cannot be loaded by BuildManager
4308         // For instance, we cannot load a type defined in the Page class
4309         private void VerifyType(Control control) {
4310             // Don't need to verify type of UserControls, since we load them using
4311             // their path instead of their type
4312             if (control is UserControl) {
4313                 return;
4314             }
4315
4316             Type type = control.GetType();
4317             string typeName = WebPartUtil.SerializeType(type);
4318             Type loadedType = WebPartUtil.DeserializeType(typeName, /* throwOnError */ false);
4319             if (loadedType != type) {
4320                 throw new InvalidOperationException(
4321                     SR.GetString(SR.WebPartManager_CantAddControlType, typeName));
4322             }
4323         }
4324
4325         #region Implementation of IPersonalizable
4326         /// <internalonly/>
4327         bool IPersonalizable.IsDirty {
4328             get {
4329                 return IsCustomPersonalizationStateDirty;
4330             }
4331         }
4332
4333         /// <internalonly/>
4334         void IPersonalizable.Load(PersonalizationDictionary state) {
4335             LoadCustomPersonalizationState(state);
4336         }
4337
4338         /// <internalonly/>
4339         void IPersonalizable.Save(PersonalizationDictionary state) {
4340             SaveCustomPersonalizationState(state);
4341         }
4342         #endregion
4343
4344         private sealed class WebPartManagerControlCollection : ControlCollection {
4345
4346             private WebPartManager _manager;
4347
4348             public WebPartManagerControlCollection(WebPartManager owner) : base(owner) {
4349                 _manager = owner;
4350                 SetCollectionReadOnly(SR.WebPartManager_CannotModify);
4351             }
4352
4353             internal void AddWebPart(WebPart webPart) {
4354                 string originalError = SetCollectionReadOnly(null);
4355                 // Extra try-catch block to prevent elevation of privilege attack via exception filter
4356                 try {
4357                     try {
4358                         AddWebPartHelper(webPart);
4359                     }
4360                     finally {
4361                         SetCollectionReadOnly(originalError);
4362                     }
4363                 }
4364                 catch {
4365                     throw;
4366                 }
4367             }
4368
4369             private void AddWebPartHelper(WebPart webPart) {
4370                 string partID = webPart.ID;
4371                 if (String.IsNullOrEmpty(partID)) {
4372                     throw new InvalidOperationException(SR.GetString(SR.WebPartManager_NoWebPartID));
4373                 }
4374                 if (_manager._partAndChildControlIDs.Contains(partID)) {
4375                    throw new InvalidOperationException(SR.GetString(SR.WebPartManager_DuplicateWebPartID, partID));
4376                 }
4377
4378                 // Add to dictionary to prevent duplicate IDs, even if this part is not authorized.  Don't want page
4379                 // developer to have 2 parts with the same ID, and not get the exception until they are both authorized.
4380                 _manager._partAndChildControlIDs.Add(partID, null);
4381
4382                 // Check and add child control ID (VSWhidbey 339482)
4383                 GenericWebPart genericWebPart = webPart as GenericWebPart;
4384                 if (genericWebPart != null) {
4385                     string childControlID = genericWebPart.ChildControl.ID;
4386
4387                     if (String.IsNullOrEmpty(childControlID)) {
4388                         throw new InvalidOperationException(SR.GetString(SR.WebPartManager_NoChildControlID));
4389                     }
4390
4391                     if (_manager._partAndChildControlIDs.Contains(childControlID)) {
4392                         throw new InvalidOperationException(SR.GetString(SR.WebPartManager_DuplicateWebPartID, childControlID));
4393                     }
4394
4395                     _manager._partAndChildControlIDs.Add(childControlID, null);
4396                 }
4397
4398                 _manager.Internals.SetIsStandalone(webPart, false);
4399                 webPart.SetWebPartManager(_manager);
4400                 Add(webPart);
4401
4402                 // Invalidate the part dictionary if it has already been created
4403                 _manager._partsForZone = null;
4404             }
4405
4406             internal void AddWebPartsFromZone(WebPartZoneBase zone, WebPartCollection webParts) {
4407                 if ((webParts != null) && (webParts.Count != 0)) {
4408                     string originalError = SetCollectionReadOnly(null);
4409
4410                     // Extra try-catch block to prevent elevation of privilege attack via exception filter
4411                     try {
4412                         try {
4413                             string zoneID = zone.ID;
4414                             int index = 0;
4415
4416                             foreach (WebPart webPart in webParts) {
4417                                 // Need to set IsShared before calling IsAuthorized
4418                                 _manager.Internals.SetIsShared(webPart, true);
4419
4420                                 WebPart webPartOrProxy = webPart;
4421                                 if (!_manager.IsAuthorized(webPart)) {
4422                                     webPartOrProxy = new UnauthorizedWebPart(webPart);
4423                                 }
4424
4425                                 _manager.Internals.SetIsStatic(webPartOrProxy, true);
4426                                 _manager.Internals.SetIsShared(webPartOrProxy, true);
4427                                 _manager.Internals.SetZoneID(webPartOrProxy, zoneID);
4428                                 _manager.Internals.SetZoneIndex(webPartOrProxy, index);
4429
4430                                 AddWebPartHelper(webPartOrProxy);
4431                                 index++;
4432                             }
4433                         }
4434                         finally {
4435                             SetCollectionReadOnly(originalError);
4436                         }
4437                     } catch {
4438                         throw;
4439                     }
4440                 }
4441             }
4442
4443             internal void RemoveWebPart(WebPart webPart) {
4444                 string originalError = SetCollectionReadOnly(null);
4445                 // Extra try-catch block to prevent elevation of privilege attack via exception filter
4446                 try {
4447                     try {
4448                         _manager._partAndChildControlIDs.Remove(webPart.ID);
4449
4450                         // Remove child control ID (VSWhidbey 339482)
4451                         GenericWebPart genericWebPart = webPart as GenericWebPart;
4452                         if (genericWebPart != null) {
4453                             _manager._partAndChildControlIDs.Remove(genericWebPart.ChildControl.ID);
4454                         }
4455
4456                         Remove(webPart);
4457                         _manager._hasDataChanged = true;
4458                         webPart.SetWebPartManager(null);
4459                         _manager.Internals.SetIsStandalone(webPart, true);
4460
4461                         // Invalidate the part dictionary if it has already been created
4462                         _manager._partsForZone = null;
4463                     }
4464                     finally {
4465                         SetCollectionReadOnly(originalError);
4466                     }
4467                 }
4468                 catch {
4469                     throw;
4470                 }
4471             }
4472         }
4473
4474         private sealed class BrowseWebPartDisplayMode : WebPartDisplayMode {
4475
4476             public BrowseWebPartDisplayMode() : base("Browse") {
4477             }
4478         }
4479
4480         private sealed class CatalogWebPartDisplayMode : WebPartDisplayMode {
4481
4482             public CatalogWebPartDisplayMode() : base("Catalog") {
4483             }
4484
4485             public override bool AllowPageDesign {
4486                 get {
4487                     return true;
4488                 }
4489             }
4490
4491             public override bool AssociatedWithToolZone {
4492                 get {
4493                     return true;
4494                 }
4495             }
4496
4497             public override bool RequiresPersonalization {
4498                 get {
4499                     return true;
4500                 }
4501             }
4502
4503             public override bool ShowHiddenWebParts {
4504                 get {
4505                     return true;
4506                 }
4507             }
4508         }
4509
4510         private sealed class ConnectionPointKey {
4511             // DevDiv Bugs 38677
4512             // used as the Cache key for Connection Points, using Type and Culture
4513             private Type _type;
4514             private CultureInfo _culture;
4515             private CultureInfo _uiCulture;
4516
4517             public ConnectionPointKey(Type type, CultureInfo culture, CultureInfo uiCulture) {
4518                  Debug.Assert(type != null && culture != null && uiCulture != null);
4519
4520                  _type = type;
4521                  _culture = culture;
4522                  _uiCulture = uiCulture;
4523             }
4524
4525             public override bool Equals(object obj) {
4526                  if (obj == this) {
4527                       return true;
4528                  }
4529
4530                  ConnectionPointKey other = obj as ConnectionPointKey;
4531                  return (other != null) &&
4532                                     (other._type.Equals(_type)) &&
4533                                     (other._culture.Equals(_culture)) &&
4534                                     (other._uiCulture.Equals(_uiCulture));
4535             }
4536
4537             [SuppressMessage("Microsoft.Usage", "CA2303:FlagTypeGetHashCode", Justification = "The types are Sytem.Web.UI.Control derived classes and not com interop types.")]
4538             public override int GetHashCode()
4539             {
4540                  int typeHashCode = _type.GetHashCode();
4541                  // This is the algorithm used in Whidbey to combine hashcodes.
4542                  // It adheres better than a simple XOR to the randomness requirement for hashcodes.
4543                  int hashCode = ((typeHashCode << 5) + typeHashCode) ^ _culture.GetHashCode();
4544                  return ((hashCode << 5) + hashCode) ^ _uiCulture.GetHashCode();
4545             }
4546         }
4547
4548         private sealed class ConnectWebPartDisplayMode : WebPartDisplayMode {
4549
4550             public ConnectWebPartDisplayMode() : base("Connect") {
4551             }
4552
4553             public override bool AllowPageDesign {
4554                 get {
4555                     return true;
4556                 }
4557             }
4558
4559             public override bool AssociatedWithToolZone {
4560                 get {
4561                     return true;
4562                 }
4563             }
4564
4565             public override bool RequiresPersonalization {
4566                 get {
4567                     return true;
4568                 }
4569             }
4570
4571             public override bool ShowHiddenWebParts {
4572                 get {
4573                     return true;
4574                 }
4575             }
4576         }
4577
4578         private sealed class DesignWebPartDisplayMode : WebPartDisplayMode {
4579
4580             public DesignWebPartDisplayMode() : base("Design") {
4581             }
4582
4583             public override bool AllowPageDesign {
4584                 get {
4585                     return true;
4586                 }
4587             }
4588
4589             public override bool RequiresPersonalization {
4590                 get {
4591                     return true;
4592                 }
4593             }
4594
4595             public override bool ShowHiddenWebParts {
4596                 get {
4597                     return true;
4598                 }
4599             }
4600         }
4601
4602         private sealed class EditWebPartDisplayMode : WebPartDisplayMode {
4603
4604             public EditWebPartDisplayMode() : base("Edit") {
4605             }
4606
4607             public override bool AllowPageDesign {
4608                 get {
4609                     return true;
4610                 }
4611             }
4612
4613             public override bool AssociatedWithToolZone {
4614                 get {
4615                     return true;
4616                 }
4617             }
4618
4619             public override bool RequiresPersonalization {
4620                 get {
4621                     return true;
4622                 }
4623             }
4624
4625             public override bool ShowHiddenWebParts {
4626                 get {
4627                     return true;
4628                 }
4629             }
4630         }
4631     }
4632 }