Merge lp:~mandel/ubuntuone-windows-installer/improve_sso_ui into lp:ubuntuone-windows-installer/beta

Proposed by Manuel de la Peña
Status: Merged
Approved by: Rick McBride
Approved revision: 90
Merged at revision: 92
Proposed branch: lp:~mandel/ubuntuone-windows-installer/improve_sso_ui
Merge into: lp:ubuntuone-windows-installer/beta
Prerequisite: lp:~mandel/ubuntuone-windows-installer/sso_di
Diff against target: 777 lines (+682/-17)
6 files modified
src/Canonical.Ubuntu.SSO.Views/Canonical.Ubuntu.SSO.Views.csproj (+12/-0)
src/Canonical.Ubuntu.SSO.Views/LoginDialog.xaml (+32/-17)
src/Canonical.Ubuntu.SSO.Views/Resources/Resources.Designer.cs (+108/-0)
src/Canonical.Ubuntu.SSO.Views/Resources/Resources.resx (+135/-0)
src/Canonical.Ubuntu.SSO.Views/WatermarkAdorner.cs (+141/-0)
src/Canonical.Ubuntu.SSO.Views/WatermarkService.cs (+254/-0)
To merge this branch: bzr merge lp:~mandel/ubuntuone-windows-installer/improve_sso_ui
Reviewer Review Type Date Requested Status
Rick McBride (community) Approve
John Lenton (community) Approve
Review via email: mp+37587@code.launchpad.net

Description of the change

Improves the login view used in the Ubuntu SSO to match better the one present in linux.

