1 //------------------------------------------------------------------------------
2 // <copyright file="MobileControlDesigner.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.ComponentModel;
11     using System.ComponentModel.Design;
12     using System.Diagnostics;
13     using System.Drawing;
14     using System.Drawing.Design;
15     using System.Collections;
16     using System.Globalization;
17     using System.IO;
18     using System.Reflection;
19     using System.Web.UI;
20     using System.Web.UI.Design;
21     using System.Web.UI.Design.MobileControls.Adapters;
22     using System.Web.UI.Design.MobileControls.Util;
23     using System.Web.UI.MobileControls;
24 
25     [
26         System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand,
27         Flags=System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode)
28     ]
29     [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.")]
30     internal class MobileControlDesigner :
31         ControlDesigner, IMobileDesigner, IDeviceSpecificDesigner
32     {
33         private bool                            _containmentStatusDirty = true;
34         private ContainmentStatus               _containmentStatus;
35         private IDesignerHost                   _host;
36         private IWebFormsDocumentService        _iWebFormsDocumentService;
37         private IMobileWebFormServices          _iMobileWebFormServices;
38         private MobileControl                   _mobileControl;
39         private System.Windows.Forms.Control    _header;
40 
41         internal static readonly String resourceDllUrl =
42             "res://" + typeof(MobileControlDesigner).Module.FullyQualifiedName;
43 
44         internal static readonly String errorIcon =
45             resourceDllUrl + "//ERROR_GIF";
46 
47         internal static readonly String infoIcon =
48             resourceDllUrl + "//INFO_GIF";
49 
50         internal static readonly String defaultErrorDesignTimeHTML =
51             @"
52                 <table cellpadding=2 cellspacing=0 width='{4}' 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'>
53                     <tr><td><span style='font-weight:bold'>&nbsp;{0}</span> - {1}</td></tr>
54                     <tr><td>
55                         <table style='font-family:tahoma;font-size:8pt;color:window;background-color:ButtonShadow'>
56                             <tr>
57                                 <td valign='top'><img src={3} /></td>
58                                 <td width='100%'>{2}</td>
59                             </tr>
60                         </table>
61                     </td></tr>
62                 </table>
63              ";
64 
65         internal static readonly String _formPanelContainmentErrorMessage =
66             SR.GetString(SR.MobileControl_FormPanelContainmentErrorMessage);
67 
68         internal static readonly String _mobilePageErrorMessage =
69             SR.GetString(SR.MobileControl_MobilePageErrorMessage);
70 
71         internal static readonly String _topPageContainmentErrorMessage =
72             SR.GetString(SR.MobileControl_TopPageContainmentErrorMessage);
73 
74         internal static readonly String _userControlWarningMessage =
75             SR.GetString(SR.MobileControl_UserControlWarningMessage);
76 
77         private const String _appliedDeviceFiltersPropName = "AppliedDeviceFilters";
78         private const String _propertyOverridesPropName = "PropertyOverrides";
79         private const String _defaultDeviceSpecificIdentifier = "unique";
80 
81         private static readonly string[] _nonBrowsableProperties = new string[] {
82             "EnableTheming",
83             "Expressions",
84             "SkinID",
85         };
86 
87         // predefined constants used for mergingContext
88         internal const int MergingContextChoices = 0;
89         internal const int MergingContextTemplates = 1;
90         internal const int MergingContextProperties = 2;
91 
92         [
93             DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
94             Editor(typeof(AppliedDeviceFiltersTypeEditor), typeof(UITypeEditor)),
95             MergableProperty(false),
96             MobileCategory(SR.Category_DeviceSpecific),
97             MobileSysDescription(SR.MobileControl_AppliedDeviceFiltersDescription),
98             ParenthesizePropertyName(true),
99         ]
100         protected String AppliedDeviceFilters
101         {
102             get
103             {
104                 return String.Empty;
105             }
106         }
107 
108         protected ContainmentStatus ContainmentStatus
109         {
110             get
111             {
112                 if (!_containmentStatusDirty)
113                 {
114                     return _containmentStatus;
115                 }
116 
117                 _containmentStatus =
118                     DesignerAdapterUtil.GetContainmentStatus(_mobileControl);
119 
120                 _containmentStatusDirty = false;
121                 return _containmentStatus;
122             }
123         }
124 
125         internal Object DesignTimeElementInternal
126         {
127             get
128             {
129                 return typeof(HtmlControlDesigner).InvokeMember("DesignTimeElement",
130                     BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.NonPublic,
131                     null, this, null, CultureInfo.InvariantCulture);
132             }
133         }
134 
135         public override bool DesignTimeHtmlRequiresLoadComplete
136         {
137             get
138             {
139                 return true;
140             }
141         }
142 
143         private IDesignerHost Host
144         {
145             get
146             {
147                 if (_host != null)
148                 {
149                     return _host;
150                 }
151                 _host = (IDesignerHost)GetService(typeof(IDesignerHost));
152                 Debug.Assert(_host != null);
153                 return _host;
154             }
155         }
156 
157         internal IMobileWebFormServices IMobileWebFormServices
158         {
159             get
160             {
161                 if (_iMobileWebFormServices == null)
162                 {
163                     _iMobileWebFormServices =
164                         (IMobileWebFormServices)GetService(typeof(IMobileWebFormServices));
165                 }
166 
167                 return _iMobileWebFormServices;
168             }
169         }
170 
171         private IWebFormsDocumentService IWebFormsDocumentService
172         {
173             get
174             {
175                 if (_iWebFormsDocumentService == null)
176                 {
177                     _iWebFormsDocumentService =
178                         (IWebFormsDocumentService)GetService(typeof(IWebFormsDocumentService));
179 
180                     Debug.Assert(_iWebFormsDocumentService != null);
181                 }
182 
183                 return _iWebFormsDocumentService;
184             }
185         }
186 
187         /// <summary>
188         ///     Indicates whether the initial page load is completed
189         /// </summary>
190         protected bool LoadComplete
191         {
192             get
193             {
194                 return !IWebFormsDocumentService.IsLoading;
195             }
196         }
197 
198         [
199             DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
200             Editor(typeof(PropertyOverridesTypeEditor), typeof(UITypeEditor)),
201             MergableProperty(false),
202             MobileCategory(SR.Category_DeviceSpecific),
203             MobileSysDescription(SR.MobileControl_DeviceSpecificPropsDescription),
204             ParenthesizePropertyName(true),
205         ]
206         protected String PropertyOverrides
207         {
208             get
209             {
210                 return String.Empty;
211             }
212         }
213 
214         private bool ValidContainment
215         {
216             get
217             {
218                 return (
219                     ContainmentStatus == ContainmentStatus.InForm ||
220                     ContainmentStatus == ContainmentStatus.InPanel ||
221                     ContainmentStatus == ContainmentStatus.InTemplateFrame);
222             }
223         }
224 
GetErrorMessage(out bool infoMode)225         protected virtual String GetErrorMessage(out bool infoMode)
226         {
227             infoMode = false;
228 
229             // Skip containment checking if the control is placed in MobileUserControl
230             if (!DesignerAdapterUtil.InMobileUserControl(_mobileControl))
231             {
232                 if (DesignerAdapterUtil.InUserControl(_mobileControl))
233                 {
234                     infoMode = true;
235                     return MobileControlDesigner._userControlWarningMessage;
236                 }
237 
238                 if (!DesignerAdapterUtil.InMobilePage(_mobileControl))
239                 {
240                     return _mobilePageErrorMessage;
241                 }
242 
243                 if (!ValidContainment)
244                 {
245                     return _formPanelContainmentErrorMessage;
246                 }
247             }
248 
249             bool containsTag;
250             bool containsDataboundLiteral;
251             _mobileControl.GetControlText(out containsTag, out containsDataboundLiteral);
252 
253             if (containsTag)
254             {
255                 return SR.GetString(SR.MobileControl_InnerTextCannotContainTagsDesigner);
256             }
257 
258             // Containment is valid, return null;
259             return null;
260         }
261 
262         /// <summary>
263         ///    <para>
264         ///       Gets the HTML to be used for the design time representation of the control runtime.
265         ///    </para>
266         /// </summary>
267         /// <returns>
268         ///    <para>
269         ///       The design time HTML.
270         ///    </para>
271         /// </returns>
GetDesignTimeHtml()272         public sealed override String GetDesignTimeHtml()
273         {
274             if (!LoadComplete)
275             {
276                 return null;
277             }
278 
279             bool infoMode = false;
280             String errorMessage = GetErrorMessage(out infoMode);
281             SetStyleAttributes();
282 
283             if (null != errorMessage)
284             {
285                 return GetDesignTimeErrorHtml(errorMessage, infoMode);
286             }
287 
288             String designTimeHTML = null;
289             try
290             {
291                 designTimeHTML = GetDesignTimeNormalHtml();
292             }
293             catch (Exception ex)
294             {
295                 Debug.Fail(ex.ToString());
296                 designTimeHTML = GetDesignTimeErrorHtml(ex.Message, false);
297             }
298 
299             return designTimeHTML;
300         }
301 
GetDesignTimeNormalHtml()302         protected virtual String GetDesignTimeNormalHtml()
303         {
304             return GetEmptyDesignTimeHtml();
305         }
306 
307         /// <summary>
308         ///    <para>
309         ///       Gets the HTML to be used at design time as the representation of the
310         ///       control when the control runtime does not return any rendered
311         ///       HTML. The default behavior is to return a string containing the name
312         ///       of the component.
313         ///    </para>
314         /// </summary>
315         /// <returns>
316         ///    <para>
317         ///       The name of the component, by default.
318         ///    </para>
319         /// </returns>
GetEmptyDesignTimeHtml()320         protected override String GetEmptyDesignTimeHtml()
321         {
322             return "<div style='width:100%'>" + base.GetEmptyDesignTimeHtml() + "</div>";
323         }
324 
GetErrorDesignTimeHtml(Exception e)325         protected override sealed String GetErrorDesignTimeHtml(Exception e)
326         {
327             return base.GetErrorDesignTimeHtml(e);
328         }
329 
330         /// <summary>
331         ///
332         /// </summary>
GetDesignTimeErrorHtml(String errorMessage, bool infoMode)333         protected virtual String GetDesignTimeErrorHtml(String errorMessage, bool infoMode)
334         {
335             return DesignerAdapterUtil.GetDesignTimeErrorHtml(
336                 errorMessage, infoMode, _mobileControl, Behavior, ContainmentStatus);
337         }
338 
339         /// <summary>
340         ///    <para>
341         ///       Gets the HTML to be persisted for the content present within the associated server control runtime.
342         ///    </para>
343         /// </summary>
344         /// <returns>
345         ///    <para>
346         ///       Persistable Inner HTML.
347         ///    </para>
348         /// </returns>
GetPersistInnerHtml()349         public override String GetPersistInnerHtml()
350         {
351             if (!IsDirty)
352             {
353                 // Returning a null string will prevent the actual save.
354                 return null;
355             }
356 
357             StringWriter sw = new StringWriter(CultureInfo.InvariantCulture);
358 
359             // HACK ALERT:
360             // We need to temporarily swap out the Text property to avoid being
361             // persisted into control inner text. However, setting the Text property
362             // will wipe out all control collections, therefore we need to cache
363             // the Text value too.
364             bool hasControls = _mobileControl.HasControls();
365             if ((_mobileControl is TextControl || _mobileControl is TextView)
366                 && hasControls)
367             {
368                 String originalText = null;
369                 Control[] children = null;
370 
371                 // Cache all child controls here.
372                 children = new Control[_mobileControl.Controls.Count];
373                 _mobileControl.Controls.CopyTo(children, 0);
374 
375                 // Replace the text with empty string.
376                 if (_mobileControl is TextControl)
377                 {
378                     originalText = ((TextControl)_mobileControl).Text;
379                     ((TextControl)_mobileControl).Text = String.Empty;
380                 }
381                 else
382                 {
383                     originalText = ((TextView)_mobileControl).Text;
384                     ((TextView)_mobileControl).Text = String.Empty;
385                 }
386 
387                 try
388                 {
389                     // Persist inner properties without Text property.
390                     MobileControlPersister.PersistInnerProperties(sw, _mobileControl, Host);
391                     // Persist the child collections.
392                     foreach (Control c in children)
393                     {
394                         MobileControlPersister.PersistControl(sw, c, Host);
395                     }
396                 }
397                 finally
398                 {
399                     // Write the original text back to control.
400                     if (_mobileControl is TextControl)
401                     {
402                         ((TextControl)_mobileControl).Text = originalText;
403                     }
404                     else
405                     {
406                         ((TextView)_mobileControl).Text = originalText;
407                     }
408 
409                     // Add the child controls back.
410                     foreach (Control c in children)
411                     {
412                         _mobileControl.Controls.Add(c);
413                     }
414                 }
415             }
416             else
417             {
418                 MobileControlPersister.PersistInnerProperties(sw, _mobileControl, Host);
419             }
420 
421             IsDirty = false;
422             return sw.ToString();
423         }
424 
425         /// <summary>
426         ///    <para>
427         ///       Initializes the designer with the component for design.
428         ///    </para>
429         /// </summary>
430         /// <param name='component'>
431         ///    The control element for design.
432         /// </param>
433         /// <remarks>
434         ///    <para>
435         ///       This is called by the designer host to establish the component for
436         ///       design.
437         ///    </para>
438         /// </remarks>
439         /// <seealso cref='System.ComponentModel.Design.IDesigner'/>
Initialize(IComponent component)440         public override void Initialize(IComponent component)
441         {
442             Debug.Assert(component is System.Web.UI.MobileControls.MobileControl,
443                 "MobileControlDesigner.Initialize - Invalid MobileControl Control");
444 
445             base.Initialize(component);
446 
447             _mobileControl = (System.Web.UI.MobileControls.MobileControl) component;
448         }
449 
SetStyleAttributes()450         protected virtual void SetStyleAttributes()
451         {
452             //Debug.Assert(Behavior != null, "Behavior is null, Load completed? " + LoadComplete.ToString());
453 
454             DesignerAdapterUtil.SetStandardStyleAttributes(Behavior, ContainmentStatus);
455         }
456 
OnComponentChanged(Object sender, ComponentChangedEventArgs ce)457         public override void OnComponentChanged(Object sender, ComponentChangedEventArgs ce)
458         {
459             // Delegate to the base class implementation first!
460             base.OnComponentChanged(sender, ce);
461 
462             MemberDescriptor member = ce.Member;
463             if (member != null &&
464                 member.GetType().FullName.Equals(Constants.ReflectPropertyDescriptorTypeFullName))
465             {
466                 PropertyDescriptor propDesc = (PropertyDescriptor)member;
467                 String propName = propDesc.Name;
468 
469                 if ((_mobileControl is TextControl || _mobileControl is TextView)
470                     && propName.Equals("Text"))
471                 {
472                     _mobileControl.Controls.Clear();
473                 }
474             }
475         }
476 
477         /// <summary>
478         ///    <para>
479         ///       Notification that is called when the associated control is parented.
480         ///    </para>
481         /// </summary>
OnSetParent()482         public override void OnSetParent()
483         {
484             base.OnSetParent();
485 
486             _containmentStatusDirty = true;
487             if (LoadComplete)
488             {
489                 UpdateRendering();
490             }
491         }
492 
PreFilterProperties(IDictionary properties)493         protected override void PreFilterProperties(IDictionary properties)
494         {
495             base.PreFilterProperties(properties);
496 
497             properties[_appliedDeviceFiltersPropName] =
498                 TypeDescriptor.CreateProperty(this.GetType(), _appliedDeviceFiltersPropName, typeof(String));
499 
500             properties[_propertyOverridesPropName] =
501                 TypeDescriptor.CreateProperty(this.GetType(), _propertyOverridesPropName, typeof(String));
502 
503             foreach (string propertyName in _nonBrowsableProperties) {
504                 PropertyDescriptor property = (PropertyDescriptor) properties[propertyName];
505                 Debug.Assert(property != null, "Property is null: " + propertyName);
506                 if (property != null) {
507                     properties[propertyName] = TypeDescriptor.CreateProperty(this.GetType(), property, BrowsableAttribute.No);
508                 }
509             }
510         }
511 
512         /*
513          *  IMobileDesigner INTERFACE IMPLEMENTATION
514          */
515 
516         /// <summary>
517         ///
518         /// </summary>
UpdateRendering()519         public void UpdateRendering()
520         {
521             _mobileControl.RefreshStyle();
522 
523             UpdateDesignTimeHtml();
524         }
525 
526         ////////////////////////////////////////////////////////////////////////
527         //  Begin IDeviceSpecificDesigner Implementation
528         ////////////////////////////////////////////////////////////////////////
529 
IDeviceSpecificDesigner.SetDeviceSpecificEditor(IRefreshableDeviceSpecificEditor editor)530         void IDeviceSpecificDesigner.SetDeviceSpecificEditor
531             (IRefreshableDeviceSpecificEditor editor)
532         {
533         }
534 
535         String IDeviceSpecificDesigner.CurrentDeviceSpecificID
536         {
537             get
538             {
539                 return _defaultDeviceSpecificIdentifier;
540             }
541         }
542 
543         System.Windows.Forms.Control IDeviceSpecificDesigner.Header
544         {
545             get
546             {
547                 return _header;
548             }
549         }
550 
551         System.Web.UI.Control IDeviceSpecificDesigner.UnderlyingControl
552         {
553             get
554             {
555                 return _mobileControl;
556             }
557         }
558 
559         Object IDeviceSpecificDesigner.UnderlyingObject
560         {
561             get
562             {
563                 return _mobileControl;
564             }
565         }
566 
IDeviceSpecificDesigner.InitHeader(int mergingContext)567         void IDeviceSpecificDesigner.InitHeader(int mergingContext)
568         {
569             HeaderPanel panel = new HeaderPanel();
570             HeaderLabel lblDescription = new HeaderLabel();
571 
572             lblDescription.TabIndex = 0;
573             lblDescription.Text = SR.GetString(
574                 SR.MobileControl_SettingGenericChoiceDescription
575             );
576             panel.Height = lblDescription.Height;
577             panel.Width = lblDescription.Width;
578             panel.Controls.Add(lblDescription);
579             _header = panel;
580         }
581 
IDeviceSpecificDesigner.RefreshHeader(int mergingContext)582         void IDeviceSpecificDesigner.RefreshHeader(int mergingContext)
583         {
584         }
585 
IDeviceSpecificDesigner.GetDeviceSpecific(String deviceSpecificParentID, out DeviceSpecific ds)586         bool IDeviceSpecificDesigner.GetDeviceSpecific(String deviceSpecificParentID, out DeviceSpecific ds)
587         {
588             Debug.Assert(_defaultDeviceSpecificIdentifier == deviceSpecificParentID);
589             ds = ((MobileControl) _mobileControl).DeviceSpecific;
590             return true;
591         }
592 
IDeviceSpecificDesigner.SetDeviceSpecific(String deviceSpecificParentID, DeviceSpecific ds)593         void IDeviceSpecificDesigner.SetDeviceSpecific(String deviceSpecificParentID, DeviceSpecific ds)
594         {
595             Debug.Assert(_defaultDeviceSpecificIdentifier == deviceSpecificParentID);
596             if (null != ds)
597             {
598                 ds.SetOwner((MobileControl) _mobileControl);
599             }
600             _mobileControl.DeviceSpecific = ds;
601         }
602 
IDeviceSpecificDesigner.UseCurrentDeviceSpecificID()603         void IDeviceSpecificDesigner.UseCurrentDeviceSpecificID()
604         {
605         }
606 
607         ////////////////////////////////////////////////////////////////////////
608         //  End IDeviceSpecificDesigner Implementation
609         ////////////////////////////////////////////////////////////////////////
610     }
611 }
612