| <html> |
| |
| <head> |
| <meta http-equiv="Content-Type" content="text/html; charset=windows-1252"> |
| <meta name="GENERATOR" content="Microsoft FrontPage 4.0"> |
| <meta name="ProgId" content="FrontPage.Editor.Document"> |
| <title>Take control of your properties</title> |
| <link rel="stylesheet" href="../default_style.css"> |
| </head> |
| |
| <body link="#0000ff" vlink="#800080"> |
| |
| <div align="right"> |
| <font face="Times New Roman, Times, serif" size="2">Copyright © 2003 |
| Broadvision Corp.</font> |
| <table border="0" cellspacing="0" cellpadding="2" width="100%"> |
| <tr> |
| <td align="LEFT" valign="TOP" colspan="2" bgcolor="#0080C0"><b><font face="Arial,Helvetica"><font color="#FFFFFF"> Eclipse |
| Corner Article</font></font></b></td> |
| </tr> |
| </table> |
| </div> |
| <div align="left"> |
| <h1><img src="images/Idea.jpg" height="86" width="120" align="CENTER"></h1> |
| </div> |
| <h1 align="CENTER">Take control of your properties</h1> |
| <blockquote> |
| <b>Summary</b><br> |
| The Eclipse workbench provides a properties view which is used to view (and/or |
| edit) properties of a selected item. In this article, you will learn how to |
| use the properties view to dynamically modify the properties of a GUI button. |
| <p><b>By Dicky Johan, Broadvision, dicky.johan@broadvision.com</b><br> |
| <font size="-1">May 20, 2003</font></p> |
| </blockquote> |
| <hr width="100%"> |
| <h2>Introduction</h2> |
| <p>The Eclipse workbench provides a lot of views, but one of the highly |
| extensible views is the properties view. It provides a way for you, as a plug-in |
| developer, to display the properties of a selected item. The properties view can |
| display read-only information, such as the properties of a file resource. Or it |
| can display information that can be edited, such as the properties of an |
| extension point in a plugin.xml file.</p> |
| <p>The properties view can display properties for various kinds of items. An |
| item may be a directory resource, a file resource, or an element within a |
| resource (such as an extension in a plugin.xml file). The items may reside in |
| different views within the Eclipse workbench, and the properties view can be |
| triggered from different views or editors to display the properties of a |
| selected item.</p> |
| <p>In this article, I will show you how to control the different properties of a |
| GUI resource using the properties view. Using a button as a sample GUI resource, |
| I will create a button, a view containing that button, and a list of editable |
| and complex properties. I will show how the button responses to changes of its |
| properties thru the property view.</p> |
| <h2>Installation</h2> |
| <p>To run the sample, please unzip <a href="propertyviewsample.zip">propertyviewsample.zip</a> |
| into your <i>eclipse</i> subdirectory. Restart eclipse as necessary.</p> |
| <h2>Running the sample</h2> |
| <p><img src="images/tryit.gif" width="61" height="13"> Switch to the Resource |
| perspective, Window>Open Perspective>Resource. Next open the properties |
| view, Window>Show View>Other... and select<br> |
| Basic>Properties. Now goto Go to Window>Show View>Other... and select |
| "Sample Category/Sample1 View" and you should see the view being shown |
| below. </p> |
| <p>When you select the "Button" in the view, notice that the |
| properties view is changed to display the current properties of the button. You |
| can modify the properties and see how the button changes! Cool!</p> |
| <p><img border="0" src="properties-view.jpg" width="486" height="220"></p> |
| <p>Now the excitement is over, let's get on with the details!</p> |
| <h2>Connecting our view to the Properties View</h2> |
| <p>The properties view is designed to respond to workbench selection changes. |
| The workbench selection is determined by the selection provider (implements <code>ISelectionProvider</code>) |
| for the currently active workbench part (view or editor).</p> |
| <p>Every workbench part has a <code>IWorkbenchPartSite</code>, and one can set |
| the selection provider for this site. When I created our sample view, I |
| instantiated a <code>ListViewer</code>, which implements <code>ISelectionProvider</code>. |
| I pass this <code>ListViewer</code> to the <code>IWorkbenchPartSite</code> |
| object via <img src="images/tag_1.gif" width="24" height="13"><code>setSelectionProvider</code>. |
| This enables the property view to be informed of selection changes in our list |
| when our view is the active workbench part.</p> |
| <pre><font color="#4444cc"> // configure the viewer |
| viewer.setContentProvider(new ListContentProvider()); |
| viewer.setLabelProvider(new LabelProvider() { |
| public String getText(Object element) { |
| return ((ButtonElement)element).getName(); |
| } |
| }); |
| viewer.setInput(input); |
| <img src="images/tag_1.gif" width="24" height="13">getSite().setSelectionProvider(viewer); |
| </font></pre> |
| <h2>Creating the IAdaptable item</h2> |
| <p>When the properties view is notified of a workbench selection change, the |
| selected item will be queried for a property source. There are two ways to |
| provide a property source for a particular selection:</p> |
| <ul> |
| <li>The selected item can implement the <code>IPropertySource</code> interface |
| and provide the properties.</li> |
| <li>The selected item can implement the <code>IAdaptable</code> interface and |
| return an <code>IPropertySource</code> object when <code>getAdapter</code> |
| is called.</li> |
| </ul> |
| <p>We will use the latter approach. The first thing we need to do is to create |
| our own custom item. In this case, it is a element used to store a GUI button.</p> |
| <pre><font color="#4444cc">public class ButtonElement implements <img src="images/tag_1.gif" width="24" height="13">IAdaptable { |
| |
| private Button button; |
| private String name; |
| |
| /** |
| * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) |
| */ |
| public Object getAdapter(Class adapter) { |
| if (adapter == IPropertySource.class) { |
| <img src="images/tag_2.gif" width="24" height="13">if (btnElPS == null) { |
| // cache the buttonelementpropertysource |
| btnElPS = new ButtonElementPropertySource(this,name); |
| } |
| return btnElPS; |
| } |
| return null; |
| }</font></pre> |
| <p>Notice that this class implements <img src="images/tag_1.gif" width="24" height="13"><code>IAdaptable</code>, |
| which is used to query for a property source. When <code>getAdapter</code> is |
| called with the <code>IPropertySource.class</code> argument, it will create an |
| instance of the class <img src="images/tag_2.gif" width="24" height="13"><code>ButtonElementPropertySource</code> |
| that describes the button's properties. We cache this instance in the class for |
| two reasons. One is for performance (since for every call, we are creating |
| similar objects), and the other is for tracking property changes as you will see |
| later.</p> |
| <h2>Creating the Property Source object</h2> |
| <p>The <code>ButtonElementPropertySource</code> class implements <code>IPropertySource</code>, |
| which is an interface that provides a description of an item's properties. In |
| our example, I am storing the button control within the element, and since I |
| will be modifying the properties of the button in real time, I want to gain |
| access to its handle within the <code>ButtonElementPropertySource</code> object. |
| Thus <img src="images/tag_1.gif" width="24" height="13">the constructor of <code>ButtonElementPropertySource</code> |
| takes a <code>ButtonElement</code> object. It also takes on a defaultText |
| string, this is used for storing the default value of the button text.</p> |
| <pre> |
| <font color="#4444cc"> /** |
| * This class provides property sheet properties |
| * for ButtonElement. |
| */ |
| public class ButtonElementPropertySource implements IPropertySource { |
| |
| private static final String PROPERTY_FONT = "mview.views.font"; |
| private static final String PROPERTY_SIZE = "mview.views.size"; |
| private static final String PROPERTY_TEXT = "mview.views.text"; |
| private final Button button; |
| private final SizePropertySource sizePropertySource = new SizePropertySource(); |
| |
| private String defText; |
| |
| private IPropertyDescriptor[] propertyDescriptors; |
| |
| /** |
| * Creates a new ButtonElementPropertySource. |
| * |
| * @param element the element whose properties this instance represents |
| */ |
| public <img src="images/tag_1.gif" width="24" height="13">ButtonElementPropertySource(ButtonElement element, String defaultText) { |
| button = element.getControl(); |
| defText = defaultText; |
| } |
| |
| /** |
| * @see org.eclipse.ui.views.properties.IPropertySource#getPropertyDescriptors() |
| */ |
| public IPropertyDescriptor[] getPropertyDescriptors() { |
| if (propertyDescriptors == null) { |
| // Create a descriptor and set a category |
| PropertyDescriptor fontDescriptor = new FontDataPropertyDescriptor(PROPERTY_FONT, "Font"); |
| <img src="images/tag_2.gif" width="24" height="13">fontDescriptor.setCategory("Label"); |
| |
| PropertyDescriptor sizeDescriptor = new PropertyDescriptor(PROPERTY_SIZE, "Size"); |
| // set a custom label provider for a point |
| sizeDescriptor.setLabelProvider(new LabelProvider() { |
| public String getText(Object element) { |
| Point point = (Point)element; |
| StringBuffer buf = new StringBuffer(); |
| buf.append("Height:"); |
| buf.append(point.y); |
| buf.append(" "); |
| buf.append("Width:"); |
| buf.append(point.x); |
| return buf.toString(); |
| } |
| }); |
| sizeDescriptor.setCategory("Button"); |
| |
| PropertyDescriptor textDescriptor = new TextPropertyDescriptor(PROPERTY_TEXT,"Text"); |
| textDescriptor.setCategory("Label"); |
| |
| <img src="images/tag_3.gif" width="24" height="13">propertyDescriptors = new IPropertyDescriptor[] { |
| fontDescriptor, |
| sizeDescriptor, // Read-only (instance of PropertyDescriptor) |
| textDescriptor}; |
| } |
| return propertyDescriptors; |
| }</font></pre> |
| <p>Every property needs to be described by a property descriptor. You can create |
| your own custom property descriptor, I will show you an example of this later, |
| or you can use some standard ones that are already included:</p> |
| <ul> |
| <li><code>PropertyDescriptor</code> - read-only property</li> |
| <li><code>TextPropertyDescriptor </code>- edits with a <code>TextCellEditor</code></li> |
| <li><code>CheckboxPropertyDescriptor</code> - edits with a <code>CheckboxCellEditor</code></li> |
| <li><code>ComboBoxPropertyDescriptor </code>- edits with a <code>ComboBoxCellEditor</code></li> |
| <li><code>ColorPropertyDescriptor </code>- edits with a <code>ColorCellEditor</code></li> |
| </ul> |
| <p>Two property descriptors are categorized under <img src="images/tag_2.gif" width="24" height="13"> |
| "Label", the other under "Button". Notice how these |
| categories show up in the properties view when the "Show Categories" |
| button is pressed in the view's local toolbar. Altogether, I created three <img src="images/tag_3.gif" width="24" height="13"> |
| property descriptors.</p> |
| <h2>Creating a custom property descriptor</h2> |
| <p>It would be too boring to only display a button with a plain vanilla default |
| font. I decided to spice it up by providing an editable font property. Checking |
| out the list of default property descriptors, I cannot find any font related |
| property descriptor. So, let's try to be a bit adventurous and create our own.</p> |
| <pre><font color="#4444cc"> public class FontDataPropertyDescriptor extends PropertyDescriptor { |
| /** |
| * Creates a property descriptor with the given id and display name. |
| * |
| * @param id the id of the property |
| * @param displayName the name to display for the property |
| */ |
| public FontPropertyDescriptor(Object id, String displayName) { |
| super(id, displayName); |
| setLabelProvider(new FontDataLabelProvider()); |
| } |
| |
| /** |
| * @see org.eclipse.ui.views.properties.IPropertyDescriptor#createPropertyEditor(Composite) |
| */ |
| public CellEditor createPropertyEditor(Composite parent) { |
| CellEditor editor = <img src="images/tag_1.gif" width="24" height="13">new FontDataDialogCellEditor(parent); |
| if (getValidator() != null) |
| editor.setValidator(getValidator()); |
| return editor; |
| } |
| }</font></pre> |
| <p>I derive the <code>FontDataPropertyDescriptor</code> class from the default <code>PropertyDescriptor</code>. |
| When <code>createPropertyEditor</code> is called, I need to instantiate our own <img src="images/tag_1.gif" width="24" height="13"><code>FontDataDialogCellEditor</code>.</p> |
| <p>The <code>FontDialogCellEditor </code>needs to instantiate a dialog, and thus |
| behaves like a <code>DialogCellEditor</code>. So, I derive from it.</p> |
| <pre><font color="#4444cc"> public class FontDataDialogCellEditor extends DialogCellEditor { |
| /** |
| * Creates a new Font dialog cell editor parented under the given control. |
| * The cell editor value is <code>null</code> initially, and has no |
| * validator. |
| * |
| * @param parent the parent control |
| */ |
| protected FontDataDialogCellEditor(Composite parent) { |
| super(parent); |
| } |
| |
| /** |
| * @see org.eclipse.jface.viewers.DialogCellEditor#openDialogBox(Control) |
| */ |
| protected Object openDialogBox(Control cellEditorWindow) { |
| <img src="images/tag_2.gif" width="24" height="13">FontDialog ftDialog = new FontDialog(cellEditorWindow.getShell()); |
| String value = (String) getValue(); |
| |
| if (getValue() != null) { |
| ftDialog.setFontData((FontData)getValue()); |
| } |
| FontData fData = ftDialog.open(); |
| |
| if (fData != null) { |
| <img src="images/tag_3.gif" width="24" height="13">return fData; |
| } |
| return getValue(); |
| } |
| }</font></pre> |
| Exploring the rich UI functionality provided by Eclipse, I find out that SWT |
| provides the system <code>FontDialog</code>. How handy! So, I just use that to <img src="images/tag_2.gif" width="24" height="13">instantiate |
| our font dialog. SWT uses a <code>FontData</code> to represent the font and this |
| is what we use as the <img src="images/tag_3.gif" width="24" height="13">property's |
| value. After setting the font, I need to present its value as a human readable |
| string in the properties view. A <code>FontDataLabelProvider</code> is used for |
| this purpose. Using a few simple classes, I have created a custom property |
| descriptor. |
| <h2>Implementing complex property descriptors</h2> |
| <p>From time to time, we encounter properties that are quite complex, i.e. their |
| values are not simple objects such as strings or integers. As an example, |
| consider the size property of a <code>Button</code>. It expects and returns a <code>Point</code> |
| object. But if you look closer, a point object is really comprised of two simple |
| integer values. Thus we can describe the size using a <code>SizePropertySource</code> |
| which has "width" and "height" properties.</p> |
| <pre><font color="#4444cc"> /** |
| * @see org.eclipse.ui.views.properties.IPropertySource#getPropertyValue(Object) |
| */ |
| public Object getPropertyValue(Object name) { |
| ... |
| if (name.equals(PROPERTY_SIZE)) { |
| // By returning a property source for the value, this property |
| // will have "child properties" in the view. |
| // These child properties are determined by the property source |
| // we return here |
| sizePropertySource.setPoint(button.getSize()); |
| <img src="images/tag_1.gif" width="24" height="13">return sizePropertySource; |
| } |
| ... |
| } |
| |
| /** |
| * @see org.eclipse.ui.views.properties.IPropertySource#setPropertyValue(Object, Object) |
| */ |
| public void setPropertyValue(Object name, Object value) { |
| ... |
| if (name.equals(PROPERTY_SIZE)) { |
| // We returned a SizePropertySource as the value for PROPERTY_SIZE |
| // The SizePropertySource's editValue will be set as the value |
| // for PROPERTY_SIZE here |
| <img src="images/tag_2.gif" width="24" height="13">button.setSize((Point)value); |
| } |
| ... |
| }</font> |
| </pre> |
| <p>The Eclipse workbench supports the notion of nested properties (good job in |
| thinking ahead!). When <code>getProperty</code> is called on the <code>ButtonElementPropertySource</code>, |
| we return an <img src="images/tag_1.gif" width="24" height="13"><code>IPropertySource</code> |
| object instead of a value. In this case, I created the <code>SizePropertySource</code> |
| class for describing the size property. <code>SizePropertySource</code> is |
| similar to <code>ButtonElementPropertySource</code>, so I would not elaborate on |
| it further. Note that when an <code>IPropertySource</code> is used as a |
| property value, its <code>getEditValue</code> is used by the properties view to <img src="images/tag_2.gif" width="24" height="13">set |
| the property value.</p> |
| <h2>Controlling the button</h2> |
| <p>In order to update the button once a property has been changed, I make a call |
| to the button within the <code>setPropertyValue</code> function of the <code>ButtonElementPropertySource</code> |
| class. Since I hold the <code>ButtonElement</code> handle within the <code>ButtonElementPropertySource</code> |
| object, I can set the properties of the element's button control directly.</p> |
| <h2>Default Properties</h2> |
| <p>The IPropertySource interface also provides a means of implementing default |
| values for properties. This is accomplished via two methods on the |
| IPropertySource interface: <code>isPropertySet</code> and <code>resetPropertyValue</code>. |
| In the diagram shown below, there is a default button that the user can press. |
| If the function <resetPropertyValue> is implemented, it will cause the the |
| property value to reset to its default.</p> |
| <p><img src="images/default.jpg" width="165" height="60"></p> |
| <p>Whenever the Default button is clicked, the isPropertySet will be called for |
| the property that is being selected. If isPropertySet returns true, then it will |
| call resetPropertyValue to reset the property to a specified default value. In |
| the sample code that is enclosed, I only show how to reset the text property, |
| but you can apply the same concept to the other properties.</p> |
| <p>I store the default Name for the button text in a member variable of the <code>ButtonElementPropertySource</code> |
| class. The default Name is <font color="#4444cc"><img src="images/tag_1.gif" width="24" height="13"></font>set |
| during construction time. In the <code>isPropertySet</code> call, <font color="#4444cc"><img src="images/tag_2.gif" width="24" height="13"></font>a |
| check is made between the current text property and the default text property. |
| If they are different, then the <code>resetPropertyValue</code> method will be |
| invoked, and in there, I made the call to <code><font color="#4444cc"><img src="images/tag_3.gif" width="24" height="13"></font>setPropertyValue</code> |
| method with the default text value.</p> |
| <pre><font color="#4444cc">/** |
| * Creates a new ButtonElementPropertySource. |
| * |
| * @param element the element whose properties this instance represents |
| * @param defaultText the default text of the button |
| */ |
| public ButtonElementPropertySource(ButtonElement element, String defaultText) { |
| btnEl = element; |
| button = element.getControl(); |
| <img src="images/tag_1.gif" width="24" height="13">defText = defaultText; |
| } |
| |
| ... |
| |
| /** |
| * @see org.eclipse.ui.views.properties.IPropertySource#isPropertySet(Object) |
| */ |
| |
| public boolean isPropertySet(Object id) { |
| if (id.equals(PROPERTY_TEXT)) { |
| <img src="images/tag_2.gif" width="24" height="13"> String curName = (String)getPropertyValue(id); |
| return !curName.equals(defText); |
| } |
| // other properties are not supported currently |
| return false; |
| } |
| |
| /** |
| * @see org.eclipse.ui.views.properties.IPropertySource#resetPropertyValue(Object) |
| */ |
| |
| public void resetPropertyValue(Object id) { |
| // tracks the text property only |
| if (id.equals(PROPERTY_TEXT)) { |
| <img src="images/tag_3.gif" width="24" height="13">setPropertyValue(id,defText); |
| } |
| }</font></pre> |
| <h2>Summary</h2> |
| <p>I have discussed how to register a workbench selection provider so that a |
| selection will be passed to the properties view. I demonstrated creating a |
| property source and its property descriptors. I showed how a descriptor supports |
| the display and editing of a property.</p> |
| <p>There are several other advanced properties view topics that have not been |
| discussed. For example, the properties view supports having more than one item |
| selected and showing only those properties which are common to all the selected |
| items. The workbench also provides a mechanism for workbench parts to provide |
| their own custom "page" for the properties view (by asking the part |
| for an <code>IPropertySheetPage</code> via <code>getAdapter</code>). Such a |
| custom page can be an instance of <code>PropertySheetPage</code> configured with |
| an <code>IPropertySourceProvider</code> or a custom root <code>IPropertySheetEntry</code> |
| or the custom page can be an independent implementation of <code>IPropertySheetPage</code>. |
| This mechanism allows the properties view to work with non-<code>IPropertySource</code> |
| items. </p> |
| <p>Now that you have discovered some of the magic of the properties view, I hope |
| that you can make good use of it.</p> |
| </body> |
| |
| </html> |