1 //------------------------------------------------------------------------------
2 // <copyright file="StyleSheetDesigner.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6 
7 namespace System.Web.UI.Design.MobileControls
8 {
9     using System;
10     using System.Collections;
11     using System.Collections.Specialized;
12     using System.ComponentModel;
13     using System.ComponentModel.Design;
14     using System.Diagnostics;
15     using System.Drawing.Design;
16     using System.Globalization;
17     using System.Text;
18     using System.Web.UI;
19     using System.Web.UI.Design;
20     using System.Web.UI.Design.MobileControls.Adapters;
21     using System.Web.UI.Design.MobileControls.Converters;
22     using System.Web.UI.Design.MobileControls.Util;
23     using System.Web.UI.MobileControls;
24     using System.Windows.Forms;
25 
26     using Control = System.Web.UI.Control;
27     using DataBindingCollectionEditor = System.Web.UI.Design.DataBindingCollectionEditor;
28 
29     [
30         System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand,
31         Flags=System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode)
32     ]
33     [Obsolete("The System.Web.Mobile.dll assembly has been deprecated and should no longer be used. For information about how to develop ASP.NET mobile applications, see http://go.microsoft.com/fwlink/?LinkId=157231.")]
34     internal class StyleSheetDesigner : MobileTemplatedControlDesigner, IDeviceSpecificDesigner
35     {
36         internal static BooleanSwitch StyleSheetDesignerSwitch =
37             new BooleanSwitch("StyleSheetDesigner", "Enable StyleSheet designer general purpose traces.");
38 
39         private IWebFormsDocumentService _iWebFormsDocumentService;
40         private IRefreshableDeviceSpecificEditor _deviceSpecificEditor;
41         private DesignerVerbCollection _designerVerbs;
42         private System.Web.UI.MobileControls.StyleSheet _styleSheet;
43         private Style _currentStyle, _tmpCurrentStyle;
44         private bool _isDuplicate;
45         private MergedUI _mergedUI = null;
46         private ArrayList _cycledStyles = null;
47         private const int _templateWidth = 300;
48         private static bool _requiresDesignTimeChanges = false;
49         private bool _shouldRepersistStyles = false;
50         private EventHandler _loadComplete = null;
51 
52         private const String _templatesStylePropName = "TemplateStyle";
53         private const String _persistedStylesPropName = "PersistedStyles";
54 
55         private const String _designTimeHTML =
56             @"
57                 <table cellpadding=4 cellspacing=0 width='300px' style='font-family:tahoma;font-size:8pt;color:buttontext;background-color:buttonface;border: solid 1px;border-top-color:buttonhighlight;border-left-color:buttonhighlight;border-bottom-color:buttonshadow;border-right-color:buttonshadow'>
58                   <tr><td colspan=2><span style='font-weight:bold'>StyleSheet</span> - {0}</td></tr>
59                   <tr><td style='padding-top:0;padding-bottom:0;width:55%;padding-left:10px;font-weight:bold'>Template Style:</td><td style='padding-top:0;padding-bottom:0'>{1}</td></tr>
60                   <tr><td style='padding-top:0;padding-bottom:0;width:55%;padding-left:10px;font-weight:bold'>Template Device Filter:</td><td style='padding-top:0;padding-bottom:0'>{2}</td></tr>
61                   <tr><td colspan=2 style='padding-top:4px'>{3}</td></tr>
62                 </table>
63              ";
64 
65         private const String _specialCaseDesignTimeHTML =
66             @"
67                 <table cellpadding=4 cellspacing=0 width='300px' style='font-family:tahoma;font-size:8pt;color:buttontext;background-color:buttonface;border: solid 1px;border-top-color:buttonhighlight;border-left-color:buttonhighlight;border-bottom-color:buttonshadow;border-right-color:buttonshadow'>
68                   <tr><td colspan=2><span style='font-weight:bold'>StyleSheet</span> - {0}</td></tr>
69                   <tr><td style='padding-top:0;padding-bottom:0;width:55%;padding-left:10px;font-weight:bold'>Template Style:</td><td style='padding-top:0;padding-bottom:0'>{1}</td></tr>
70                   <tr><td style='padding-top:0;padding-bottom:0;width:55%;padding-left:10px;font-weight:bold'>Template Device Filter:</td><td style='padding-top:0;padding-bottom:0'>{2}</td></tr>
71                   <tr><td colspan=2 style='padding-top:4px'>{3}</td></tr>
72                   <tr><td colspan=2>
73                     <table style='font-size:8pt;color:window;background-color:ButtonShadow'>
74                       <tr><td valign='top'><img src='{4}'/></td><td>{5}</td></tr>
75                     </table>
76                   </td></tr>
77                 </table>
78              ";
79 
80         private const int _headerFooterTemplates            = 0;
81         private const int _itemTemplates                    = 1;
82         private const int _separatorTemplate                = 2;
83         private const int _contentTemplate                  = 3;
84         private const int _numberOfTemplateFrames           = 4;
85 
86         private static readonly String[][] _templateFrameNames =
87             new String[][] {
88                                new String [] { Constants.HeaderTemplateTag, Constants.FooterTemplateTag },
89                                new String [] { Constants.ItemTemplateTag, Constants.AlternatingItemTemplateTag, Constants.ItemDetailsTemplateTag },
90                                new String [] { Constants.SeparatorTemplateTag },
91                                new String [] { Constants.ContentTemplateTag }
92                            };
93 
94         private const String _templateStyle = "__TemplateStyle__";
95 
96         // used by DesignerAdapterUtil.GetMaxWidthToFit
97         // and needs to be exposed in object model because
98         // custom controls may need to access the value just like
99         // DesignerAdapterUtil.GetMaxWidthToFit does.
100         public override int TemplateWidth
101         {
102             get
103             {
104                 return _templateWidth;
105             }
106         }
107 
108         private MobilePage MobilePage
109         {
110             get
111             {
112                 IComponent component = DesignerAdapterUtil.GetRootComponent(Component);
113                 if (component is MobileUserControl)
114                 {
115                     return ((Control)component).Page as MobilePage;
116                 }
117                 return component as MobilePage;
118             }
119         }
120 
121         private Control RootControl
122         {
123             get
124             {
125                 IComponent component = DesignerAdapterUtil.GetRootComponent(Component);
126                 return component as Control;
127             }
128         }
129 
130         /// <summary>
131         ///    <para>
132         ///       Initializes the designer.
133         ///    </para>
134         /// </summary>
135         /// <param name='component'>
136         ///    The control element being designed.
137         /// </param>
138         /// <remarks>
139         ///    <para>
140         ///       This is called by the designer host to establish the component being
141         ///       designed.
142         ///    </para>
143         /// </remarks>
144         /// <seealso cref='System.ComponentModel.Design.IDesigner'/>
Initialize(IComponent component)145         public override void Initialize(IComponent component)
146         {
147             Debug.Assert(component is System.Web.UI.MobileControls.StyleSheet,
148                          "StyleSheetDesigner.Initialize - Invalid StyleSheet Control");
149             base.Initialize(component);
150 
151             _isDuplicate = false;
152             _styleSheet = (System.Web.UI.MobileControls.StyleSheet) component;
153             if(_requiresDesignTimeChanges)
154             {
155                 _shouldRepersistStyles = true;
156             }
157             _loadComplete = new EventHandler(this.OnLoadComplete);
158             IWebFormsDocumentService.LoadComplete += _loadComplete;
159 
160             if (IMobileWebFormServices != null)
161             {
162                 TemplateStyle = (String) IMobileWebFormServices.GetCache(_styleSheet.ID, _templateStyle);
163                 TemplateDeviceFilter =
164                     (String) IMobileWebFormServices.GetCache(
165                     _styleSheet.ID,
166                     MobileTemplatedControlDesigner.DefaultTemplateDeviceFilter);
167             }
168         }
169 
OnLoadComplete(Object source, EventArgs e)170         private void OnLoadComplete(Object source, EventArgs e)
171         {
172             if(_shouldRepersistStyles)
173             {
174                 IsDirty = true;
175                 OnInternalChange();
176             }
177             _requiresDesignTimeChanges = false;
178             _shouldRepersistStyles = false;
179 
180             UpdateDesignTimeHtml();
181         }
182 
SetRequiresDesignTimeChanges()183         internal static void SetRequiresDesignTimeChanges()
184         {
185             _requiresDesignTimeChanges = true;
186         }
187 
188         private IWebFormsDocumentService IWebFormsDocumentService
189         {
190             get
191             {
192                 if (_iWebFormsDocumentService == null)
193                 {
194                     _iWebFormsDocumentService =
195                         (IWebFormsDocumentService)GetService(typeof(IWebFormsDocumentService));
196 
197                     Debug.Assert(_iWebFormsDocumentService != null);
198                 }
199 
200                 return _iWebFormsDocumentService;
201             }
202         }
203 
CreateTemplateEditingFrame(TemplateEditingVerb verb)204         protected override ITemplateEditingFrame CreateTemplateEditingFrame(TemplateEditingVerb verb)
205         {
206             ITemplateEditingService teService =
207                 (ITemplateEditingService)GetService(typeof(ITemplateEditingService));
208             Debug.Assert(teService != null,
209                 "How did we get this far without an ITemplateEditingService");
210 
211             String[] templateNames = GetTemplateFrameNames(verb.Index);
212             ITemplateEditingFrame editingFrame = teService.CreateFrame(
213                 this,
214                 TemplateDeviceFilter + " (" + TemplateStyle + ")",
215                 templateNames,
216                 WebCtrlStyle,
217                 null /* we don't have template styles */);
218 
219             editingFrame.InitialWidth = _templateWidth;
220             return editingFrame;
221         }
222 
Dispose(bool disposing)223         protected override void Dispose(bool disposing)
224         {
225             if (disposing)
226             {
227                 UpdateActiveStyleSheet();
228 
229                 if (_loadComplete != null)
230                 {
231                     IWebFormsDocumentService.LoadComplete -= _loadComplete;
232                     _loadComplete = null;
233                 }
234 
235                 if (IMobileWebFormServices != null)
236                 {
237                     // If the page is in loading mode, it means the remove is trigged by webformdesigner.
238                     if (!LoadComplete)
239                     {
240                         IMobileWebFormServices.SetCache(_styleSheet.ID, (Object) _templateStyle, (Object) this.TemplateStyle);
241                     }
242                     else
243                     {
244                         // setting to null will remove the entry.
245                         IMobileWebFormServices.SetCache(_styleSheet.ID, (Object) _templateStyle, null);
246                     }
247                 }
248             }
249 
250             base.Dispose(disposing);
251         }
252 
UpdateActiveStyleSheet()253         private void UpdateActiveStyleSheet()
254         {
255             if (MobilePage != null && MobilePage.StyleSheet == _styleSheet)
256             {
257                 IDesigner designer = null;
258 
259                 // currently active stylesheet is deleted
260                 MobilePage.StyleSheet = StyleSheet.Default;
261                 StyleSheet _newStyleSheet = null;
262 
263                 Debug.Assert(RootControl != null);
264                 foreach (Control control in RootControl.Controls)
265                 {
266                     // Find new stylesheet
267                     if (control is StyleSheet && _newStyleSheet == null && control != _styleSheet)
268                     {
269                         designer = Host.GetDesigner((IComponent) control);
270                         // AUI 7285
271                         if (designer != null)
272                         {
273                             _newStyleSheet = (StyleSheet) control;
274                         }
275                     }
276                 }
277 
278                 MobilePage.StyleSheet = _newStyleSheet;
279                 if (null != _newStyleSheet)
280                 {
281                     Debug.Assert(designer != null);
282                     StyleSheetDesigner ssd = designer as StyleSheetDesigner;
283                     Debug.Assert(ssd != null, "ssd is null in StyleSheetDesigner");
284                     ssd.TreatAsDuplicate(false);
285                 }
286                 RefreshPageView();
287             }
288         }
289 
GetTemplateFrameNames(int index)290         protected override String[] GetTemplateFrameNames(int index)
291         {
292             Debug.Assert(index >= 0 & index <= _templateFrameNames.Length);
293             return _templateFrameNames[index];
294         }
295 
GetTemplateVerbs()296         protected override TemplateEditingVerb[] GetTemplateVerbs()
297         {
298             TemplateEditingVerb[] templateVerbs = new TemplateEditingVerb[_numberOfTemplateFrames];
299 
300             templateVerbs[_headerFooterTemplates] = new TemplateEditingVerb(
301                 SR.GetString(SR.TemplateFrame_HeaderFooterTemplates),
302                 _headerFooterTemplates,
303                 this);
304             templateVerbs[_itemTemplates] = new TemplateEditingVerb(
305                 SR.GetString(SR.TemplateFrame_ItemTemplates),
306                 _itemTemplates,
307                 this);
308             templateVerbs[_separatorTemplate] = new TemplateEditingVerb(
309                 SR.GetString(SR.TemplateFrame_SeparatorTemplate),
310                 _separatorTemplate,
311                 this);
312             templateVerbs[_contentTemplate] = new TemplateEditingVerb(
313                 SR.GetString(SR.TemplateFrame_ContentTemplate),
314                 _contentTemplate,
315                 this);
316 
317             return templateVerbs;
318         }
319 
320         /// <summary>
321         ///    <para>
322         ///       Delegate to handle component changed event.
323         ///    </para>
324         /// </summary>
325         /// <param name='sender'>
326         ///    The object sending the event.
327         /// </param>
328         /// <param name='ce'>
329         ///    The event object used when firing a component changed notification.
330         /// </param>
331         /// <remarks>
332         ///    <para>
333         ///       This is called after a property has been changed. It allows the implementor
334         ///       to do any post-processing that may be needed after a property change.
335         ///    </para>
336         /// </remarks>
OnComponentChanged(Object sender, ComponentChangedEventArgs ce)337         public override void OnComponentChanged(Object sender, ComponentChangedEventArgs ce)
338         {
339             // Delegate to the base class implementation first!
340             base.OnComponentChanged(sender, ce);
341 
342             MemberDescriptor member = ce.Member;
343             if (member != null &&
344                 member.GetType().FullName.Equals(Constants.ReflectPropertyDescriptorTypeFullName))
345             {
346                 PropertyDescriptor propDesc = (PropertyDescriptor)member;
347 
348                 if (propDesc.Name.Equals("ID"))
349                 {
350                     // Update the dictionary of device filters stored in the page designer
351                     // setting to null will remove the entry.
352                     IMobileWebFormServices.SetCache(ce.OldValue.ToString(), (Object) _templateStyle, null);
353                 }
354             }
355         }
356 
OnStylesChanged()357         internal void OnStylesChanged()
358         {
359             // If this is not a new stylesheet and it is the current stylesheet
360             if (MobilePage != null && MobilePage.StyleSheet == _styleSheet)
361             {
362                 // Refresh the whole page assuming styles have been changed.
363                 RefreshPageView();
364                 ClearCycledStyles();
365             }
366         }
367 
RefreshPageView()368         private void RefreshPageView()
369         {
370             if (IMobileWebFormServices != null)
371             {
372                 IMobileWebFormServices.RefreshPageView();
373             }
374         }
375 
OnSetParent()376         public override void OnSetParent()
377         {
378             base.OnSetParent();
379 
380             // This is not a MobilePage or the styleSheet is already the active styleSheet.
381             // The latter happens when the active StyleSheet is drag/drop to another location
382             // which forces its parent to be changed.
383             if (MobilePage == null)
384             {
385                 return;
386             }
387 
388             if (MobilePage.StyleSheet == _styleSheet)
389             {
390                 if (!(_styleSheet.Parent is MobilePage
391                     || _styleSheet.Parent is MobileUserControl))
392                 {
393                     UpdateActiveStyleSheet();
394                 }
395                 return;
396             }
397 
398             if (MobilePage.StyleSheet != StyleSheet.Default)
399             {
400                 // can't accept more than 1 stylesheet
401                 TreatAsDuplicate(true);
402 
403                 // the current valid StyleSheet is intentionaly refreshed because
404                 // if this stylesheet instance is recreated via a Undo operation
405                 // the current valid StyleSheet appears as a duplicate if not refreshed.
406                 IDesigner designer = Host.GetDesigner((IComponent) MobilePage.StyleSheet);
407                 Debug.Assert(designer != null, "designer is null in StyleSheetDesigner");
408                 StyleSheetDesigner ssd = (StyleSheetDesigner) designer;
409                 ssd.UpdateRendering();
410             }
411             else if (_styleSheet.Parent is MobilePage ||
412                      _styleSheet.Parent is MobileUserControl)
413             {
414                 // the active stylesheet is changed
415                 MobilePage.StyleSheet = _styleSheet;
416                 _isDuplicate = false;
417             }
418             RefreshPageView();
419         }
420 
OnTemplateModeChanged()421         protected override void OnTemplateModeChanged()
422         {
423             base.OnTemplateModeChanged();
424 
425             // Refresh all mobilecontrols after exit template editing mode.
426             if (!InTemplateMode)
427             {
428                 RefreshPageView();
429             }
430         }
431 
TreatAsDuplicate(bool isDuplicate)432         public void TreatAsDuplicate(bool isDuplicate)
433         {
434             if (isDuplicate != _isDuplicate)
435             {
436                 _isDuplicate = isDuplicate;
437                 SetTemplateVerbsDirty();
438                 UpdateDesignTimeHtml();
439             }
440         }
441 
442         protected override bool ErrorMode
443         {
444             get
445             {
446                 return base.ErrorMode
447                     || _isDuplicate
448                     || _styleSheet.DuplicateStyles.Count > 0;
449             }
450         }
451 
GetDuplicateStyleNames()452         private StringCollection GetDuplicateStyleNames()
453         {
454             StringCollection duplicateNamesList = new StringCollection();
455 
456             // Filter out repeated duplicate names using case insensitive
457             // hash table
458             HybridDictionary duplicateNamesHash = new HybridDictionary(
459                 true /* Names not case sensitive */ );
460             foreach(Style style in _styleSheet.DuplicateStyles)
461             {
462                 duplicateNamesHash[style.Name] = true;
463             }
464 
465             // Copy remaining names into a string list
466             foreach(DictionaryEntry entry in duplicateNamesHash)
467             {
468                 duplicateNamesList.Add((String)entry.Key);
469             }
470             return duplicateNamesList;
471         }
472 
GetDesignTimeNormalHtml()473         protected override String GetDesignTimeNormalHtml()
474         {
475             String curStyle, message;
476             ArrayList lstStylesInCycle = null;
477 
478             if (null == CurrentStyle)
479             {
480                 curStyle = SR.GetString(SR.StyleSheet_PropNotSet);
481             }
482             else
483             {
484                 curStyle = HttpUtility.HtmlEncode(CurrentStyle.Name);
485             }
486 
487             String curChoice;
488 
489             if (null == CurrentChoice)
490             {
491                 curChoice = SR.GetString(SR.StyleSheet_PropNotSet);
492             }
493             else
494             {
495                 if (CurrentChoice.Filter.Length == 0)
496                 {
497                     curChoice = SR.GetString(SR.DeviceFilter_DefaultChoice);
498                 }
499                 else
500                 {
501                     curChoice = HttpUtility.HtmlEncode(DesignerUtility.ChoiceToUniqueIdentifier(CurrentChoice));
502                 }
503             }
504 
505             message = SR.GetString(SR.StyleSheet_DefaultMessage);
506 
507             bool renderErrorMsg = false;
508             String errorMsg = null;
509             String errorIconUrl = null;
510 
511             if(_isDuplicate)
512             {
513                 renderErrorMsg = true;
514                 errorMsg = SR.GetString(SR.StyleSheet_DuplicateWarningMessage);
515                 errorIconUrl = MobileControlDesigner.errorIcon;
516             }
517             else if(_styleSheet.DuplicateStyles.Count > 0)
518             {
519                 renderErrorMsg = true;
520                 errorMsg = SR.GetString(
521                     SR.StyleSheet_DuplicateStyleNamesMessage,
522                     GenericUI.BuildCommaDelimitedList(
523                         GetDuplicateStyleNames()
524                     )
525                 );
526                 errorIconUrl = MobileControlDesigner.errorIcon;
527             }
528             else if (null != CurrentStyle && null != CurrentChoice)
529             {
530                 if (IsHTMLSchema(CurrentChoice))
531                 {
532                     message = SR.GetString(SR.StyleSheet_TemplateEditingMessage);
533                 }
534                 else
535                 {
536                     // User has selected non-html schema
537                     renderErrorMsg = true;
538                     errorMsg = SR.GetString(SR.MobileControl_NonHtmlSchemaErrorMessage);
539                     errorIconUrl = MobileControlDesigner.infoIcon;
540                 }
541             }
542 
543             if (renderErrorMsg)
544             {
545                 Debug.Assert(errorMsg != null && errorIconUrl != null);
546                 return String.Format(CultureInfo.CurrentCulture, _specialCaseDesignTimeHTML,
547                     new Object[]
548                                      {
549                                          _styleSheet.Site.Name,
550                                          curStyle,
551                                          curChoice,
552                                          message,
553                                          errorIconUrl,
554                                          errorMsg
555                                      });
556             }
557             else
558             {
559                 lstStylesInCycle = DetectCycles();
560 
561                 //
562 
563                 if (lstStylesInCycle != null && lstStylesInCycle.Count > 0)
564                 {
565                     String cycledStyles = String.Empty;
566                     //
567 
568                     foreach (Object obj in lstStylesInCycle)
569                     {
570                         Style cycledStyle = (Style) obj;
571                         if (cycledStyles.Length > 0)
572                         {
573                             cycledStyles += ", ";
574                         }
575                         cycledStyles += cycledStyle.Name;
576                     }
577                     return String.Format(CultureInfo.CurrentCulture, _specialCaseDesignTimeHTML,
578                         new Object[]
579                                          {
580                                              _styleSheet.Site.Name,
581                                              curStyle,
582                                              curChoice,
583                                              message,
584                                              MobileControlDesigner.errorIcon,
585                                              SR.GetString(SR.StyleSheet_RefCycleErrorMessage, cycledStyles)
586                                          });
587                 }
588                 else
589                 {
590                     return String.Format(CultureInfo.CurrentCulture, _designTimeHTML,
591                         new Object[]
592                                          {
593                                              _styleSheet.Site.Name,
594                                              curStyle,
595                                              curChoice,
596                                              message
597                                          });
598                 }
599             }
600         }
601 
ClearCycledStyles()602         private void ClearCycledStyles()
603         {
604             _cycledStyles = null;
605         }
606 
607 /* O(n) algorithm for loop detection
608         private HybridDictionary DetectCycles()
609         {
610             if (_cycledStyles == null)
611             {
612                 _cycledStyles = new HybridDictionary();
613                 ICollection styles = _styleSheet.Styles;
614 
615                 // Initialize the set
616                 Hashtable styleSet = new Hashtable(styles.Count);
617                 foreach (String key in styles)
618                 {
619                     styleSet.Add(key, true);
620                 }
621 
622                 while (styleSet.Count > 0)
623                 {
624                     Style style = null;
625                     foreach (String key in styleSet.Keys)
626                     {
627                         style = (Style)_styleSheet[key];
628                         Debug.Assert(style != null);
629                         break;
630                     }
631 
632                     int count = 0;
633                     Traverse(styleSet, style, count);
634                 }
635             }
636             return _cycledStyles;
637         }
638 
639         private bool Traverse(Hashtable styleSet, Style style)
640         {
641             String reference = style.StyleReference;
642             Style nextStyle = null;
643             bool result = false;
644 
645             styleSet.Remove(style.Name.ToLower(CultureInfo.InvariantCulture));
646 
647             if (reference == null || reference.Length == 0 ||
648                 ((nextStyle = (Style)_styleSheet[reference]) == null) ||
649                 (!styleSet.Contains(nextStyle)))
650             {
651                 result = false;
652             }
653             else if (_cycledStyles.Contains(nextStyle) ||
654                 Traverse(styleSet, nextStyle, ++count))
655             {
656                 Debug.Assert(_cycledStyles != null);
657                 if (!_cycledStyles.Contains(style))
658                 {
659                     _cycledStyles.Add(style, "");
660                 }
661                 result = true;
662             }
663 
664             return result;
665         }
666 */
DetectCycles()667         private ArrayList DetectCycles()
668         {
669             if (_cycledStyles == null)
670             {
671                 _cycledStyles = new ArrayList();
672                 ICollection styles = _styleSheet.Styles;
673 
674                 foreach (String key in styles)
675                 {
676                     Style style = (Style) _styleSheet[key];
677                     Style styleTmp;
678                     Debug.Assert(style != null);
679 
680                     bool cycle = false;
681                     String reference = style.StyleReference;
682                     String name = style.Name;
683 
684                     int count = styles.Count + 1;
685 
686                     while ((reference != null && reference.Length > 0) && count > 0)
687                     {
688                         if (0 == String.Compare(name, reference, StringComparison.OrdinalIgnoreCase))
689                         {
690                             cycle = true;
691                             break;
692                         }
693                         else
694                         {
695                             styleTmp = _styleSheet[reference];
696                             if (null != styleTmp)
697                             {
698                                 reference = styleTmp.StyleReference;
699                                 count --;
700                             }
701                             else
702                             {
703                                 reference = null;
704                             }
705                         }
706                     }
707 
708                     if (cycle)
709                     {
710                         _cycledStyles.Add(style);
711                     }
712                 }
713             }
714 
715             return _cycledStyles;
716         }
717 
718         ////////////////////////////////////////////////////////////////////////
719         //  Begin IDeviceSpecificDesigner Implementation
720         ////////////////////////////////////////////////////////////////////////
721 
IDeviceSpecificDesigner.SetDeviceSpecificEditor(IRefreshableDeviceSpecificEditor editor)722         void IDeviceSpecificDesigner.SetDeviceSpecificEditor
723             (IRefreshableDeviceSpecificEditor editor)
724         {
725             _deviceSpecificEditor = editor;
726         }
727 
728         String IDeviceSpecificDesigner.CurrentDeviceSpecificID
729         {
730             get
731             {
732                 if (_tmpCurrentStyle == null)
733                 {
734                     return null;
735                 }
736 
737                 if (_styleSheet[_tmpCurrentStyle.Name] == null)
738                 {
739                     _tmpCurrentStyle = null;
740                 }
741                 return (_tmpCurrentStyle != null) ? _tmpCurrentStyle.Name.ToLower(CultureInfo.InvariantCulture) : null;
742             }
743         }
744 
745         System.Windows.Forms.Control IDeviceSpecificDesigner.Header
746         {
747             get
748             {
749                 return _mergedUI;
750             }
751         }
752 
753         System.Web.UI.Control IDeviceSpecificDesigner.UnderlyingControl
754         {
755             get
756             {
757                 return _styleSheet;
758             }
759         }
760 
761         Object IDeviceSpecificDesigner.UnderlyingObject
762         {
763             get
764             {
765                 if (null != _mergedUI.CbStyles.SelectedItem)
766                 {
767                     String styleName = (String) _mergedUI.CbStyles.SelectedItem;
768                     return _styleSheet[styleName];
769                 }
770                 else
771                 {
772                     return null;
773                 }
774             }
775         }
776 
IDeviceSpecificDesigner.GetDeviceSpecific(String deviceSpecificParentID, out DeviceSpecific ds)777         bool IDeviceSpecificDesigner.GetDeviceSpecific(String deviceSpecificParentID, out DeviceSpecific ds)
778         {
779             Style style = (Style) _styleSheet[deviceSpecificParentID];
780             if (null == style)
781             {
782                 ds = null;
783                 return false;
784             }
785             else
786             {
787                 ds = style.DeviceSpecific;
788                 return true;
789             }
790         }
791 
IDeviceSpecificDesigner.SetDeviceSpecific(String deviceSpecificParentID, DeviceSpecific ds)792         void IDeviceSpecificDesigner.SetDeviceSpecific(String deviceSpecificParentID, DeviceSpecific ds)
793         {
794             Style style = (Style) _styleSheet[deviceSpecificParentID];
795             Debug.Assert(null != style, "style is null in IDeviceSpecificDesigner.SetDeviceSpecific");
796             if (null != ds)
797             {
798                 ds.SetOwner((MobileControl) _styleSheet);
799             }
800             style.DeviceSpecific = ds;
801 
802             if (CurrentChoice != null && 0 == String.Compare(CurrentStyle.Name, deviceSpecificParentID, StringComparison.OrdinalIgnoreCase))
803             {
804                 if (ds == null)
805                 {
806                     CurrentChoice = null;
807                 }
808                 else
809                 {
810                     // This makes sure that the CurrentChoice value is set to null is
811                     // it was deleted during the deviceSpecific object editing
812                     if (CurrentChoice.Filter.Length == 0)
813                     {
814                         TemplateDeviceFilter = SR.GetString(SR.DeviceFilter_DefaultChoice);
815                     }
816                     else
817                     {
818                         TemplateDeviceFilter = DesignerUtility.ChoiceToUniqueIdentifier(CurrentChoice);
819                     }
820                 }
821             }
822         }
823 
IDeviceSpecificDesigner.InitHeader(int mergingContext)824         void IDeviceSpecificDesigner.InitHeader(int mergingContext)
825         {
826             _mergedUI = new MergedUI();
827             _mergedUI.LblStyles.Text = SR.GetString(SR.StyleSheet_StylesCaption);
828             _mergedUI.LblStyles.TabIndex = 1;
829 
830             _mergedUI.CbStyles.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
831             _mergedUI.CbStyles.SelectedIndexChanged += new EventHandler(this.OnSelectedIndexChangedStylesComboBox);
832             _mergedUI.CbStyles.TabIndex = 2;
833             _mergedUI.CbStyles.Sorted = true;
834 
835             _mergedUI.BtnEdit.Text = SR.GetString(SR.Stylesheet_EditBtnCaption);
836             _mergedUI.BtnEdit.Click += new EventHandler(this.OnClickEditStylesButton);
837             _mergedUI.BtnEdit.TabIndex = 3;
838 
839             switch (mergingContext)
840             {
841                 case MobileControlDesigner.MergingContextTemplates:
842                 {
843                     _mergedUI.LblHeader.Text = SR.GetString(SR.StyleSheet_SettingTemplatingStyleChoiceDescription);
844 
845                     // AUI 2730
846                     _mergedUI.CbStyles.Width = 195;
847                     _mergedUI.BtnEdit.Location = new System.Drawing.Point(201, 39);
848                     break;
849                 }
850 
851                 default:
852                 {
853                     _mergedUI.LblHeader.Text = SR.GetString(SR.StyleSheet_SettingGenericStyleChoiceDescription);
854 
855                     // AUI 2730
856                     _mergedUI.CbStyles.Width = 195;
857                     _mergedUI.BtnEdit.Location = new System.Drawing.Point(201, 39);
858                     break;
859                 }
860             }
861         }
862 
IDeviceSpecificDesigner.RefreshHeader(int mergingContext)863         void IDeviceSpecificDesigner.RefreshHeader(int mergingContext)
864         {
865             _mergedUI.CbStyles.Items.Clear();
866             ICollection styles = _styleSheet.Styles;
867             foreach (String key in styles)
868             {
869                 Style style = (Style) _styleSheet[key];
870                 Debug.Assert(style != null);
871 
872                 _mergedUI.CbStyles.Items.Add(style.Name);
873             }
874 
875             if (_mergedUI.CbStyles.Items.Count > 0)
876             {
877                 Debug.Assert(null != CurrentStyle);
878                 _mergedUI.CbStyles.SelectedItem = CurrentStyle.Name;
879                 _oldSelectedIndex = _mergedUI.CbStyles.SelectedIndex;
880             }
881 
882             _mergedUI.CbStyles.Enabled = (_mergedUI.CbStyles.Items.Count > 0);
883         }
884 
IDeviceSpecificDesigner.UseCurrentDeviceSpecificID()885         void IDeviceSpecificDesigner.UseCurrentDeviceSpecificID()
886         {
887             if (CurrentStyle != _tmpCurrentStyle)
888             {
889                 CurrentChoice = null;
890                 CurrentStyle = _tmpCurrentStyle;
891             }
892         }
893 
894         /////////////////////////////////////////////////////////////////////////
895         //  End IDeviceSpecificDesigner Implementation
896         /////////////////////////////////////////////////////////////////////////
897 
898         private int _oldSelectedIndex;
899 
OnSelectedIndexChangedStylesComboBox(Object source, EventArgs e)900         private void OnSelectedIndexChangedStylesComboBox(Object source, EventArgs e)
901         {
902             if (_mergedUI.CbStyles.SelectedIndex != _oldSelectedIndex
903                 && !_deviceSpecificEditor.RequestRefresh())
904             {
905                 // User needs to correct error before editing a new style.
906                 _mergedUI.CbStyles.SelectedIndex = _oldSelectedIndex;
907                 return;
908             }
909 
910             if (_mergedUI.CbStyles.SelectedIndex >= 0)
911             {
912                 _tmpCurrentStyle = (Style) _styleSheet[((String) _mergedUI.CbStyles.SelectedItem).ToLower(CultureInfo.InvariantCulture)];
913                 _deviceSpecificEditor.Refresh((String) _mergedUI.CbStyles.SelectedItem, _tmpCurrentStyle.DeviceSpecific);
914             }
915             _oldSelectedIndex = _mergedUI.CbStyles.SelectedIndex;
916         }
917 
OnStyleRenamedInEditor(Object source, StyleRenamedEventArgs e)918         private void OnStyleRenamedInEditor(Object source, StyleRenamedEventArgs e)
919         {
920             _deviceSpecificEditor.DeviceSpecificRenamed(e.OldName, e.NewName);
921         }
922 
OnStyleDeletedInEditor(Object source, StyleDeletedEventArgs e)923         private void OnStyleDeletedInEditor(Object source, StyleDeletedEventArgs e)
924         {
925             _deviceSpecificEditor.DeviceSpecificDeleted(e.Name);
926         }
927 
OnClickEditStylesButton(Object source, EventArgs e)928         private void OnClickEditStylesButton(Object source, EventArgs e)
929         {
930 
931             StylesEditorDialog dialog;
932 
933             try
934             {
935                 dialog = new StylesEditorDialog(
936                     _styleSheet,
937                     this,
938                     (null != _tmpCurrentStyle) ? _tmpCurrentStyle.Name : null
939                 );
940             }
941             catch(ArgumentException ex)
942             {
943                 Debug.Fail(ex.ToString());
944                 // Block user from entering StylesEditorDialog until they fix
945                 // duplicate style declarations.
946                 return;
947             }
948 
949             StylesEditorDialog.StyleRenamedEventHandler renameHandler =
950                 new StylesEditorDialog.StyleRenamedEventHandler(OnStyleRenamedInEditor);
951             StylesEditorDialog.StyleDeletedEventHandler deleteHandler =
952                 new StylesEditorDialog.StyleDeletedEventHandler(OnStyleDeletedInEditor);
953             dialog.StyleRenamed += renameHandler;
954             dialog.StyleDeleted += deleteHandler;
955             try
956             {
957                 _deviceSpecificEditor.BeginExternalDeviceSpecificEdit();
958                 if (dialog.ShowDialog() == DialogResult.OK)
959                 {
960                     _deviceSpecificEditor.EndExternalDeviceSpecificEdit(
961                         true /* commit changes */ );
962                     OnInternalChange();
963 
964                     ((IDeviceSpecificDesigner) this).RefreshHeader(0);
965                     // using mergingContext 0 because this implementation does not use the param.
966                     if (_mergedUI.CbStyles.Items.Count == 0)
967                     {
968                         _deviceSpecificEditor.Refresh(null, null); // force the clean up and
969                         // disabling of the filter controls.
970                         _tmpCurrentStyle = null;
971                     }
972 
973                     _deviceSpecificEditor.UnderlyingObjectsChanged();
974                 }
975                 else
976                 {
977                     _deviceSpecificEditor.EndExternalDeviceSpecificEdit(
978                         false /* do not commit changes */ );
979                 }
980             }
981             finally
982             {
983                dialog.StyleRenamed -= renameHandler;
984                dialog.StyleDeleted -= deleteHandler;
985             }
986         }
987 
988         public Style CurrentStyle
989         {
990            get
991            {
992                if (null == _currentStyle)
993                {
994                    // Since this property is registered to property window (from TemplateStyle),
995                    // it will be accessed even before Initialize is called. In that case,
996                    // _styleSheet will be null;
997                    if (_styleSheet != null && _styleSheet.Styles.Count > 0)
998                    {
999                        // how else can you get an entry in the Styles hashtable?
1000                        // this needs to be fixed once we use an ordered list of styles.
1001                        ICollection styles = _styleSheet.Styles;
1002                        foreach (String key in styles)
1003                        {
1004                            _currentStyle = (Style) _styleSheet[key];
1005                            Debug.Assert (_currentStyle != null);
1006                            break;
1007                        }
1008                    }
1009                }
1010                return _currentStyle;
1011            }
1012            set
1013            {
1014                _currentStyle = value;
1015            }
1016         }
1017 
1018         public override DeviceSpecific CurrentDeviceSpecific
1019         {
1020             get
1021             {
1022                 if (null == CurrentStyle)
1023                 {
1024                     return null;
1025                 }
1026 
1027                 return CurrentStyle.DeviceSpecific;
1028             }
1029         }
1030 
1031         public String TemplateStyle
1032         {
1033             get
1034             {
1035                 if (null == CurrentStyle)
1036                 {
1037                     return SR.GetString(SR.StyleSheet_PropNotSet);
1038                 }
1039                 return CurrentStyle.Name;
1040             }
1041             set
1042             {
1043                 // Clear DeviceSpecificChoice of previously selected Style
1044                 CurrentChoice = null;
1045                 CurrentStyle = null;
1046                 if (!String.IsNullOrEmpty(value) &&
1047                     !value.Equals(SR.GetString(SR.StyleSheet_PropNotSet)))
1048                 {
1049                     ICollection styles = _styleSheet.Styles;
1050                     foreach (String key in styles)
1051                     {
1052                         Style style = (Style) _styleSheet[key];
1053                         if (style.Name.Equals(value))
1054                         {
1055                             CurrentStyle = style;
1056                             break;
1057                         }
1058                     }
1059                 }
1060                 // Clear DeviceSpecificChoice of currently selected Style
1061                 CurrentChoice = null;
1062 
1063                 // Invalidate the type descriptor so that the TemplateDeviceFilter gets updated
1064                 TypeDescriptor.Refresh(Component);
1065             }
1066         }
1067 
SetStyleAttributes()1068         protected override void SetStyleAttributes()
1069         {
1070             Debug.Assert(Behavior != null, "Behavior is null");
1071 
1072             String marginTop = null, marginBottom = null, marginRight = null;
1073 
1074             if (ContainmentStatus == ContainmentStatus.AtTopLevel)
1075             {
1076                 marginTop = "5px";
1077                 marginBottom = "5px";
1078                 marginRight = "30%";
1079             }
1080             else
1081             {
1082                 marginTop = "3px";
1083                 marginBottom = "3px";
1084                 marginRight = "5px";
1085             }
1086 
1087             Behavior.SetStyleAttribute("marginTop", true, marginTop, true);
1088             Behavior.SetStyleAttribute("marginBottom", true, marginBottom, true);
1089             Behavior.SetStyleAttribute("marginRight", true, marginRight, true);
1090             Behavior.SetStyleAttribute("marginLeft", true, "5px", true);
1091         }
1092 
PreFilterProperties(IDictionary properties)1093         protected override void PreFilterProperties(IDictionary properties)
1094         {
1095             base.PreFilterProperties(properties);
1096 
1097             // DesignTime Property only, we will use this to select the current style.
1098             PropertyDescriptor designerTemplateStyleProp;
1099 
1100             designerTemplateStyleProp =
1101                 TypeDescriptor.CreateProperty(this.GetType(), _templatesStylePropName, typeof(String),
1102                                      DesignerSerializationVisibilityAttribute.Hidden,
1103                                      MobileCategoryAttribute.Design,
1104                                      InTemplateMode ? ReadOnlyAttribute.Yes : ReadOnlyAttribute.No,
1105                                      InTemplateMode ? BrowsableAttribute.No : BrowsableAttribute.Yes,
1106                                      new DefaultValueAttribute(SR.GetString(SR.StyleSheet_PropNotSet)),
1107                                      new TypeConverterAttribute(typeof(StyleConverter)),
1108                                      new DescriptionAttribute(SR.GetString(SR.StyleSheet_TemplateStyleDescription)));
1109             properties[_templatesStylePropName] = designerTemplateStyleProp;
1110 
1111             PropertyDescriptor designerPersistedStyles;
1112 
1113             designerPersistedStyles =
1114                 TypeDescriptor.CreateProperty(this.GetType(), _persistedStylesPropName, typeof(ICollection),
1115                                      //PersistenceTypeAttribute.InnerChild,
1116                                      PersistenceModeAttribute.InnerDefaultProperty,
1117                                      BrowsableAttribute.No);
1118             properties[_persistedStylesPropName] = designerPersistedStyles;
1119         }
1120 
1121         public ICollection PersistedStyles
1122         {
1123             get
1124             {
1125                 Debug.Assert(null != _styleSheet, "_styleSheet is null");
1126                 ICollection styleKeys = _styleSheet.Styles;
1127                 ArrayList persistedStyles = new ArrayList();
1128                 foreach (String key in styleKeys)
1129                 {
1130                     Style style = _styleSheet[key];
1131                     persistedStyles.Add(style);
1132                 }
1133                 foreach (Style style in _styleSheet.DuplicateStyles)
1134                 {
1135                     persistedStyles.Add(style);
1136                 }
1137                 return persistedStyles;
1138             }
1139         }
1140 
1141         /// <summary>
1142         ///    <para>
1143         ///       The designer's collection of verbs.
1144         ///    </para>
1145         /// </summary>
1146         /// <value>
1147         ///    <para>
1148         ///       An array of type <see cref='DesignerVerb'/> containing the verbs available to the
1149         ///       designer.
1150         ///    </para>
1151         /// </value>
1152         public override DesignerVerbCollection Verbs
1153         {
1154             get
1155             {
1156                 if (_designerVerbs == null)
1157                 {
1158                     _designerVerbs = base.Verbs;
1159                     _designerVerbs.Add(new DesignerVerb(SR.GetString(SR.StyleSheet_StylesEditorVerb),
1160                                                         new EventHandler(this.OnShowStylesEditor)));
1161                 }
1162                 Debug.Assert(_designerVerbs.Count == 2);
1163 
1164                 _designerVerbs[0].Enabled = !this.InTemplateMode;
1165                 _designerVerbs[1].Enabled = !this.InTemplateMode;
1166                 return _designerVerbs;
1167             }
1168         }
1169 
1170         /////////////////////////////////////////////////////////////////////////
1171         //  BEGIN STYLE DESIGNER EVENTHANDLERS
1172         /////////////////////////////////////////////////////////////////////////
1173 
OnShowStylesEditor(Object sender, EventArgs e)1174         protected void OnShowStylesEditor(Object sender, EventArgs e)
1175         {
1176             IComponentChangeService changeService = null;
1177 
1178             changeService = (IComponentChangeService)GetService(typeof(IComponentChangeService));
1179             if (changeService != null)
1180             {
1181                 try
1182                 {
1183                     changeService.OnComponentChanging(_styleSheet, null);
1184                 }
1185                 catch (CheckoutException ex)
1186                 {
1187                     if (ex == CheckoutException.Canceled)
1188                     {
1189                         return;
1190                     }
1191                     throw;
1192                 }
1193             }
1194 
1195             DialogResult result = DialogResult.Cancel;
1196             try
1197             {
1198                 StylesEditorDialog dialog = new StylesEditorDialog(_styleSheet, this, null);
1199                 result = dialog.ShowDialog();
1200             }
1201             catch(ArgumentException ex)
1202             {
1203                 Debug.Fail(ex.ToString());
1204                 // Block user from entering StylesEditorDialog until they fix
1205                 // duplicate style declarations.
1206             }
1207             finally
1208             {
1209                 if (changeService != null)
1210                 {
1211                     changeService.OnComponentChanged(_styleSheet, null, null, null);
1212 
1213                     if (IMobileWebFormServices != null)
1214                     {
1215                         IMobileWebFormServices.ClearUndoStack();
1216                     }
1217                 }
1218             }
1219         }
1220 
OnCurrentChoiceChange()1221         protected override void OnCurrentChoiceChange()
1222         {
1223             SetCurrentChoice();
1224             RefreshPageView();
1225         }
1226 
SetCurrentChoice()1227         private void SetCurrentChoice()
1228         {
1229             if (CurrentStyle != null && CurrentStyle.DeviceSpecific != null)
1230             {
1231                 this.CurrentStyle.DeviceSpecific.SetDesignerChoice(CurrentChoice);
1232             }
1233         }
1234 
1235         private bool ValidContainment
1236         {
1237             get
1238             {
1239                 return (ContainmentStatus == ContainmentStatus.AtTopLevel);
1240             }
1241         }
1242 
GetErrorMessage(out bool infoMode)1243         protected override String GetErrorMessage(out bool infoMode)
1244         {
1245             infoMode = false;
1246 
1247             if (!DesignerAdapterUtil.InMobileUserControl(_styleSheet))
1248             {
1249                 if (DesignerAdapterUtil.InUserControl(_styleSheet))
1250                 {
1251                     infoMode = true;
1252                     return MobileControlDesigner._userControlWarningMessage;
1253                 }
1254 
1255                 if (!DesignerAdapterUtil.InMobilePage(_styleSheet))
1256                 {
1257                     return MobileControlDesigner._mobilePageErrorMessage;
1258                 }
1259             }
1260 
1261             if (!ValidContainment)
1262             {
1263                 return MobileControlDesigner._topPageContainmentErrorMessage;
1264             }
1265 
1266             // No error condition, return null;
1267             return null;
1268         }
1269 
1270         /////////////////////////////////////////////////////////////////////////
1271         //  END STYLE DESIGNER EVENTHANDLERS
1272         /////////////////////////////////////////////////////////////////////////
1273 
1274         [
1275             System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand,
1276             Flags=System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode)
1277         ]
1278         private class MergedUI : HeaderPanel
1279         {
1280             internal System.Windows.Forms.Label LblStyles;
1281             internal System.Windows.Forms.ComboBox CbStyles;
1282             internal System.Windows.Forms.Button BtnEdit;
1283             internal HeaderLabel LblHeader;
1284 
MergedUI()1285             internal MergedUI()
1286             {
1287                 this.LblStyles = new System.Windows.Forms.Label();
1288                 this.CbStyles = new System.Windows.Forms.ComboBox();
1289                 this.BtnEdit = new System.Windows.Forms.Button();
1290                 this.LblHeader = new HeaderLabel();
1291 //                this.LblStyles.Anchor = ((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
1292 //                    | System.Windows.Forms.AnchorStyles.Right);
1293                 this.LblStyles.Location = new System.Drawing.Point(0, 24);
1294                 this.LblStyles.Size = new System.Drawing.Size(160, 16);
1295 //                this.CbStyles.Anchor = ((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
1296 //                    | System.Windows.Forms.AnchorStyles.Right);
1297                 this.CbStyles.DropDownWidth = 124;
1298                 this.CbStyles.Location = new System.Drawing.Point(0, 40);
1299                 this.CbStyles.Size = new System.Drawing.Size(160, 21);
1300 //                this.BtnEdit.Anchor = (System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right);
1301                 this.BtnEdit.Location = new System.Drawing.Point(164, 39);
1302                 this.BtnEdit.Size = new System.Drawing.Size(75, 23);
1303                 this.LblHeader.Location = new System.Drawing.Point(0, 0);
1304                 this.LblHeader.Size = new System.Drawing.Size(240, 16);
1305                 this.Controls.AddRange(new System.Windows.Forms.Control[] {this.CbStyles,
1306                                                                            this.LblStyles,
1307                                                                            this.BtnEdit,
1308                                                                            this.LblHeader});
1309                 this.Size = new System.Drawing.Size(240, 70);
1310                 this.Location = new System.Drawing.Point(5,6);
1311             }
1312         }
1313     }
1314 }
1315