Categories
Design Time Support Uncategorized

Custom Controls Design Time Support Part 7: UITypeEditor Introduction

In the previous posts in this series I introduced how to use some basic and advanced Attributes and how to add an image for your control to appear in the toolbox and then I gave an introduction on TypeConverters and examples here and here on how to use the TypeConverters. Now I will give an introduction on how UITypeEditors used in design time.

First, what is a UITypeEditor anyway from MSDN :

The UITypeEditor class provides a base class that you can derive from and extend to implement a custom type editor for the design-time environment. Typically, your custom type editor interacts with the PropertyGrid control.

[more]

So the UITypeEditor interacts with the PropertyGrid where does it appear?? It appears in the left hand side of the property or just the value of the property in the PropertyWindow.

Any examples ?? yes there are multiple built in UITypeEditors for a lot types, one example is the FontEditor, when you edit any property of type Font you find by default a button ellipses like this .

Another example is the ColorEditor, while trying to get a screen shot for the color editor I found something interesting, in Visual Studio 2005 is different than that in Visual Studio 2008 more over in VS 2008 the color editor used with Web Controls is different than that used with windows controls.

Visual Studio 2005 Version

Visual Studio 2008 Windows Version

Visual Studio 2008 Web Version

 

Exploring the System.Drawing.Design.UITypeEditor methods.

GetEditStyle  Gets the editor style used by the EditValue method.
EditValue  Edits the value of the specified object using the editor style indicated by the GetEditStyle method.
GetPaintSupported  Indicates whether this editor supports painting a representation of an object's value.
PaintValue  Paints a representation of the value of an object using the specified PaintValueEventArgs.

The property.

 IsDropDownResizable  Gets a value indicating whether drop-down editors should be resizable by the user.

So, from the above pictures, the methods and the single property we can guess what a UITypeEditor can let us do.

  1. The editor can have one of three styles
    1. Modal -> a popup window as the FontEditor.
    2. DropDown -> a dropdown form as the VS2005 ColorEditor.
    3. None -> neither Modal nor DropDown just text as the Name property. (default Style for all Properties)
  2. You can draw anything within the small rectangle beside the property value (e.g. ColorEditor draws a solid rectangle with the chosen color beside it).
  3. When using the DropDown style you can make it resizable or not (e.g the VS2008 Windows ColorEditor is Resizable while the 2005 is not resizable).

Well thats enough for a fast introduction next part I'll give an example or two on how to implement an Editor from scratch, may be a new ColorEditor too.Smile

Categories
Design Time Support Uncategorized

Custom Controls Design Time Support Part 6: Custom TypeConverter 2

The last post in the series I have showed you how to implement a custom TypeConverter and override some of the virtual methods from the base class.

In this post I'll show how to some more advanced examples on how to get the most of TypeConverters. First look at the strucure of the example.

[more] 