To post a comment you must log in.
Revision history for this message
John Lenton (chipaca) :
review: Approve
Revision history for this message
Rick McBride (rmcbride) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/Canonical.Ubuntu.SSO.Views/Canonical.Ubuntu.SSO.Views.csproj'
2--- src/Canonical.Ubuntu.SSO.Views/Canonical.Ubuntu.SSO.Views.csproj 2010-10-05 11:24:46 +0000
3+++ src/Canonical.Ubuntu.SSO.Views/Canonical.Ubuntu.SSO.Views.csproj 2010-10-05 11:24:47 +0000
4@@ -72,11 +72,23 @@
5 <DependentUpon>Settings.settings</DependentUpon>
6 <DesignTimeSharedInput>True</DesignTimeSharedInput>
7 </Compile>
8+ <Compile Include="Resources\Resources.Designer.cs">
9+ <AutoGen>True</AutoGen>
10+ <DesignTime>True</DesignTime>
11+ <DependentUpon>Resources.resx</DependentUpon>
12+ </Compile>
13+ <Compile Include="WatermarkAdorner.cs" />
14+ <Compile Include="WatermarkService.cs" />
15 <EmbeddedResource Include="Properties\Resources.resx">
16 <Generator>ResXFileCodeGenerator</Generator>
17 <LastGenOutput>Resources.Designer.cs</LastGenOutput>
18 <SubType>Designer</SubType>
19 </EmbeddedResource>
20+ <EmbeddedResource Include="Resources\Resources.resx">
21+ <Generator>PublicResXFileCodeGenerator</Generator>
22+ <LastGenOutput>Resources.Designer.cs</LastGenOutput>
23+ <SubType>Designer</SubType>
24+ </EmbeddedResource>
25 <None Include="Properties\Settings.settings">
26 <Generator>SettingsSingleFileGenerator</Generator>
27 <LastGenOutput>Settings.Designer.cs</LastGenOutput>
28
29=== modified file 'src/Canonical.Ubuntu.SSO.Views/LoginDialog.xaml'
30--- src/Canonical.Ubuntu.SSO.Views/LoginDialog.xaml 2010-10-05 11:24:46 +0000
31+++ src/Canonical.Ubuntu.SSO.Views/LoginDialog.xaml 2010-10-05 11:24:47 +0000
32@@ -1,8 +1,10 @@
33 <Window x:Class="Canonical.Ubuntu.SSO.Views.LoginDialog"
34 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
35- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
36- Title="Login" Height="300" Width="300">
37- <Grid>
38+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
39+ xmlns:controls="clr-namespace:Canonical.Ubuntu.SSO.Views"
40+ xmlns:resx="clr-namespace:Canonical.Ubuntu.SSO.Views.Resources"
41+ Title="Login" Height="350" Width="550">
42+ <Grid Margin="10">
43 <Grid.RowDefinitions>
44 <RowDefinition Height="*" />
45 <RowDefinition Height="28" />
46@@ -12,35 +14,48 @@
47 <RowDefinition Height="*" />
48 <RowDefinition Height="34" />
49 <RowDefinition Height="34" />
50+ <RowDefinition Height="34" />
51 <RowDefinition Height="*" />
52 </Grid.RowDefinitions>
53 <Grid Grid.Row="0">
54 <Grid.RowDefinitions>
55- <RowDefinition Height="32" />
56+ <RowDefinition Height="*" />
57 <RowDefinition Height="*" />
58 </Grid.RowDefinitions>
59- <Label Name="InfoLabel" Grid.Row="0" Margin="3" >Please provide the email you used register in</Label>
60- <Label Grid.Row="1">Ubuntu One and you password.</Label>
61+ <TextBlock Name="TitleLabel" Grid.Row="0" Margin="3" FontSize="20" FontFamily="Calibry" Text="{x:Static resx:Resources.LoginViewTitle}"></TextBlock>
62+ <TextBlock Name="InfoText" Grid.Row="1" Margin="3" FontFamily="Calibry" Text="{x:Static resx:Resources.LoginViewInfo}"></TextBlock>
63 </Grid>
64 <Grid Grid.Row="1">
65 <Grid.ColumnDefinitions>
66 <ColumnDefinition Width="*"/>
67- <ColumnDefinition Width="120"/>
68- <ColumnDefinition Width="120"/>
69+ <ColumnDefinition Width="240"/>
70 <ColumnDefinition Width="*"/>
71 </Grid.ColumnDefinitions>
72- <Label Name="MessageLabel" Grid.Column="1" Margin="3">Email</Label>
73- <TextBox Name="EmailTextBox" Grid.Column="2" Margin="3"></TextBox>
74+ <TextBox Name="EmailTextBox" Grid.Column="1" Margin="3">
75+ <controls:WatermarkService.Watermark>
76+ <TextBlock Text="{x:Static resx:Resources.LoginEmailAddressWatermark}"></TextBlock>
77+ </controls:WatermarkService.Watermark>
78+ </TextBox>
79 </Grid>
80 <Grid Grid.Row="2">
81 <Grid.ColumnDefinitions>
82 <ColumnDefinition Width="*"/>
83- <ColumnDefinition Width="120"/>
84- <ColumnDefinition Width="120"/>
85- <ColumnDefinition Width="*"/>
86- </Grid.ColumnDefinitions>
87- <Label Name="PasswordLabel" Grid.Column="1" Margin="3">Password</Label>
88- <PasswordBox Name="PasswordTextBox" Grid.Column="2" Margin="3" PasswordChar="*"></PasswordBox >
89+ <ColumnDefinition Width="240"/>
90+ <ColumnDefinition Width="*"/>
91+ </Grid.ColumnDefinitions>
92+ <PasswordBox Name="PasswordTextBox" Grid.Column="1" Margin="3" PasswordChar="*">
93+ <controls:WatermarkService.Watermark>
94+ <TextBlock Text="{x:Static resx:Resources.LoginPasswordWatermark}"></TextBlock>
95+ </controls:WatermarkService.Watermark>
96+ </PasswordBox >
97+ </Grid>
98+ <Grid Grid.Row="3">
99+ <Grid.ColumnDefinitions>
100+ <ColumnDefinition Width="*"/>
101+ <ColumnDefinition Width="240"/>
102+ <ColumnDefinition Width="*"/>
103+ </Grid.ColumnDefinitions>
104+ <TextBlock Name="ForgottenLink" Grid.Column="1" Margin="3" TextAlignment="Center"><Hyperlink >I've forgotten my password.</Hyperlink></TextBlock>
105 </Grid>
106 </Grid>
107 <Grid Grid.Row="1">
108@@ -49,7 +64,7 @@
109 <ColumnDefinition Width="85"/>
110 <ColumnDefinition Width="85"/>
111 </Grid.ColumnDefinitions>
112- <Button Name="LoginButton" Grid.Column="1" Margin="3" Click="LoginButton_Click">Login</Button>
113+ <Button Name="LoginButton" Grid.Column="1" Margin="3" Click="LoginButton_Click">Connect</Button>
114 <Button Name="CancelButton" Grid.Column="2" Margin="3" Click="CancelButton_Click">Cancel</Button>
115 </Grid>
116 </Grid>
117
118=== added directory 'src/Canonical.Ubuntu.SSO.Views/Resources'
119=== added file 'src/Canonical.Ubuntu.SSO.Views/Resources/Resources.Designer.cs'
120--- src/Canonical.Ubuntu.SSO.Views/Resources/Resources.Designer.cs 1970-01-01 00:00:00 +0000
121+++ src/Canonical.Ubuntu.SSO.Views/Resources/Resources.Designer.cs 2010-10-05 11:24:47 +0000
122@@ -0,0 +1,108 @@
123+//------------------------------------------------------------------------------
124+// <auto-generated>
125+// This code was generated by a tool.
126+// Runtime Version:2.0.50727.4952
127+//
128+// Changes to this file may cause incorrect behavior and will be lost if
129+// the code is regenerated.
130+// </auto-generated>
131+//------------------------------------------------------------------------------
132+
133+namespace Canonical.Ubuntu.SSO.Views.Resources {
134+ using System;
135+
136+
137+ /// <summary>
138+ /// A strongly-typed resource class, for looking up localized strings, etc.
139+ /// </summary>
140+ // This class was auto-generated by the StronglyTypedResourceBuilder
141+ // class via a tool like ResGen or Visual Studio.
142+ // To add or remove a member, edit your .ResX file then rerun ResGen
143+ // with the /str option, or rebuild your VS project.
144+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
145+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
146+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
147+ public class Resources {
148+
149+ private static global::System.Resources.ResourceManager resourceMan;
150+
151+ private static global::System.Globalization.CultureInfo resourceCulture;
152+
153+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
154+ internal Resources() {
155+ }
156+
157+ /// <summary>
158+ /// Returns the cached ResourceManager instance used by this class.
159+ /// </summary>
160+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
161+ public static global::System.Resources.ResourceManager ResourceManager {
162+ get {
163+ if (object.ReferenceEquals(resourceMan, null)) {
164+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Canonical.Ubuntu.SSO.Views.Resources.Resources", typeof(Resources).Assembly);
165+ resourceMan = temp;
166+ }
167+ return resourceMan;
168+ }
169+ }
170+
171+ /// <summary>
172+ /// Overrides the current thread's CurrentUICulture property for all
173+ /// resource lookups using this strongly typed resource class.
174+ /// </summary>
175+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
176+ public static global::System.Globalization.CultureInfo Culture {
177+ get {
178+ return resourceCulture;
179+ }
180+ set {
181+ resourceCulture = value;
182+ }
183+ }
184+
185+ /// <summary>
186+ /// Looks up a localized string similar to Email address.
187+ /// </summary>
188+ public static string LoginEmailAddressWatermark {
189+ get {
190+ return ResourceManager.GetString("LoginEmailAddressWatermark", resourceCulture);
191+ }
192+ }
193+
194+ /// <summary>
195+ /// Looks up a localized string similar to I&apos;ve forgotten my password..
196+ /// </summary>
197+ public static string LoginForgottenLink {
198+ get {
199+ return ResourceManager.GetString("LoginForgottenLink", resourceCulture);
200+ }
201+ }
202+
203+ /// <summary>
204+ /// Looks up a localized string similar to Password.
205+ /// </summary>
206+ public static string LoginPasswordWatermark {
207+ get {
208+ return ResourceManager.GetString("LoginPasswordWatermark", resourceCulture);
209+ }
210+ }
211+
212+ /// <summary>
213+ /// Looks up a localized string similar to To connect this computer to Ubuntu One enter your details below..
214+ /// </summary>
215+ public static string LoginViewInfo {
216+ get {
217+ return ResourceManager.GetString("LoginViewInfo", resourceCulture);
218+ }
219+ }
220+
221+ /// <summary>
222+ /// Looks up a localized string similar to Connect to Ubuntu One.
223+ /// </summary>
224+ public static string LoginViewTitle {
225+ get {
226+ return ResourceManager.GetString("LoginViewTitle", resourceCulture);
227+ }
228+ }
229+ }
230+}
231
232=== added file 'src/Canonical.Ubuntu.SSO.Views/Resources/Resources.resx'
233--- src/Canonical.Ubuntu.SSO.Views/Resources/Resources.resx 1970-01-01 00:00:00 +0000
234+++ src/Canonical.Ubuntu.SSO.Views/Resources/Resources.resx 2010-10-05 11:24:47 +0000
235@@ -0,0 +1,135 @@
236+<?xml version="1.0" encoding="utf-8"?>
237+<root>
238+ <!--
239+ Microsoft ResX Schema
240+
241+ Version 2.0
242+
243+ The primary goals of this format is to allow a simple XML format
244+ that is mostly human readable. The generation and parsing of the
245+ various data types are done through the TypeConverter classes
246+ associated with the data types.
247+
248+ Example:
249+
250+ ... ado.net/XML headers & schema ...
251+ <resheader name="resmimetype">text/microsoft-resx</resheader>
252+ <resheader name="version">2.0</resheader>
253+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
254+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
255+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
256+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
257+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
258+ <value>[base64 mime encoded serialized .NET Framework object]</value>
259+ </data>
260+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
261+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
262+ <comment>This is a comment</comment>
263+ </data>
264+
265+ There are any number of "resheader" rows that contain simple
266+ name/value pairs.
267+
268+ Each data row contains a name, and value. The row also contains a
269+ type or mimetype. Type corresponds to a .NET class that support
270+ text/value conversion through the TypeConverter architecture.
271+ Classes that don't support this are serialized and stored with the
272+ mimetype set.
273+
274+ The mimetype is used for serialized objects, and tells the
275+ ResXResourceReader how to depersist the object. This is currently not
276+ extensible. For a given mimetype the value must be set accordingly:
277+
278+ Note - application/x-microsoft.net.object.binary.base64 is the format
279+ that the ResXResourceWriter will generate, however the reader can
280+ read any of the formats listed below.
281+
282+ mimetype: application/x-microsoft.net.object.binary.base64
283+ value : The object must be serialized with
284+ : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
285+ : and then encoded with base64 encoding.
286+
287+ mimetype: application/x-microsoft.net.object.soap.base64
288+ value : The object must be serialized with
289+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
290+ : and then encoded with base64 encoding.
291+
292+ mimetype: application/x-microsoft.net.object.bytearray.base64
293+ value : The object must be serialized into a byte array
294+ : using a System.ComponentModel.TypeConverter
295+ : and then encoded with base64 encoding.
296+ -->
297+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
298+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
299+ <xsd:element name="root" msdata:IsDataSet="true">
300+ <xsd:complexType>
301+ <xsd:choice maxOccurs="unbounded">
302+ <xsd:element name="metadata">
303+ <xsd:complexType>
304+ <xsd:sequence>
305+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
306+ </xsd:sequence>
307+ <xsd:attribute name="name" use="required" type="xsd:string" />
308+ <xsd:attribute name="type" type="xsd:string" />
309+ <xsd:attribute name="mimetype" type="xsd:string" />
310+ <xsd:attribute ref="xml:space" />
311+ </xsd:complexType>
312+ </xsd:element>
313+ <xsd:element name="assembly">
314+ <xsd:complexType>
315+ <xsd:attribute name="alias" type="xsd:string" />
316+ <xsd:attribute name="name" type="xsd:string" />
317+ </xsd:complexType>
318+ </xsd:element>
319+ <xsd:element name="data">
320+ <xsd:complexType>
321+ <xsd:sequence>
322+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
323+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
324+ </xsd:sequence>
325+ <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
326+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
327+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
328+ <xsd:attribute ref="xml:space" />
329+ </xsd:complexType>
330+ </xsd:element>
331+ <xsd:element name="resheader">
332+ <xsd:complexType>
333+ <xsd:sequence>
334+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
335+ </xsd:sequence>
336+ <xsd:attribute name="name" type="xsd:string" use="required" />
337+ </xsd:complexType>
338+ </xsd:element>
339+ </xsd:choice>
340+ </xsd:complexType>
341+ </xsd:element>
342+ </xsd:schema>
343+ <resheader name="resmimetype">
344+ <value>text/microsoft-resx</value>
345+ </resheader>
346+ <resheader name="version">
347+ <value>2.0</value>
348+ </resheader>
349+ <resheader name="reader">
350+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
351+ </resheader>
352+ <resheader name="writer">
353+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
354+ </resheader>
355+ <data name="LoginEmailAddressWatermark" xml:space="preserve">
356+ <value>Email address</value>
357+ </data>
358+ <data name="LoginForgottenLink" xml:space="preserve">
359+ <value>I've forgotten my password.</value>
360+ </data>
361+ <data name="LoginPasswordWatermark" xml:space="preserve">
362+ <value>Password</value>
363+ </data>
364+ <data name="LoginViewInfo" xml:space="preserve">
365+ <value>To connect this computer to Ubuntu One enter your details below.</value>
366+ </data>
367+ <data name="LoginViewTitle" xml:space="preserve">
368+ <value>Connect to Ubuntu One</value>
369+ </data>
370+</root>
371\ No newline at end of file
372
373=== added file 'src/Canonical.Ubuntu.SSO.Views/WatermarkAdorner.cs'
374--- src/Canonical.Ubuntu.SSO.Views/WatermarkAdorner.cs 1970-01-01 00:00:00 +0000
375+++ src/Canonical.Ubuntu.SSO.Views/WatermarkAdorner.cs 2010-10-05 11:24:47 +0000
376@@ -0,0 +1,141 @@
377+/*
378+ * Copyright 2010 Canonical Ltd.
379+ *
380+ * This file is part of UbuntuOne on Windows.
381+ *
382+ * UbuntuOne on Windows is free software: you can redistribute it and/or modify
383+ * it under the terms of the GNU Lesser General Public License version
384+ * as published by the Free Software Foundation.
385+ *
386+ * Ubuntu One on Windows is distributed in the hope that it will be useful,
387+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
388+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
389+ * GNU Lesser General Public License for more details.
390+ *
391+ * You should have received a copy of the GNU Lesser General Public License
392+ * along with UbuntuOne for Windows. If not, see <http://www.gnu.org/licenses/>.
393+ *
394+ * Authors: Manuel de la Peña <manuel.delapena@canonical.com>
395+ */
396+using System.Windows;
397+using System.Windows.Controls;
398+using System.Windows.Data;
399+using System.Windows.Documents;
400+using System.Windows.Media;
401+
402+namespace Canonical.Ubuntu.SSO.Views
403+{
404+ /// <summary>
405+ /// Adorner for the watermark
406+ /// </summary>
407+ internal class WatermarkAdorner : Adorner
408+ {
409+ #region Private Fields
410+
411+ /// <summary>
412+ /// <see cref="ContentPresenter"/> that holds the watermark
413+ /// </summary>
414+ private readonly ContentPresenter _contentPresenter;
415+
416+ #endregion
417+
418+ #region Constructor
419+
420+ /// <summary>
421+ /// Initializes a new instance of the <see cref="WatermarkAdorner"/> class
422+ /// </summary>
423+ /// <param name="adornedElement"><see cref="UIElement"/> to be adorned</param>
424+ /// <param name="watermark">The watermark</param>
425+ public WatermarkAdorner(UIElement adornedElement, object watermark) :
426+ base(adornedElement)
427+ {
428+ IsHitTestVisible = false;
429+
430+ _contentPresenter = new ContentPresenter
431+ {
432+ Content = watermark,
433+ Opacity = 0.5,
434+ Margin =
435+ new Thickness(Control.Margin.Left + Control.Padding.Left,
436+ Control.Margin.Top + Control.Padding.Top, 0, 0)
437+ };
438+
439+ if (Control is ItemsControl && !(Control is ComboBox))
440+ {
441+ _contentPresenter.VerticalAlignment = VerticalAlignment.Center;
442+ _contentPresenter.HorizontalAlignment = HorizontalAlignment.Center;
443+ }
444+
445+ // Hide the control adorner when the adorned element is hidden
446+ var binding = new Binding("IsVisible")
447+ {
448+ Source = adornedElement,
449+ Converter = new BooleanToVisibilityConverter()
450+ };
451+ SetBinding(VisibilityProperty, binding);
452+ }
453+
454+ #endregion
455+
456+ #region Protected Properties
457+
458+ /// <summary>
459+ /// Gets the number of children for the <see cref="ContainerVisual"/>.
460+ /// </summary>
461+ protected override int VisualChildrenCount
462+ {
463+ get { return 1; }
464+ }
465+
466+ #endregion
467+
468+ #region Private Properties
469+
470+ /// <summary>
471+ /// Gets the control that is being adorned
472+ /// </summary>
473+ private Control Control
474+ {
475+ get { return (Control)AdornedElement; }
476+ }
477+
478+ #endregion
479+
480+ #region Protected Overrides
481+
482+ /// <summary>
483+ /// Returns a specified child <see cref="Visual"/> for the parent <see cref="ContainerVisual"/>.
484+ /// </summary>
485+ /// <param name="index">A 32-bit signed integer that represents the index value of the child <see cref="Visual"/>. The value of index must be between 0 and <see cref="VisualChildrenCount"/> - 1.</param>
486+ /// <returns>The child <see cref="Visual"/>.</returns>
487+ protected override Visual GetVisualChild(int index)
488+ {
489+ return _contentPresenter;
490+ }
491+
492+ /// <summary>
493+ /// Implements any custom measuring behavior for the adorner.
494+ /// </summary>
495+ /// <param name="constraint">A size to constrain the adorner to.</param>
496+ /// <returns>A <see cref="Size"/> object representing the amount of layout space needed by the adorner.</returns>
497+ protected override Size MeasureOverride(Size constraint)
498+ {
499+ // Here's the secret to getting the adorner to cover the whole control
500+ _contentPresenter.Measure(Control.RenderSize);
501+ return Control.RenderSize;
502+ }
503+
504+ /// <summary>
505+ /// When overridden in a derived class, positions child elements and determines a size for a <see cref="FrameworkElement"/> derived class.
506+ /// </summary>
507+ /// <param name="finalSize">The final area within the parent that this element should use to arrange itself and its children.</param>
508+ /// <returns>The actual size used.</returns>
509+ protected override Size ArrangeOverride(Size finalSize)
510+ {
511+ _contentPresenter.Arrange(new Rect(finalSize));
512+ return finalSize;
513+ }
514+
515+ #endregion
516+ }
517+}
518\ No newline at end of file
519
520=== added file 'src/Canonical.Ubuntu.SSO.Views/WatermarkService.cs'
521--- src/Canonical.Ubuntu.SSO.Views/WatermarkService.cs 1970-01-01 00:00:00 +0000
522+++ src/Canonical.Ubuntu.SSO.Views/WatermarkService.cs 2010-10-05 11:24:47 +0000
523@@ -0,0 +1,254 @@
524+/*
525+ * Copyright 2010 Canonical Ltd.
526+ *
527+ * This file is part of UbuntuOne on Windows.
528+ *
529+ * UbuntuOne on Windows is free software: you can redistribute it and/or modify
530+ * it under the terms of the GNU Lesser General Public License version
531+ * as published by the Free Software Foundation.
532+ *
533+ * Ubuntu One on Windows is distributed in the hope that it will be useful,
534+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
535+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
536+ * GNU Lesser General Public License for more details.
537+ *
538+ * You should have received a copy of the GNU Lesser General Public License
539+ * along with UbuntuOne for Windows. If not, see <http://www.gnu.org/licenses/>.
540+ *
541+ * Authors: Manuel de la Peña <manuel.delapena@canonical.com>
542+ */
543+using System;
544+using System.Collections.Generic;
545+using System.ComponentModel;
546+using System.Windows;
547+using System.Windows.Controls;
548+using System.Windows.Controls.Primitives;
549+using System.Windows.Documents;
550+
551+namespace Canonical.Ubuntu.SSO.Views
552+{
553+ /// <summary>
554+ /// Class that provides the Watermark attached property
555+ /// </summary>
556+ public static class WatermarkService
557+ {
558+ /// <summary>
559+ /// Watermark Attached Dependency Property
560+ /// </summary>
561+ public static readonly DependencyProperty WatermarkProperty = DependencyProperty.RegisterAttached(
562+ "Watermark",
563+ typeof(object),
564+ typeof(WatermarkService),
565+ new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnWatermarkChanged)));
566+
567+ #region Private Fields
568+
569+ /// <summary>
570+ /// Dictionary of ItemsControls
571+ /// </summary>
572+ private static readonly Dictionary<object, ItemsControl> _itemsControls = new Dictionary<object, ItemsControl>();
573+
574+ #endregion
575+
576+ /// <summary>
577+ /// Gets the Watermark property. This dependency property indicates the watermark for the control.
578+ /// </summary>
579+ /// <param name="d"><see cref="DependencyObject"/> to get the property from</param>
580+ /// <returns>The value of the Watermark property</returns>
581+ public static object GetWatermark(DependencyObject d)
582+ {
583+ return d.GetValue(WatermarkProperty);
584+ }
585+
586+ /// <summary>
587+ /// Sets the Watermark property. This dependency property indicates the watermark for the control.
588+ /// </summary>
589+ /// <param name="d"><see cref="DependencyObject"/> to set the property on</param>
590+ /// <param name="value">value of the property</param>
591+ public static void SetWatermark(DependencyObject d, object value)
592+ {
593+ d.SetValue(WatermarkProperty, value);
594+ }
595+
596+ /// <summary>
597+ /// Handles changes to the Watermark property.
598+ /// </summary>
599+ /// <param name="d"><see cref="DependencyObject"/> that fired the event</param>
600+ /// <param name="e">A <see cref="DependencyPropertyChangedEventArgs"/> that contains the event data.</param>
601+ private static void OnWatermarkChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
602+ {
603+ var control = (Control)d;
604+ control.Loaded += ControlLoaded;
605+
606+ if (d is ComboBox || d is TextBox || d is PasswordBox)
607+ {
608+ control.GotKeyboardFocus += ControlGotKeyboardFocus;
609+ control.LostKeyboardFocus += ControlLoaded;
610+ }
611+
612+ if (d is ItemsControl && !(d is ComboBox))
613+ {
614+ var i = (ItemsControl)d;
615+
616+ // for Items property
617+ i.ItemContainerGenerator.ItemsChanged += ItemsChanged;
618+ _itemsControls.Add(i.ItemContainerGenerator, i);
619+
620+ // for ItemsSource property
621+ DependencyPropertyDescriptor prop = DependencyPropertyDescriptor.FromProperty(ItemsControl.ItemsSourceProperty, i.GetType());
622+ prop.AddValueChanged(i, ItemsSourceChanged);
623+ }
624+ }
625+
626+ #region Event Handlers
627+
628+ /// <summary>
629+ /// Handle the GotFocus event on the control
630+ /// </summary>
631+ /// <param name="sender">The source of the event.</param>
632+ /// <param name="e">A <see cref="RoutedEventArgs"/> that contains the event data.</param>
633+ private static void ControlGotKeyboardFocus(object sender, RoutedEventArgs e)
634+ {
635+ var c = (Control)sender;
636+ if (ShouldShowWatermark(c))
637+ {
638+ RemoveWatermark(c);
639+ }
640+ }
641+
642+ /// <summary>
643+ /// Handle the Loaded and LostFocus event on the control
644+ /// </summary>
645+ /// <param name="sender">The source of the event.</param>
646+ /// <param name="e">A <see cref="RoutedEventArgs"/> that contains the event data.</param>
647+ private static void ControlLoaded(object sender, RoutedEventArgs e)
648+ {
649+ var control = (Control)sender;
650+ if (ShouldShowWatermark(control))
651+ {
652+ ShowWatermark(control);
653+ }
654+ }
655+
656+ /// <summary>
657+ /// Event handler for the items source changed event
658+ /// </summary>
659+ /// <param name="sender">The source of the event.</param>
660+ /// <param name="e">A <see cref="EventArgs"/> that contains the event data.</param>
661+ private static void ItemsSourceChanged(object sender, EventArgs e)
662+ {
663+ var c = (ItemsControl)sender;
664+ if (c.ItemsSource != null)
665+ {
666+ if (ShouldShowWatermark(c))
667+ {
668+ ShowWatermark(c);
669+ }
670+ else
671+ {
672+ RemoveWatermark(c);
673+ }
674+ }
675+ else
676+ {
677+ ShowWatermark(c);
678+ }
679+ }
680+
681+ /// <summary>
682+ /// Event handler for the items changed event
683+ /// </summary>
684+ /// <param name="sender">The source of the event.</param>
685+ /// <param name="e">A <see cref="ItemsChangedEventArgs"/> that contains the event data.</param>
686+ private static void ItemsChanged(object sender, ItemsChangedEventArgs e)
687+ {
688+ ItemsControl control;
689+ if (_itemsControls.TryGetValue(sender, out control))
690+ {
691+ if (ShouldShowWatermark(control))
692+ {
693+ ShowWatermark(control);
694+ }
695+ else
696+ {
697+ RemoveWatermark(control);
698+ }
699+ }
700+ }
701+
702+ #endregion
703+
704+ #region Helper Methods
705+
706+ /// <summary>
707+ /// Remove the watermark from the specified element
708+ /// </summary>
709+ /// <param name="control">Element to remove the watermark from</param>
710+ private static void RemoveWatermark(UIElement control)
711+ {
712+ AdornerLayer layer = AdornerLayer.GetAdornerLayer(control);
713+
714+ // layer could be null if control is no longer in the visual tree
715+ if (layer != null)
716+ {
717+ Adorner[] adorners = layer.GetAdorners(control);
718+ if (adorners == null)
719+ {
720+ return;
721+ }
722+
723+ foreach (Adorner adorner in adorners)
724+ {
725+ if (adorner is WatermarkAdorner)
726+ {
727+ adorner.Visibility = Visibility.Hidden;
728+ layer.Remove(adorner);
729+ }
730+ }
731+ }
732+ }
733+
734+ /// <summary>
735+ /// Show the watermark on the specified control
736+ /// </summary>
737+ /// <param name="control">Control to show the watermark on</param>
738+ private static void ShowWatermark(Control control)
739+ {
740+ AdornerLayer layer = AdornerLayer.GetAdornerLayer(control);
741+
742+ // layer could be null if control is no longer in the visual tree
743+ if (layer != null)
744+ {
745+ layer.Add(new WatermarkAdorner(control, GetWatermark(control)));
746+ }
747+ }
748+
749+ /// <summary>
750+ /// Indicates whether or not the watermark should be shown on the specified control
751+ /// </summary>
752+ /// <param name="c"><see cref="Control"/> to test</param>
753+ /// <returns>true if the watermark should be shown; false otherwise</returns>
754+ private static bool ShouldShowWatermark(Control c)
755+ {
756+ if (c is ComboBox)
757+ {
758+ return (c as ComboBox).Text == string.Empty;
759+ }
760+ if (c is TextBoxBase)
761+ {
762+ return (c as TextBox).Text == string.Empty;
763+ }
764+ if(c is PasswordBox)
765+ {
766+ return (c as PasswordBox).Password == string.Empty;
767+ }
768+ if (c is ItemsControl)
769+ {
770+ return (c as ItemsControl).Items.Count == 0;
771+ }
772+ return false;
773+ }
774+
775+ #endregion
776+ }
777+}

Subscribers

People subscribed via source and target branches

to all changes: