summaryrefslogtreecommitdiff
path: root/propertysheet/src/org/eclipse/wb/internal/core/model/property
diff options
context:
space:
mode:
authorTor Norbye <tnorbye@google.com>2012-03-22 08:43:06 -0700
committerTor Norbye <tnorbye@google.com>2012-03-22 08:43:06 -0700
commit562c581f49027009d6e99ba7b0162c53a051b1c4 (patch)
tree98a407a56524827aaee16c2fd90208c07db79edf /propertysheet/src/org/eclipse/wb/internal/core/model/property
parent062f011b9ecb3e13ecdd5f72a1156046e6764a32 (diff)
downloadeclipse-windowbuilder-562c581f49027009d6e99ba7b0162c53a051b1c4.tar.gz
Add WindowBuilder propertysheet code. See README.txt for details.
Change-Id: I1274fe2c46805731d89ad75dd10419974a399a06
Diffstat (limited to 'propertysheet/src/org/eclipse/wb/internal/core/model/property')
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/ComplexProperty.java209
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/EmptyProperty.java59
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/Property.java232
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/PropertyManager.java36
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/category/PropertyCategory.java159
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/category/PropertyCategoryProvider.java26
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/category/PropertyCategoryProviders.java85
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/AbstractComboBoxPropertyEditor.java156
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/AbstractComboPropertyEditor.java153
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/AbstractListPropertyEditor.java173
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/AbstractTextPropertyEditor.java306
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/BooleanObjectPropertyEditor.java118
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/BooleanPropertyEditor.java112
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/CharacterPropertyEditor.java80
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/DoubleObjectPropertyEditor.java92
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/DoublePropertyEditor.java84
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/EnumerationValuesPropertyEditor.java129
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/FloatPropertyEditor.java83
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/ITextValuePropertyEditor.java26
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/IValueSourcePropertyEditor.java25
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/IntegerObjectPropertyEditor.java92
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/IntegerPropertyEditor.java84
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/LocalePropertyEditor.java69
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/LongObjectPropertyEditor.java92
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/LongPropertyEditor.java83
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/PropertyDescriptorEditorProvider.java73
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/PropertyEditor.java117
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/PropertyEditorProvider.java44
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/ShortObjectPropertyEditor.java92
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/ShortPropertyEditor.java83
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/StringArrayPropertyEditor.java80
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/StringComboPropertyEditor.java65
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/StringListPropertyEditor.java95
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/TextControlActionsManager.java46
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/TextDialogPropertyEditor.java64
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/TextDisplayPropertyEditor.java66
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/complex/IComplexPropertyEditor.java27
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/presentation/ButtonPropertyEditorPresentation.java114
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/presentation/ButtonPropertyEditorPresentationImpl.java224
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/presentation/ButtonPropertyEditorPresentationImplMac.java57
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/presentation/CompoundPropertyEditorPresentation.java70
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/presentation/PropertyEditorPresentation.java41
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/string/StringPropertyDialog.java141
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/string/StringPropertyEditor.java99
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/table/HtmlTooltipHelper.java332
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/table/IPropertyExceptionHandler.java25
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/table/IPropertyTooltipSite.java30
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/table/PropertyTable.java1602
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/table/PropertyTableTooltipHelper.java191
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/table/PropertyTooltipProvider.java117
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/table/PropertyTooltipTextProvider.java67
-rw-r--r--propertysheet/src/org/eclipse/wb/internal/core/model/property/table/Tooltip.css35
52 files changed, 6760 insertions, 0 deletions
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/ComplexProperty.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/ComplexProperty.java
new file mode 100644
index 0000000..69bb455
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/ComplexProperty.java
@@ -0,0 +1,209 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property;
+
+import org.eclipse.wb.internal.core.model.property.editor.TextDisplayPropertyEditor;
+import org.eclipse.wb.internal.core.model.property.editor.complex.IComplexPropertyEditor;
+import org.eclipse.wb.internal.core.model.property.editor.presentation.PropertyEditorPresentation;
+import org.eclipse.wb.internal.core.model.property.table.PropertyTable;
+import org.eclipse.wb.internal.core.model.property.table.PropertyTooltipProvider;
+import org.eclipse.wb.internal.core.model.property.table.PropertyTooltipTextProvider;
+
+import org.eclipse.swt.graphics.Point;
+
+import java.util.List;
+
+/**
+ * Implementation of {@link Property} that shows given inner {@link Property}'s using
+ * {@link IComplexPropertyEditor}.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property
+ */
+public class ComplexProperty extends Property {
+ private final String m_title;
+ private String m_text;
+ private String m_tooltip;
+ private boolean m_modified;
+ private Property[] m_properties;
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Constructors
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public ComplexProperty(String title, String text) {
+ this(title, text, new Property[0]);
+ }
+
+ public ComplexProperty(String title, String text, Property[] properties) {
+ super(new ComplexPropertyEditor());
+ m_title = title;
+ m_text = text;
+ setText(text);
+ setProperties(properties);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Access
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * Sets the text.
+ */
+ public void setText(String text) {
+ m_text = text;
+ }
+
+ /**
+ * @return the text to display as value.
+ */
+ public String getText() throws Exception {
+ return m_text;
+ }
+
+ /**
+ * Sets the tooltip text.
+ */
+ public void setTooltip(String tooltip) {
+ m_tooltip = tooltip;
+ }
+
+ /**
+ * Specifies the {@link PropertyEditorPresentation}, for example to displaying "..." button.
+ */
+ public void setEditorPresentation(PropertyEditorPresentation presentation) {
+ ((ComplexPropertyEditor) getEditor()).m_presentation = presentation;
+ }
+
+ /**
+ * @return the sub-properties.
+ */
+ public Property[] getProperties() {
+ return m_properties;
+ }
+
+ /**
+ * Sets the sub-properties.
+ */
+ public void setProperties(Property[] properties) {
+ m_properties = properties;
+ }
+
+ /**
+ * Sets the sub-properties.
+ */
+ public void setProperties(List<Property> properties) {
+ Property[] propertiesArray = properties.toArray(new Property[properties.size()]);
+ setProperties(propertiesArray);
+ }
+
+ /**
+ * Sets the "modified" flag.
+ */
+ public void setModified(boolean modified) {
+ m_modified = modified;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Property
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public String getTitle() {
+ return m_title;
+ }
+
+ @Override
+ public boolean isModified() throws Exception {
+ return m_modified;
+ }
+
+ @Override
+ public Object getValue() throws Exception {
+ return null;
+ }
+
+ @Override
+ public void setValue(Object value) throws Exception {
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Adapter
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public <T> T getAdapter(Class<T> adapter) {
+ if (adapter == PropertyTooltipProvider.class && m_tooltip != null) {
+ return adapter.cast(new PropertyTooltipTextProvider() {
+ @Override
+ protected String getText(Property property) throws Exception {
+ return m_tooltip;
+ }
+ });
+ }
+ return super.getAdapter(adapter);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // ComplexPropertyEditor
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private static final class ComplexPropertyEditor extends TextDisplayPropertyEditor
+ implements
+ IComplexPropertyEditor {
+ private PropertyEditorPresentation m_presentation;
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // IComplexPropertyEditor
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public Property[] getProperties(Property property) throws Exception {
+ return ((ComplexProperty) property).getProperties();
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // TextDisplayPropertyEditor
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ protected String getText(Property property) throws Exception {
+ return ((ComplexProperty) property).getText();
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // PropertyEditor
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public boolean activate(PropertyTable propertyTable, Property property, Point location)
+ throws Exception {
+ return false;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Presentation
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public PropertyEditorPresentation getPresentation() {
+ return m_presentation;
+ }
+ }
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/EmptyProperty.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/EmptyProperty.java
new file mode 100644
index 0000000..0f12a5a
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/EmptyProperty.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property;
+
+import org.eclipse.wb.internal.core.model.property.editor.PropertyEditor;
+import org.eclipse.wb.internal.core.model.property.editor.string.StringPropertyEditor;
+
+/**
+ * Empty {@link Property}, that has no title or value.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property
+ */
+public class EmptyProperty extends Property {
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Constructor
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public EmptyProperty() {
+ super(StringPropertyEditor.INSTANCE);
+ }
+
+ public EmptyProperty(PropertyEditor editor) {
+ super(editor);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Property
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public String getTitle() {
+ return null;
+ }
+
+ @Override
+ public boolean isModified() throws Exception {
+ return false;
+ }
+
+ @Override
+ public Object getValue() throws Exception {
+ return UNKNOWN_VALUE;
+ }
+
+ @Override
+ public void setValue(Object value) throws Exception {
+ }
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/Property.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/Property.java
new file mode 100644
index 0000000..28afcd3
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/Property.java
@@ -0,0 +1,232 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property;
+
+import com.google.common.collect.Maps;
+
+import org.eclipse.wb.internal.core.model.property.category.PropertyCategory;
+import org.eclipse.wb.internal.core.model.property.editor.PropertyEditor;
+
+import java.util.Comparator;
+import java.util.Map;
+
+/**
+ * {@link Property} is used to display/change properties of ObjectInfo's.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property
+ */
+public abstract class Property {
+ /**
+ * The value that should be used when we don't know real value of {@link Property}. We can not use
+ * <code>null</code> because <code>null</code> can be valid value.
+ */
+ public static final Object UNKNOWN_VALUE = new Object() {
+ @Override
+ public String toString() {
+ return "UNKNOWN_VALUE";
+ }
+ };
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Instance fields
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ protected final PropertyEditor m_editor;
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Constructor
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public Property(PropertyEditor editor) {
+ m_category = PropertyCategory.NORMAL;
+ m_editor = editor;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Presentation
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * @return the title displayed to the user to identify the property.
+ */
+ public abstract String getTitle();
+
+ /**
+ * @return <code>true</code> if this property has a non-default value
+ */
+ public abstract boolean isModified() throws Exception;
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Category
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private PropertyCategory m_category;
+
+ /**
+ * @return current {@link PropertyCategory}.
+ */
+ public final PropertyCategory getCategory() {
+ return m_category;
+ }
+
+ /**
+ * Sets the {@link PropertyCategory} for this {@link Property}.
+ */
+ public final void setCategory(PropertyCategory category) {
+ m_category = category;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Value
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * @return the current value of this {@link Property} or {@link #UNKNOWN_VALUE}.
+ */
+ public abstract Object getValue() throws Exception;
+
+ /**
+ * Sets the new value of this {@link Property}.
+ *
+ * @param the
+ * new value of {@link Property} or {@link #UNKNOWN_VALUE} if {@link Property}
+ * modification should be removed.
+ */
+ public abstract void setValue(Object value) throws Exception;
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Editor
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * @return the {@link PropertyEditor}.
+ */
+ public final PropertyEditor getEditor() {
+ return m_editor;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Composite
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * @return the composite {@link Property} for given array of {@link Property}'s or
+ * <code>null</code> if no composite {@link Property} can be created.
+ */
+ public Property getComposite(Property[] properties) {
+ return null;
+ }
+
+ public <T> T getAdapter(Class<T> adapter) {
+ return null;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Arbitrary values map
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private Map<Object, Object> m_arbitraryMap;
+
+ /**
+ * Associates the given value with the given key.
+ */
+ public final void putArbitraryValue(Object key, Object value) {
+ if (m_arbitraryMap == null) {
+ m_arbitraryMap = Maps.newHashMap();
+ }
+ m_arbitraryMap.put(key, value);
+ }
+
+ /**
+ * @return the value to which the given key is mapped, or <code>null</code>.
+ */
+ public final Object getArbitraryValue(Object key) {
+ if (m_arbitraryMap != null) {
+ return m_arbitraryMap.get(key);
+ }
+ return null;
+ }
+
+ /**
+ * Removes the mapping for a key.
+ */
+ public final void removeArbitraryValue(Object key) {
+ if (m_arbitraryMap != null) {
+ m_arbitraryMap.remove(key);
+ }
+ }
+
+ // BEGIN ADT MODIFICATIONS
+
+ /**
+ * Returns the name of the property (which is not always the same as the
+ * title; for example, the "maxWidth" property has title "Max Width" and
+ * name "maxWidth".
+ * <p>
+ * This is shown in tooltips to users etc to make it clear what they should
+ * use in their own code.
+ *
+ * @return the name of the property
+ */
+ public String getName() {
+ return getTitle();
+ }
+
+ private int mPriority;
+
+ /**
+ * Gets the custom sort priority of this property
+ *
+ * @return the sort priority
+ */
+ public int getPriority() {
+ return mPriority;
+ }
+
+ /**
+ * Sets the custom sort priority of this property
+ *
+ * @param priority the new priority to use
+ */
+ public void setPriority(int priority) {
+ this.mPriority = priority;
+ }
+
+ /** Sort {@link Property} instances alphabetically by property name */
+ public static final Comparator<Property> ALPHABETICAL = new Comparator<Property>() {
+ @Override
+ public int compare(Property p1, Property p2) {
+ return p1.getName().compareTo(p2.getName());
+ }
+ };
+
+ /** Sort {@link Property} instances by priority */
+ public static final Comparator<Property> PRIORITY = new Comparator<Property>() {
+ @Override
+ public int compare(Property p1, Property p2) {
+ int delta = p1.mPriority - p2.mPriority;
+ if (delta != 0) {
+ return delta;
+ }
+
+ return p1.getName().compareTo(p2.getName());
+ }
+ };
+ // END ADT MODIFICATIONS
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/PropertyManager.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/PropertyManager.java
new file mode 100644
index 0000000..7152999
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/PropertyManager.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property;
+
+import org.eclipse.wb.internal.core.model.property.category.PropertyCategory;
+
+
+/**
+ * {@link PropertyManager} is used to get/set attributes of {@link Property}.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property
+ */
+public final class PropertyManager {
+ public static PropertyCategory getCategory(Property property) {
+ // Note: In WindowBuilder there was a bunch of support for loading custom
+ // categories here based on toolkits; in ADT we'll need to do it differently
+ // so this code was all stripped out.
+ return property.getCategory();
+ }
+
+ /**
+ * @return the forced {@link PropertyCategory} of given Property, may be <code>null</code>.
+ */
+ public static PropertyCategory getCategoryForced(Property property) {
+ return null;
+ }
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/category/PropertyCategory.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/category/PropertyCategory.java
new file mode 100644
index 0000000..a135b03
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/category/PropertyCategory.java
@@ -0,0 +1,159 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.category;
+
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.utils.check.Assert;
+
+/**
+ * Describes category of {@link Property}.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property
+ */
+public final class PropertyCategory {
+ /**
+ * "Normal" category, used for properties that should be displayed without any effect.
+ */
+ public static final PropertyCategory NORMAL = new PropertyCategory(0, "NORMAL");
+ /**
+ * "Preferred" category, for properties that are most useful for component.
+ */
+ public static final PropertyCategory PREFERRED = new PropertyCategory(-1, "PREFERRED");
+ /**
+ * "Advanced" category, for properties that are rarely used, visible if modified, even if not
+ * enabled.
+ */
+ public static final PropertyCategory ADVANCED = new PropertyCategory(1, "ADVANCED");
+ /**
+ * "Advanced" category, for properties that are rarely used, visible only if enabled.
+ */
+ public static final PropertyCategory ADVANCED_REALLY = new PropertyCategory(2, "ADVANCED_REALLY");
+ /**
+ * "Hidden" category, for properties that should not be displayed.
+ */
+ public static final PropertyCategory HIDDEN = new PropertyCategory(3, "HIDDEN");
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // System
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * @return the system {@link PropertyCategory} with given priority.
+ */
+ public static final PropertyCategory system(int priority) {
+ return new PropertyCategory(SYSTEM_BASE + priority, "SYSTEM:" + priority);
+ }
+
+ /**
+ * @return the system {@link PropertyCategory} with priority
+ * <code>system.getPriority() + additional</code>.
+ */
+ public static final PropertyCategory system(PropertyCategory system, int additional) {
+ Assert.isTrue(system.isSystem());
+ return system(system.getPriority() - SYSTEM_BASE + additional);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Instance fields
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private static final int SYSTEM_BASE = 1000;
+ private final int m_priority;
+ private final String m_string;
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Constructor
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private PropertyCategory(int priority, String string) {
+ m_priority = priority;
+ m_string = string;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Object
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public String toString() {
+ return m_string;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof PropertyCategory) {
+ PropertyCategory category = (PropertyCategory) obj;
+ return m_priority == category.m_priority;
+ }
+ // unknown class
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return m_priority;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Access
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * @return <code>true</code> if this property is preferred.
+ */
+ public boolean isPreferred() {
+ return this == PREFERRED;
+ }
+
+ /**
+ * @return <code>true</code> if this property is advanced.
+ */
+ public boolean isAdvanced() {
+ return this == ADVANCED;
+ }
+
+ /**
+ * @return <code>true</code> if this property is really advanced.
+ */
+ public boolean isAdvancedReally() {
+ return this == ADVANCED_REALLY;
+ }
+
+ /**
+ * @return <code>true</code> if this property is hidden.
+ */
+ public boolean isHidden() {
+ return this == HIDDEN;
+ }
+
+ /**
+ * @return <code>true</code> if this property is system.
+ */
+ public boolean isSystem() {
+ return m_priority >= 900;
+ }
+
+ /**
+ * @return the priority of this category.
+ */
+ public int getPriority() {
+ return m_priority;
+ }
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/category/PropertyCategoryProvider.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/category/PropertyCategoryProvider.java
new file mode 100644
index 0000000..b435576
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/category/PropertyCategoryProvider.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.category;
+
+import org.eclipse.wb.internal.core.model.property.Property;
+
+/**
+ * This interface is used to get {@link PropertyCategory} for {@link Property}.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property
+ */
+public interface PropertyCategoryProvider {
+ /**
+ * @return the {@link PropertyCategory} of given Property, not <code>null</code>.
+ */
+ PropertyCategory getCategory(Property property);
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/category/PropertyCategoryProviders.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/category/PropertyCategoryProviders.java
new file mode 100644
index 0000000..83aaebb
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/category/PropertyCategoryProviders.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.category;
+
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.model.property.PropertyManager;
+
+/**
+ * Factory for {@link PropertyCategoryProvider} instances.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property
+ */
+public final class PropertyCategoryProviders {
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Simple providers
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private static final PropertyCategoryProvider FROM_PROPERTY = new PropertyCategoryProvider() {
+ public PropertyCategory getCategory(Property property) {
+ return property.getCategory();
+ }
+ };
+
+ /**
+ * Returns result of {@link Property#getCategory()}, never <code>null</code>.
+ */
+ public static PropertyCategoryProvider fromProperty() {
+ return FROM_PROPERTY;
+ }
+
+ private static final PropertyCategoryProvider FORCED_BY_USER = new PropertyCategoryProvider() {
+ public PropertyCategory getCategory(Property property) {
+ return PropertyManager.getCategoryForced(property);
+ }
+ };
+
+ /**
+ * Returns category forced by user, may be <code>null</code>.
+ */
+ public static PropertyCategoryProvider forcedByUser() {
+ return FORCED_BY_USER;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Compound
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * Returns first not <code>null</code> category returned by provider.
+ */
+ public static PropertyCategoryProvider combine(final PropertyCategoryProvider... providers) {
+ return new PropertyCategoryProvider() {
+ public PropertyCategory getCategory(Property property) {
+ for (PropertyCategoryProvider provider : providers) {
+ PropertyCategory category = provider.getCategory(property);
+ if (category != null) {
+ return category;
+ }
+ }
+ throw new IllegalStateException("Can not provide category for " + property.getTitle());
+ }
+ };
+ }
+
+ private static final PropertyCategoryProvider DEF = combine(forcedByUser(), fromProperty());
+
+ /**
+ * Returns the default combination of {@link PropertyCategoryProvider}s - first
+ * {@link #forcedByUser()}, then {@link #fromProperty()}.
+ */
+ public static PropertyCategoryProvider def() {
+ return DEF;
+ }
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/AbstractComboBoxPropertyEditor.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/AbstractComboBoxPropertyEditor.java
new file mode 100644
index 0000000..f122381
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/AbstractComboBoxPropertyEditor.java
@@ -0,0 +1,156 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor;
+
+import org.eclipse.wb.core.controls.CCombo3;
+import org.eclipse.wb.core.controls.CComboBox;
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.model.property.table.PropertyTable;
+import org.eclipse.wb.internal.core.utils.execution.ExecutionUtils;
+import org.eclipse.wb.internal.core.utils.execution.RunnableEx;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusAdapter;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+
+/**
+ * The {@link PropertyEditor} for selecting single value using {@link CComboBox}. This editor has
+ * in-line search-feature and is more suitable (vs {@link AbstractComboPropertyEditor}) for
+ * properties with large lists of value items.
+ *
+ * @author sablin_aa
+ * @author scheglov_ke
+ * @coverage core.model.property.editor
+ */
+public abstract class AbstractComboBoxPropertyEditor extends TextDisplayPropertyEditor {
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Editing
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private CComboBox m_combo;
+ private String m_dropDelayedText;
+
+ @Override
+ public final boolean activate(final PropertyTable propertyTable,
+ final Property property,
+ Point location) throws Exception {
+ m_combo = new CComboBox(propertyTable, SWT.NONE);
+ // initialize
+ addItems(property, m_combo);
+ selectItem(property, m_combo);
+ // install listeners
+ m_combo.addKeyListener(new KeyAdapter() {
+ @Override
+ public void keyPressed(KeyEvent e) {
+ handleKeyPressed(propertyTable, property, e);
+ }
+ });
+ m_combo.addFocusListener(new FocusAdapter() {
+ @Override
+ public void focusLost(FocusEvent e) {
+ propertyTable.deactivateEditor(true);
+ }
+ });
+ m_combo.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ propertyTable.deactivateEditor(true);
+ }
+ });
+ m_combo.setFocus();
+ // schedule showing drop-down, because we don't have bounds yet
+ ExecutionUtils.runAsync(new RunnableEx() {
+ public void run() throws Exception {
+ m_combo.comboDropDown(true);
+ if (m_dropDelayedText != null) {
+ m_combo.setEditText(m_dropDelayedText);
+ m_combo.setEditSelection(m_dropDelayedText.length(), m_dropDelayedText.length());
+ m_dropDelayedText = null;
+ }
+ }
+ });
+ // keep editor active
+ return true;
+ }
+
+ private void handleKeyPressed(PropertyTable propertyTable, Property property, KeyEvent e) {
+ if (e.keyCode == SWT.ESC) {
+ propertyTable.deactivateEditor(false);
+ } else if (e.keyCode == SWT.ARROW_UP || e.keyCode == SWT.ARROW_DOWN) {
+ e.doit = false;
+ propertyTable.deactivateEditor(true);
+ propertyTable.navigate(e);
+ }
+ }
+
+ @Override
+ public final void deactivate(PropertyTable propertyTable, Property property, boolean save) {
+ if (save) {
+ toProperty(propertyTable, property);
+ }
+ if (m_combo != null) {
+ m_combo.dispose();
+ m_combo = null;
+ }
+ }
+
+ private void toProperty(PropertyTable propertyTable, Property property) {
+ try {
+ toPropertyEx(property, m_combo);
+ } catch (Throwable e) {
+ propertyTable.handleException(e);
+ }
+ }
+
+ @Override
+ public void setBounds(Rectangle bounds) {
+ m_combo.setBounds(bounds);
+ }
+
+ @Override
+ public void keyDown(PropertyTable propertyTable, Property property, KeyEvent event)
+ throws Exception {
+ boolean withAlt = (event.stateMask & SWT.ALT) != 0;
+ boolean withCtrl = (event.stateMask & SWT.CTRL) != 0;
+ if (event.character > 0x20 && !(withAlt || withCtrl)) {
+ propertyTable.activateEditor(property, null);
+ m_dropDelayedText = "" + event.character;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Abstract methods
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * Adds items to given {@link CComboBox}.
+ */
+ protected abstract void addItems(Property property, CComboBox combo) throws Exception;
+
+ /**
+ * Selects current item in given {@link CCombo3}.
+ */
+ protected void selectItem(Property property, CComboBox combo) throws Exception {
+ }
+
+ /**
+ * Transfers data from widget to {@link Property}.
+ */
+ protected abstract void toPropertyEx(Property property, CComboBox combo) throws Exception;
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/AbstractComboPropertyEditor.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/AbstractComboPropertyEditor.java
new file mode 100644
index 0000000..a225f45
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/AbstractComboPropertyEditor.java
@@ -0,0 +1,153 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor;
+
+import org.eclipse.wb.core.controls.CCombo3;
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.model.property.table.PropertyTable;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusAdapter;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+
+/**
+ * The {@link PropertyEditor} for selecting single value using {@link CCombo3}.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.editor
+ */
+public abstract class AbstractComboPropertyEditor extends TextDisplayPropertyEditor {
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Editing
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private CCombo3 m_combo;
+ private boolean m_doDropDown;
+
+ @Override
+ public boolean activate(final PropertyTable propertyTable, final Property property, Point location)
+ throws Exception {
+ // create combo
+ {
+ m_combo = new CCombo3(propertyTable, SWT.NONE);
+ m_doDropDown = true;
+ // add items
+ addItems(property, m_combo);
+ // select item
+ selectItem(property, m_combo);
+ }
+ // add listeners
+ m_combo.addFocusListener(new FocusAdapter() {
+ @Override
+ public void focusLost(FocusEvent e) {
+ propertyTable.deactivateEditor(true);
+ }
+ });
+ m_combo.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ int index = m_combo.getSelectionIndex();
+ toProperty(propertyTable, property, index);
+ }
+ });
+ m_combo.addListener(SWT.KeyDown, new Listener() {
+ public void handleEvent(Event event) {
+ switch (event.keyCode) {
+ case SWT.ESC :
+ propertyTable.deactivateEditor(false);
+ break;
+ case SWT.DEL :
+ try {
+ property.setValue(Property.UNKNOWN_VALUE);
+ event.doit = false;
+ selectItem(property, m_combo);
+ } catch (Throwable e) {
+ propertyTable.handleException(e);
+ propertyTable.deactivateEditor(false);
+ }
+ m_combo.doDropDown(false);
+ break;
+ }
+ }
+ });
+ m_combo.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseDoubleClick(MouseEvent e) {
+ int index = (m_combo.getSelectionIndex() + 1) % m_combo.getItemCount();
+ toProperty(propertyTable, property, index);
+ }
+ });
+ // keep editor active
+ return true;
+ }
+
+ @Override
+ public final void setBounds(Rectangle bounds) {
+ m_combo.setBounds(bounds);
+ // editor created without bounds, so activate it after first setBounds()
+ if (m_doDropDown) {
+ m_doDropDown = false;
+ m_combo.setFocus();
+ m_combo.doDropDown(true);
+ m_combo.startDrag();
+ }
+ }
+
+ @Override
+ public final void deactivate(PropertyTable propertyTable, Property property, boolean save) {
+ if (m_combo != null) {
+ m_combo.dispose();
+ m_combo = null;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Abstract methods
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * Adds items to given {@link CCombo3}.
+ */
+ protected abstract void addItems(Property property, CCombo3 combo) throws Exception;
+
+ /**
+ * Selects current item in given {@link CCombo3}.
+ */
+ protected abstract void selectItem(Property property, CCombo3 combo) throws Exception;
+
+ /**
+ * Transfers data from widget to {@link Property}.
+ */
+ protected abstract void toPropertyEx(Property property, CCombo3 combo, int index)
+ throws Exception;
+
+ /**
+ * Transfers data from widget to {@link Property}.
+ */
+ private void toProperty(PropertyTable propertyTable, Property property, int index) {
+ try {
+ toPropertyEx(property, m_combo, index);
+ } catch (Throwable e) {
+ propertyTable.handleException(e);
+ }
+ propertyTable.deactivateEditor(false);
+ }
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/AbstractListPropertyEditor.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/AbstractListPropertyEditor.java
new file mode 100644
index 0000000..ba34103
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/AbstractListPropertyEditor.java
@@ -0,0 +1,173 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor;
+
+import org.eclipse.wb.core.controls.CCombo3;
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.utils.check.Assert;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * The {@link PropertyEditor} for selecting single expression from given set.
+ *
+ * @author sablin_aa
+ * @coverage core.model.property.editor
+ */
+public abstract class AbstractListPropertyEditor extends AbstractComboPropertyEditor
+ implements
+ IValueSourcePropertyEditor {
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // TextDisplayPropertyEditor
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public String getText(Property property) throws Exception {
+ // return title for value
+ Object value = property.getValue();
+ if (value != Property.UNKNOWN_VALUE) {
+ int index = getValueIndex(value);
+ if (index >= 0) {
+ return getTitle(index);
+ } else {
+ if (value instanceof String) {
+ return (String) value;
+ }
+ }
+ }
+ // unknown value
+ return null;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // IValueSourcePropertyEditor
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+public String getValueSource(Object value) throws Exception {
+ // return expression for value
+ if (value != Property.UNKNOWN_VALUE) {
+ int index = getValueIndex(value);
+ if (index >= 0) {
+ return getExpression(index);
+ }
+ }
+ // unknown value
+ return null;
+ }
+
+// ////////////////////////////////////////////////////////////////////////////
+// //
+// // IClipboardSourceProvider
+// //
+// ////////////////////////////////////////////////////////////////////////////
+// @Override
+//public String getClipboardSource(GenericProperty property) throws Exception {
+// Object value = property.getValue();
+// return getValueSource(value);
+// }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Combo
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ protected void addItems(Property property, CCombo3 combo) throws Exception {
+ for (int i = 0; i < getCount(); i++) {
+ combo.add(getTitle(i));
+ }
+ }
+
+ @Override
+ protected void selectItem(Property property, CCombo3 combo) throws Exception {
+ combo.setText(getText(property));
+ }
+
+ @Override
+ protected void toPropertyEx(Property property, CCombo3 combo, int index) throws Exception {
+// if (property instanceof GenericProperty) {
+// GenericProperty genericProperty = (GenericProperty) property;
+// String expression = getExpression(index);
+// Object evaluatedExpression = evaluateExpression(genericProperty, expression);
+// // apply expression
+// genericProperty.setExpression(expression, evaluatedExpression);
+// } else {
+ toPropertyEx_simpleProperty(property, combo, index);
+// }
+ }
+
+// private static Object evaluateExpression(final GenericProperty genericProperty,
+// final String expression) {
+// return ExecutionUtils.runObjectIgnore(new RunnableObjectEx<Object>() {
+// public Object runObject() throws Exception {
+// JavaInfo javaInfo = genericProperty.getJavaInfo();
+// ClassLoader classLoader = JavaInfoUtils.getClassLoader(javaInfo);
+// return ScriptUtils.evaluate(classLoader, expression);
+// }
+// }, Property.UNKNOWN_VALUE);
+// System.out.println("HACK 1234");
+// return Property.UNKNOWN_VALUE;
+// }
+
+ /**
+ * Sets value of simple {@link Property}, not {@link GenericProperty}.
+ */
+ protected void toPropertyEx_simpleProperty(Property property, CCombo3 combo, int index)
+ throws Exception {
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Access to list items
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ abstract protected int getCount();
+
+ abstract protected int getValueIndex(Object value);
+
+ abstract protected String getTitle(int index);
+
+ abstract protected String getExpression(int index) throws Exception;
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Utils
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * Extract string array from parameters.
+ */
+ protected static String[] getParameterAsArray(Map<String, Object> parameters, String name) {
+ return getParameterAsArray(parameters, name, false);
+ }
+
+ @SuppressWarnings("unchecked")
+ protected static String[] getParameterAsArray(Map<String, Object> parameters,
+ String name,
+ boolean noAssert) {
+ String[] values = null;
+ if (parameters.containsKey(name)) {
+ List<String> list = (List<String>) parameters.get(name);
+ values = list.toArray(new String[list.size()]);
+ } else {
+ if (noAssert) {
+ values = null;
+ } else {
+ Assert.fail(String.format("No parameter %s in %s.", name, parameters));
+ }
+ }
+ return values;
+ }
+} \ No newline at end of file
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/AbstractTextPropertyEditor.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/AbstractTextPropertyEditor.java
new file mode 100644
index 0000000..1cf9574
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/AbstractTextPropertyEditor.java
@@ -0,0 +1,306 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor;
+
+import org.eclipse.jface.bindings.keys.KeyStroke;
+import org.eclipse.jface.fieldassist.ContentProposalAdapter;
+import org.eclipse.jface.fieldassist.IContentProposalProvider;
+import org.eclipse.jface.fieldassist.IControlContentAdapter;
+import org.eclipse.jface.fieldassist.TextContentAdapter;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.model.property.table.PropertyTable;
+
+/**
+ * Abstract {@link PropertyEditor} for that uses {@link Text} as control.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.editor
+ */
+public abstract class AbstractTextPropertyEditor extends TextDisplayPropertyEditor {
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Editing
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private Text m_textControl;
+ private boolean m_ignoreFocusLost;
+
+ // BEGIN ADT MODIFICATIONS
+ // ContentProposalAdapter which exposes the openProposalPopup method such
+ // that we can open the dialog up immediately on focus gain to show all available
+ // alternatives (the default implementation requires at least one keytroke before
+ // it shows up)
+ private static class ImmediateProposalAdapter extends ContentProposalAdapter {
+ public ImmediateProposalAdapter(Text control,
+ IControlContentAdapter controlContentAdapter,
+ IContentProposalProvider proposalProvider, KeyStroke keyStroke,
+ char[] autoActivationCharacters) {
+ super(control, controlContentAdapter, proposalProvider, keyStroke,
+ autoActivationCharacters);
+
+ // On focus gain, start completing
+ control.addFocusListener(new FocusListener() {
+ @Override
+ public void focusGained(FocusEvent event) {
+ openIfNecessary();
+ }
+
+ @Override
+ public void focusLost(FocusEvent event) {
+ }
+ });
+
+ /* Triggering on empty is disabled for now: it has the unfortunate side-effect
+ that it's impossible to enter a blank text field - blank matches everything,
+ so the first item will automatically be selected when you press return.
+
+
+ // If you edit the text and delete everything, the normal implementation
+ // will close the popup; we'll reopen it
+ control.addModifyListener(new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent event) {
+ if (((Text) getControl()).getText().isEmpty()) {
+ openIfNecessary();
+ }
+ }
+ });
+ */
+ }
+
+ private void openIfNecessary() {
+ getControl().getDisplay().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (!isProposalPopupOpen()) {
+ openProposalPopup();
+ }
+ }
+ });
+ }
+ }
+ // END ADT MODIFICATIONS
+
+ @Override
+ public boolean activate(final PropertyTable propertyTable, final Property property, Point location)
+ throws Exception {
+ // create Text
+ {
+ m_textControl = new Text(propertyTable, SWT.NONE);
+ new TextControlActionsManager(m_textControl);
+ m_textControl.setEditable(isEditable());
+
+ // BEGIN ADT MODIFICATIONS
+ // Add support for field completion, if the property provides an IContentProposalProvider
+ // via its the getAdapter method.
+ IContentProposalProvider completion = property.getAdapter(IContentProposalProvider.class);
+ if (completion != null) {
+ ImmediateProposalAdapter adapter = new ImmediateProposalAdapter(
+ m_textControl, new TextContentAdapter(), completion, null, null);
+ adapter.setFilterStyle(ContentProposalAdapter.FILTER_NONE);
+ adapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE);
+ ILabelProvider labelProvider = property.getAdapter(ILabelProvider.class);
+ if (labelProvider != null) {
+ adapter.setLabelProvider(labelProvider);
+ }
+ }
+ // END ADT MODIFICATIONS
+ m_textControl.setFocus();
+ }
+ // add listeners
+ m_textControl.addKeyListener(new KeyAdapter() {
+ @Override
+ public void keyPressed(KeyEvent e) {
+ try {
+ handleKeyPressed(propertyTable, property, e);
+ } catch (Throwable ex) {
+ propertyTable.deactivateEditor(false);
+ propertyTable.handleException(ex);
+ }
+ }
+ });
+ m_textControl.addListener(SWT.FocusOut, new Listener() {
+ @Override
+ public void handleEvent(Event event) {
+ if (!m_ignoreFocusLost) {
+ propertyTable.deactivateEditor(true);
+ }
+ }
+ });
+ // set data
+ toWidget(property);
+ // keep us active
+ return true;
+ }
+
+ @Override
+ public final void setBounds(Rectangle bounds) {
+ m_textControl.setBounds(bounds);
+ }
+
+ @Override
+ public final void deactivate(PropertyTable propertyTable, Property property, boolean save) {
+ if (save) {
+ try {
+ toProperty(property);
+ } catch (Throwable e) {
+ propertyTable.deactivateEditor(false);
+ propertyTable.handleException(e);
+ }
+ }
+ // dispose Text widget
+ if (m_textControl != null) {
+ m_textControl.dispose();
+ m_textControl = null;
+ }
+ }
+
+ @Override
+ public void keyDown(PropertyTable propertyTable, Property property, KeyEvent event)
+ throws Exception {
+ boolean withAlt = (event.stateMask & SWT.ALT) != 0;
+ boolean withCtrl = (event.stateMask & SWT.CTRL) != 0;
+ if (event.character != 0 && !(withAlt || withCtrl)) {
+ propertyTable.activateEditor(property, null);
+ postKeyEvent(SWT.KeyDown, event);
+ postKeyEvent(SWT.KeyUp, event);
+ }
+ }
+
+ /**
+ * Posts low-level {@link SWT.KeyDown} or {@link SWT.KeyUp} event.
+ */
+ private static void postKeyEvent(int type, KeyEvent event) {
+ Event lowEvent = new Event();
+ lowEvent.type = type;
+ lowEvent.keyCode = event.keyCode;
+ lowEvent.character = event.character;
+ // post event
+ Display.getCurrent().post(lowEvent);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Events
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * Handles {@link KeyListener#keyPressed(KeyEvent)}.
+ */
+ private void handleKeyPressed(PropertyTable propertyTable, Property property, KeyEvent e)
+ throws Exception {
+ if (e.keyCode == SWT.CR) {
+ toProperty(property);
+
+ // BEGIN ADT MODIFICATIONS
+ // After pressing return, dismiss the text cursor to make the value "committed".
+ // I'm not sure why this is necessary here and not in WindowBuilder proper.
+ propertyTable.deactivateEditor(true);
+ // END ADT MODIFICATIONS
+ } else if (e.keyCode == SWT.ESC) {
+ propertyTable.deactivateEditor(false);
+ } else if (e.keyCode == SWT.ARROW_UP || e.keyCode == SWT.ARROW_DOWN) {
+ e.doit = false;
+ boolean success = toProperty(property);
+ // don't allow navigation if current text can not be transferred to property
+ if (!success) {
+ return;
+ }
+ // OK, deactivate and navigate
+ propertyTable.deactivateEditor(true);
+ propertyTable.navigate(e);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Implementation
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private String m_currentText;
+
+ /**
+ * Transfers data from {@link Property} to widget.
+ */
+ private void toWidget(Property property) throws Exception {
+ // prepare text
+ String text = getEditorText(property);
+ if (text == null) {
+ text = "";
+ }
+ // set text
+ m_currentText = text;
+ m_textControl.setText(text);
+ m_textControl.selectAll();
+ }
+
+ /**
+ * Transfers data from widget to {@link Property}.
+ *
+ * @return <code>true</code> if transfer was successful.
+ */
+ private boolean toProperty(Property property) throws Exception {
+ String text = m_textControl.getText();
+ // change property only if text was changed
+ if (!m_currentText.equals(text)) {
+ m_ignoreFocusLost = true;
+ try {
+ boolean success = setEditorText(property, text);
+ if (!success) {
+ return false;
+ }
+ } finally {
+ m_ignoreFocusLost = false;
+ }
+ // if value was successfully changed, update current text
+ m_currentText = text;
+ }
+ // OK, success
+ return true;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Operations
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * @return <code>true</code> if this editor can modify text.
+ */
+ protected boolean isEditable() {
+ return true;
+ }
+
+ /**
+ * @return the text to display in {@link Text} control.
+ */
+ protected abstract String getEditorText(Property property) throws Exception;
+
+ /**
+ * Modifies {@link Property} using given text.
+ *
+ * @return <code>true</code> if {@link Property} was successfully modified.
+ */
+ protected abstract boolean setEditorText(Property property, String text) throws Exception;
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/BooleanObjectPropertyEditor.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/BooleanObjectPropertyEditor.java
new file mode 100644
index 0000000..4f80bb9
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/BooleanObjectPropertyEditor.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor;
+
+import org.eclipse.wb.internal.core.DesignerPlugin;
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.model.property.table.PropertyTable;
+import org.eclipse.wb.internal.core.utils.ui.DrawUtils;
+
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+
+/**
+ * The {@link PropertyEditor} for <code>Boolean</code>.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.editor
+ */
+public final class BooleanObjectPropertyEditor extends PropertyEditor {
+ private static final Image m_nullImage = DesignerPlugin.getImage("properties/BooleanNull.png");
+ private static final Image m_trueImage = DesignerPlugin.getImage("properties/true.png");
+ private static final Image m_falseImage = DesignerPlugin.getImage("properties/false.png");
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Instance
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public static final PropertyEditor INSTANCE = new BooleanObjectPropertyEditor();
+
+ private BooleanObjectPropertyEditor() {
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Presentation
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public void paint(Property property, GC gc, int x, int y, int width, int height) throws Exception {
+ Object value = property.getValue();
+ if (value instanceof Boolean) {
+ boolean booleanValue = ((Boolean) value).booleanValue();
+ Image image = booleanValue ? m_trueImage : m_falseImage;
+ String text = Boolean.toString(booleanValue);
+ paint(gc, x, y, width, height, text, image);
+ }
+ if (value == null) {
+ Image image = m_nullImage;
+ String text = "null";
+ paint(gc, x, y, width, height, text, image);
+ }
+ }
+
+ private void paint(GC gc, int x, int y, int width, int height, String text, Image image) {
+ // draw image
+ {
+ DrawUtils.drawImageCV(gc, image, x, y, height);
+ // prepare new position/width
+ int imageWidth = image.getBounds().width + 2;
+ x += imageWidth;
+ width -= imageWidth;
+ }
+ // draw text
+ {
+ DrawUtils.drawStringCV(gc, text, x, y, width, height);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Editing
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public boolean activate(PropertyTable propertyTable, Property property, Point location)
+ throws Exception {
+ // check that user clicked on image
+ if (location == null || location.x < m_trueImage.getBounds().width + 2) {
+ invertValue(property);
+ }
+ // don't activate
+ return false;
+ }
+
+ @Override
+ public void doubleClick(Property property, Point location) throws Exception {
+ invertValue(property);
+ }
+
+ /**
+ * Inverts the value of given boolean {@link Property}.
+ */
+ private void invertValue(Property property) throws Exception {
+ Object value = property.getValue();
+ // null
+ if (value == null) {
+ property.setValue(true);
+ return;
+ }
+ // boolean
+ if (value instanceof Boolean) {
+ boolean booleanValue = ((Boolean) value).booleanValue();
+ property.setValue(!booleanValue);
+ return;
+ }
+ // unknown
+ property.setValue(true);
+ }
+} \ No newline at end of file
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/BooleanPropertyEditor.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/BooleanPropertyEditor.java
new file mode 100644
index 0000000..6639afe
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/BooleanPropertyEditor.java
@@ -0,0 +1,112 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor;
+
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.wb.internal.core.DesignerPlugin;
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.model.property.table.PropertyTable;
+import org.eclipse.wb.internal.core.utils.ui.DrawUtils;
+
+/**
+ * The {@link PropertyEditor} for <code>boolean</code>.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.editor
+ */
+public final class BooleanPropertyEditor extends PropertyEditor {
+ private static final Image m_trueImage = DesignerPlugin.getImage("properties/true.png");
+ private static final Image m_falseImage = DesignerPlugin.getImage("properties/false.png");
+ private static final Image m_unknownImage =
+ DesignerPlugin.getImage("properties/BooleanUnknown.png");
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Instance
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public static final PropertyEditor INSTANCE = new BooleanPropertyEditor();
+
+ private BooleanPropertyEditor() {
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Presentation
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public void paint(Property property, GC gc, int x, int y, int width, int height) throws Exception {
+ Object value = property.getValue();
+ if (value instanceof Boolean) {
+ boolean booleanValue = ((Boolean) value).booleanValue();
+ Image image = booleanValue ? m_trueImage : m_falseImage;
+ String text = Boolean.toString(booleanValue);
+ paint(gc, x, y, width, height, image, text);
+ } else {
+ paint(gc, x, y, width, height, m_unknownImage, "unknown");
+ }
+ }
+
+ /**
+ * Paints {@link Image} and text.
+ */
+ private void paint(GC gc, int x, int y, int width, int height, Image image, String text) {
+ // draw image
+ {
+ DrawUtils.drawImageCV(gc, image, x, y, height);
+ // prepare new position/width
+ int imageWidth = image.getBounds().width + 2;
+ x += imageWidth;
+ width -= imageWidth;
+ }
+ // draw text
+ DrawUtils.drawStringCV(gc, text, x, y, width, height);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Editing
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public boolean activate(PropertyTable propertyTable, Property property, Point location)
+ throws Exception {
+ // check that user clicked on image
+ if (location == null || location.x < m_trueImage.getBounds().width + 2) {
+ invertValue(property);
+ }
+ // don't activate
+ return false;
+ }
+
+ @Override
+ public void doubleClick(Property property, Point location) throws Exception {
+ invertValue(property);
+ }
+
+ /**
+ * Inverts the value of given boolean {@link Property}.
+ */
+ private void invertValue(Property property) throws Exception {
+ // prepare current boolean value
+ boolean booleanValue = false;
+ {
+ Object value = property.getValue();
+ if (value instanceof Boolean) {
+ booleanValue = ((Boolean) value).booleanValue();
+ }
+ }
+ // set inverted value
+ property.setValue(!booleanValue);
+ }
+} \ No newline at end of file
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/CharacterPropertyEditor.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/CharacterPropertyEditor.java
new file mode 100644
index 0000000..7e6cfe8
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/CharacterPropertyEditor.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor;
+
+import org.eclipse.wb.internal.core.DesignerPlugin;
+import org.eclipse.wb.internal.core.model.ModelMessages;
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.utils.ui.UiUtils;
+
+import java.text.MessageFormat;
+
+/**
+ * The {@link PropertyEditor} for {@link String}.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.editor
+ */
+public final class CharacterPropertyEditor extends AbstractTextPropertyEditor {
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Instance
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public static final PropertyEditor INSTANCE = new CharacterPropertyEditor();
+
+ private CharacterPropertyEditor() {
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Presentation
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public String getText(Property property) throws Exception {
+ Object value = property.getValue();
+ if (value instanceof Character) {
+ return String.valueOf(((Character) value).charValue());
+ }
+ return null;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Editing
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ protected String getEditorText(Property property) throws Exception {
+ return getText(property);
+ }
+
+ @Override
+ protected boolean setEditorText(Property property, String text) throws Exception {
+ // check for delete
+ if (text.length() == 0) {
+ property.setValue(Property.UNKNOWN_VALUE);
+ return true;
+ }
+ // only one character
+ if (text.length() > 1) {
+ UiUtils.openWarning(
+ DesignerPlugin.getShell(),
+ property.getTitle(),
+ MessageFormat.format(ModelMessages.CharacterPropertyEditor_notValid, text));
+ return false;
+ }
+ // modify property
+ property.setValue(new Character(text.charAt(0)));
+ return true;
+ }
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/DoubleObjectPropertyEditor.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/DoubleObjectPropertyEditor.java
new file mode 100644
index 0000000..bb7dfc5
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/DoubleObjectPropertyEditor.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor;
+
+import org.eclipse.wb.internal.core.DesignerPlugin;
+import org.eclipse.wb.internal.core.model.ModelMessages;
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.utils.ui.UiUtils;
+
+import java.text.MessageFormat;
+
+/**
+ * The {@link PropertyEditor} for {@link Double}.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.editor
+ */
+public final class DoubleObjectPropertyEditor extends AbstractTextPropertyEditor {
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Instance
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public static final DoubleObjectPropertyEditor INSTANCE = new DoubleObjectPropertyEditor();
+
+ private DoubleObjectPropertyEditor() {
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Presentation
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public String getText(Property property) throws Exception {
+ Object value = property.getValue();
+ if (value == null) {
+ return "null";
+ }
+ if (value instanceof Double) {
+ return value.toString();
+ }
+ return null;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Editing
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ protected String getEditorText(Property property) throws Exception {
+ return getText(property);
+ }
+
+ @Override
+ protected boolean setEditorText(Property property, String text) throws Exception {
+ text = text.trim();
+ // check for delete
+ if (text.length() == 0) {
+ property.setValue(Property.UNKNOWN_VALUE);
+ return true;
+ }
+ // check for "null"
+ if (text.equals("null")) {
+ property.setValue(null);
+ return true;
+ }
+ // prepare value
+ Double value;
+ try {
+ value = Double.valueOf(text);
+ } catch (Throwable e) {
+ UiUtils.openWarning(
+ DesignerPlugin.getShell(),
+ property.getTitle(),
+ MessageFormat.format(ModelMessages.DoubleObjectPropertyEditor_notValidDouble, text));
+ return false;
+ }
+ // modify property
+ property.setValue(value);
+ return true;
+ }
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/DoublePropertyEditor.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/DoublePropertyEditor.java
new file mode 100644
index 0000000..40b73bf
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/DoublePropertyEditor.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor;
+
+import org.eclipse.wb.internal.core.DesignerPlugin;
+import org.eclipse.wb.internal.core.model.ModelMessages;
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.utils.ui.UiUtils;
+
+import java.text.MessageFormat;
+
+/**
+ * The {@link PropertyEditor} for <code>double</code>.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.editor
+ */
+public final class DoublePropertyEditor extends AbstractTextPropertyEditor {
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Instance
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public static final PropertyEditor INSTANCE = new DoublePropertyEditor();
+
+ private DoublePropertyEditor() {
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Presentation
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public String getText(Property property) throws Exception {
+ Object value = property.getValue();
+ if (value instanceof Number) {
+ double doubleValue = ((Number) value).doubleValue();
+ return Double.toString(doubleValue);
+ }
+ return null;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Editing
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ protected String getEditorText(Property property) throws Exception {
+ return getText(property);
+ }
+
+ @Override
+ protected boolean setEditorText(Property property, String text) throws Exception {
+ text = text.trim();
+ // check for delete
+ if (text.length() == 0) {
+ property.setValue(Property.UNKNOWN_VALUE);
+ }
+ // prepare value
+ Double value;
+ try {
+ value = Double.valueOf(text);
+ } catch (Throwable e) {
+ UiUtils.openWarning(
+ DesignerPlugin.getShell(),
+ property.getTitle(),
+ MessageFormat.format(ModelMessages.DoublePropertyEditor_notValidDouble, text));
+ return false;
+ }
+ // modify property
+ property.setValue(value);
+ return true;
+ }
+} \ No newline at end of file
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/EnumerationValuesPropertyEditor.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/EnumerationValuesPropertyEditor.java
new file mode 100644
index 0000000..a715df3
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/EnumerationValuesPropertyEditor.java
@@ -0,0 +1,129 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor;
+
+import com.google.common.base.Objects;
+
+import org.eclipse.wb.core.controls.CCombo3;
+import org.eclipse.wb.internal.core.model.property.Property;
+
+import java.beans.PropertyDescriptor;
+
+/**
+ * {@link PropertyEditor} for "enumerationValues" attribute of {@link PropertyDescriptor}.
+ * <p>
+ * See http://javadude.com/articles/javabeanattributes.html for attributes.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.editor
+ */
+public class EnumerationValuesPropertyEditor extends AbstractComboPropertyEditor
+ implements
+ IValueSourcePropertyEditor {
+ private final String[] m_names;
+ private final Object[] m_values;
+ private final String[] m_sources;
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Constructor
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public EnumerationValuesPropertyEditor(Object attributeValue) {
+ Object[] enumElements = (Object[]) attributeValue;
+ int items = enumElements.length / 3;
+ m_names = new String[items];
+ m_values = new Object[items];
+ m_sources = new String[items];
+ for (int i = 0; i < items; i++) {
+ m_names[i] = (String) enumElements[3 * i + 0];
+ m_values[i] = enumElements[3 * i + 1];
+ m_sources[i] = (String) enumElements[3 * i + 2];
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // TextDisplayPropertyEditor
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public String getText(Property property) throws Exception {
+ Object value = property.getValue();
+ // return name for value
+ if (value != Property.UNKNOWN_VALUE) {
+ for (int i = 0; i < m_values.length; i++) {
+ if (Objects.equal(m_values[i], value)) {
+ return m_names[i];
+ }
+ }
+ }
+ // unknown value
+ return null;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // IValueSourcePropertyEditor
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+public String getValueSource(Object value) throws Exception {
+ if (value != Property.UNKNOWN_VALUE) {
+ for (int i = 0; i < m_values.length; i++) {
+ if (Objects.equal(m_values[i], value)) {
+ return m_sources[i];
+ }
+ }
+ }
+ // unknown value
+ return null;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // IClipboardSourceProvider
+ //
+ ////////////////////////////////////////////////////////////////////////////
+// public String getClipboardSource(GenericProperty property) throws Exception {
+// Object value = property.getValue();
+// return getValueSource(value);
+// }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Combo
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ protected void addItems(Property property, CCombo3 combo) throws Exception {
+ for (String title : m_names) {
+ combo.add(title);
+ }
+ }
+
+ @Override
+ protected void selectItem(Property property, CCombo3 combo) throws Exception {
+ combo.setText(getText(property));
+ }
+
+ @Override
+ protected void toPropertyEx(Property property, CCombo3 combo, int index) throws Exception {
+ Object value = m_values[index];
+// if (property instanceof GenericProperty) {
+// GenericProperty genericProperty = (GenericProperty) property;
+// String source = getValueSource(value);
+// genericProperty.setExpression(source, value);
+// } else {
+ property.setValue(value);
+// }
+ }
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/FloatPropertyEditor.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/FloatPropertyEditor.java
new file mode 100644
index 0000000..d4b468e
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/FloatPropertyEditor.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor;
+
+import org.eclipse.wb.internal.core.DesignerPlugin;
+import org.eclipse.wb.internal.core.model.ModelMessages;
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.utils.ui.UiUtils;
+
+import java.text.MessageFormat;
+
+/**
+ * The {@link PropertyEditor} for <code>float</code>.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.editor
+ */
+public class FloatPropertyEditor extends AbstractTextPropertyEditor {
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Instance
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public static final PropertyEditor INSTANCE = new FloatPropertyEditor();
+
+ protected FloatPropertyEditor() {
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Presentation
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public String getText(Property property) throws Exception {
+ Object value = property.getValue();
+ if (value instanceof Float) {
+ return value.toString();
+ }
+ return null;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Editing
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ protected String getEditorText(Property property) throws Exception {
+ return getText(property);
+ }
+
+ @Override
+ protected boolean setEditorText(Property property, String text) throws Exception {
+ text = text.trim();
+ // check for delete
+ if (text.length() == 0) {
+ property.setValue(Property.UNKNOWN_VALUE);
+ }
+ // prepare value
+ Float value;
+ try {
+ value = Float.valueOf(text);
+ } catch (Throwable e) {
+ UiUtils.openWarning(
+ DesignerPlugin.getShell(),
+ property.getTitle(),
+ MessageFormat.format(ModelMessages.FloatPropertyEditor_notValidFloat, text));
+ return false;
+ }
+ // modify property
+ property.setValue(value);
+ return true;
+ }
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/ITextValuePropertyEditor.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/ITextValuePropertyEditor.java
new file mode 100644
index 0000000..ed38c04
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/ITextValuePropertyEditor.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor;
+
+import org.eclipse.wb.internal.core.model.property.Property;
+
+/**
+ * Extension of {@link PropertyEditor} that can set value using its text presentation.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.editor
+ */
+public interface ITextValuePropertyEditor {
+ /**
+ * Sets value that corresponds given text.
+ */
+ void setText(Property property, String text) throws Exception;
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/IValueSourcePropertyEditor.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/IValueSourcePropertyEditor.java
new file mode 100644
index 0000000..2999bf1
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/IValueSourcePropertyEditor.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor;
+
+/**
+ * Extension for {@link PropertyEditor} that can be used to convert {@link Object} value into Java
+ * source.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.editor
+ */
+public interface IValueSourcePropertyEditor {
+ /**
+ * @return the Java source for given value.
+ */
+ String getValueSource(Object value) throws Exception;
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/IntegerObjectPropertyEditor.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/IntegerObjectPropertyEditor.java
new file mode 100644
index 0000000..f488dff
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/IntegerObjectPropertyEditor.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor;
+
+import org.eclipse.wb.internal.core.DesignerPlugin;
+import org.eclipse.wb.internal.core.model.ModelMessages;
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.utils.ui.UiUtils;
+
+import java.text.MessageFormat;
+
+/**
+ * The {@link PropertyEditor} for {@link Integer}.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.editor
+ */
+public final class IntegerObjectPropertyEditor extends AbstractTextPropertyEditor {
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Instance
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public static final IntegerObjectPropertyEditor INSTANCE = new IntegerObjectPropertyEditor();
+
+ private IntegerObjectPropertyEditor() {
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Presentation
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public String getText(Property property) throws Exception {
+ Object value = property.getValue();
+ if (value == null) {
+ return "null";
+ }
+ if (value instanceof Integer) {
+ return value.toString();
+ }
+ return null;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Editing
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ protected String getEditorText(Property property) throws Exception {
+ return getText(property);
+ }
+
+ @Override
+ protected boolean setEditorText(Property property, String text) throws Exception {
+ text = text.trim();
+ // check for delete
+ if (text.length() == 0) {
+ property.setValue(Property.UNKNOWN_VALUE);
+ return true;
+ }
+ // check for "null"
+ if (text.equals("null")) {
+ property.setValue(null);
+ return true;
+ }
+ // prepare value
+ Integer value;
+ try {
+ value = Integer.valueOf(text);
+ } catch (Throwable e) {
+ UiUtils.openWarning(
+ DesignerPlugin.getShell(),
+ property.getTitle(),
+ MessageFormat.format(ModelMessages.IntegerObjectPropertyEditor_notValidInt, text));
+ return false;
+ }
+ // modify property
+ property.setValue(value);
+ return true;
+ }
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/IntegerPropertyEditor.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/IntegerPropertyEditor.java
new file mode 100644
index 0000000..5be13da
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/IntegerPropertyEditor.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor;
+
+import org.eclipse.wb.internal.core.DesignerPlugin;
+import org.eclipse.wb.internal.core.model.ModelMessages;
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.utils.ui.UiUtils;
+
+import java.text.MessageFormat;
+
+/**
+ * The {@link PropertyEditor} for <code>int</code>.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.editor
+ */
+public final class IntegerPropertyEditor extends AbstractTextPropertyEditor {
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Instance
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public static final IntegerPropertyEditor INSTANCE = new IntegerPropertyEditor();
+
+ private IntegerPropertyEditor() {
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Presentation
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public String getText(Property property) throws Exception {
+ Object value = property.getValue();
+ if (value instanceof Integer) {
+ return value.toString();
+ }
+ return null;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Editing
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ protected String getEditorText(Property property) throws Exception {
+ return getText(property);
+ }
+
+ @Override
+ protected boolean setEditorText(Property property, String text) throws Exception {
+ text = text.trim();
+ // check for delete
+ if (text.length() == 0) {
+ property.setValue(Property.UNKNOWN_VALUE);
+ return true;
+ }
+ // prepare value
+ Integer value;
+ try {
+ value = Integer.valueOf(text);
+ } catch (Throwable e) {
+ UiUtils.openWarning(
+ DesignerPlugin.getShell(),
+ property.getTitle(),
+ MessageFormat.format(ModelMessages.IntegerPropertyEditor_notValidInt, text));
+ return false;
+ }
+ // modify property
+ property.setValue(value);
+ return true;
+ }
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/LocalePropertyEditor.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/LocalePropertyEditor.java
new file mode 100644
index 0000000..9a6563d
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/LocalePropertyEditor.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor;
+
+import org.eclipse.wb.internal.core.model.property.Property;
+
+import java.util.Locale;
+
+/**
+ * {@link PropertyEditor} for {@link Locale}.
+ *
+ * @author sablin_aa
+ * @coverage core.model.property.editor
+ */
+public final class LocalePropertyEditor extends TextDialogPropertyEditor {
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Instance
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public static final PropertyEditor INSTANCE = new LocalePropertyEditor();
+
+ private LocalePropertyEditor() {
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Presentation
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ protected String getText(Property property) throws Exception {
+ Object value = property.getValue();
+ if (value instanceof Locale) {
+ return ((Locale) value).getDisplayName();
+ }
+ // unknown value
+ return null;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Editing
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ protected void openDialog(Property property) throws Exception {
+ Object value = property.getValue();
+// ChooseLocaleDialog localeDialog;
+// if (value instanceof Locale) {
+// localeDialog = new ChooseLocaleDialog(DesignerPlugin.getShell(), (Locale) value);
+// } else {
+// localeDialog = new ChooseLocaleDialog(DesignerPlugin.getShell(), null);
+// }
+// // open dialog
+// if (localeDialog.open() == Window.OK) {
+// property.setValue(localeDialog.getSelectedLocale().getLocale());
+// }
+ System.out.println("TODO: Custom locale chooser here");
+ }
+} \ No newline at end of file
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/LongObjectPropertyEditor.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/LongObjectPropertyEditor.java
new file mode 100644
index 0000000..7a74ded
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/LongObjectPropertyEditor.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor;
+
+import org.eclipse.wb.internal.core.DesignerPlugin;
+import org.eclipse.wb.internal.core.model.ModelMessages;
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.utils.ui.UiUtils;
+
+import java.text.MessageFormat;
+
+/**
+ * The {@link PropertyEditor} for {@link Long}.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.editor
+ */
+public final class LongObjectPropertyEditor extends AbstractTextPropertyEditor {
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Instance
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public static final LongObjectPropertyEditor INSTANCE = new LongObjectPropertyEditor();
+
+ private LongObjectPropertyEditor() {
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Presentation
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public String getText(Property property) throws Exception {
+ Object value = property.getValue();
+ if (value == null) {
+ return "null";
+ }
+ if (value instanceof Long) {
+ return value.toString();
+ }
+ return null;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Editing
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ protected String getEditorText(Property property) throws Exception {
+ return getText(property);
+ }
+
+ @Override
+ protected boolean setEditorText(Property property, String text) throws Exception {
+ text = text.trim();
+ // check for delete
+ if (text.length() == 0) {
+ property.setValue(Property.UNKNOWN_VALUE);
+ return true;
+ }
+ // check for "null"
+ if (text.equals("null")) {
+ property.setValue(null);
+ return true;
+ }
+ // prepare value
+ Long value;
+ try {
+ value = Long.valueOf(text);
+ } catch (Throwable e) {
+ UiUtils.openWarning(
+ DesignerPlugin.getShell(),
+ property.getTitle(),
+ MessageFormat.format(ModelMessages.LongObjectPropertyEditor_notValidLong, text));
+ return false;
+ }
+ // modify property
+ property.setValue(value);
+ return true;
+ }
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/LongPropertyEditor.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/LongPropertyEditor.java
new file mode 100644
index 0000000..8c17f83
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/LongPropertyEditor.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor;
+
+import org.eclipse.wb.internal.core.DesignerPlugin;
+import org.eclipse.wb.internal.core.model.ModelMessages;
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.utils.ui.UiUtils;
+
+import java.text.MessageFormat;
+
+/**
+ * The {@link PropertyEditor} for <code>long</code>.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.editor
+ */
+public class LongPropertyEditor extends AbstractTextPropertyEditor {
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Instance
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public static final PropertyEditor INSTANCE = new LongPropertyEditor();
+
+ private LongPropertyEditor() {
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Presentation
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public String getText(Property property) throws Exception {
+ Object value = property.getValue();
+ if (value instanceof Long) {
+ return value.toString();
+ }
+ return null;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Editing
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ protected String getEditorText(Property property) throws Exception {
+ return getText(property);
+ }
+
+ @Override
+ protected boolean setEditorText(Property property, String text) throws Exception {
+ text = text.trim();
+ // check for delete
+ if (text.length() == 0) {
+ property.setValue(Property.UNKNOWN_VALUE);
+ }
+ // prepare value
+ Long value;
+ try {
+ value = Long.valueOf(text);
+ } catch (Throwable e) {
+ UiUtils.openWarning(
+ DesignerPlugin.getShell(),
+ property.getTitle(),
+ MessageFormat.format(ModelMessages.LongPropertyEditor_notValidLong, text));
+ return false;
+ }
+ // modify property
+ property.setValue(value);
+ return true;
+ }
+} \ No newline at end of file
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/PropertyDescriptorEditorProvider.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/PropertyDescriptorEditorProvider.java
new file mode 100644
index 0000000..a60b698
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/PropertyDescriptorEditorProvider.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor;
+
+import java.beans.PropertyDescriptor;
+
+/**
+ * {@link PropertyEditorProvider} that creates editors based on {@link PropertyDescriptor}
+ * attributes, such as "enumerationValues".
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.editor
+ */
+public final class PropertyDescriptorEditorProvider extends PropertyEditorProvider {
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // PropertyEditorProvider
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public PropertyEditor getEditorForPropertyDescriptor(PropertyDescriptor descriptor)
+ throws Exception {
+ {
+ Object attributeValue = descriptor.getValue("enumerationValues");
+ if (isEnumerationProperty(descriptor)) {
+ return new EnumerationValuesPropertyEditor(attributeValue);
+ }
+ }
+ return null;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Utils
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * @return <code>true</code> if given {@link PropertyDescriptor} has attribute "enumerationValues"
+ * with valid value structure.
+ */
+ private static boolean isEnumerationProperty(PropertyDescriptor descriptor) {
+ Object attributeValue = descriptor.getValue("enumerationValues");
+ // should be Object[]
+ if (!(attributeValue instanceof Object[])) {
+ return false;
+ }
+ Object[] enumElements = (Object[]) attributeValue;
+ // should be multiple 3
+ if (enumElements.length % 3 != 0) {
+ return false;
+ }
+ // elements should be sequence of [String,Object,String]
+ for (int i = 0; i < enumElements.length; i++) {
+ Object element = enumElements[i];
+ if (i % 3 == 0 && !(element instanceof String)) {
+ return false;
+ }
+ if (i % 3 == 2 && !(element instanceof String)) {
+ return false;
+ }
+ }
+ // OK
+ return true;
+ }
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/PropertyEditor.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/PropertyEditor.java
new file mode 100644
index 0000000..fd2fa8f
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/PropertyEditor.java
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.model.property.editor.presentation.PropertyEditorPresentation;
+import org.eclipse.wb.internal.core.model.property.table.PropertyTable;
+
+/**
+ * Abstract editor for {@link Property}.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.editor
+ */
+public abstract class PropertyEditor {
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Presentation
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * @return the instance of {@link PropertyEditorPresentation}.
+ */
+ public PropertyEditorPresentation getPresentation() {
+ return null;
+ }
+
+ /**
+ * Paints given {@link Property} given rectangle <code>(x, y, width, height)</code> of {@link GC}.
+ */
+ public abstract void paint(Property property, GC gc, int x, int y, int width, int height)
+ throws Exception;
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Editing
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * Activates editor for given {@link Property} at given place of {@link Composite}. Activation
+ * happens when user selects property in {@link PropertyTable}. {@link PropertyEditor} should
+ * create here any {@link Control}'s required to edit {@link Property}.
+ *
+ * If any exception happens, {@link PropertyEditor} will be deactivated.
+ *
+ * @param location
+ * the mouse location, if editor is activated using mouse click, or <code>null</code> if
+ * it is activated using keyboard.
+ *
+ * @return <code>true</code> if editor should be remembered as active for future
+ * {@link #setBounds(Rectangle)} and {@link #deactivate(boolean)} invocation. Some editors
+ * need such local activation (for example for String), some - not (for boolean).
+ */
+ public boolean activate(PropertyTable propertyTable, Property property, Point location)
+ throws Exception {
+ return false;
+ }
+
+ /**
+ * Sets the new bounds for editor's control.
+ */
+ public void setBounds(Rectangle bounds) {
+ }
+
+ /**
+ * Deactivates editor for current {@link Property}. {@link PropertyEditor} should dispose any
+ * {@link Control}'s created before in {@link #activate(PropertyTable, Property, Point)}.
+ *
+ * If any exception happened during activation, editor still should be able to deactivate
+ * correctly.
+ *
+ * @param save
+ * is <code>true</code> if property should save value to {@link Property}.
+ */
+ public void deactivate(PropertyTable propertyTable, Property property, boolean save) {
+ }
+
+ /**
+ * Handles double click on {@link Property} value in {@link PropertyTable}.
+ *
+ * @param location
+ * the mouse location, relative to editor
+ */
+ public void doubleClick(Property property, Point location) throws Exception {
+ }
+
+ /**
+ * Handles {@link SWT#KeyDown} event in {@link PropertyTable}.
+ */
+ public void keyDown(PropertyTable propertyTable, Property property, KeyEvent event)
+ throws Exception {
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // IAdaptable
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public <T> T getAdapter(Class<T> adapter) {
+ return null;
+ }
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/PropertyEditorProvider.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/PropertyEditorProvider.java
new file mode 100644
index 0000000..2d11cbc
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/PropertyEditorProvider.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor;
+
+import java.beans.PropertyDescriptor;
+
+/**
+ * Provider for creating {@link PropertyEditor}'s.
+ *
+ * @author lobas_av
+ * @coverage core.model.property.editor
+ */
+public class PropertyEditorProvider {
+ /**
+ * @return the {@link PropertyEditor} for given property type or <code>null</code>.
+ */
+ public PropertyEditor getEditorForType(Class<?> propertyType) throws Exception {
+ return null;
+ }
+
+ /**
+ * @return the {@link PropertyEditor} for given {@link java.beans.PropertyEditor} editor type or
+ * <code>null</code>.
+ */
+ public PropertyEditor getEditorForEditorType(Class<?> editorType) throws Exception {
+ return null;
+ }
+
+ /**
+ * @return the {@link PropertyEditor} for given {@link PropertyDescriptor} or <code>null</code>.
+ */
+ public PropertyEditor getEditorForPropertyDescriptor(PropertyDescriptor descriptor)
+ throws Exception {
+ return null;
+ }
+} \ No newline at end of file
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/ShortObjectPropertyEditor.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/ShortObjectPropertyEditor.java
new file mode 100644
index 0000000..c1f8383
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/ShortObjectPropertyEditor.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor;
+
+import org.eclipse.wb.internal.core.DesignerPlugin;
+import org.eclipse.wb.internal.core.model.ModelMessages;
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.utils.ui.UiUtils;
+
+import java.text.MessageFormat;
+
+/**
+ * The {@link PropertyEditor} for {@link Short}.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.editor
+ */
+public final class ShortObjectPropertyEditor extends AbstractTextPropertyEditor {
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Instance
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public static final ShortObjectPropertyEditor INSTANCE = new ShortObjectPropertyEditor();
+
+ private ShortObjectPropertyEditor() {
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Presentation
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public String getText(Property property) throws Exception {
+ Object value = property.getValue();
+ if (value == null) {
+ return "null";
+ }
+ if (value instanceof Short) {
+ return value.toString();
+ }
+ return null;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Editing
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ protected String getEditorText(Property property) throws Exception {
+ return getText(property);
+ }
+
+ @Override
+ protected boolean setEditorText(Property property, String text) throws Exception {
+ text = text.trim();
+ // check for delete
+ if (text.length() == 0) {
+ property.setValue(Property.UNKNOWN_VALUE);
+ return true;
+ }
+ // check for "null"
+ if (text.equals("null")) {
+ property.setValue(null);
+ return true;
+ }
+ // prepare value
+ Short value;
+ try {
+ value = Short.valueOf(text);
+ } catch (Throwable e) {
+ UiUtils.openWarning(
+ DesignerPlugin.getShell(),
+ property.getTitle(),
+ MessageFormat.format(ModelMessages.ShortObjectPropertyEditor_notValidShort, text));
+ return false;
+ }
+ // modify property
+ property.setValue(value);
+ return true;
+ }
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/ShortPropertyEditor.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/ShortPropertyEditor.java
new file mode 100644
index 0000000..dba61c9
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/ShortPropertyEditor.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor;
+
+import org.eclipse.wb.internal.core.DesignerPlugin;
+import org.eclipse.wb.internal.core.model.ModelMessages;
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.utils.ui.UiUtils;
+
+import java.text.MessageFormat;
+
+/**
+ * The {@link PropertyEditor} for <code>short</code>.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.editor
+ */
+public class ShortPropertyEditor extends AbstractTextPropertyEditor {
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Instance
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public static final PropertyEditor INSTANCE = new ShortPropertyEditor();
+
+ private ShortPropertyEditor() {
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Presentation
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public String getText(Property property) throws Exception {
+ Object value = property.getValue();
+ if (value instanceof Short) {
+ return value.toString();
+ }
+ return null;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Editing
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ protected String getEditorText(Property property) throws Exception {
+ return getText(property);
+ }
+
+ @Override
+ protected boolean setEditorText(Property property, String text) throws Exception {
+ text = text.trim();
+ // check for delete
+ if (text.length() == 0) {
+ property.setValue(Property.UNKNOWN_VALUE);
+ }
+ // prepare value
+ Short value;
+ try {
+ value = Short.valueOf(text);
+ } catch (Throwable e) {
+ UiUtils.openWarning(
+ DesignerPlugin.getShell(),
+ property.getTitle(),
+ MessageFormat.format(ModelMessages.ShortPropertyEditor_notValidShort, text));
+ return false;
+ }
+ // modify property
+ property.setValue(value);
+ return true;
+ }
+} \ No newline at end of file
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/StringArrayPropertyEditor.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/StringArrayPropertyEditor.java
new file mode 100644
index 0000000..fd78e01
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/StringArrayPropertyEditor.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor;
+
+import com.google.common.base.Joiner;
+
+import org.eclipse.jface.window.Window;
+import org.eclipse.wb.internal.core.DesignerPlugin;
+import org.eclipse.wb.internal.core.model.ModelMessages;
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.utils.ui.dialogs.StringsDialog;
+
+/**
+ * {@link PropertyEditor} for array of {@link String}'s.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.editor
+ */
+public final class StringArrayPropertyEditor extends TextDialogPropertyEditor {
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Instance
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public static final PropertyEditor INSTANCE = new StringArrayPropertyEditor();
+
+ private StringArrayPropertyEditor() {
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Presentation
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ protected String getText(Property property) throws Exception {
+ String[] items = getItems(property);
+ return "[" + Joiner.on(", ").join(items) + "]";
+ }
+
+ /**
+ * @return the items specified in value of given {@link Property}.
+ */
+ private static String[] getItems(Property property) throws Exception {
+ Object value = property.getValue();
+ if (value instanceof String[]) {
+ return (String[]) value;
+ }
+ // no items
+ return new String[0];
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Editing
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ protected void openDialog(Property property) throws Exception {
+ StringsDialog itemsDialog =
+ new StringsDialog(DesignerPlugin.getShell(),
+ DesignerPlugin.getDefault(),
+ property.getTitle(),
+ ModelMessages.StringArrayPropertyEditor_itemsLabel,
+ ModelMessages.StringArrayPropertyEditor_hint);
+ itemsDialog.setItems(getItems(property));
+ // open dialog
+ if (itemsDialog.open() == Window.OK) {
+ property.setValue(itemsDialog.getItems());
+ }
+ }
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/StringComboPropertyEditor.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/StringComboPropertyEditor.java
new file mode 100644
index 0000000..1861475
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/StringComboPropertyEditor.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor;
+
+import org.eclipse.wb.core.controls.CCombo3;
+import org.eclipse.wb.internal.core.model.property.Property;
+
+/**
+ * The {@link PropertyEditor} for selecting single {@link String} value from given array.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.editor
+ */
+public class StringComboPropertyEditor extends AbstractComboPropertyEditor {
+ private final String[] m_items;
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Constructor
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public StringComboPropertyEditor(String... items) {
+ m_items = items;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Presentation
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ protected String getText(Property property) throws Exception {
+ return (String) property.getValue();
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // AbstractComboPropertyEditor
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ protected void addItems(Property property, CCombo3 combo) throws Exception {
+ for (String item : m_items) {
+ combo.add(item);
+ }
+ }
+
+ @Override
+ protected void selectItem(Property property, CCombo3 combo) throws Exception {
+ combo.setText(getText(property));
+ }
+
+ @Override
+ protected void toPropertyEx(Property property, CCombo3 combo, int index) throws Exception {
+ property.setValue(m_items[index]);
+ }
+} \ No newline at end of file
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/StringListPropertyEditor.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/StringListPropertyEditor.java
new file mode 100644
index 0000000..1bb8cd8
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/StringListPropertyEditor.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor;
+
+import org.eclipse.wb.core.controls.CCombo3;
+import org.eclipse.wb.internal.core.model.property.Property;
+
+/**
+ * The {@link PropertyEditor} for selecting single string from given set.
+ *
+ * @author sablin_aa
+ * @coverage core.model.property.editor
+ */
+public final class StringListPropertyEditor extends AbstractListPropertyEditor {
+ private boolean m_ignoreCase;
+ private String[] m_strings;
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Combo
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ protected void toPropertyEx_simpleProperty(Property property, CCombo3 combo, int index)
+ throws Exception {
+ property.setValue(m_strings[index]);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Access to list items
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ protected int getCount() {
+ return m_strings.length;
+ }
+
+ @Override
+ protected int getValueIndex(Object value) {
+ if (value instanceof String) {
+ String string = (String) value;
+ for (int i = 0; i < getCount(); i++) {
+ if (m_ignoreCase) {
+ if (string.equalsIgnoreCase(m_strings[i])) {
+ return i;
+ }
+ } else {
+ if (string.equals(m_strings[i])) {
+ return i;
+ }
+ }
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ protected String getTitle(int index) {
+ return m_strings[index];
+ }
+
+ @Override
+ protected String getExpression(int index) throws Exception {
+ //return StringConverter.INSTANCE.toJavaSource(null, m_strings[index]);
+ // HACK!!
+ System.out.println("HACK!");
+ return m_strings[index];
+ }
+//
+// ////////////////////////////////////////////////////////////////////////////
+// //
+// // IConfigurablePropertyObject
+// //
+// ////////////////////////////////////////////////////////////////////////////
+// public void configure(EditorState state, Map<String, Object> parameters) throws Exception {
+// m_strings = getParameterAsArray(parameters, "strings");
+// m_ignoreCase = "true".equals(parameters.get("ignoreCase"));
+// }
+//
+// /**
+// * Configures this editor externally.
+// */
+// public void configure(String[] strings) {
+// m_strings = strings;
+// }
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/TextControlActionsManager.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/TextControlActionsManager.java
new file mode 100644
index 0000000..dc7ba74
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/TextControlActionsManager.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor;
+
+import org.eclipse.wb.internal.core.utils.binding.editors.controls.DefaultControlActionsManager;
+
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * Manager for installing/unistalling global handlers for {@link Text} actions commands.
+ *
+ * @author mitin_aa
+ * @author sablin_aa
+ * @coverage core.model.property.editor
+ */
+public final class TextControlActionsManager extends DefaultControlActionsManager {
+ private final Text m_text;
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Constructor
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public TextControlActionsManager(final Text text) {
+ super(text);
+ m_text = text;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Handlers
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ protected void selectAllExecuted() {
+ m_text.selectAll();
+ }
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/TextDialogPropertyEditor.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/TextDialogPropertyEditor.java
new file mode 100644
index 0000000..885d4ef
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/TextDialogPropertyEditor.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor;
+
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.model.property.editor.presentation.ButtonPropertyEditorPresentation;
+import org.eclipse.wb.internal.core.model.property.editor.presentation.PropertyEditorPresentation;
+import org.eclipse.wb.internal.core.model.property.table.PropertyTable;
+
+import org.eclipse.swt.graphics.Point;
+
+/**
+ * Abstract {@link PropertyEditor} that displays text and button to open dialog.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.editor
+ */
+public abstract class TextDialogPropertyEditor extends TextDisplayPropertyEditor {
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Presentation
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private final PropertyEditorPresentation m_presentation = new ButtonPropertyEditorPresentation() {
+ @Override
+ protected void onClick(PropertyTable propertyTable, Property property) throws Exception {
+ openDialog(property);
+ }
+ };
+
+ @Override
+ public final PropertyEditorPresentation getPresentation() {
+ return m_presentation;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Editing
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public boolean activate(PropertyTable propertyTable, Property property, Point location)
+ throws Exception {
+ // activate using keyboard
+ if (location == null) {
+ openDialog(property);
+ }
+ // don't activate
+ return false;
+ }
+
+ /**
+ * Opens editing dialog.
+ */
+ protected abstract void openDialog(Property property) throws Exception;
+} \ No newline at end of file
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/TextDisplayPropertyEditor.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/TextDisplayPropertyEditor.java
new file mode 100644
index 0000000..9cf3703
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/TextDisplayPropertyEditor.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor;
+
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.model.property.table.PropertyTable;
+import org.eclipse.wb.internal.core.model.property.table.PropertyTooltipProvider;
+import org.eclipse.wb.internal.core.utils.ui.DrawUtils;
+
+/**
+ * Abstract {@link PropertyEditor} for displaying text as {@link Property} value in
+ * {@link PropertyTable}.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.editor
+ */
+public abstract class TextDisplayPropertyEditor extends PropertyEditor {
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Presentation
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public void paint(Property property, GC gc, int x, int y, int width, int height) throws Exception {
+ String text = getText(property);
+ if (text != null) {
+ DrawUtils.drawStringCV(gc, text, x, y, width, height);
+ }
+ }
+
+ /**
+ * @return the text for displaying value of given {@link Property} or <code>null</code> if value
+ * of {@link Property} is unknown.
+ */
+ protected abstract String getText(Property property) throws Exception;
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // IAdaptable
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public <T> T getAdapter(Class<T> adapter) {
+ // tooltip for value text
+ if (adapter == PropertyTooltipProvider.class) {
+ return adapter.cast(createPropertyTooltipProvider());
+ }
+ return super.getAdapter(adapter);
+ }
+
+ /**
+ * @return the {@link PropertyTooltipProvider} to display value tooltip.
+ */
+ protected PropertyTooltipProvider createPropertyTooltipProvider() {
+ return null;
+ }
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/complex/IComplexPropertyEditor.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/complex/IComplexPropertyEditor.java
new file mode 100644
index 0000000..0634cfe
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/complex/IComplexPropertyEditor.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor.complex;
+
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.model.property.editor.PropertyEditor;
+
+/**
+ * Extension for {@link PropertyEditor} that specifies that it has sub-properties.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.editor
+ */
+public interface IComplexPropertyEditor {
+ /**
+ * @return sub-properties of given complex property.
+ */
+ Property[] getProperties(Property property) throws Exception;
+} \ No newline at end of file
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/presentation/ButtonPropertyEditorPresentation.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/presentation/ButtonPropertyEditorPresentation.java
new file mode 100644
index 0000000..e33970d
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/presentation/ButtonPropertyEditorPresentation.java
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor.presentation;
+
+import org.eclipse.wb.internal.core.DesignerPlugin;
+import org.eclipse.wb.internal.core.EnvironmentUtils;
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.model.property.table.PropertyTable;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Button;
+
+/**
+ * Implementation of {@link PropertyEditorPresentation} for displaying {@link Button}.
+ *
+ * @author scheglov_ke
+ * @author mitin_aa
+ * @coverage core.model.property.editor
+ */
+public abstract class ButtonPropertyEditorPresentation extends PropertyEditorPresentation {
+ private final int m_style;
+ private final ButtonPropertyEditorPresentationImpl m_impl;
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Constructors
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public ButtonPropertyEditorPresentation() {
+ this(SWT.NONE);
+ }
+
+ public ButtonPropertyEditorPresentation(int style) {
+ m_style = style;
+ m_impl =
+ EnvironmentUtils.IS_MAC
+ ? new ButtonPropertyEditorPresentationImplMac(this)
+ : new ButtonPropertyEditorPresentationImpl(this);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Access
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * Sets "selection" property of {@link Button}.
+ */
+ public final void setSelection(PropertyTable propertyTable, Property property, boolean selected) {
+ m_impl.setSelection(propertyTable, property, selected);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // PropertyEditorPresentation
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public final int show(final PropertyTable propertyTable,
+ final Property property,
+ final int x,
+ final int y,
+ final int width,
+ final int height) {
+ return m_impl.show(propertyTable, property, x, y, width, height);
+ }
+
+ @Override
+ public final void hide(PropertyTable propertyTable, Property property) {
+ m_impl.hide(propertyTable, property);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Access
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ final int getStyle() {
+ return m_style;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Implementation
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * @return the {@link Image} to display on {@link Button}.
+ */
+ protected Image getImage() {
+ return DesignerPlugin.getImage("properties/dots.gif");
+ }
+
+ /**
+ * @return the tooltip text to display for {@link Button}.
+ */
+ protected String getTooltip() {
+ return null;
+ }
+
+ /**
+ * Handles click on {@link Button}.
+ */
+ protected abstract void onClick(PropertyTable propertyTable, Property property) throws Exception;
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/presentation/ButtonPropertyEditorPresentationImpl.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/presentation/ButtonPropertyEditorPresentationImpl.java
new file mode 100644
index 0000000..209bf39
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/presentation/ButtonPropertyEditorPresentationImpl.java
@@ -0,0 +1,224 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor.presentation;
+
+import com.google.common.collect.Maps;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.model.property.table.PropertyTable;
+import org.eclipse.wb.internal.core.utils.Pair;
+
+import java.util.Map;
+
+/**
+ * Internal implementation of {@link PropertyEditorPresentation} for displaying {@link Button}.
+ *
+ * @author scheglov_ke
+ * @author mitin_aa
+ * @coverage core.model.property.editor
+ */
+class ButtonPropertyEditorPresentationImpl extends PropertyEditorPresentation {
+ protected final PropertyToControlMap m_propertyToControl = new PropertyToControlMap();
+ private final ButtonPropertyEditorPresentation m_presentation;
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Constructor
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public ButtonPropertyEditorPresentationImpl(ButtonPropertyEditorPresentation presentation) {
+ m_presentation = presentation;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // PropertyEditorPresentation
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public final void hide(PropertyTable propertyTable, Property property) {
+ Control control = m_propertyToControl.remove(propertyTable, property);
+ if (control != null) {
+ control.dispose();
+ }
+ }
+
+ @Override
+ public final int show(PropertyTable propertyTable,
+ Property property,
+ int x,
+ int y,
+ int width,
+ int height) {
+ // prepare control
+ Control control = m_propertyToControl.get(propertyTable, property);
+ if (control == null) {
+ control = createControl(propertyTable, property);
+ }
+ // set bounds
+ final int controlWidth = height;
+ final int controlX = x + width - controlWidth;
+ setBounds(control, controlX, y, controlWidth, height);
+ return controlWidth;
+ }
+
+ /**
+ * Finds and select the appropriate {@link Control} belonging to given property.
+ */
+ public void setSelection(PropertyTable propertyTable, Property property, boolean selected) {
+ Button button = (Button) m_propertyToControl.get(propertyTable, property);
+ if (button != null) {
+ button.setSelection(selected);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Control
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * Creates the control for given property and initializes newly created control.
+ */
+ private Control createControl(final PropertyTable propertyTable, final Property property) {
+ Control control = createControlImpl(propertyTable, property);
+ m_propertyToControl.put(propertyTable, property, control);
+ // when Control disposed, remove Control/Property from map to avoid memory leak
+ control.addListener(SWT.Dispose, new Listener() {
+ @Override
+ public void handleEvent(Event e) {
+ m_propertyToControl.remove(propertyTable, property);
+ }
+ });
+ // activate property on mouse down
+ control.addListener(SWT.MouseDown, new Listener() {
+ @Override
+ public void handleEvent(Event event) {
+ propertyTable.deactivateEditor(true);
+ propertyTable.setActiveProperty(property);
+ }
+ });
+ // return focus on propertyTable after click
+ control.addListener(SWT.MouseUp, new Listener() {
+ @Override
+ public void handleEvent(Event event) {
+ propertyTable.forceFocus();
+ }
+ });
+ // handle selection
+ control.addListener(SWT.Selection, new Listener() {
+ @Override
+ public void handleEvent(Event event) {
+ try {
+ getPresentation().onClick(propertyTable, property);
+ } catch (Throwable e) {
+ propertyTable.deactivateEditor(false);
+ propertyTable.handleException(e);
+ }
+ }
+ });
+ return control;
+ }
+
+ /**
+ * Creates the {@link Control} instance. By default, {@link Button} instance created.
+ */
+ protected Control createControlImpl(final PropertyTable propertyTable, final Property property) {
+ Button button = new Button(propertyTable, getPresentation().getStyle());
+ button.setImage(getPresentation().getImage());
+ button.setToolTipText(getPresentation().getTooltip());
+ return button;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Access
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * @return the 'parent' presentation. Internal usage only.
+ */
+ protected final ButtonPropertyEditorPresentation getPresentation() {
+ return m_presentation;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Utils
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * Sets new bounds for {@link Control}, optimizing when possible.
+ */
+ private static void setBounds(Control control, int newX, int newY, int newWidth, int newHeight) {
+ // check, may be Control is invisible, so no reason to change bounds
+ {
+ // is in negative zone
+ if (newY + newHeight < 0) {
+ control.setVisible(false);
+ return;
+ }
+ // is out of client area height
+ Rectangle parentArea = control.getParent().getClientArea();
+ if (newY > parentArea.height) {
+ control.setVisible(false);
+ return;
+ }
+ }
+ // well, now we sure that Control is visible
+ if (!control.getVisible()) {
+ control.setVisible(true);
+ }
+ // prepare old size, remember new
+ Integer oldWidthObject = (Integer) control.getData("oldWidth");
+ Integer oldHeightObject = (Integer) control.getData("oldHeight");
+ control.setData("oldWidth", newWidth);
+ control.setData("oldHeight", newHeight);
+ // check, may be same size
+ if (oldWidthObject != null) {
+ int oldWidth = oldWidthObject.intValue();
+ int oldHeight = oldHeightObject.intValue();
+ if (oldWidth == newWidth && oldHeight == newHeight) {
+ control.setLocation(newX, newY);
+ return;
+ }
+ }
+ // no any optimization possible, just set bounds
+ control.setBounds(newX, newY, newWidth, newHeight);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Controls map
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ protected static final class PropertyToControlMap {
+ private final Map<Pair<PropertyTable, Property>, Control> m_map = Maps.newHashMap();
+
+ void put(PropertyTable propertyTable, Property property, Control control) {
+ m_map.put(Pair.create(propertyTable, property), control);
+ }
+
+ Control remove(PropertyTable propertyTable, Property property) {
+ return m_map.remove(Pair.create(propertyTable, property));
+ }
+
+ Control get(PropertyTable propertyTable, Property property) {
+ return m_map.get(Pair.create(propertyTable, property));
+ }
+ }
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/presentation/ButtonPropertyEditorPresentationImplMac.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/presentation/ButtonPropertyEditorPresentationImplMac.java
new file mode 100644
index 0000000..d61a606
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/presentation/ButtonPropertyEditorPresentationImplMac.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor.presentation;
+
+import org.eclipse.wb.core.controls.CFlatButton;
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.model.property.table.PropertyTable;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Control;
+
+/**
+ * Internal implementation of {@link PropertyEditorPresentation} for displaying special owner-draw
+ * button for Mac OSX.
+ *
+ * @author mitin_aa
+ * @coverage core.model.property.editor
+ */
+final class ButtonPropertyEditorPresentationImplMac extends ButtonPropertyEditorPresentationImpl {
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Constructor
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public ButtonPropertyEditorPresentationImplMac(ButtonPropertyEditorPresentation presentation) {
+ super(presentation);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Control
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ protected final Control createControlImpl(final PropertyTable propertyTable, Property property) {
+ CFlatButton button = new CFlatButton(propertyTable, SWT.NONE);
+ button.setImage(getPresentation().getImage());
+ button.setToolTipText(getPresentation().getTooltip());
+ return button;
+ }
+
+ @Override
+ public final void setSelection(PropertyTable propertyTable, Property property, boolean selected) {
+ CFlatButton button = (CFlatButton) m_propertyToControl.get(propertyTable, property);
+ if (button != null) {
+ button.setSelected(selected);
+ }
+ }
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/presentation/CompoundPropertyEditorPresentation.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/presentation/CompoundPropertyEditorPresentation.java
new file mode 100644
index 0000000..39bfa7a
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/presentation/CompoundPropertyEditorPresentation.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor.presentation;
+
+import com.google.common.collect.Lists;
+
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.model.property.table.PropertyTable;
+
+import java.util.List;
+
+/**
+ * Implementation of {@link PropertyEditorPresentation} that contains zero or more other
+ * {@link PropertyEditorPresentation}'s.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.editor
+ */
+public class CompoundPropertyEditorPresentation extends PropertyEditorPresentation {
+ private final List<PropertyEditorPresentation> m_presentations = Lists.newArrayList();
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Access
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * Adds child {@link PropertyEditorPresentation}.<br>
+ * Child {@link PropertyEditorPresentation}'s are displayed from right to left.
+ */
+ public void add(PropertyEditorPresentation presentation) {
+ m_presentations.add(presentation);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // PropertyEditorPresentation
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public int show(PropertyTable propertyTable,
+ Property property,
+ int x,
+ int y,
+ int width,
+ int height) {
+ int sumWidth = 0;
+ for (PropertyEditorPresentation presentation : m_presentations) {
+ int presentationWidth = presentation.show(propertyTable, property, x, y, width, height);
+ sumWidth += presentationWidth;
+ width -= presentationWidth;
+ }
+ return sumWidth;
+ }
+
+ @Override
+ public void hide(PropertyTable propertyTable, Property property) {
+ for (PropertyEditorPresentation presentation : m_presentations) {
+ presentation.hide(propertyTable, property);
+ }
+ }
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/presentation/PropertyEditorPresentation.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/presentation/PropertyEditorPresentation.java
new file mode 100644
index 0000000..843338e
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/presentation/PropertyEditorPresentation.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor.presentation;
+
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.model.property.editor.PropertyEditor;
+import org.eclipse.wb.internal.core.model.property.table.PropertyTable;
+
+/**
+ * Implementations of {@link PropertyEditorPresentation} are used to show some presentation for
+ * visible, but not activated yet {@link PropertyEditor}.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.editor
+ */
+public abstract class PropertyEditorPresentation {
+ /**
+ * Shows presentation for given {@link Property}.
+ *
+ * @return the width that this presentation occupies on the right of given rectangle.
+ */
+ public abstract int show(PropertyTable propertyTable,
+ Property property,
+ int x,
+ int y,
+ int width,
+ int height);
+
+ /**
+ * Hides presentation.
+ */
+ public abstract void hide(PropertyTable propertyTable, Property property);
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/string/StringPropertyDialog.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/string/StringPropertyDialog.java
new file mode 100644
index 0000000..2b0d47e
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/string/StringPropertyDialog.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor.string;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.wb.internal.core.DesignerPlugin;
+import org.eclipse.wb.internal.core.model.ModelMessages;
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.utils.execution.ExecutionUtils;
+import org.eclipse.wb.internal.core.utils.execution.RunnableEx;
+import org.eclipse.wb.internal.core.utils.ui.GridDataFactory;
+import org.eclipse.wb.internal.core.utils.ui.dialogs.ResizableDialog;
+
+/**
+ * {@link Dialog} for editing value in {@link StringPropertyEditor}.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.editor
+ */
+public class StringPropertyDialog extends ResizableDialog {
+ // NOTE: In WindowBuilder this class had a lot of support for
+ // editing Java strings, dealing with automatic localization
+ // etc. This will need to be done differently in ADT (and had hooks
+ // into a bunch of other parts of WindowBuilder we're not including)
+ // so this was all stripped down to a plain String editor.
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Final fields
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private final Property m_property;
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Constructor
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public StringPropertyDialog(Shell parentShell, Property property) throws Exception {
+ super(parentShell, DesignerPlugin.getDefault());
+ m_property = property;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // GUI
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private Text m_valueText;
+
+ @Override
+ public void create() {
+ super.create();
+ m_valueText.selectAll();
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ Composite area = (Composite) super.createDialogArea(parent);
+ // value
+ {
+ // BEGIN ADT MODIFICATIONS
+ if (isMultiLine()) {
+ // END ADT MODIFICATIONS
+ m_valueText = new Text(area, SWT.BORDER | SWT.MULTI | SWT.WRAP);
+ GridDataFactory.create(m_valueText).grab().hintC(80, 8).fill();
+ // BEGIN ADT MODIFICATIONS
+ } else {
+ m_valueText = new Text(area, SWT.BORDER | SWT.SINGLE);
+ GridDataFactory.create(m_valueText).grab().hintC(50, 1).fill();
+ }
+ // END ADT MODIFICATIONS
+ // initial value
+ ExecutionUtils.runLog(new RunnableEx() {
+ @Override
+ public void run() throws Exception {
+ Object value = m_property.getValue();
+ if (value instanceof String) {
+ m_valueText.setText((String) value);
+ }
+ }
+ });
+ // handle Ctrl+Enter as OK
+ m_valueText.addKeyListener(new KeyAdapter() {
+ @Override
+ public void keyPressed(KeyEvent e) {
+ if (e.stateMask == SWT.CTRL && e.keyCode == SWT.CR) {
+ okPressed();
+ }
+ }
+ });
+ }
+
+ return area;
+ }
+
+ // BEGIN ADT MODIFICATIONS
+ protected boolean isMultiLine() {
+ return true;
+ }
+ // END ADT MODIFICATIONS
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Shell
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ protected void configureShell(Shell newShell) {
+ super.configureShell(newShell);
+ newShell.setText(ModelMessages.StringPropertyDialog_title);
+ }
+
+ @Override
+ protected void okPressed() {
+ final String value = m_valueText.getText();
+ ExecutionUtils.runLog(new RunnableEx() {
+ @Override
+ public void run() throws Exception {
+ m_property.setValue(value);
+ }
+ });
+ // close dialog
+ super.okPressed();
+ }
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/string/StringPropertyEditor.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/string/StringPropertyEditor.java
new file mode 100644
index 0000000..0202fe5
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/editor/string/StringPropertyEditor.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.editor.string;
+
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.model.property.editor.AbstractTextPropertyEditor;
+import org.eclipse.wb.internal.core.model.property.editor.PropertyEditor;
+import org.eclipse.wb.internal.core.model.property.editor.presentation.ButtonPropertyEditorPresentation;
+import org.eclipse.wb.internal.core.model.property.editor.presentation.PropertyEditorPresentation;
+import org.eclipse.wb.internal.core.model.property.table.PropertyTable;
+
+import org.eclipse.jface.window.Window;
+
+/**
+ * The {@link PropertyEditor} for {@link String}.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.editor
+ */
+public class StringPropertyEditor extends AbstractTextPropertyEditor {
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Instance
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public static final PropertyEditor INSTANCE = new StringPropertyEditor();
+
+ private StringPropertyEditor() {
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Presentation
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private final PropertyEditorPresentation m_presentation = new ButtonPropertyEditorPresentation() {
+ @Override
+ protected void onClick(PropertyTable propertyTable, Property property) throws Exception {
+ openDialog(propertyTable, property);
+ }
+ };
+
+ @Override
+ public PropertyEditorPresentation getPresentation() {
+ return m_presentation;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Presentation
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public String getText(Property property) throws Exception {
+ Object value = property.getValue();
+ if (value instanceof String) {
+ return (String) value;
+ }
+ return null;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Editing
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ protected String getEditorText(Property property) throws Exception {
+ return getText(property);
+ }
+
+ @Override
+ protected boolean setEditorText(Property property, String text) throws Exception {
+ property.setValue(text);
+ return true;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Editing in dialog
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * Opens editing dialog.
+ */
+ private void openDialog(PropertyTable propertyTable, Property property) throws Exception {
+ StringPropertyDialog dialog = new StringPropertyDialog(propertyTable.getShell(), property);
+ if (dialog.open() == Window.OK) {
+ }
+ }
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/table/HtmlTooltipHelper.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/table/HtmlTooltipHelper.java
new file mode 100644
index 0000000..5e05549
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/table/HtmlTooltipHelper.java
@@ -0,0 +1,332 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.table;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Joiner;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.browser.Browser;
+import org.eclipse.swt.browser.LocationAdapter;
+import org.eclipse.swt.browser.LocationEvent;
+import org.eclipse.swt.browser.ProgressAdapter;
+import org.eclipse.swt.browser.ProgressEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.browser.IWebBrowser;
+import org.eclipse.ui.browser.IWorkbenchBrowserSupport;
+import org.eclipse.wb.draw2d.IColorConstants;
+import org.eclipse.wb.internal.core.DesignerPlugin;
+import org.eclipse.wb.internal.core.EnvironmentUtils;
+import org.eclipse.wb.internal.core.utils.reflect.ReflectionUtils;
+import org.eclipse.wb.internal.core.utils.ui.GridDataFactory;
+import org.eclipse.wb.internal.core.utils.ui.PixelConverter;
+
+import java.io.StringReader;
+import java.net.URL;
+import java.text.MessageFormat;
+
+/**
+ * Helper for displaying HTML tooltips.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.table
+ */
+public final class HtmlTooltipHelper {
+ public static Control createTooltipControl(Composite parent, String header, String details) {
+ return createTooltipControl(parent, header, details, 0);
+ }
+
+ public static Control createTooltipControl(Composite parent,
+ String header,
+ String details,
+ int heightLimit) {
+ // prepare Control
+ Control control;
+ try {
+ String html = "<table cellspacing=2 cellpadding=0 border=0 margins=0 id=_wbp_tooltip_body>";
+ if (header != null) {
+ html += "<tr align=center><td><b>" + header + "</b></td></tr>";
+ }
+ html += "<tr><td align=justify>" + details + "</td></tr>";
+ html += "</table>";
+ control = createTooltipControl_Browser(parent, html, heightLimit);
+ } catch (Throwable e) {
+ control = createTooltipControl_Label(parent, details);
+ }
+ // set listeners
+ {
+ Listener listener = new Listener() {
+ @Override
+ public void handleEvent(Event event) {
+ Control tooltipControl = (Control) event.widget;
+ hideTooltip(tooltipControl);
+ }
+ };
+ control.addListener(SWT.MouseExit, listener);
+ }
+ // done
+ return control;
+ }
+
+ /**
+ * Creates {@link Browser} for displaying tooltip.
+ */
+ private static Control createTooltipControl_Browser(Composite parent,
+ String html,
+ final int heightLimitChars) {
+ // prepare styles
+ String styles;
+ try {
+ styles = DesignerPlugin.readFile(PropertyTable.class.getResourceAsStream("Tooltip.css"),
+ Charsets.US_ASCII);
+ if (styles == null) {
+ styles = "";
+ }
+ } catch (Throwable e) {
+ styles = "";
+ }
+ // prepare HTML with styles and tags
+ String wrappedHtml;
+ {
+ String bodyAttributes =
+ MessageFormat.format(
+ "text=''{0}'' bgcolor=''{1}''",
+ getColorWebString(IColorConstants.tooltipForeground),
+ getColorWebString(IColorConstants.tooltipBackground));
+ String closeElement =
+ EnvironmentUtils.IS_LINUX
+ ? " <a href='' style='position:absolute;right:1em;' id=_wbp_close>Close</a>"
+ : "";
+ wrappedHtml =
+ /*CodeUtils.*/getSource(
+ "<html>",
+ " <style CHARSET='ISO-8859-1' TYPE='text/css'>",
+ styles,
+ " </style>",
+ " <body " + bodyAttributes + ">",
+ closeElement,
+ html,
+ " </body>",
+ "</html>");
+ }
+ // prepare Browser
+ final Browser browser = new Browser(parent, SWT.NONE);
+ browser.setText(wrappedHtml);
+ // open URLs in new window
+ browser.addLocationListener(new LocationAdapter() {
+ @Override
+ public void changing(LocationEvent event) {
+ event.doit = false;
+ hideTooltip((Browser) event.widget);
+ if (!"about:blank".equals(event.location)) {
+ try {
+ IWorkbenchBrowserSupport support = PlatformUI.getWorkbench().getBrowserSupport();
+ IWebBrowser browserSupport = support.createBrowser("wbp.browser");
+ browserSupport.openURL(new URL(event.location));
+ } catch (Throwable e) {
+ DesignerPlugin.log(e);
+ }
+ }
+ }
+ });
+ // set size
+ {
+ int textLength = getTextLength(html);
+ // horizontal hint
+ int hintH = 50;
+ if (textLength < 100) {
+ hintH = 40;
+ }
+ // vertical hint
+ int hintV = textLength / hintH + 3;
+ hintV = Math.min(hintV, 8);
+ // do set
+ GridDataFactory.create(browser).hintC(hintH, hintV);
+ }
+ // tweak size after rendering HTML
+ browser.addProgressListener(new ProgressAdapter() {
+ @Override
+ public void completed(ProgressEvent event) {
+ browser.removeProgressListener(this);
+ tweakBrowserSize(browser, heightLimitChars);
+ browser.getShell().setVisible(true);
+ }
+ });
+ // done
+ return browser;
+ }
+
+ private static void tweakBrowserSize(Browser browser, int heightLimitChars) {
+ GridDataFactory.create(browser).grab().fill();
+ // limit height
+ if (heightLimitChars != 0) {
+ PixelConverter pixelConverter = new PixelConverter(browser);
+ int maxHeight = pixelConverter.convertHeightInCharsToPixels(heightLimitChars);
+ expandShellToShowFullPage_Height(browser, maxHeight);
+ }
+ // if no limit, then show all, so make as tall as required
+ if (heightLimitChars == 0) {
+ expandShellToShowFullPage_Height(browser, Integer.MAX_VALUE);
+ }
+ }
+
+ private static void expandShellToShowFullPage_Height(Browser browser, int maxHeight) {
+ try {
+ Shell shell = browser.getShell();
+ // calculate required
+ int contentHeight;
+ {
+ getContentOffsetHeight(browser);
+ contentHeight = getContentScrollHeight(browser);
+ }
+ // apply height
+ int useHeight = Math.min(contentHeight + ((EnvironmentUtils.IS_LINUX) ? 2 : 10), maxHeight);
+ shell.setSize(shell.getSize().x, useHeight);
+ // trim height to content
+ {
+ int offsetHeight = getBodyOffsetHeight(browser);
+ int scrollHeight = getBodyScrollHeight(browser);
+ int delta = scrollHeight - offsetHeight;
+ if (delta != 0 && delta < 10) {
+ Point size = shell.getSize();
+ shell.setSize(size.x, size.y + delta + 1);
+ }
+ }
+ // trim width to content
+ {
+ int offsetWidth = getContentOffsetWidth(browser);
+ {
+ Point size = shell.getSize();
+ shell.setSize(offsetWidth + ((EnvironmentUtils.IS_MAC) ? 6 : 10), size.y);
+ }
+ }
+ // hide 'Close' if too narrow
+ if (EnvironmentUtils.IS_LINUX) {
+ if (shell.getSize().y < 30) {
+ hideCloseElement(browser);
+ }
+ }
+ } catch (Throwable e) {
+ }
+ }
+
+ private static int getContentOffsetWidth(Browser browser) throws Exception {
+ return evaluateScriptInt(
+ browser,
+ "return document.getElementById('_wbp_tooltip_body').offsetWidth;");
+ }
+
+ private static int getContentOffsetHeight(Browser browser) throws Exception {
+ return evaluateScriptInt(
+ browser,
+ "return document.getElementById('_wbp_tooltip_body').offsetHeight;");
+ }
+
+ private static int getContentScrollHeight(Browser browser) throws Exception {
+ return evaluateScriptInt(
+ browser,
+ "return document.getElementById('_wbp_tooltip_body').scrollHeight;");
+ }
+
+ private static int getBodyOffsetHeight(Browser browser) throws Exception {
+ return evaluateScriptInt(browser, "return document.body.offsetHeight;");
+ }
+
+ private static int getBodyScrollHeight(Browser browser) throws Exception {
+ return evaluateScriptInt(browser, "return document.body.scrollHeight;");
+ }
+
+ private static int evaluateScriptInt(Browser browser, String script) throws Exception {
+ Object o = ReflectionUtils.invokeMethod(browser, "evaluate(java.lang.String)", script);
+ return ((Number) o).intValue();
+ }
+
+ private static void hideCloseElement(Browser browser) throws Exception {
+ String script = "document.getElementById('_wbp_close').style.display = 'none'";
+ ReflectionUtils.invokeMethod(browser, "evaluate(java.lang.String)", script);
+ }
+
+ /**
+ * @return the length of text in given HTML. Uses internal class, so may fail, in this case
+ * returns length on HTML.
+ */
+ private static int getTextLength(String html) {
+ StringReader htmlStringReader = new StringReader(html);
+ try {
+ ClassLoader classLoader = PropertyTable.class.getClassLoader();
+ Class<?> readerClass =
+ classLoader.loadClass("org.eclipse.jface.internal.text.html.HTML2TextReader");
+ Object reader = readerClass.getConstructors()[0].newInstance(htmlStringReader, null);
+ String text = (String) ReflectionUtils.invokeMethod(reader, "getString()");
+ return text.length();
+ } catch (Throwable e) {
+ return html.length();
+ }
+ }
+
+ /**
+ * Returns a string representation of {@link Color} suitable for web pages.
+ *
+ * @param color
+ * the {@link Color} instance, not <code>null</code>.
+ * @return a string representation of {@link Color} suitable for web pages.
+ */
+ private static String getColorWebString(final Color color) {
+ String colorString = "#" + Integer.toHexString(color.getRed());
+ colorString += Integer.toHexString(color.getGreen());
+ colorString += Integer.toHexString(color.getBlue());
+ return colorString;
+ }
+
+ /**
+ * Creates {@link Label} if {@link Browser} can not be used.
+ */
+ private static Control createTooltipControl_Label(Composite parent, String html) {
+ // prepare Label
+ final Label label = new Label(parent, SWT.WRAP);
+ label.setText(html);
+ // set size
+ int requiredWidth = label.computeSize(SWT.DEFAULT, SWT.DEFAULT).x;
+ GridDataFactory.create(label).hintHC(50).hintHMin(requiredWidth);
+ // copy colors
+ label.setForeground(parent.getForeground());
+ label.setBackground(parent.getBackground());
+ // done
+ parent.getDisplay().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ Shell shell = label.getShell();
+ shell.setVisible(true);
+ }
+ });
+ return label;
+ }
+
+ private static void hideTooltip(Control tooltip) {
+ tooltip.getShell().dispose();
+ }
+
+ // Copied from CodeUtils.java: CodeUtils.getSource()
+ /**
+ * @return the source as single {@link String}, lines joined using "\n".
+ */
+ public static String getSource(String... lines) {
+ return Joiner.on('\n').join(lines);
+ }
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/table/IPropertyExceptionHandler.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/table/IPropertyExceptionHandler.java
new file mode 100644
index 0000000..879f699
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/table/IPropertyExceptionHandler.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.table;
+
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.model.property.editor.PropertyEditor;
+
+/**
+ * Handler for any {@link Exception} that happens in {@link PropertyTable}, i.e. exceptions during
+ * {@link Property} modifications using {@link PropertyEditor}'s.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.table
+ */
+public interface IPropertyExceptionHandler {
+ void handle(Throwable e);
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/table/IPropertyTooltipSite.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/table/IPropertyTooltipSite.java
new file mode 100644
index 0000000..e2fee14
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/table/IPropertyTooltipSite.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.table;
+
+/**
+ * Interface that allows control of {@link PropertyTooltipProvider} interact with
+ * {@link PropertyTableTooltipHelper}.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.table
+ */
+public interface IPropertyTooltipSite {
+ /**
+ * @return the {@link PropertyTable} of this site.
+ */
+ PropertyTable getTable();
+
+ /**
+ * Hides current tooltip.
+ */
+ void hideTooltip();
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/table/PropertyTable.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/table/PropertyTable.java
new file mode 100644
index 0000000..7a49cb3
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/table/PropertyTable.java
@@ -0,0 +1,1602 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.table;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseMoveListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.ScrollBar;
+import org.eclipse.wb.draw2d.IColorConstants;
+import org.eclipse.wb.draw2d.ICursorConstants;
+import org.eclipse.wb.internal.core.DesignerPlugin;
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.model.property.category.PropertyCategory;
+import org.eclipse.wb.internal.core.model.property.category.PropertyCategoryProvider;
+import org.eclipse.wb.internal.core.model.property.category.PropertyCategoryProviders;
+import org.eclipse.wb.internal.core.model.property.editor.PropertyEditor;
+import org.eclipse.wb.internal.core.model.property.editor.complex.IComplexPropertyEditor;
+import org.eclipse.wb.internal.core.model.property.editor.presentation.PropertyEditorPresentation;
+import org.eclipse.wb.internal.core.utils.check.Assert;
+import org.eclipse.wb.internal.core.utils.ui.DrawUtils;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Control that can display {@link Property}'s and edit them using {@link PropertyEditor}'s.
+ *
+ * @author scheglov_ke
+ * @author lobas_av
+ * @coverage core.model.property.table
+ */
+public class PropertyTable extends Canvas implements ISelectionProvider {
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Colors
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private static final Color COLOR_BACKGROUND = IColorConstants.listBackground;
+ private static final Color COLOR_NO_PROPERTIES = IColorConstants.gray;
+ private static final Color COLOR_LINE = IColorConstants.lightGray;
+ private static final Color COLOR_COMPLEX_LINE = DrawUtils.getShiftedColor(
+ IColorConstants.lightGray,
+ -32);
+ private static final Color COLOR_PROPERTY_BG = DrawUtils.getShiftedColor(COLOR_BACKGROUND, -12);
+ private static final Color COLOR_PROPERTY_BG_MODIFIED = COLOR_BACKGROUND;
+ private static final Color COLOR_PROPERTY_FG_TITLE = IColorConstants.listForeground;
+ private static final Color COLOR_PROPERTY_FG_VALUE =
+ DrawUtils.isDarkColor(IColorConstants.listBackground)
+ ? IColorConstants.lightBlue
+ : IColorConstants.darkBlue;
+ private static final Color COLOR_PROPERTY_BG_SELECTED = IColorConstants.listSelection;
+ private static final Color COLOR_PROPERTY_FG_SELECTED = IColorConstants.listSelectionText;
+ private static final Color COLOR_PROPERTY_FG_ADVANCED = IColorConstants.gray;
+ // BEGIN ADT MODIFICATIONS
+ public static final Color COLOR_PROPERTY_FG_DEFAULT = IColorConstants.darkGray;
+ // END ADT MODIFICATIONS
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Sizes
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private static final int MIN_COLUMN_WIDTH = 75;
+ private static final int MARGIN_LEFT = 2;
+ private static final int MARGIN_RIGHT = 1;
+ private static final int STATE_IMAGE_MARGIN_RIGHT = 4;
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Images
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private static final Image m_plusImage = DesignerPlugin.getImage("properties/plus.gif");
+ private static final Image m_minusImage = DesignerPlugin.getImage("properties/minus.gif");
+ private static int m_stateWidth = 9;
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Instance fields
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private final PropertyTableTooltipHelper m_tooltipHelper;
+ private boolean m_showAdvancedProperties;
+ private Property[] m_rawProperties;
+ private List<PropertyInfo> m_properties;
+ private final Set<String> m_expandedIds = Sets.newTreeSet();
+ // BEGIN ADT MODIFICATIONS
+ // Add support for "expand by default" : If you specify ids to be collapsed by
+ // default, then any *other* ids will be expanded by default.
+ private Set<String> m_collapsedIds = null;
+
+ /**
+ * Sets a set of ids that should be collapsed by default. Everything else
+ * will be expanded by default. If this method is not called, ids are
+ * collapsed by default instead.
+ *
+ * @param names set of ids to be collapsed
+ */
+ public void setDefaultCollapsedNames(Collection<String> names) {
+ m_collapsedIds = Sets.newTreeSet();
+ for (String name : names) {
+ m_collapsedIds.add("|" + name); // See PropertyInfo constructor for id syntax
+ }
+ }
+ // END ADT MODIFICATIONS
+
+ private Image m_bufferedImage;
+ private int m_rowHeight;
+ private int m_selection;
+ private int m_page;
+ private int m_splitter = -1;
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Constructor
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public PropertyTable(Composite parent, int style) {
+ super(parent, style | SWT.V_SCROLL | SWT.NO_BACKGROUND | SWT.NO_REDRAW_RESIZE);
+ hookControlEvents();
+ // calculate sizes
+ {
+ GC gc = new GC(this);
+ try {
+ m_rowHeight = 1 + gc.getFontMetrics().getHeight() + 1;
+ } finally {
+ gc.dispose();
+ }
+ }
+ // install tooltip helper
+ m_tooltipHelper = new PropertyTableTooltipHelper(this);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Events
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * Adds listeners for events.
+ */
+ private void hookControlEvents() {
+ addListener(SWT.Dispose, new Listener() {
+ @Override
+ public void handleEvent(Event event) {
+ disposeBufferedImage();
+ }
+ });
+ addListener(SWT.Resize, new Listener() {
+ @Override
+ public void handleEvent(Event event) {
+ handleResize();
+ }
+ });
+ addListener(SWT.Paint, new Listener() {
+ @Override
+ public void handleEvent(Event event) {
+ handlePaint(event.gc, event.x, event.y, event.width, event.height);
+ }
+ });
+ getVerticalBar().addListener(SWT.Selection, new Listener() {
+ @Override
+ public void handleEvent(Event event) {
+ handleVerticalScrolling();
+ }
+ });
+ addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseDown(MouseEvent event) {
+ forceFocus();
+ handleMouseDown(event);
+ }
+
+ @Override
+ public void mouseUp(MouseEvent event) {
+ handleMouseUp(event);
+ }
+
+ @Override
+ public void mouseDoubleClick(MouseEvent event) {
+ handleMouseDoubleClick(event);
+ }
+ });
+ addMouseMoveListener(new MouseMoveListener() {
+ @Override
+ public void mouseMove(MouseEvent event) {
+ handleMouseMove(event);
+ }
+ });
+ // keyboard
+ addKeyListener(new KeyAdapter() {
+ @Override
+ public void keyPressed(KeyEvent e) {
+ handleKeyDown(e);
+ }
+ });
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Events: dispose, resize, scroll
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * Disposes image used for double buffered painting.
+ */
+ private void disposeBufferedImage() {
+ if (m_bufferedImage != null) {
+ m_bufferedImage.dispose();
+ m_bufferedImage = null;
+ }
+ }
+
+ /**
+ * Handles {@link SWT#Resize} event.
+ */
+ private void handleResize() {
+ disposeBufferedImage();
+ configureScrolling();
+ // splitter
+ {
+ // set default value for splitter
+ if (m_splitter <= MIN_COLUMN_WIDTH) {
+ m_splitter = Math.max((int) (getClientArea().width * 0.4), MIN_COLUMN_WIDTH);
+ }
+ configureSplitter();
+ }
+ }
+
+ /**
+ * Handles {@link SWT#Selection} event for vertical {@link ScrollBar}.
+ */
+ private void handleVerticalScrolling() {
+ ScrollBar verticalBar = getVerticalBar();
+ if (verticalBar.getEnabled()) {
+ // update selection
+ m_selection = verticalBar.getSelection();
+ // redraw (but not include vertical bar to avoid flashing)
+ {
+ Rectangle clientArea = getClientArea();
+ redraw(clientArea.x, clientArea.y, clientArea.width, clientArea.height, false);
+ }
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Keyboard
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * Handles {@link SWT#KeyDown} event.
+ */
+ private void handleKeyDown(KeyEvent e) {
+ if (m_activePropertyInfo != null) {
+ try {
+ Property property = m_activePropertyInfo.getProperty();
+ // expand/collapse
+ if (m_activePropertyInfo.isComplex()) {
+ if (!m_activePropertyInfo.isExpanded()
+ && (e.character == '+' || e.keyCode == SWT.ARROW_RIGHT)) {
+ m_activePropertyInfo.expand();
+ configureScrolling();
+ return;
+ }
+ if (m_activePropertyInfo.isExpanded()
+ && (e.character == '-' || e.keyCode == SWT.ARROW_LEFT)) {
+ m_activePropertyInfo.collapse();
+ configureScrolling();
+ return;
+ }
+ }
+ // navigation
+ if (navigate(e)) {
+ return;
+ }
+ // editor activation
+ if (e.character == ' ' || e.character == SWT.CR) {
+ activateEditor(property, null);
+ return;
+ }
+ // DEL
+ if (e.keyCode == SWT.DEL) {
+ e.doit = false;
+ property.setValue(Property.UNKNOWN_VALUE);
+ return;
+ }
+ // send to editor
+ property.getEditor().keyDown(this, property, e);
+ } catch (Throwable ex) {
+ DesignerPlugin.log(ex);
+ }
+ }
+ }
+
+ /**
+ * @return <code>true</code> if given {@link KeyEvent} was navigation event, so new
+ * {@link PropertyInfo} was selected.
+ */
+ public boolean navigate(KeyEvent e) {
+ int index = m_properties.indexOf(m_activePropertyInfo);
+ Rectangle clientArea = getClientArea();
+ //
+ int newIndex = index;
+ if (e.keyCode == SWT.HOME) {
+ newIndex = 0;
+ } else if (e.keyCode == SWT.END) {
+ newIndex = m_properties.size() - 1;
+ } else if (e.keyCode == SWT.PAGE_UP) {
+ newIndex = Math.max(index - m_page + 1, 0);
+ } else if (e.keyCode == SWT.PAGE_DOWN) {
+ newIndex = Math.min(index + m_page - 1, m_properties.size() - 1);
+ } else if (e.keyCode == SWT.ARROW_UP) {
+ newIndex = Math.max(index - 1, 0);
+ } else if (e.keyCode == SWT.ARROW_DOWN) {
+ newIndex = Math.min(index + 1, m_properties.size() - 1);
+ }
+ // activate new property
+ if (newIndex != index && newIndex < m_properties.size()) {
+ setActivePropertyInfo(m_properties.get(newIndex));
+ // check for scrolling
+ int y = m_rowHeight * (newIndex - m_selection);
+ if (y < 0) {
+ m_selection = newIndex;
+ configureScrolling();
+ } else if (y + m_rowHeight > clientArea.height) {
+ m_selection = newIndex - m_page + 1;
+ configureScrolling();
+ }
+ // repaint
+ redraw();
+ return true;
+ }
+ // no navigation change
+ return false;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Events: mouse
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private boolean m_splitterResizing;
+ /**
+ * We do expand/collapse on to events: click on state sign and on double click. But when we double
+ * click on state sign, we will have <em>two</em> events, so we should ignore double click.
+ */
+ private long m_lastExpandCollapseTime;
+
+ /**
+ * Handles {@link SWT#MouseDown} event.
+ */
+ private void handleMouseDown(MouseEvent event) {
+ m_splitterResizing = event.button == 1 && m_properties != null && isLocationSplitter(event.x);
+ // click in property
+ if (!m_splitterResizing && m_properties != null) {
+ int propertyIndex = getPropertyIndex(event.y);
+ if (propertyIndex >= m_properties.size()) {
+ return;
+ }
+ // prepare property
+ setActivePropertyInfo(m_properties.get(propertyIndex));
+ Property property = m_activePropertyInfo.getProperty();
+ // de-activate current editor
+ deactivateEditor(true);
+ redraw();
+ // activate editor
+ if (isLocationValue(event.x)) {
+ activateEditor(property, getValueRelativeLocation(event.x, event.y));
+ }
+ }
+ }
+
+ /**
+ * Handles {@link SWT#MouseUp} event.
+ */
+ private void handleMouseUp(MouseEvent event) {
+ if (event.button == 1) {
+ // resize splitter
+ if (m_splitterResizing) {
+ m_splitterResizing = false;
+ return;
+ }
+ // if out of bounds, then ignore
+ if (!getClientArea().contains(event.x, event.y)) {
+ return;
+ }
+ // update
+ if (m_properties != null) {
+ int index = getPropertyIndex(event.y);
+ if (index < m_properties.size()) {
+ PropertyInfo propertyInfo = m_properties.get(index);
+ // check for expand/collapse
+ if (isLocationState(propertyInfo, event.x)) {
+ try {
+ m_lastExpandCollapseTime = System.currentTimeMillis();
+ propertyInfo.flip();
+ configureScrolling();
+ } catch (Throwable e) {
+ DesignerPlugin.log(e);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Handles {@link SWT#MouseDoubleClick} event.
+ */
+ private void handleMouseDoubleClick(MouseEvent event) {
+ if (System.currentTimeMillis() - m_lastExpandCollapseTime > getDisplay().getDoubleClickTime()) {
+ try {
+ if (m_activePropertyInfo != null) {
+ if (m_activePropertyInfo.isComplex()) {
+ m_activePropertyInfo.flip();
+ configureScrolling();
+ } else {
+ Property property = m_activePropertyInfo.getProperty();
+ property.getEditor().doubleClick(property, getValueRelativeLocation(event.x, event.y));
+ }
+ }
+ } catch (Throwable e) {
+ handleException(e);
+ }
+ }
+ }
+
+ /**
+ * Handles {@link SWT#MouseMove} event.
+ */
+ private void handleMouseMove(MouseEvent event) {
+ int x = event.x;
+ // resize splitter
+ if (m_splitterResizing) {
+ m_splitter = x;
+ configureSplitter();
+ redraw();
+ return;
+ }
+ // if out of bounds, then ignore
+ if (!getClientArea().contains(event.x, event.y)) {
+ return;
+ }
+ // update
+ if (m_properties != null) {
+ // update cursor
+ if (isLocationSplitter(x)) {
+ setCursor(ICursorConstants.SIZEWE);
+ } else {
+ setCursor(null);
+ }
+ // update tooltip helper
+ updateTooltip(event);
+ } else {
+ updateTooltipNoProperty();
+ }
+ }
+
+ /**
+ * Updates {@link PropertyTableTooltipHelper}.
+ */
+ private void updateTooltip(MouseEvent event) {
+ int x = event.x;
+ int propertyIndex = getPropertyIndex(event.y);
+ //
+ if (propertyIndex < m_properties.size()) {
+ PropertyInfo propertyInfo = m_properties.get(propertyIndex);
+ Property property = propertyInfo.getProperty();
+ int y = (propertyIndex - m_selection) * m_rowHeight;
+ // check for title
+ {
+ int titleX = getTitleTextX(propertyInfo);
+ int titleRight = m_splitter - 2;
+ if (titleX <= x && x < titleRight) {
+ m_tooltipHelper.update(property, true, false, titleX, titleRight, y, m_rowHeight);
+ return;
+ }
+ }
+ // check for value
+ {
+ int valueX = m_splitter + 3;
+ if (x > valueX) {
+ m_tooltipHelper.update(
+ property,
+ false,
+ true,
+ valueX,
+ getClientArea().width,
+ y,
+ m_rowHeight);
+ }
+ }
+ } else {
+ updateTooltipNoProperty();
+ }
+ }
+
+ private void updateTooltipNoProperty() {
+ m_tooltipHelper.update(null, false, false, 0, 0, 0, 0);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Editor
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private PropertyInfo m_activePropertyInfo;
+ private String m_activePropertyId;
+ private PropertyEditor m_activeEditor;
+
+ /**
+ * Tries to activate editor for {@link PropertyInfo} under cursor.
+ *
+ * @param location
+ * the mouse location, if editor is activated using mouse click, or <code>null</code> if
+ * it is activated using keyboard.
+ */
+ public void activateEditor(Property property, Point location) {
+ try {
+ // de-activate old editor
+ deactivateEditor(true);
+ // activate editor
+ PropertyEditor editor = property.getEditor();
+ try {
+ if (editor.activate(this, property, location)) {
+ m_activeEditor = editor;
+ }
+ } catch (Throwable e) {
+ handleException(e);
+ }
+ // set bounds
+ setActiveEditorBounds();
+ } catch (Throwable e) {
+ DesignerPlugin.log(e);
+ }
+ }
+
+ /**
+ * Deactivates current {@link PropertyEditor}.
+ */
+ public void deactivateEditor(boolean save) {
+ if (m_activeEditor != null) {
+ PropertyEditor activeEditor = m_activeEditor;
+ m_activeEditor = null;
+ if (m_activePropertyInfo != null && m_activePropertyInfo.m_property != null) {
+ activeEditor.deactivate(this, m_activePropertyInfo.m_property, save);
+ }
+ }
+ }
+
+ /**
+ * Sets correct bounds for active editor, for example we need update bounds after scrolling.
+ */
+ private void setActiveEditorBounds() {
+ if (m_activeEditor != null) {
+ int index = m_properties.indexOf(m_activePropertyInfo);
+ if (index == -1) {
+ // it is possible that active property was hidden because its parent was collapsed
+ deactivateEditor(true);
+ } else {
+ // prepare bounds for editor
+ Rectangle bounds;
+ {
+ Rectangle clientArea = getClientArea();
+ int x = m_splitter + 1;
+ int width = clientArea.width - x - MARGIN_RIGHT;
+ int y = m_rowHeight * (index - m_selection) + 1;
+ int height = m_rowHeight - 1;
+ bounds = new Rectangle(x, y, width, height);
+ }
+ // update bounds using presentation
+ {
+ PropertyEditorPresentation presentation = m_activeEditor.getPresentation();
+ if (presentation != null) {
+ int presentationWidth =
+ presentation.show(
+ this,
+ m_activePropertyInfo.m_property,
+ bounds.x,
+ bounds.y,
+ bounds.width,
+ bounds.height);
+ bounds.width -= presentationWidth;
+ }
+ }
+ // set editor bounds
+ m_activeEditor.setBounds(bounds);
+ }
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Exceptions
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private IPropertyExceptionHandler m_exceptionHandler;
+
+ /**
+ * Sets {@link IPropertyExceptionHandler} for handling all exceptions.
+ */
+ public void setExceptionHandler(IPropertyExceptionHandler exceptionHandler) {
+ m_exceptionHandler = exceptionHandler;
+ }
+
+ /**
+ * Handles given {@link Throwable}.<br>
+ * Right now it just logs it, but in future we can open some dialog here.
+ */
+ public void handleException(Throwable e) {
+ m_exceptionHandler.handle(e);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Scrolling
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * Configures vertical {@link ScrollBar}.
+ */
+ private void configureScrolling() {
+ ScrollBar verticalBar = getVerticalBar();
+ if (m_properties == null) {
+ verticalBar.setEnabled(false);
+ } else {
+ m_page = getClientArea().height / m_rowHeight;
+ m_selection = Math.max(0, Math.min(m_properties.size() - m_page, m_selection));
+ verticalBar.setValues(m_selection, 0, m_properties.size(), m_page, 1, m_page);
+ // enable/disable scrolling
+ if (m_properties.size() <= m_page) {
+ verticalBar.setEnabled(false);
+ } else {
+ verticalBar.setEnabled(true);
+ }
+ }
+ // redraw, we reconfigure scrolling only if list of properties was changed, so we should redraw
+ redraw();
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Location/size utils
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * @return the <code>X</code> position for first pixel of {@link PropertyInfo} title (location of
+ * state image).
+ */
+ private int getTitleX(PropertyInfo propertyInfo) {
+ return MARGIN_LEFT + getLevelIndent() * propertyInfo.getLevel();
+ }
+
+ /**
+ * @return the <code>X</code> position for first pixel of {@link PropertyInfo} title text.
+ */
+ private int getTitleTextX(PropertyInfo propertyInfo) {
+ return getTitleX(propertyInfo) + getLevelIndent();
+ }
+
+ /**
+ * @return the indentation for single level.
+ */
+ private int getLevelIndent() {
+ return m_stateWidth + STATE_IMAGE_MARGIN_RIGHT;
+ }
+
+ /**
+ * Checks horizontal splitter value to boundary values.
+ */
+ private void configureSplitter() {
+ Rectangle clientArea = getClientArea();
+ // check title width
+ if (m_splitter < MIN_COLUMN_WIDTH) {
+ m_splitter = MIN_COLUMN_WIDTH;
+ }
+ // check value width
+ if (clientArea.width - m_splitter < MIN_COLUMN_WIDTH) {
+ m_splitter = clientArea.width - MIN_COLUMN_WIDTH;
+ }
+ }
+
+ /**
+ * @return the index in {@link #m_properties} corresponding given <code>y</code> location.
+ */
+ private int getPropertyIndex(int y) {
+ return m_selection + y / m_rowHeight;
+ }
+
+ /**
+ * @return <code>true</code> if given <code>x</code> coordinate is on state (plus/minus) image.
+ */
+ private boolean isLocationState(PropertyInfo propertyInfo, int x) {
+ int levelX = getTitleX(propertyInfo);
+ return propertyInfo.isComplex() && levelX <= x && x <= levelX + m_stateWidth;
+ }
+
+ /**
+ * Returns <code>true</code> if <code>x</code> coordinate is on splitter.
+ */
+ private boolean isLocationSplitter(int x) {
+ return Math.abs(m_splitter - x) < 2;
+ }
+
+ /**
+ * @return <code>true</code> if given <code>x</code> is on value part of property.
+ */
+ private boolean isLocationValue(int x) {
+ return x > m_splitter + 2;
+ }
+
+ /**
+ * @param x
+ * the {@link PropertyTable} relative coordinate.
+ * @param y
+ * the {@link PropertyTable} relative coordinate.
+ *
+ * @return the location relative to the value part of property.
+ */
+ private Point getValueRelativeLocation(int x, int y) {
+ return new Point(x - (m_splitter + 2), y - m_rowHeight * getPropertyIndex(y));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Access
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * Shows or hides {@link Property}-s with {@link PropertyCategory#ADVANCED}.
+ */
+ public void setShowAdvancedProperties(boolean showAdvancedProperties) {
+ m_showAdvancedProperties = showAdvancedProperties;
+ setInput0();
+ }
+
+ /**
+ * Sets the array of {@link Property}'s to display/edit.
+ */
+ public void setInput(Property[] properties) {
+ m_rawProperties = properties;
+ setInput0();
+ }
+
+ private void setInput0() {
+ // send "hide" to all PropertyEditorPresentation's
+ if (m_properties != null) {
+ for (PropertyInfo propertyInfo : m_properties) {
+ Property property = propertyInfo.getProperty();
+ // hide presentation
+ {
+ PropertyEditorPresentation presentation = property.getEditor().getPresentation();
+ if (presentation != null) {
+ presentation.hide(this, property);
+ }
+ }
+ }
+ }
+ // set new properties
+ if (m_rawProperties == null || m_rawProperties.length == 0) {
+ deactivateEditor(false);
+ m_properties = Lists.newArrayList();
+ } else {
+ try {
+ // add PropertyInfo for each Property
+ m_properties = Lists.newArrayList();
+ for (Property property : m_rawProperties) {
+ if (rawProperties_shouldShow(property)) {
+ PropertyInfo propertyInfo = new PropertyInfo(property);
+ m_properties.add(propertyInfo);
+ }
+ }
+ // expand properties using history
+ while (true) {
+ boolean expanded = false;
+ List<PropertyInfo> currentProperties = Lists.newArrayList(m_properties);
+ for (PropertyInfo propertyInfo : currentProperties) {
+ expanded |= propertyInfo.expandFromHistory();
+ }
+ // stop
+ if (!expanded) {
+ break;
+ }
+ }
+ } catch (Throwable e) {
+ DesignerPlugin.log(e);
+ }
+ }
+ // update active property
+ if (m_activePropertyId != null) {
+ PropertyInfo newActivePropertyInfo = null;
+ // try to find corresponding PropertyInfo
+ if (m_properties != null) {
+ for (PropertyInfo propertyInfo : m_properties) {
+ if (propertyInfo.m_id.equals(m_activePropertyId)) {
+ newActivePropertyInfo = propertyInfo;
+ break;
+ }
+ }
+ }
+ // set new PropertyInfo
+ setActivePropertyInfo(newActivePropertyInfo);
+ }
+ // update scroll bar
+ configureScrolling();
+ }
+
+ /**
+ * @return <code>true</code> if given {@link Property} should be displayed.
+ */
+ private boolean rawProperties_shouldShow(Property property) throws Exception {
+ PropertyCategory category = getCategory(property);
+ // filter out hidden properties
+ if (category.isHidden()) {
+ return false;
+ }
+ // filter out advanced properties
+ if (category.isAdvanced()) {
+ if (!m_showAdvancedProperties && !property.isModified()) {
+ return false;
+ }
+ }
+ if (category.isAdvancedReally()) {
+ return m_showAdvancedProperties;
+ }
+ // OK
+ return true;
+ }
+
+ /**
+ * Activates given {@link Property}.
+ */
+ public void setActiveProperty(Property property) {
+ for (PropertyInfo propertyInfo : m_properties) {
+ if (propertyInfo.m_property == property) {
+ setActivePropertyInfo(propertyInfo);
+ break;
+ }
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Access: only for testing
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * @return the count of properties in "expanded" list.
+ */
+ public int forTests_getPropertiesCount() {
+ return m_properties.size();
+ }
+
+ /**
+ * @return the {@link Property} from "expanded" list.
+ */
+ public Property forTests_getProperty(int index) {
+ return m_properties.get(index).getProperty();
+ }
+
+ /**
+ * Expands the {@link PropertyInfo} with given index.
+ */
+ public void forTests_expand(int index) throws Exception {
+ m_properties.get(index).expand();
+ }
+
+ /**
+ * @return the position of splitter.
+ */
+ public int forTests_getSplitter() {
+ return m_splitter;
+ }
+
+ /**
+ * @return the location of state image (plus/minus) for given {@link Property}.
+ */
+ public Point forTests_getStateLocation(Property property) {
+ PropertyInfo propertyInfo = getPropertyInfo(property);
+ if (propertyInfo != null) {
+ int index = m_properties.indexOf(propertyInfo);
+ int x = getTitleX(propertyInfo);
+ int y = m_rowHeight * (index - m_selection) + 1;
+ return new Point(x, y);
+ }
+ return null;
+ }
+
+ /**
+ * @return the location of state image (plus/minus) for given {@link Property}.
+ */
+ public Point forTests_getValueLocation(Property property) {
+ PropertyInfo propertyInfo = getPropertyInfo(property);
+ if (propertyInfo != null) {
+ int index = m_properties.indexOf(propertyInfo);
+ int x = m_splitter + 5;
+ int y = m_rowHeight * (index - m_selection) + 1;
+ return new Point(x, y);
+ }
+ return null;
+ }
+
+ /**
+ * @return the active {@link PropertyEditor}.
+ */
+ public PropertyEditor forTests_getActiveEditor() {
+ return m_activeEditor;
+ }
+
+ /**
+ * @return the {@link PropertyCategory} that is used by this {@link PropertyTable} to display.
+ */
+ public PropertyCategory forTests_getCategory(Property property) {
+ return getCategory(property);
+ }
+
+ /**
+ * @return the {@link PropertyInfo}for given {@link Property}.
+ */
+ private PropertyInfo getPropertyInfo(Property property) {
+ for (PropertyInfo propertyInfo : m_properties) {
+ if (propertyInfo.getProperty() == property) {
+ return propertyInfo;
+ }
+ }
+ return null;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // ISelectionProvider
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private final List<ISelectionChangedListener> m_selectionListeners = Lists.newArrayList();
+
+ @Override
+public void addSelectionChangedListener(ISelectionChangedListener listener) {
+ if (!m_selectionListeners.contains(listener)) {
+ m_selectionListeners.add(listener);
+ }
+ }
+
+ @Override
+public void removeSelectionChangedListener(ISelectionChangedListener listener) {
+ m_selectionListeners.add(listener);
+ }
+
+ @Override
+public ISelection getSelection() {
+ if (m_activePropertyInfo != null) {
+ return new StructuredSelection(m_activePropertyInfo.getProperty());
+ } else {
+ return StructuredSelection.EMPTY;
+ }
+ }
+
+ @Override
+ public void setSelection(ISelection selection) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Sets the new active {@link PropertyInfo} and sends event to {@link ISelectionChangedListener}
+ * 's.
+ */
+ private void setActivePropertyInfo(PropertyInfo activePropertyInfo) {
+ m_activePropertyInfo = activePropertyInfo;
+ // update m_activePropertyId only when really select property,
+ // not just remove selection because there are no corresponding property for old active
+ // so, later for some other component, if we don't select other property, old active will be selected
+ if (m_activePropertyInfo != null) {
+ m_activePropertyId = m_activePropertyInfo.m_id;
+ }
+ // make sure that active property is visible
+ if (m_activePropertyInfo != null) {
+ int row = m_properties.indexOf(m_activePropertyInfo);
+ if (m_selection <= row && row < m_selection + m_page) {
+ } else {
+ m_selection = row;
+ configureScrolling();
+ }
+ }
+ // send events
+ SelectionChangedEvent selectionEvent = new SelectionChangedEvent(this, getSelection());
+ for (ISelectionChangedListener listener : m_selectionListeners) {
+ listener.selectionChanged(selectionEvent);
+ }
+ // re-draw
+ redraw();
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Painting
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private boolean m_painting;
+ private Font m_baseFont;
+ private Font m_boldFont;
+ private Font m_italicFont;
+
+ /**
+ * Handles {@link SWT#Paint} event.
+ */
+ private void handlePaint(GC gc, int x, int y, int width, int height) {
+ // sometimes we disable Eclipse Shell to prevent user actions, but we do this for short time
+ if (!isEnabled()) {
+ return;
+ }
+ // prevent recursion
+ if (m_painting) {
+ return;
+ }
+ m_painting = true;
+ //
+ try {
+ setActiveEditorBounds();
+ // prepare buffered image
+ if (m_bufferedImage == null || m_bufferedImage.isDisposed()) {
+ Point size = getSize();
+ m_bufferedImage = new Image(DesignerPlugin.getStandardDisplay(), size.x, size.y);
+ }
+ // prepare buffered GC
+ GC bufferedGC = null;
+ try {
+ // perform some drawing
+ {
+ bufferedGC = new GC(m_bufferedImage);
+ bufferedGC.setClipping(x, y, width, height);
+ bufferedGC.setBackground(gc.getBackground());
+ bufferedGC.setForeground(gc.getForeground());
+ bufferedGC.setFont(gc.getFont());
+ bufferedGC.setLineStyle(gc.getLineStyle());
+ bufferedGC.setLineWidth(gc.getLineWidth());
+ }
+ // fill client area
+ {
+ Rectangle clientArea = getClientArea();
+ bufferedGC.setBackground(COLOR_BACKGROUND);
+ bufferedGC.fillRectangle(clientArea);
+ }
+ // draw content
+ if (m_properties == null || m_properties.size() == 0) {
+ drawEmptyContent(bufferedGC);
+ } else {
+ drawContent(bufferedGC);
+ }
+ } finally {
+ // flush image
+ if (bufferedGC != null) {
+ bufferedGC.dispose();
+ }
+ }
+ gc.drawImage(m_bufferedImage, 0, 0);
+ } finally {
+ m_painting = false;
+ }
+ }
+
+ /**
+ * Draws content when there are no properties.
+ */
+ private void drawEmptyContent(GC gc) {
+ Rectangle area = getClientArea();
+ // draw message
+ gc.setForeground(COLOR_NO_PROPERTIES);
+ DrawUtils.drawStringCHCV(
+ gc,
+ "<No properties>",
+ 0,
+ 0,
+ area.width,
+ area.height);
+ }
+
+ /**
+ * Draws all {@link PropertyInfo}'s, separators, etc.
+ */
+ private void drawContent(GC gc) {
+ Rectangle clientArea = getClientArea();
+ // prepare fonts
+ m_baseFont = gc.getFont();
+ m_boldFont = DrawUtils.getBoldFont(m_baseFont);
+ m_italicFont = DrawUtils.getItalicFont(m_baseFont);
+ // show presentations
+ int[] presentationsWidth = showPresentations(clientArea);
+ // draw properties
+ {
+ int y = clientArea.y - m_rowHeight * m_selection;
+ for (int i = 0; i < m_properties.size(); i++) {
+ // skip, if not visible yet
+ if (y + m_rowHeight < 0) {
+ y += m_rowHeight;
+ continue;
+ }
+ // stop, if already invisible
+ if (y > clientArea.height) {
+ break;
+ }
+ // draw single property
+ {
+ PropertyInfo propertyInfo = m_properties.get(i);
+ drawProperty(gc, propertyInfo, y + 1, m_rowHeight - 1, clientArea.width
+ - presentationsWidth[i]);
+ y += m_rowHeight;
+ }
+ // draw row separator
+ gc.setForeground(COLOR_LINE);
+ gc.drawLine(0, y, clientArea.width, y);
+ }
+ }
+ // draw expand line
+ drawExpandLines(gc, clientArea);
+ // draw rectangle around table
+ gc.setForeground(COLOR_LINE);
+ gc.drawRectangle(0, 0, clientArea.width - 1, clientArea.height - 1);
+ // draw splitter
+ gc.setForeground(COLOR_LINE);
+ gc.drawLine(m_splitter, 0, m_splitter, clientArea.height);
+ // dispose font
+ m_boldFont.dispose();
+ m_italicFont.dispose();
+ }
+
+ /**
+ * Shows {@link PropertyEditorPresentation}'s for all {@link Property}'s, i.e. updates also their
+ * bounds. So, some {@link PropertyEditorPresentation}'s become invisible because they are moved
+ * above or below visible client area.
+ *
+ * @return the array of width for each {@link PropertyEditorPresentation}'s, consumed on the
+ * right.
+ */
+ private int[] showPresentations(Rectangle clientArea) {
+ int[] presentationsWidth = new int[m_properties.size()];
+ // prepare value rectangle
+ int x = m_splitter + 4;
+ int w = clientArea.width - x - MARGIN_RIGHT;
+ // show presentation's for all properties
+ int y = clientArea.y - m_rowHeight * m_selection;
+ for (int i = 0; i < m_properties.size(); i++) {
+ PropertyInfo propertyInfo = m_properties.get(i);
+ Property property = propertyInfo.getProperty();
+ PropertyEditorPresentation presentation = property.getEditor().getPresentation();
+ if (presentation != null) {
+ presentationsWidth[i] = presentation.show(this, property, x, y + 1, w, m_rowHeight - 1);
+ }
+ y += m_rowHeight;
+ }
+ return presentationsWidth;
+ }
+
+ /**
+ * Draws lines from expanded complex property to its last sub-property.
+ */
+ private void drawExpandLines(GC gc, Rectangle clientArea) {
+ int height = m_rowHeight - 1;
+ int xOffset = m_plusImage.getBounds().width / 2;
+ int yOffset = (height - m_plusImage.getBounds().width) / 2;
+ //
+ int y = clientArea.y - m_selection * m_rowHeight;
+ gc.setForeground(COLOR_COMPLEX_LINE);
+ for (int i = 0; i < m_properties.size(); i++) {
+ PropertyInfo propertyInfo = m_properties.get(i);
+ //
+ if (propertyInfo.isExpanded()) {
+ int index = m_properties.indexOf(propertyInfo);
+ // prepare index of last sub-property
+ int index2 = index;
+ for (; index2 < m_properties.size(); index2++) {
+ PropertyInfo nextPropertyInfo = m_properties.get(index2);
+ if (nextPropertyInfo != propertyInfo
+ && nextPropertyInfo.getLevel() <= propertyInfo.getLevel()) {
+ break;
+ }
+ }
+ index2--;
+ // draw line if there are children
+ if (index2 > index) {
+ int x = getTitleX(propertyInfo) + xOffset;
+ int y1 = y + height - yOffset;
+ int y2 = y + m_rowHeight * (index2 - index) + m_rowHeight / 2;
+ gc.drawLine(x, y1, x, y2);
+ gc.drawLine(x, y2, x + m_rowHeight / 3, y2);
+ }
+ }
+ //
+ y += m_rowHeight;
+ }
+ }
+
+ /**
+ * Draws single {@link PropertyInfo} in specified rectangle.
+ */
+ private void drawProperty(GC gc, PropertyInfo propertyInfo, int y, int height, int width) {
+ // remember colors
+ Color oldBackground = gc.getBackground();
+ Color oldForeground = gc.getForeground();
+ // draw property
+ try {
+ Property property = propertyInfo.getProperty();
+ boolean isActiveProperty =
+ m_activePropertyInfo != null && m_activePropertyInfo.getProperty() == property;
+ // set background
+ boolean modified = property.isModified();
+ {
+ if (isActiveProperty) {
+ gc.setBackground(COLOR_PROPERTY_BG_SELECTED);
+ } else {
+ if (modified) {
+ gc.setBackground(COLOR_PROPERTY_BG_MODIFIED);
+ } else {
+ gc.setBackground(COLOR_PROPERTY_BG);
+ }
+ }
+ gc.fillRectangle(0, y, width, height);
+ }
+ // draw state image
+ if (propertyInfo.isShowComplex()) {
+ Image stateImage = propertyInfo.isExpanded() ? m_minusImage : m_plusImage;
+ DrawUtils.drawImageCV(gc, stateImage, getTitleX(propertyInfo), y, height);
+ }
+ // draw title
+ {
+ // configure GC
+ {
+ gc.setForeground(COLOR_PROPERTY_FG_TITLE);
+ // check category
+ if (getCategory(property).isAdvanced()) {
+ gc.setForeground(COLOR_PROPERTY_FG_ADVANCED);
+ gc.setFont(m_italicFont);
+ } else if (getCategory(property).isPreferred() || getCategory(property).isSystem()) {
+ gc.setFont(m_boldFont);
+ }
+ // check for active
+ if (isActiveProperty) {
+ gc.setForeground(COLOR_PROPERTY_FG_SELECTED);
+ }
+ }
+ // paint title
+ int x = getTitleTextX(propertyInfo);
+ DrawUtils.drawStringCV(gc, property.getTitle(), x, y, m_splitter - x, height);
+ }
+ // draw value
+ {
+ // configure GC
+ gc.setFont(m_baseFont);
+ if (!isActiveProperty) {
+ gc.setForeground(COLOR_PROPERTY_FG_VALUE);
+ }
+ // prepare value rectangle
+ int x = m_splitter + 4;
+ int w = width - x - MARGIN_RIGHT;
+ // paint value
+
+ // BEGIN ADT MODIFICATIONS
+ if (!modified) {
+ gc.setForeground(COLOR_PROPERTY_FG_DEFAULT);
+ }
+ // END ADT MODIFICATIONS
+
+ property.getEditor().paint(property, gc, x, y, w, height);
+ }
+ } catch (Throwable e) {
+ DesignerPlugin.log(e);
+ } finally {
+ // restore colors
+ gc.setBackground(oldBackground);
+ gc.setForeground(oldForeground);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // PropertyCategory
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private PropertyCategoryProvider m_propertyCategoryProvider =
+ PropertyCategoryProviders.fromProperty();
+
+ /**
+ * Sets the {@link PropertyCategoryProvider} that can be used to tweak usual
+ * {@link PropertyCategory}.
+ */
+ public void setPropertyCategoryProvider(PropertyCategoryProvider propertyCategoryProvider) {
+ m_propertyCategoryProvider = propertyCategoryProvider;
+ }
+
+ /**
+ * @return the {@link PropertyCategory} that is used by this {@link PropertyTable} to display.
+ */
+ private PropertyCategory getCategory(Property property) {
+ return m_propertyCategoryProvider.getCategory(property);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // PropertyInfo
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * Class with information about single {@link Property}.
+ *
+ * @author scheglov_ke
+ */
+ private final class PropertyInfo {
+ private final String m_id;
+ private final int m_level;
+ private final Property m_property;
+ private final boolean m_stateComplex;
+ private boolean m_stateExpanded;
+ private List<PropertyInfo> m_children;
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Constructor
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public PropertyInfo(Property property) {
+ this(property, "", 0);
+ }
+
+ private PropertyInfo(Property property, String idPrefix, int level) {
+ // BEGIN ADT MODIFICATIONS
+ //m_id = idPrefix + "|" + property.getTitle();
+ m_id = idPrefix + "|" + property.getName();
+ // END ADT MODIFICATIONS
+ m_level = level;
+ m_property = property;
+ m_stateComplex = property.getEditor() instanceof IComplexPropertyEditor;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // State
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * @return <code>true</code> if this property is complex.
+ */
+ public boolean isComplex() {
+ return m_stateComplex;
+ }
+
+ public boolean isShowComplex() throws Exception {
+ if (m_stateComplex) {
+ prepareChildren();
+ return m_children != null && !m_children.isEmpty();
+ }
+ return false;
+ }
+
+ /**
+ * @return <code>true</code> if this complex property is expanded.
+ */
+ public boolean isExpanded() {
+ return m_stateExpanded;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Access
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * @return the level of this property, i.e. on which level of complex property it is located.
+ */
+ public int getLevel() {
+ return m_level;
+ }
+
+ /**
+ * @return the {@link Property}.
+ */
+ public Property getProperty() {
+ return m_property;
+ }
+
+ /**
+ * Flips collapsed/expanded state and adds/removes sub-properties.
+ */
+ public void flip() throws Exception {
+ Assert.isTrue(m_stateComplex);
+ if (m_stateExpanded) {
+ collapse();
+ } else {
+ expand();
+ }
+ }
+
+ /**
+ * Expands this property.
+ */
+ public void expand() throws Exception {
+ Assert.isTrue(m_stateComplex);
+ Assert.isTrue(!m_stateExpanded);
+ //
+ m_stateExpanded = true;
+ m_expandedIds.add(m_id);
+ // BEGIN ADT MODIFICATIONS
+ if (m_collapsedIds != null) {
+ m_collapsedIds.remove(m_id);
+ }
+ // END ADT MODIFICATIONS
+ prepareChildren();
+ //
+ int index = m_properties.indexOf(this);
+ addChildren(index + 1);
+ }
+
+ /**
+ * Collapses this property.
+ */
+ public void collapse() throws Exception {
+ Assert.isTrue(m_stateComplex);
+ Assert.isTrue(m_stateExpanded);
+ //
+ m_stateExpanded = false;
+ m_expandedIds.remove(m_id);
+ // BEGIN ADT MODIFICATIONS
+ if (m_collapsedIds != null) {
+ m_collapsedIds.add(m_id);
+ }
+ // END ADT MODIFICATIONS
+ prepareChildren();
+ //
+ int index = m_properties.indexOf(this);
+ removeChildren(index + 1);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Internal
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * Adds children properties.
+ *
+ * @return the index for new properties to add.
+ */
+ private int addChildren(int index) throws Exception {
+ prepareChildren();
+ for (PropertyInfo child : m_children) {
+ // skip if should not display raw Property
+ if (!rawProperties_shouldShow(child.m_property)) {
+ continue;
+ }
+ // add child
+ m_properties.add(index++, child);
+ // add children of current child
+ if (child.isExpanded()) {
+ index = child.addChildren(index);
+ }
+ }
+ return index;
+ }
+
+ /**
+ * Removes children properties.
+ */
+ private void removeChildren(int index) throws Exception {
+ prepareChildren();
+ for (PropertyInfo child : m_children) {
+ // skip if should not display raw Property
+ if (!rawProperties_shouldShow(child.m_property)) {
+ continue;
+ }
+ // hide presentation
+ {
+ PropertyEditorPresentation presentation =
+ child.getProperty().getEditor().getPresentation();
+ if (presentation != null) {
+ presentation.hide(PropertyTable.this, child.getProperty());
+ }
+ }
+ // remove child
+ m_properties.remove(index);
+ // remove children of current child
+ if (child.isExpanded()) {
+ child.removeChildren(index);
+ }
+ }
+ }
+
+ /**
+ * Prepares children {@link PropertyInfo}'s, for sub-properties.
+ */
+ private void prepareChildren() throws Exception {
+ if (m_children == null) {
+ m_children = Lists.newArrayList();
+ for (Property subProperty : getSubProperties()) {
+ PropertyInfo subPropertyInfo = createSubPropertyInfo(subProperty);
+ m_children.add(subPropertyInfo);
+ }
+ }
+ }
+
+ private PropertyInfo createSubPropertyInfo(Property subProperty) {
+ return new PropertyInfo(subProperty, m_id, m_level + 1);
+ }
+
+ private Property[] getSubProperties() throws Exception {
+ IComplexPropertyEditor complexEditor = (IComplexPropertyEditor) m_property.getEditor();
+ List<Property> subProperties = Lists.newArrayList();
+ for (Property subProperty : complexEditor.getProperties(m_property)) {
+ if (getCategory(subProperty).isHidden() && !subProperty.isModified()) {
+ // skip hidden properties
+ continue;
+ }
+ subProperties.add(subProperty);
+ }
+ return subProperties.toArray(new Property[subProperties.size()]);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Persistent expanding support
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * @return <code>true</code> if this {@link PropertyInfo} was expanded from history.
+ */
+ public boolean expandFromHistory() throws Exception {
+ if (isComplex() && !isExpanded() && m_expandedIds.contains(m_id)) {
+ expand();
+ return true;
+ }
+ // BEGIN ADT MODIFICATIONS
+ if (m_collapsedIds != null && isComplex() && !isExpanded()
+ && !m_collapsedIds.contains(m_id)) {
+ expand();
+ return true;
+ }
+ // END ADT MODIFICATIONS
+ return false;
+ }
+ }
+
+ // BEGIN ADT MODIFICATIONS
+ /** Collapse all top-level properties */
+ public void collapseAll() {
+ try {
+ m_lastExpandCollapseTime = System.currentTimeMillis();
+ if (m_collapsedIds != null) {
+ m_collapsedIds.addAll(m_expandedIds);
+ }
+ m_expandedIds.clear();
+ setInput(m_rawProperties);
+ redraw();
+ } catch (Throwable e) {
+ DesignerPlugin.log(e);
+ }
+ }
+
+ /** Expand all top-level properties */
+ public void expandAll() {
+ try {
+ m_lastExpandCollapseTime = System.currentTimeMillis();
+ if (m_collapsedIds != null) {
+ m_collapsedIds.clear();
+ }
+ m_expandedIds.clear();
+ for (PropertyInfo info : m_properties) {
+ if (info.m_stateComplex) {
+ m_expandedIds.add(info.m_id);
+ }
+ }
+ setInput(m_rawProperties);
+ redraw();
+ } catch (Throwable e) {
+ DesignerPlugin.log(e);
+ }
+ }
+ // END ADT MODIFICATIONS
+} \ No newline at end of file
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/table/PropertyTableTooltipHelper.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/table/PropertyTableTooltipHelper.java
new file mode 100644
index 0000000..16b9d8f
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/table/PropertyTableTooltipHelper.java
@@ -0,0 +1,191 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.table;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.wb.internal.core.EnvironmentUtils;
+import org.eclipse.wb.internal.core.model.property.Property;
+import org.eclipse.wb.internal.core.utils.ui.GridLayoutFactory;
+
+/**
+ * Helper class for displaying tooltips.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.table
+ */
+class PropertyTableTooltipHelper implements IPropertyTooltipSite {
+ private final PropertyTable m_table;
+ private Shell m_tooltip;
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Constructor
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public PropertyTableTooltipHelper(PropertyTable table) {
+ m_table = table;
+ m_table.addListener(SWT.MouseHover, new Listener() {
+ @Override
+ public void handleEvent(Event event) {
+ if (event.stateMask == 0) {
+ showTooltip();
+ }
+ }
+ });
+ m_table.addListener(SWT.MouseExit, new Listener() {
+ @Override
+ public void handleEvent(Event event) {
+ // check, may be cursor is now on tooltip, so ignore this MouseExit
+ {
+ Control control = Display.getCurrent().getCursorControl();
+ while (control != null) {
+ if (control == m_tooltip) {
+ return;
+ }
+ control = control.getParent();
+ }
+ }
+ // no, we should hide tooltip
+ hideTooltip();
+ }
+ });
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Access
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private Property m_property;
+ private boolean m_onTitle;
+ private boolean m_onValue;
+ private int m_beginX;
+ private int m_endX;
+ private int m_y;
+ private int m_rowHeight;
+
+ /**
+ * {@link PropertyTable} call this method to inform that cursor location was changed.
+ */
+ public void update(Property property,
+ boolean onTitle,
+ boolean onValue,
+ int beginX,
+ int endX,
+ int y,
+ int rowHeight) {
+ m_property = property;
+ m_onTitle = onTitle;
+ m_onValue = onValue;
+ m_beginX = beginX;
+ m_endX = endX;
+ m_y = y;
+ m_rowHeight = rowHeight;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // IPropertyTooltipSite
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+public PropertyTable getTable() {
+ return m_table;
+ }
+
+ @Override
+public void hideTooltip() {
+ if (m_tooltip != null && !m_tooltip.isDisposed()) {
+ m_tooltip.dispose();
+ }
+ m_tooltip = null;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Showing tooltip
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private void showTooltip() {
+ hideTooltip();
+ // check for property
+ if (m_property == null) {
+ return;
+ }
+ //
+ if (m_onTitle) {
+ showTooltip(m_property.getAdapter(PropertyTooltipProvider.class), m_beginX, m_endX);
+ }
+ if (m_onValue) {
+ showTooltip(m_property.getEditor().getAdapter(PropertyTooltipProvider.class),
+ m_beginX, m_endX);
+ }
+ }
+
+ private void showTooltip(PropertyTooltipProvider provider, int startX, int endX) {
+ if (provider == null) {
+ return;
+ }
+ // create Shell
+ {
+ m_tooltip = new Shell(m_table.getShell(), SWT.NO_FOCUS | SWT.ON_TOP | SWT.TOOL | SWT.SINGLE);
+ configureColors(m_tooltip);
+ GridLayoutFactory.create(m_tooltip).noMargins();
+ }
+ // prepare control
+ Control control = provider.createTooltipControl(m_property, m_tooltip, endX - startX, this);
+ if (control == null) {
+ hideTooltip();
+ return;
+ }
+ // show Shell
+ {
+ // prepare tooltip location
+ Point tooltipLocation;
+ if (provider.getTooltipPosition() == PropertyTooltipProvider.ON) {
+ tooltipLocation = m_table.toDisplay(new Point(startX, m_y));
+ } else {
+ tooltipLocation = m_table.toDisplay(new Point(startX, m_y + m_rowHeight));
+ }
+ // set location/size and open
+ m_tooltip.setLocation(tooltipLocation.x, tooltipLocation.y);
+ // for non-windows systems the tooltip may have invalid tooltip bounds
+ // because some widget's API functions may fail if tooltip content is not visible
+ // ex., on MacOSX tree widget's items has zero bounds since they are not yet visible.
+ // the workaround is to preset tooltip size to big values before any computeSize called.
+ if (!EnvironmentUtils.IS_WINDOWS) {
+ m_tooltip.setSize(1000, 1000);
+ }
+ m_tooltip.setSize(m_tooltip.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+ provider.show(m_tooltip);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Utils
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * Sets given {@link Control} correct background/foreground for tooltips.
+ */
+ private void configureColors(Control control) {
+ Display display = Display.getCurrent();
+ control.setForeground(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND));
+ control.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
+ }
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/table/PropertyTooltipProvider.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/table/PropertyTooltipProvider.java
new file mode 100644
index 0000000..1c3d4fe
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/table/PropertyTooltipProvider.java
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.table;
+
+import org.eclipse.wb.internal.core.model.property.Property;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * Provider for tooltip controls.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.table
+ */
+public abstract class PropertyTooltipProvider {
+ /**
+ * Show tooltip directly on property row.
+ */
+ public static final int ON = 0;
+ /**
+ * Show tooltip below property row.
+ */
+ public static final int BELOW = 1;
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // PropertyTooltipProvider
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * Create tooltip control.
+ */
+ public abstract Control createTooltipControl(Property property,
+ Composite parent,
+ int availableWidth,
+ IPropertyTooltipSite site);
+
+ /**
+ * Shows tooltip {@link Shell}.
+ */
+ public void show(Shell shell) {
+ shell.setVisible(true);
+ }
+
+ /**
+ * Returns position for tooltip control. Usually we should show directly on same row, because we
+ * use tooltip to show just longer (full) text of property. But for "class" property we show
+ * hierarchy, so it is better show it below and allow user see also property row.
+ */
+ public int getTooltipPosition() {
+ return ON;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Tooltip listener
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * {@link Listener} that hides tooltip on mouse exit or click.
+ */
+ protected static final class HideListener implements Listener {
+ private final IPropertyTooltipSite m_site;
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Constructor
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public HideListener(IPropertyTooltipSite site) {
+ m_site = site;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Listener
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public void handleEvent(Event event) {
+ Control tooltipControl = (Control) event.widget;
+ switch (event.type) {
+ case SWT.MouseDown : {
+ PropertyTable table = m_site.getTable();
+ // convert location from tooltip to table
+ Point p = new Point(event.x, event.y);
+ p = tooltipControl.toDisplay(p);
+ p = table.toControl(p);
+ // send MouseDown to table
+ Event newEvent = new Event();
+ newEvent.x = p.x;
+ newEvent.y = p.y;
+ table.notifyListeners(SWT.MouseDown, newEvent);
+ // hide tooltip
+ m_site.hideTooltip();
+ break;
+ }
+ case SWT.MouseExit :
+ m_site.hideTooltip();
+ break;
+ }
+ }
+ }
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/table/PropertyTooltipTextProvider.java b/propertysheet/src/org/eclipse/wb/internal/core/model/property/table/PropertyTooltipTextProvider.java
new file mode 100644
index 0000000..b2e9b69
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/table/PropertyTooltipTextProvider.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.internal.core.model.property.table;
+
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.wb.internal.core.model.property.Property;
+
+/**
+ * Implementation of {@link PropertyTooltipProvider} for text.
+ *
+ * @author scheglov_ke
+ * @coverage core.model.property.table
+ */
+public abstract class PropertyTooltipTextProvider extends PropertyTooltipProvider {
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // PropertyTooltipProvider
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public Control createTooltipControl(Property property,
+ Composite parent,
+ int availableWidth,
+ IPropertyTooltipSite site) {
+ // prepare header and content
+ String header = null;
+ String content = null;
+ try {
+ // BEGIN ADT MODIFICATIONS
+ // was: header = property.getTitle();
+ header = property.getName();
+ // END ADT MODIFICATIONS
+ content = getText(property);
+ } catch (Throwable e) {
+ }
+ if (header == null || content == null) {
+ return null;
+ }
+ // create tooltip Control
+ return HtmlTooltipHelper.createTooltipControl(parent, header, content, 8);
+ }
+
+ @Override
+ public void show(Shell shell) {
+ // do nothing, Shell will be displayed when Browser will complete rendering
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Text
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * @return the text to show as tooltip.
+ */
+ protected abstract String getText(Property property) throws Exception;
+}
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/model/property/table/Tooltip.css b/propertysheet/src/org/eclipse/wb/internal/core/model/property/table/Tooltip.css
new file mode 100644
index 0000000..2ba2a02
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/internal/core/model/property/table/Tooltip.css
@@ -0,0 +1,35 @@
+/* Font definitions */
+html { font-family: 'Segoe UI','Verdana','Helvetica',sans-serif; font-size: 9pt; font-style: normal; font-weight: normal; }
+body, h1, h2, h3, h4, h5, h6, p, table, td, caption, th, ul, ol, dl, li, dd, dt { font-size: 1em; }
+pre { font-family: monospace; }
+
+/* Margins */
+body { overflow: auto; margin-top: 0px; margin-bottom: 0px; margin-left: 0.3em; margin-right: 0.3em; }
+div { margin: 0px; }
+h1 { margin-top: 0.3em; margin-bottom: 0.04em; }
+h2 { margin-top: 2em; margin-bottom: 0.25em; }
+h3 { margin-top: 1.7em; margin-bottom: 0.25em; }
+h4 { margin-top: 2em; margin-bottom: 0.3em; }
+h5 { margin-top: 0px; margin-bottom: 0px; }
+p { margin-top: 0em; margin-bottom: 0em; }
+pre { margin-left: 0.6em; }
+ul { margin-top: 0px; margin-bottom: 1em; }
+li { margin-top: 0px; margin-bottom: 0px; }
+li p { margin-top: 0px; margin-bottom: 0px; }
+ol { margin-top: 0px; margin-bottom: 1em; }
+dl { margin-top: 0px; margin-bottom: 1em; }
+dt { margin-top: 0px; margin-bottom: 0px; font-weight: bold; }
+dd { margin-top: 0px; margin-bottom: 0px; }
+
+/* Styles and colors */
+a:link { color: #0000FF; }
+a:hover { color: #000080; }
+a:visited { text-decoration: underline; }
+a.header:link { text-decoration: none; color: InfoText }
+a.header:visited { text-decoration: none; color: InfoText }
+a.header:hover { text-decoration: underline; color: #000080; }
+h4 { font-style: italic; }
+strong { font-weight: bold; }
+em { font-style: italic; }
+var { font-style: italic; }
+th { font-weight: bold; }