[code:c#]

public enum Processor
{
  TwoPointFour,
  TwoPointEight,
  ThreePointTwo,
  ThreePointSix
}

public class Computer
{
  private Processor _processorSpeed;
  public Processor ProcessorSpeed
  {
    get { return _processorSpeed; }
    set { _processorSpeed = value; }
  }

  private ComputerType _type;
  public ComputerType Type
  {
    get { return _type; }
    set { _type = value; }
  }
}

public abstract class ComputerType
{
  private int _hardDiskSize;
  public int HardDiskSize
  {
    get { return _hardDiskSize; }
    set { _hardDiskSize = value; }
  }
}

public class DesktopPC : ComputerType
{
  private bool _hasInternalUPS;
  public bool HasInternalUPS
  {
    get { return _hasInternalUPS; }
    set { _hasInternalUPS = value; }
  }
}

public class Laptop : ComputerType
{
  private bool _hasBluetooth;
  public bool HasBluetooth
  {
    get { return _hasBluetooth; }
    set { _hasBluetooth = value; }
  }
}

public class PocketPC : ComputerType
{
  private bool _canMakeCalls;
  public bool CanMakeCalls
  {
    get { return _canMakeCalls; }
    set { _canMakeCalls = value; }
  }
}

[/code]

Now to setup a test enivronment I made a new windows forms application added a Button and a PropertyGrid control, on button click.

 

[code:c#]

Computer toshiba = new Computer();
toshiba.ProcessorSpeed = Processor.TwoPointEight;
toshiba.Type = new Laptop();

propertyGrid1.SelectedObject = toshiba;

[/code]

And this is how it looks.

Now we need to enhance how that looks, first lets change how the Processor enum appears. The enum appears like that as the default behaviour of the EnumConverter which shows the enum values as is, to change that behaviour lets start by deriving from the EnumConverter and changing how it converts to and from a string.

[code:c#]

public class ProcessorConverter : EnumConverter
{
  private Type _enumType;
  private Dictionary _enumValues;

  public ProcessorConverter(Type enumType) : base(enumType)
  {
    _enumType = enumType;
    if (_enumValues == null)
    {
      _enumValues = new Dictionary();
      _enumValues.Add(Processor.TwoPointFour, "2.4 Ghz");
      _enumValues.Add(Processor.TwoPointEight, "2.8 Ghz");
      _enumValues.Add(Processor.ThreePointTwo, "3.2 Ghz");
      _enumValues.Add(Processor.ThreePointSix, "3.6 Ghz");
    }
  }

  public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object src)
  {
    if (src is string)
    {
      if (_enumValues.ContainsValue((string)src))
      {
        foreach (KeyValuePair item in _enumValues)
        {
          if(item.Value == (string)src)
            return item.Key;
        }
      }
      return null;
    }
    return base.ConvertFrom(context, culture, src);
  }
  public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object src, Type destinationType)
  {
    if (destinationType == typeof(string) && src is Processor)
    {
      return _enumValues[(Processor)src];
    }
    return base.ConvertTo(context, culture, src, destinationType);
  }
}

[/code]

As you can notice when deriving from the EnumConverter you have to implement the constructor having enumtype parameter. Now don't forget to associate the ProcessorConverter with the Processor enum.

[code:c#]

[TypeConverter(typeof(ProcessorConverter))]
public enum Processor

[/code]

And here is the result.

Now lets implement a ComputerTypeConverter, I will derive from the ExpandableObjectConverter which is already useful for listing the inner properties.

[code:c#]

public class ComputerTypeConverter : ExpandableObjectConverter

[/code]

By applying this converter as it is without implementing any custom code gives the following result. Now lets first override the CanConvert methods to allow our Converter to work with strings.

[code:c#]

public class ComputerTypeConverter : ExpandableObjectConverter
{
  public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
  {
    if (sourceType == typeof(string))
    {
      return true;
    }
    return base.CanConvertFrom(context, sourceType);
  }
  public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
  {
    if (destinationType == typeof(string))
    {
      return true;
    }
    return base.CanConvertTo(context, destinationType);
  }

  public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object src)
  {
    if (src is string)
    {
      switch ((string)src)
      {
        case "Desktop PC": return new DesktopPC();
        case "Laptop": return new Laptop();
        case "Pocket PC": return new PocketPC();
        case "(None)":
        default:
          return null;
      }
    }
    return base.ConvertFrom(context, culture, src);
  }
  public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object src, Type destinationType)
  {
    if (destinationType == typeof(string))
    {
      if(src == null) return "(None)";
      if(src is DesktopPC) return "Desktop PC";
      if(src is Laptop) return "Laptop";
      if(src is PocketPC) return "Pocket PC";
    }
    return base.ConvertTo(context, culture, src, destinationType);
  }
}

[/code]

What we have done here is kind of nice, now we can write the string representing the computer type in the property grid and the TypeConverter automatically converts it for us. But the only problem here is that if the user/developer might not memorize all computer types and with the exact letter case, so we need a way to make it easy on them. Yes, its time to override the GetStandardValues method.

[code:c#]

private ComputerType[] _standardValues = new ComputerType[] { null, new DesktopPC(), new Laptop(), new PocketPC() };
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
{
  return true;
}
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
  return new StandardValuesCollection(_standardValues);
}

[/code]

The final looks like this.

 

So, this is the end of TypeConverters I hope it become useful to someone someday. Next parts I will talk about UITypeEditors.

Computer.cs (5.67 kb)        

Categories
Design Time Support Uncategorized

Custom Controls Design Time Support Part 5: Custom TypeConverters

In the previous post I gave an introduction on common TypeConverters and how to use them, in this post I will show you how to implement custom TypeConverters for your own custom data types.

First, lets explore the TypeConverter base type virtual methods …

Method Description
CanConvertFrom Returns a Boolean value indicating whether the converter can convert an object of the specified type to the type that this converter represents.
CanConvertTo Returns a Boolean value indicating whether the converter can convert an object to the specified type.
ConvertFrom Converts the specified value to the type represented by this converter.
ConvertFromInvariantString Converts the string representation of a value to a type that this converter represents, using the invariant culture, which is English.
ConvertFromString Converts the string representation of a value to a type that this converter represents, using the given culture.
ConvertTo Converts the given object to the specified type.
ConvertToInvariantString Converts the given object to a string, using the invariant culture.
ConvertToString Converts the given object to a string, using the specified culture.
CreateInstance Creates or recreates an object given a dictionary of property values. The dictionary contains property name-value pairs.
GetCreateInstanceSupported Returns a Boolean value indicating whether CreateInstance has been implemented.
GetProperties Returns a collection of PropertyDescriptor objects for the given object.
GetPropertiesSupported Returns a Boolean value indicating whether the given object supports properties.
GetStandardValues Returns a collection of standard values for the type that this converter represents.
GetStandardValuesExclusive Returns a Boolean value indicating whether the standard values are mutually exclusive.
GetStandardValuesSupported Returns a Boolean value indicating whether GetStandardValues is implemented.
IsValid Returns a Boolean value indicating whether the specified value is valid for the type that this converter represents.

[more] 

Now lets implement a simple one, considering a type Point3D which simply has 3 int properties representing a point in the 3D (x,y,z).

[code:c#]

public struct Point3D
{
    private int _x;
    private int _y;
    private int _z;

    public int X { get { return _x; } set { _x = value; } }
    public int Y { get { return _y; } set { _y = value; } }
    public int Z { get { return _z; } set { _z = value; } }
}

[/code]

When adding a Point3D property to our testing ButtonEx Control the Point would look like this in the PropertyWindow

[code:c#]

public class Point3DConverter : TypeConverter
{
   public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
   {
   if (sourceType == typeof(string))
      return true;
   else
      return base.CanConvertFrom(context, sourceType);
   }

   public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
   {
      if (destinationType == typeof(Point3D))
         return true;
      else
         return base.CanConvertTo(context, destinationType);
   }

   public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object src, Type destinationType)
   {
       //convert to a string
       if (destinationType == typeof(string))
      {
         Point3D p3 = (Point3D)src;
         string result = p3.X + "," + p3.Y + "," + p3.Z;
         return result;
       }
       return base.ConvertTo(context, culture, src, destinationType);
  }
   public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object src) {
  {
      //convert from a string
      if (src is string)
     {
         Point3D p3 = new Point3D();
         string[] temp = ((string)src).Split(',');
         p3.X = int.Parse(temp[0]);
         p3.Y = int.Parse(temp[1]);
         p3.Z = int.Parse(temp[2]);
        return p3;
       }
     return base.ConvertFrom(context, culture, src);
   }
}

[/code]

Now apply the Point3DConverter to the Point3D struct, so anytime the Point3D is used then the Point3DConverter is used by default as when you use the Size type it is always associated with the SizeConverter, same to FontConverter used default with Font type.

[code:c#]

[TypeConverter(typeof(Point3DConverter))]
public struct Point3D

[/code]

After applying the Converter the property would look like this:

 

This would be enough to use the Point3D smoothly in the desing time, but we can make it more fancy by overriding GetPropertiesSupported and GetProperties methods.

[code:c#]

public override bool GetPropertiesSupported(ITypeDescriptorContext context)
{
   return true;
}

public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object src, Attribute[] attributes)
{
   return TypeDescriptor.GetProperties(src, attributes);
}

[/code]

Now it will be expanded in the PropertyWindow

 

To show how the GetStandardValuesSupported and GetStandardValues work take a look on the following properties.

As you are expecting the values appearing in the drop down list are the StandardValues, accordingly the EnumConverter overrides those two methods in order to return the values of the Enum.

Next part I will show how to use the StandardValues and the rest of the methods.

Point3D.cs (2.58 kb)

Categories
Design Time Support Uncategorized

Custom Controls Design Time Support Part 4: TypeConverters Introduction

 I mentioned in my Introduction post of this series the TypeConverters

Overview: For those who don't know what is a TypeConverter you can expect that it is something responsible to convert between types, there are times when you need to convert from one data type to another. Type converters are classes that describe how a particular object converts to and from other data types. For example, to display a date on the screen(console, windows form, web ..) it will need to be converted to a string representation. Vice Versa is true, if there is a string value of a date that needs to be stored for example in database. Usually casting is enough when the types are simple. But with complex types, a better technique is used.

TypeConverters are classes that define how an object converts to and from other types. Which are used during design time for sting conversion ( used by the PropertyGrid ), also in runtime in validations and conversions.

So, first lets take a look on some of the Common .NET Type Converters that are already built for us to use.

All the following classes are in the System.ComponentModel and the System.Drawing namespaces.

  1. StringConverter
  2. BooleanConverter
  3. CharConverter
  4. CollectionConverter
  5. CultureInfoConverter
  6. DateTimeConverter
  7. EnumConverter
  8. ExpandableObjectConverter
  9. GuidConverter
  10. TimeSpanConverter
  11. ColorConverter
  12. FontConverter
  13. PointConverter
  14. RectangleConverter
  15. SizeConverter

And much more. [more]

From the most Converters that I personally like is the ExpandableObjectConverter you can apply it using the following syntax.

Example:

[code:c#]

public class Info
{
int i;
string s;
public int IntProperty
{
get { return i;}
set { i = value; }
}
public int StringProperty
{
get { return s; }
set { s = value; }
}
}

public class ButtonEx : Button
{

private Info i;
[TypeConverter(typeof(ExpandableObjectConverter))]
public Info ComplexObject
{
get { return i; }
set { i = value; }
}
}

[/code]

Without the attribute, the property would look like this
After applying the converter it is like this

Next part I will implement a custom converter.

Categories
Design Time Support Uncategorized

Custom Controls Design Time Support Part 3: Adding Image in the Toolbox

Attributes Applied To Description
ToolboxBitmap Controls           Allows you to specify an icon to represent a control in a container, such as the Microsoft Visual Studio Form Designer.

» ToolboxBitmapAttribute if you want to redistribute your custom control you should use this attribute to add an icon to it.

[code:c#]

[ToolboxBitmap(typeof(Button))]
public class ButtonEx : Button

[/code]

This will show the default icon of the Windows.Forms.Button control, to add a custom icon you will use one of the other two ToolboxBitmapAttribute constructors, the first one accepts a string as the full path for the image, the second one with a string and a type this one is used more frequently.

[code:c#]

[ToolboxBitmap(typeof(ButtonEx),"ButtonEx.png")]
public class ButtonEx : Button

[/code]

Note: For this to work you need to be sure of 2 things:

  1. The image name would be exactly spelled as the type (control).
  2. Right click the image and make sure its BuildAction is Embedded Resource.
Categories
Design Time Support Uncategorized

Custom Controls Design Time Support Part 2: More Design Time Attributes

In my previous post I pointed out the most common used Attributes for Design Time Support. In this part I will point out some more Attributes that take advantage of the Design Time Environment.

Attributes Applied To Description
DisplayName Properties & Events Specifies the display name for a property or an event.
ParenthesizeProperty Properties  Indicates whether the name of the associated property is displayed with parentheses in the Properties window.
RefreshProperties Properties Indicates that the property grid should refresh when the associated property value changes.
NotifyParentProperty Properties Indicates that the parent property is notified when the value of the property that this attribute is applied to is modified.
ReadOnly Properties Specifies whether the property this attribute is bound to is read-only or read/write.
DesignOnly Properties

Specifies whether a property can only be set at design time.

[more] 

» DisplayNameAttribute is useful when you need the name displayed in the PropertyWindow different than property actual name.

[code:c#]

[DisplayName("Number of Clicks")]
public int NumOfClicks

[/code]

DisplayNameAttribute 

» ParenthesizePropertyAttribute when you have a special property such as Name and need it to appear between brackets this is the attribute to use.

[code:c#]

[ParenthesizePropertyName(true)]
public string SpecialProperty

[/code]

» RefreshPropertiesAttribute when you have property's value which depends on the value of another one then you will need this attribute, mark the property that when changed should refresh others with this attribute.

[code:c#]

[RefreshProperties(RefreshProperties.All)]
public string RefreshOtherProperty

[/code]

» NotifyParentPropertyAttribute Apply this one to a property if its parent property should receive notification of changes to the property's values. For example, the Size property has two nested properties: height and width. These nested properties should be marked with NotifyParentPropertyAttribute(true) so they notify the parent property to update its value and display when the property values change.

[code:c#]

[NotifyParentProperty(true)]
public string NotifyparentProperty

[/code]

» ReadOnlyAttribute When applying this attribute with parameter true then it will be unchangable in the design time, this is different than making a property without a set accessor since properties marked with ReadOnlyAttribute can be changed using code.

[code:c#]

[ReadOnly(true)]
public string ReadOnlyProperty

[/code]

» DesignOnlyAttribute from the name implies that the property marked with this attribute will only be available in the design mode.

[code:c#]

[DesignOnly(true)]
public string DesignTimeOnlyProperty

[/code]

ButtonEx.cs (3.36 kb)

Categories
Design Time Support Uncategorized

Custom Controls Design Time Support Part 1: Design Time Attributes

As I mentioned in my previous post, I am willing to write a multi part tutorial on how to add Design Time Support to your custom controls.

In this part, I will talk about the common attributes for Properties and Events

Attribute Applied To Description
Browsable Properties and events Specifies whether a property or an event should be displayed in the property browser.
Category

Properties and events

Specifies the name of the category in which to group a property or event. When categories are used, component properties and events can be displayed in logical groupings in the property browser.
Description Properties and events Defines a small block of text to be displayed at the bottom of the property browser when the user selects a property or event.
DefaultProperty Properties
(Insert this attribute before the class declaration.)
Specifies the default property for the component. This property is selected in the property browser when a user clicks on the control.
DefaultValue Properties Sets a simple default value for a property.
DefaultEvent Events
(Insert this attribute before the class declaration.)
Specifies the default event for the component. This is the event that is selected in the property browser when a user clicks on the component.

To illustrate how these attributes work I need first to set a custom control, let's start with simple windows forms button. [more]

[code:c#]

using System;
using System.Windows.Forms;

namespace Elsehemy.Controls
{
  public class ButtonEx : Button
  {
  
  }
}

[/code]

Now add a property to make use of some attributes (I will use simple ones first)

[code:c#]

private int _numOfClicks;

public int NumOfClicks
{
  get { return _numOfClicks; }
  set { _numOfClicks = value; }
}

[/code]

Now add the ButtonEx control to a windows form to test the effect of attributes one by one.

[code:c#]

[Description("Tells how many time the button has been clicked")]
public int NumOfClicks{…}

[/code]

DescriptionAttribute

[code:c#]

[Category("Special Properties")]
[Description("Tells how many time the button has been clicked")]
public int NumOfClicks{…}

[/code]

[code:c#]

[DefaultValue(10)]
[Category("Special Properties")]
[Description("Tells how many time the button has been clicked")]
public int NumOfClicks{…}

[/code]

As you can notice the default value attribute now enabled the Reset context menu item which (of course) will reset the Property value to 10, the Reset command is only enabled when the value is not equal to 10, further more the value is always bold when it is not the default.

NOTE: The DefaultValue Attribute just writes the value of the box beside the property name to the value chosen, which means the actual inner variable isn't set to that value, so if you reset the value and 10 is written then ran the program and tested for NumOfClicks value you will find it equal to 0, even though its written 10.

Solution: Make sure to set the default value in the constructor of the control to have it work as expected.

More on DefaultValue Attribute as you already noticed the constructor has overloads for different types however all types are simple (bool, int, short, string ….) and one more constructor overload that has 2 parameters a type and a string value, consider we have a System.Drawing.Color Property that needs to have a default value.

[code:c#]

[DefaultValue(typeof(System.Drawing.Color),"Red")]
public System.Drawing.Color ColorProperty

[/code]

More over not only KnownColors can be set as default values, you can set the default value as RGB by supplying its Hex value..

[code:c#]

[DefaultValue(typeof(System.Drawing.Color),"#FFBA00")]
public System.Drawing.Color ColorProperty

[/code]

Sometimes there are more complex properties that need default values as System.Drawing.Font where DefaultValueAttribute will not fit, two special purpose methods named

void ResetPropertyname(), bool ShouldSerializePropertyname().

if Reset method is available it will be called one Reset command, ShouldSerialize method is for (should the designer generate a line in the form.designer.cs file or not) so obviously you should serialize when the value is not the default and not serialize if the property value is changed.

[code:c#]

System.Drawing.Font f;
public System.Drawing.Font FontProperty
{
  get
  {
    if (f == null)
      return this.Font; //this should be the default value you want
    else return f;
  }
  set { f = value; }
}

void ResetFontProperty()
{
  f = null;
}
bool ShouldSerializeFontProperty()
{
  return f == null ? false : true;
}

[/code]

The DefaultPropertyAttribute just tells the designer which Property should be selected when the PropretyWindow opens (control:right click > Properties Or selected control: press F4). For example, Text is the default property of the TextBox control.

The DefaultEventAttribute tells the designer which Event should be selected when the ProperyWindow (Events Tab) opens, more over when double click the control the designer will generate an event handler method for that event. For example, Click is the default event of the Button control.

[code:c#]

[DefaultEvent("NumofClicksChanged")]
[DefaultProperty("NumOfClicks"]

public class ButtonEx : Button

[/code]

To be continued…

References:

http://msdn2.microsoft.com/en-us/library/tk67c2t8.aspx

Download Code : ButtonEx.cs (2.10 kb)

Categories
Design Time Support Uncategorized

Custom Controls Design Time Support Part 0: Introduction

In my amr-elsehemy.blogspot.com I started a design time support tutorial for custom controls but I didn't manage to finish them so I will start my blog here on amrelsehemy.net by editing my previous posts and adding new tutorials.

So if you came from my blogspot you may still find some new useful information, so lets start.

You need to be familiar with some terms when working with the design time environment .

Design Time Archticeture

[more]

Type: The Custom Control or Component that will take advantage of the design time environment.

Member(s): The members of the Type usually Properties and Events, sometimes methods.

Attributes: They are responsible to associate the Type and/or the Member(s) of the type with a class that extends design time behaviour.

Designers: They are used to customize the behavior of a component at design time, including its appearance, initialization, and interaction with the user. A designer can add, remove, or replace properties listed in a property browser for a selected component. They can provide user-defined methods that can be linked to certain component events or executed from a custom menu command, or DesignerVerb. A designer can also use services provided by a design-time environment.

Type Converters: They can be implemented to convert values between the type it is built to support and other data types that it can translate values to or from. A type converter can also provide logic to enable configuration of a property within a property browser at design time. A type converter can provide a list of standard values for a property of the type it supports at design time in a property browser. A type converter can also produce initialization code to initialize a property at design time.

UI Type Editors: They can provide a custom user interface (UI) for editing the value of a property and displaying a representation of the value of the property at design time. A UI type editor is type-specific and provides a user interface for configuring properties of the type it is built to support, or derived types which do not have an overriding attribute, at design time. A UI type editor can display a Windows Form or drop-down configuration interface for configuring a property.

Design Time Environment: The Visual Studio would be the perfect host.

Design Time Services: Services provided by the Visual Studio as ( IComponentChangeService, ISelectionService, IMenuCommandService and much more )

Forms Designer: The actual area that you interacts with, where you place controls on.

Properties Window: The special property grid window in the visual studio.

I will try to discuss each one with some few code examples to make everything clear.

References:

http://msdn2.microsoft.com/en-us/library/c5z9s1h4.aspx