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