1765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye/*******************************************************************************
2765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye * Copyright (c) 2011 Google, Inc.
3765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye * All rights reserved. This program and the accompanying materials
4765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye * are made available under the terms of the Eclipse Public License v1.0
5765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye * which accompanies this distribution, and is available at
6765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye * http://www.eclipse.org/legal/epl-v10.html
7765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye *
8765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye * Contributors:
9765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye *    Google, Inc. - initial API and implementation
10765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye *******************************************************************************/
11765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyepackage org.eclipse.wb.internal.core.model.property.table;
12765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
13765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport com.google.common.collect.Lists;
14765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport com.google.common.collect.Sets;
15765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
16765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.jface.viewers.ISelection;
17765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.jface.viewers.ISelectionChangedListener;
18765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.jface.viewers.ISelectionProvider;
19765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.jface.viewers.SelectionChangedEvent;
20765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.jface.viewers.StructuredSelection;
21765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.SWT;
22765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.events.KeyAdapter;
23765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.events.KeyEvent;
24765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.events.MouseAdapter;
25765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.events.MouseEvent;
26765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.events.MouseMoveListener;
27765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.graphics.Color;
28765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.graphics.Font;
29765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.graphics.GC;
30765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.graphics.Image;
31765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.graphics.Point;
32765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.graphics.Rectangle;
33765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.widgets.Canvas;
34765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.widgets.Composite;
35765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.widgets.Event;
36765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.widgets.Listener;
37765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.swt.widgets.ScrollBar;
38765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.wb.draw2d.IColorConstants;
39765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.wb.draw2d.ICursorConstants;
40765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.wb.internal.core.DesignerPlugin;
4162a54a64746b33b65f33c9e71bf8dc54e96a37b6Tor Norbyeimport org.eclipse.wb.internal.core.EnvironmentUtils;
42765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.wb.internal.core.model.property.Property;
43765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.wb.internal.core.model.property.category.PropertyCategory;
44765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.wb.internal.core.model.property.category.PropertyCategoryProvider;
45765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.wb.internal.core.model.property.category.PropertyCategoryProviders;
46765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.wb.internal.core.model.property.editor.PropertyEditor;
47765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.wb.internal.core.model.property.editor.complex.IComplexPropertyEditor;
4862a54a64746b33b65f33c9e71bf8dc54e96a37b6Tor Norbyeimport org.eclipse.wb.internal.core.model.property.editor.presentation.ButtonPropertyEditorPresentation;
49765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.wb.internal.core.model.property.editor.presentation.PropertyEditorPresentation;
50765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.wb.internal.core.utils.check.Assert;
51765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport org.eclipse.wb.internal.core.utils.ui.DrawUtils;
52765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
53765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport java.util.Collection;
54765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport java.util.List;
55765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyeimport java.util.Set;
56765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
57765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye/**
58765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye * Control that can display {@link Property}'s and edit them using {@link PropertyEditor}'s.
59765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye *
60765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye * @author scheglov_ke
61765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye * @author lobas_av
62765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye * @coverage core.model.property.table
63765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye */
64765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyepublic class PropertyTable extends Canvas implements ISelectionProvider {
65765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
66765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
67765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // Colors
68765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
69765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
70765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private static final Color COLOR_BACKGROUND = IColorConstants.listBackground;
71765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private static final Color COLOR_NO_PROPERTIES = IColorConstants.gray;
72765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private static final Color COLOR_LINE = IColorConstants.lightGray;
73765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private static final Color COLOR_COMPLEX_LINE = DrawUtils.getShiftedColor(
74765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      IColorConstants.lightGray,
75765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      -32);
76765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private static final Color COLOR_PROPERTY_BG = DrawUtils.getShiftedColor(COLOR_BACKGROUND, -12);
77765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private static final Color COLOR_PROPERTY_BG_MODIFIED = COLOR_BACKGROUND;
78765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private static final Color COLOR_PROPERTY_FG_TITLE = IColorConstants.listForeground;
79765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private static final Color COLOR_PROPERTY_FG_VALUE =
80765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      DrawUtils.isDarkColor(IColorConstants.listBackground)
81765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          ? IColorConstants.lightBlue
82765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          : IColorConstants.darkBlue;
83765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private static final Color COLOR_PROPERTY_BG_SELECTED = IColorConstants.listSelection;
84765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private static final Color COLOR_PROPERTY_FG_SELECTED = IColorConstants.listSelectionText;
85765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private static final Color COLOR_PROPERTY_FG_ADVANCED = IColorConstants.gray;
86765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // BEGIN ADT MODIFICATIONS
87765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  public static final Color COLOR_PROPERTY_FG_DEFAULT = IColorConstants.darkGray;
88765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // END ADT MODIFICATIONS
89765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
90765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
91765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // Sizes
92765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
93765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
94765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private static final int MIN_COLUMN_WIDTH = 75;
95765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private static final int MARGIN_LEFT = 2;
96765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private static final int MARGIN_RIGHT = 1;
97765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private static final int STATE_IMAGE_MARGIN_RIGHT = 4;
98765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
99765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
100765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // Images
101765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
102765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
103765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private static final Image m_plusImage = DesignerPlugin.getImage("properties/plus.gif");
104765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private static final Image m_minusImage = DesignerPlugin.getImage("properties/minus.gif");
105765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private static int m_stateWidth = 9;
106765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
107765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
108765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // Instance fields
109765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
110765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
111765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private final PropertyTableTooltipHelper m_tooltipHelper;
112765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private boolean m_showAdvancedProperties;
113765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private Property[] m_rawProperties;
114765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private List<PropertyInfo> m_properties;
115765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private final Set<String> m_expandedIds = Sets.newTreeSet();
116765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // BEGIN ADT MODIFICATIONS
117765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // Add support for "expand by default" : If you specify ids to be collapsed by
118765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // default, then any *other* ids will be expanded by default.
119765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private Set<String> m_collapsedIds = null;
120765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
121765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    /**
122765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye     * Sets a set of ids that should be collapsed by default. Everything else
123765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye     * will be expanded by default. If this method is not called, ids are
124765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye     * collapsed by default instead.
125765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye     *
126765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye     * @param names set of ids to be collapsed
127765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye     */
128765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  public void setDefaultCollapsedNames(Collection<String> names) {
129765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_collapsedIds = Sets.newTreeSet();
130765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      for (String name : names) {
131765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          m_collapsedIds.add("|" + name); // See PropertyInfo constructor for id syntax
132765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
133765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
134765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // END ADT MODIFICATIONS
135765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
136765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private Image m_bufferedImage;
137765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private int m_rowHeight;
138765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private int m_selection;
139765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private int m_page;
140765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private int m_splitter = -1;
141765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
142765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
143765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
144765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // Constructor
145765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
146765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
147765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  public PropertyTable(Composite parent, int style) {
148765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    super(parent, style | SWT.V_SCROLL | SWT.NO_BACKGROUND | SWT.NO_REDRAW_RESIZE);
149765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    hookControlEvents();
150765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // calculate sizes
151765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    {
152765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      GC gc = new GC(this);
153765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      try {
154765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        m_rowHeight = 1 + gc.getFontMetrics().getHeight() + 1;
155765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      } finally {
156765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        gc.dispose();
157765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
158765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
159765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // install tooltip helper
160765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    m_tooltipHelper = new PropertyTableTooltipHelper(this);
161765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
162765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
163765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
164765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
165765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // Events
166765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
167765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
168765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
169765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Adds listeners for events.
170765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
171765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private void hookControlEvents() {
172765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    addListener(SWT.Dispose, new Listener() {
173765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      @Override
174765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    public void handleEvent(Event event) {
175765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        disposeBufferedImage();
176765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
177765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    });
178765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    addListener(SWT.Resize, new Listener() {
179765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      @Override
180765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    public void handleEvent(Event event) {
181765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        handleResize();
182765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
183765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    });
184765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    addListener(SWT.Paint, new Listener() {
185765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      @Override
186765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    public void handleEvent(Event event) {
187765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        handlePaint(event.gc, event.x, event.y, event.width, event.height);
188765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
189765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    });
190765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    getVerticalBar().addListener(SWT.Selection, new Listener() {
191765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      @Override
192765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    public void handleEvent(Event event) {
193765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        handleVerticalScrolling();
194765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
195765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    });
196765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    addMouseListener(new MouseAdapter() {
197765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      @Override
198765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      public void mouseDown(MouseEvent event) {
199765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        forceFocus();
200765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        handleMouseDown(event);
201765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
202765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
203765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      @Override
204765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      public void mouseUp(MouseEvent event) {
205765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        handleMouseUp(event);
206765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
207765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
208765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      @Override
209765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      public void mouseDoubleClick(MouseEvent event) {
210765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        handleMouseDoubleClick(event);
211765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
212765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    });
213765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    addMouseMoveListener(new MouseMoveListener() {
214765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      @Override
215765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    public void mouseMove(MouseEvent event) {
216765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        handleMouseMove(event);
217765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
218765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    });
219765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // keyboard
220765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    addKeyListener(new KeyAdapter() {
221765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      @Override
222765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      public void keyPressed(KeyEvent e) {
223765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        handleKeyDown(e);
224765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
225765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    });
226765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
227765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
228765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
229765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
230765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // Events: dispose, resize, scroll
231765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
232765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
233765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
234765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Disposes image used for double buffered painting.
235765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
236765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private void disposeBufferedImage() {
237765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (m_bufferedImage != null) {
238765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_bufferedImage.dispose();
239765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_bufferedImage = null;
240765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
241765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
242765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
243765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
244765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Handles {@link SWT#Resize} event.
245765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
246765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private void handleResize() {
247765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    disposeBufferedImage();
248765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    configureScrolling();
249765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // splitter
250765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    {
251765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // set default value for splitter
252765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      if (m_splitter <= MIN_COLUMN_WIDTH) {
253765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        m_splitter = Math.max((int) (getClientArea().width * 0.4), MIN_COLUMN_WIDTH);
254765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
255765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      configureSplitter();
256765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
257765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
258765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
259765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
260765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Handles {@link SWT#Selection} event for vertical {@link ScrollBar}.
261765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
262765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private void handleVerticalScrolling() {
263765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    ScrollBar verticalBar = getVerticalBar();
264765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (verticalBar.getEnabled()) {
265765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // update selection
266765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_selection = verticalBar.getSelection();
267765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // redraw (but not include vertical bar to avoid flashing)
268765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      {
269765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        Rectangle clientArea = getClientArea();
270765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        redraw(clientArea.x, clientArea.y, clientArea.width, clientArea.height, false);
271765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
272765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
273765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
274765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
275765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
276765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
277765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // Keyboard
278765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
279765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
280765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
281765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Handles {@link SWT#KeyDown} event.
282765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
283765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private void handleKeyDown(KeyEvent e) {
284765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (m_activePropertyInfo != null) {
285765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      try {
286765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        Property property = m_activePropertyInfo.getProperty();
287765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // expand/collapse
288765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        if (m_activePropertyInfo.isComplex()) {
289765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          if (!m_activePropertyInfo.isExpanded()
290765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye              && (e.character == '+' || e.keyCode == SWT.ARROW_RIGHT)) {
291765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            m_activePropertyInfo.expand();
292765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            configureScrolling();
293765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            return;
294765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          }
295765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          if (m_activePropertyInfo.isExpanded()
296765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye              && (e.character == '-' || e.keyCode == SWT.ARROW_LEFT)) {
297765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            m_activePropertyInfo.collapse();
298765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            configureScrolling();
299765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            return;
300765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          }
301765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
302765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // navigation
303765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        if (navigate(e)) {
304765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          return;
305765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
306765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // editor activation
307765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        if (e.character == ' ' || e.character == SWT.CR) {
308765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          activateEditor(property, null);
309765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          return;
310765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
311765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // DEL
312765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        if (e.keyCode == SWT.DEL) {
313765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          e.doit = false;
314765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          property.setValue(Property.UNKNOWN_VALUE);
315765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          return;
316765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
317765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // send to editor
318765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        property.getEditor().keyDown(this, property, e);
319765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      } catch (Throwable ex) {
320765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        DesignerPlugin.log(ex);
321765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
322765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
323765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
324765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
325765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
326765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * @return <code>true</code> if given {@link KeyEvent} was navigation event, so new
327765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   *         {@link PropertyInfo} was selected.
328765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
329765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  public boolean navigate(KeyEvent e) {
330765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    int index = m_properties.indexOf(m_activePropertyInfo);
331765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    Rectangle clientArea = getClientArea();
332765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    //
333765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    int newIndex = index;
334765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (e.keyCode == SWT.HOME) {
335765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      newIndex = 0;
336765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    } else if (e.keyCode == SWT.END) {
337765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      newIndex = m_properties.size() - 1;
338765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    } else if (e.keyCode == SWT.PAGE_UP) {
339765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      newIndex = Math.max(index - m_page + 1, 0);
340765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    } else if (e.keyCode == SWT.PAGE_DOWN) {
341765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      newIndex = Math.min(index + m_page - 1, m_properties.size() - 1);
342765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    } else if (e.keyCode == SWT.ARROW_UP) {
343765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      newIndex = Math.max(index - 1, 0);
344765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    } else if (e.keyCode == SWT.ARROW_DOWN) {
345765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      newIndex = Math.min(index + 1, m_properties.size() - 1);
346765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
347765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // activate new property
348765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (newIndex != index && newIndex < m_properties.size()) {
349765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      setActivePropertyInfo(m_properties.get(newIndex));
350765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // check for scrolling
351765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      int y = m_rowHeight * (newIndex - m_selection);
352765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      if (y < 0) {
353765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        m_selection = newIndex;
354765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        configureScrolling();
355765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      } else if (y + m_rowHeight > clientArea.height) {
356765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        m_selection = newIndex - m_page + 1;
357765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        configureScrolling();
358765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
359765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // repaint
360765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      redraw();
361765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      return true;
362765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
363765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // no navigation change
364765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    return false;
365765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
366765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
367765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
368765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
369765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // Events: mouse
370765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
371765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
372765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private boolean m_splitterResizing;
373765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
374765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * We do expand/collapse on to events: click on state sign and on double click. But when we double
375765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * click on state sign, we will have <em>two</em> events, so we should ignore double click.
376765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
377765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private long m_lastExpandCollapseTime;
378765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
379765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
380765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Handles {@link SWT#MouseDown} event.
381765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
382765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private void handleMouseDown(MouseEvent event) {
383765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    m_splitterResizing = event.button == 1 && m_properties != null && isLocationSplitter(event.x);
384765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // click in property
385765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (!m_splitterResizing && m_properties != null) {
386765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      int propertyIndex = getPropertyIndex(event.y);
387765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      if (propertyIndex >= m_properties.size()) {
388765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        return;
389765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
390765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // prepare property
391765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      setActivePropertyInfo(m_properties.get(propertyIndex));
392765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      Property property = m_activePropertyInfo.getProperty();
393765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // de-activate current editor
394765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      deactivateEditor(true);
395765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      redraw();
396765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // activate editor
397765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      if (isLocationValue(event.x)) {
398765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        activateEditor(property, getValueRelativeLocation(event.x, event.y));
399765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
400765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
401765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
402765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
403765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
404765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Handles {@link SWT#MouseUp} event.
405765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
406765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private void handleMouseUp(MouseEvent event) {
407765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (event.button == 1) {
408765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // resize splitter
409765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      if (m_splitterResizing) {
410765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        m_splitterResizing = false;
411765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        return;
412765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
413765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // if out of bounds, then ignore
414765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      if (!getClientArea().contains(event.x, event.y)) {
415765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        return;
416765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
417765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // update
418765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      if (m_properties != null) {
419765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        int index = getPropertyIndex(event.y);
420765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        if (index < m_properties.size()) {
421765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          PropertyInfo propertyInfo = m_properties.get(index);
422765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          // check for expand/collapse
423765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          if (isLocationState(propertyInfo, event.x)) {
424765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            try {
425765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye              m_lastExpandCollapseTime = System.currentTimeMillis();
426765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye              propertyInfo.flip();
427765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye              configureScrolling();
428765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            } catch (Throwable e) {
429765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye              DesignerPlugin.log(e);
430765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            }
431765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          }
432765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
433765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
434765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
435765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
436765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
437765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
438765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Handles {@link SWT#MouseDoubleClick} event.
439765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
440765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private void handleMouseDoubleClick(MouseEvent event) {
441765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (System.currentTimeMillis() - m_lastExpandCollapseTime > getDisplay().getDoubleClickTime()) {
442765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      try {
443765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        if (m_activePropertyInfo != null) {
444765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          if (m_activePropertyInfo.isComplex()) {
445765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            m_activePropertyInfo.flip();
446765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            configureScrolling();
447765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          } else {
448765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            Property property = m_activePropertyInfo.getProperty();
449765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            property.getEditor().doubleClick(property, getValueRelativeLocation(event.x, event.y));
450765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          }
451765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
452765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      } catch (Throwable e) {
453765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        handleException(e);
454765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
455765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
456765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
457765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
458765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
459765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Handles {@link SWT#MouseMove} event.
460765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
461765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private void handleMouseMove(MouseEvent event) {
462765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    int x = event.x;
463765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // resize splitter
464765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (m_splitterResizing) {
465765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_splitter = x;
466765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      configureSplitter();
467765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      redraw();
468765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      return;
469765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
470765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // if out of bounds, then ignore
471765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (!getClientArea().contains(event.x, event.y)) {
472765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      return;
473765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
474765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // update
475765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (m_properties != null) {
476765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // update cursor
477765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      if (isLocationSplitter(x)) {
478765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        setCursor(ICursorConstants.SIZEWE);
479765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      } else {
480765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        setCursor(null);
481765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
482765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // update tooltip helper
483765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      updateTooltip(event);
484765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    } else {
485765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      updateTooltipNoProperty();
486765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
487765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
488765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
489765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
490765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Updates {@link PropertyTableTooltipHelper}.
491765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
492765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private void updateTooltip(MouseEvent event) {
493765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    int x = event.x;
494765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    int propertyIndex = getPropertyIndex(event.y);
495765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    //
496765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (propertyIndex < m_properties.size()) {
497765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      PropertyInfo propertyInfo = m_properties.get(propertyIndex);
498765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      Property property = propertyInfo.getProperty();
499765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      int y = (propertyIndex - m_selection) * m_rowHeight;
500765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // check for title
501765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      {
502765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        int titleX = getTitleTextX(propertyInfo);
503765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        int titleRight = m_splitter - 2;
504765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        if (titleX <= x && x < titleRight) {
505765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          m_tooltipHelper.update(property, true, false, titleX, titleRight, y, m_rowHeight);
506765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          return;
507765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
508765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
509765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // check for value
510765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      {
511765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        int valueX = m_splitter + 3;
512765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        if (x > valueX) {
513765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          m_tooltipHelper.update(
514765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye              property,
515765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye              false,
516765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye              true,
517765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye              valueX,
518765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye              getClientArea().width,
519765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye              y,
520765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye              m_rowHeight);
521765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
522765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
523765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    } else {
524765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      updateTooltipNoProperty();
525765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
526765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
527765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
528765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private void updateTooltipNoProperty() {
529765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    m_tooltipHelper.update(null, false, false, 0, 0, 0, 0);
530765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
531765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
532765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
533765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
534765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // Editor
535765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
536765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
537765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private PropertyInfo m_activePropertyInfo;
538765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private String m_activePropertyId;
539765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private PropertyEditor m_activeEditor;
540765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
541765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
542765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Tries to activate editor for {@link PropertyInfo} under cursor.
543765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   *
544765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * @param location
545765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   *          the mouse location, if editor is activated using mouse click, or <code>null</code> if
546765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   *          it is activated using keyboard.
547765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
548765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  public void activateEditor(Property property, Point location) {
549765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    try {
550765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // de-activate old editor
551765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      deactivateEditor(true);
552765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // activate editor
553765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      PropertyEditor editor = property.getEditor();
554765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      try {
555765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        if (editor.activate(this, property, location)) {
556765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          m_activeEditor = editor;
557765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
558765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      } catch (Throwable e) {
559765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        handleException(e);
560765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
561765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // set bounds
562765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      setActiveEditorBounds();
56362a54a64746b33b65f33c9e71bf8dc54e96a37b6Tor Norbye    } catch (NullPointerException e) {
56462a54a64746b33b65f33c9e71bf8dc54e96a37b6Tor Norbye        if (EnvironmentUtils.IS_MAC) {
56562a54a64746b33b65f33c9e71bf8dc54e96a37b6Tor Norbye            // Workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=388574
56662a54a64746b33b65f33c9e71bf8dc54e96a37b6Tor Norbye            PropertyEditor editor = property.getEditor();
56762a54a64746b33b65f33c9e71bf8dc54e96a37b6Tor Norbye            PropertyEditorPresentation presentation = editor.getPresentation();
56862a54a64746b33b65f33c9e71bf8dc54e96a37b6Tor Norbye            if (presentation instanceof ButtonPropertyEditorPresentation) {
56962a54a64746b33b65f33c9e71bf8dc54e96a37b6Tor Norbye                ButtonPropertyEditorPresentation button =
57062a54a64746b33b65f33c9e71bf8dc54e96a37b6Tor Norbye                        (ButtonPropertyEditorPresentation) presentation;
57162a54a64746b33b65f33c9e71bf8dc54e96a37b6Tor Norbye                try {
57262a54a64746b33b65f33c9e71bf8dc54e96a37b6Tor Norbye                    button.click(this, property);
57362a54a64746b33b65f33c9e71bf8dc54e96a37b6Tor Norbye                } catch (Exception ex) {
57462a54a64746b33b65f33c9e71bf8dc54e96a37b6Tor Norbye                    deactivateEditor(false);
57562a54a64746b33b65f33c9e71bf8dc54e96a37b6Tor Norbye                    handleException(e);
57662a54a64746b33b65f33c9e71bf8dc54e96a37b6Tor Norbye                }
57762a54a64746b33b65f33c9e71bf8dc54e96a37b6Tor Norbye                return;
57862a54a64746b33b65f33c9e71bf8dc54e96a37b6Tor Norbye            }
57962a54a64746b33b65f33c9e71bf8dc54e96a37b6Tor Norbye        }
58062a54a64746b33b65f33c9e71bf8dc54e96a37b6Tor Norbye        DesignerPlugin.log(e);
581765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    } catch (Throwable e) {
582765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      DesignerPlugin.log(e);
583765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
584765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
585765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
586765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
587765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Deactivates current {@link PropertyEditor}.
588765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
589765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  public void deactivateEditor(boolean save) {
590765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (m_activeEditor != null) {
591765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      PropertyEditor activeEditor = m_activeEditor;
592765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_activeEditor = null;
593765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      if (m_activePropertyInfo != null && m_activePropertyInfo.m_property != null) {
594765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        activeEditor.deactivate(this, m_activePropertyInfo.m_property, save);
595765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
596765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
597765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
598765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
599765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
600765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Sets correct bounds for active editor, for example we need update bounds after scrolling.
601765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
602765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private void setActiveEditorBounds() {
603765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (m_activeEditor != null) {
604765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      int index = m_properties.indexOf(m_activePropertyInfo);
605765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      if (index == -1) {
606765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // it is possible that active property was hidden because its parent was collapsed
607765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        deactivateEditor(true);
608765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      } else {
609765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // prepare bounds for editor
610765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        Rectangle bounds;
611765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        {
612765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          Rectangle clientArea = getClientArea();
613765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          int x = m_splitter + 1;
614765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          int width = clientArea.width - x - MARGIN_RIGHT;
615765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          int y = m_rowHeight * (index - m_selection) + 1;
616765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          int height = m_rowHeight - 1;
617765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          bounds = new Rectangle(x, y, width, height);
618765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
619765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // update bounds using presentation
620765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        {
621765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          PropertyEditorPresentation presentation = m_activeEditor.getPresentation();
622765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          if (presentation != null) {
623765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            int presentationWidth =
624765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                presentation.show(
625765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                    this,
626765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                    m_activePropertyInfo.m_property,
627765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                    bounds.x,
628765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                    bounds.y,
629765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                    bounds.width,
630765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                    bounds.height);
631765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            bounds.width -= presentationWidth;
632765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          }
633765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
634765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // set editor bounds
635765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        m_activeEditor.setBounds(bounds);
636765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
637765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
638765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
639765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
640765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
641765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
642765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // Exceptions
643765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
644765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
645765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private IPropertyExceptionHandler m_exceptionHandler;
646765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
647765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
648765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Sets {@link IPropertyExceptionHandler} for handling all exceptions.
649765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
650765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  public void setExceptionHandler(IPropertyExceptionHandler exceptionHandler) {
651765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    m_exceptionHandler = exceptionHandler;
652765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
653765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
654765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
655765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Handles given {@link Throwable}.<br>
656765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Right now it just logs it, but in future we can open some dialog here.
657765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
658765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  public void handleException(Throwable e) {
659765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    m_exceptionHandler.handle(e);
660765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
661765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
662765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
663765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
664765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // Scrolling
665765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
666765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
667765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
668765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Configures vertical {@link ScrollBar}.
669765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
670765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private void configureScrolling() {
671765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    ScrollBar verticalBar = getVerticalBar();
672765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (m_properties == null) {
673765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      verticalBar.setEnabled(false);
674765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    } else {
675765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_page = getClientArea().height / m_rowHeight;
676765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_selection = Math.max(0, Math.min(m_properties.size() - m_page, m_selection));
677765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      verticalBar.setValues(m_selection, 0, m_properties.size(), m_page, 1, m_page);
678765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // enable/disable scrolling
679765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      if (m_properties.size() <= m_page) {
680765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        verticalBar.setEnabled(false);
681765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      } else {
682765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        verticalBar.setEnabled(true);
683765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
684765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
685765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // redraw, we reconfigure scrolling only if list of properties was changed, so we should redraw
686765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    redraw();
687765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
688765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
689765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
690765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
691765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // Location/size utils
692765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
693765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
694765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
695765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * @return the <code>X</code> position for first pixel of {@link PropertyInfo} title (location of
696765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   *         state image).
697765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
698765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private int getTitleX(PropertyInfo propertyInfo) {
699765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    return MARGIN_LEFT + getLevelIndent() * propertyInfo.getLevel();
700765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
701765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
702765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
703765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * @return the <code>X</code> position for first pixel of {@link PropertyInfo} title text.
704765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
705765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private int getTitleTextX(PropertyInfo propertyInfo) {
706765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    return getTitleX(propertyInfo) + getLevelIndent();
707765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
708765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
709765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
710765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * @return the indentation for single level.
711765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
712765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private int getLevelIndent() {
713765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    return m_stateWidth + STATE_IMAGE_MARGIN_RIGHT;
714765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
715765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
716765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
717765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Checks horizontal splitter value to boundary values.
718765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
719765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private void configureSplitter() {
720765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    Rectangle clientArea = getClientArea();
721765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // check title width
722765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (m_splitter < MIN_COLUMN_WIDTH) {
723765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_splitter = MIN_COLUMN_WIDTH;
724765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
725765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // check value width
726765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (clientArea.width - m_splitter < MIN_COLUMN_WIDTH) {
727765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_splitter = clientArea.width - MIN_COLUMN_WIDTH;
728765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
729765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
730765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
731765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
732765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * @return the index in {@link #m_properties} corresponding given <code>y</code> location.
733765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
734765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private int getPropertyIndex(int y) {
735765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    return m_selection + y / m_rowHeight;
736765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
737765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
738765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
739765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * @return <code>true</code> if given <code>x</code> coordinate is on state (plus/minus) image.
740765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
741765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private boolean isLocationState(PropertyInfo propertyInfo, int x) {
742765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    int levelX = getTitleX(propertyInfo);
743765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    return propertyInfo.isComplex() && levelX <= x && x <= levelX + m_stateWidth;
744765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
745765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
746765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
747765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Returns <code>true</code> if <code>x</code> coordinate is on splitter.
748765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
749765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private boolean isLocationSplitter(int x) {
750765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    return Math.abs(m_splitter - x) < 2;
751765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
752765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
753765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
754765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * @return <code>true</code> if given <code>x</code> is on value part of property.
755765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
756765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private boolean isLocationValue(int x) {
757765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    return x > m_splitter + 2;
758765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
759765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
760765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
761765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * @param x
762765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   *          the {@link PropertyTable} relative coordinate.
763765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * @param y
764765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   *          the {@link PropertyTable} relative coordinate.
765765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   *
766765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * @return the location relative to the value part of property.
767765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
768765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private Point getValueRelativeLocation(int x, int y) {
769765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    return new Point(x - (m_splitter + 2), y - m_rowHeight * getPropertyIndex(y));
770765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
771765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
772765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
773765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
774765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // Access
775765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
776765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
777765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
778765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Shows or hides {@link Property}-s with {@link PropertyCategory#ADVANCED}.
779765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
780765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  public void setShowAdvancedProperties(boolean showAdvancedProperties) {
781765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    m_showAdvancedProperties = showAdvancedProperties;
782765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    setInput0();
783765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
784765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
785765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
786765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Sets the array of {@link Property}'s to display/edit.
787765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
788765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  public void setInput(Property[] properties) {
789765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    m_rawProperties = properties;
790765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    setInput0();
791765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
792765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
793765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private void setInput0() {
794765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // send "hide" to all PropertyEditorPresentation's
795765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (m_properties != null) {
796765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      for (PropertyInfo propertyInfo : m_properties) {
797765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        Property property = propertyInfo.getProperty();
798765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // hide presentation
799765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        {
800765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          PropertyEditorPresentation presentation = property.getEditor().getPresentation();
801765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          if (presentation != null) {
802765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            presentation.hide(this, property);
803765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          }
804765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
805765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
806765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
807765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // set new properties
808765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (m_rawProperties == null || m_rawProperties.length == 0) {
809765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      deactivateEditor(false);
810765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_properties = Lists.newArrayList();
811765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    } else {
812765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      try {
813765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // add PropertyInfo for each Property
814765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        m_properties = Lists.newArrayList();
815765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        for (Property property : m_rawProperties) {
816765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          if (rawProperties_shouldShow(property)) {
817765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            PropertyInfo propertyInfo = new PropertyInfo(property);
818765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            m_properties.add(propertyInfo);
819765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          }
820765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
821765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // expand properties using history
822765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        while (true) {
823765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          boolean expanded = false;
824765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          List<PropertyInfo> currentProperties = Lists.newArrayList(m_properties);
825765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          for (PropertyInfo propertyInfo : currentProperties) {
826765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            expanded |= propertyInfo.expandFromHistory();
827765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          }
828765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          // stop
829765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          if (!expanded) {
830765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            break;
831765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          }
832765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
833765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      } catch (Throwable e) {
834765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        DesignerPlugin.log(e);
835765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
836765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
837765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // update active property
838765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (m_activePropertyId != null) {
839765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      PropertyInfo newActivePropertyInfo = null;
840765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // try to find corresponding PropertyInfo
841765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      if (m_properties != null) {
842765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        for (PropertyInfo propertyInfo : m_properties) {
843765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          if (propertyInfo.m_id.equals(m_activePropertyId)) {
844765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            newActivePropertyInfo = propertyInfo;
845765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            break;
846765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          }
847765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
848765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
849765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // set new PropertyInfo
850765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      setActivePropertyInfo(newActivePropertyInfo);
851765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
852765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // update scroll bar
853765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    configureScrolling();
854765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
855765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
856765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
857765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * @return <code>true</code> if given {@link Property} should be displayed.
858765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
859765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private boolean rawProperties_shouldShow(Property property) throws Exception {
860765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    PropertyCategory category = getCategory(property);
861765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // filter out hidden properties
862765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (category.isHidden()) {
863765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      return false;
864765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
865765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // filter out advanced properties
866765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (category.isAdvanced()) {
867765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      if (!m_showAdvancedProperties && !property.isModified()) {
868765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        return false;
869765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
870765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
871765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (category.isAdvancedReally()) {
872765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      return m_showAdvancedProperties;
873765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
874765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // OK
875765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    return true;
876765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
877765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
878765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
879765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Activates given {@link Property}.
880765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
881765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  public void setActiveProperty(Property property) {
882765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    for (PropertyInfo propertyInfo : m_properties) {
883765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      if (propertyInfo.m_property == property) {
884765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        setActivePropertyInfo(propertyInfo);
885765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        break;
886765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
887765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
888765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
889765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
890765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
891765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
892765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // Access: only for testing
893765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
894765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
895765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
896765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * @return the count of properties in "expanded" list.
897765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
898765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  public int forTests_getPropertiesCount() {
899765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    return m_properties.size();
900765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
901765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
902765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
903765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * @return the {@link Property} from "expanded" list.
904765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
905765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  public Property forTests_getProperty(int index) {
906765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    return m_properties.get(index).getProperty();
907765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
908765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
909765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
910765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Expands the {@link PropertyInfo} with given index.
911765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
912765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  public void forTests_expand(int index) throws Exception {
913765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    m_properties.get(index).expand();
914765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
915765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
916765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
917765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * @return the position of splitter.
918765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
919765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  public int forTests_getSplitter() {
920765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    return m_splitter;
921765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
922765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
923765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
924765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * @return the location of state image (plus/minus) for given {@link Property}.
925765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
926765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  public Point forTests_getStateLocation(Property property) {
927765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    PropertyInfo propertyInfo = getPropertyInfo(property);
928765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (propertyInfo != null) {
929765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      int index = m_properties.indexOf(propertyInfo);
930765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      int x = getTitleX(propertyInfo);
931765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      int y = m_rowHeight * (index - m_selection) + 1;
932765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      return new Point(x, y);
933765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
934765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    return null;
935765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
936765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
937765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
938765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * @return the location of state image (plus/minus) for given {@link Property}.
939765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
940765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  public Point forTests_getValueLocation(Property property) {
941765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    PropertyInfo propertyInfo = getPropertyInfo(property);
942765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (propertyInfo != null) {
943765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      int index = m_properties.indexOf(propertyInfo);
944765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      int x = m_splitter + 5;
945765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      int y = m_rowHeight * (index - m_selection) + 1;
946765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      return new Point(x, y);
947765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
948765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    return null;
949765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
950765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
951765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
952765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * @return the active {@link PropertyEditor}.
953765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
954765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  public PropertyEditor forTests_getActiveEditor() {
955765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    return m_activeEditor;
956765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
957765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
958765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
959765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * @return the {@link PropertyCategory} that is used by this {@link PropertyTable} to display.
960765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
961765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  public PropertyCategory forTests_getCategory(Property property) {
962765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    return getCategory(property);
963765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
964765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
965765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
966765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * @return the {@link PropertyInfo}for given {@link Property}.
967765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
968765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private PropertyInfo getPropertyInfo(Property property) {
969765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    for (PropertyInfo propertyInfo : m_properties) {
970765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      if (propertyInfo.getProperty() == property) {
971765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        return propertyInfo;
972765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
973765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
974765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    return null;
975765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
976765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
977765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
978765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
979765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // ISelectionProvider
980765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
981765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
982765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private final List<ISelectionChangedListener> m_selectionListeners = Lists.newArrayList();
983765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
984765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  @Override
985765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyepublic void addSelectionChangedListener(ISelectionChangedListener listener) {
986765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (!m_selectionListeners.contains(listener)) {
987765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_selectionListeners.add(listener);
988765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
989765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
990765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
991765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  @Override
992765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyepublic void removeSelectionChangedListener(ISelectionChangedListener listener) {
993765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    m_selectionListeners.add(listener);
994765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
995765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
996765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  @Override
997765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbyepublic ISelection getSelection() {
998765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (m_activePropertyInfo != null) {
999765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      return new StructuredSelection(m_activePropertyInfo.getProperty());
1000765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    } else {
1001765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      return StructuredSelection.EMPTY;
1002765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
1003765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
1004765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1005765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  @Override
1006765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  public void setSelection(ISelection selection) {
1007765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    throw new UnsupportedOperationException();
1008765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
1009765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1010765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
1011765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Sets the new active {@link PropertyInfo} and sends event to {@link ISelectionChangedListener}
1012765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * 's.
1013765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
1014765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private void setActivePropertyInfo(PropertyInfo activePropertyInfo) {
1015765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    m_activePropertyInfo = activePropertyInfo;
1016765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // update m_activePropertyId only when really select property,
1017765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // not just remove selection because there are no corresponding property for old active
1018765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // so, later for some other component, if we don't select other property, old active will be selected
1019765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (m_activePropertyInfo != null) {
1020765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_activePropertyId = m_activePropertyInfo.m_id;
1021765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
1022765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // make sure that active property is visible
1023765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (m_activePropertyInfo != null) {
1024765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      int row = m_properties.indexOf(m_activePropertyInfo);
1025765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      if (m_selection <= row && row < m_selection + m_page) {
1026765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      } else {
1027765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        m_selection = row;
1028765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        configureScrolling();
1029765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
1030765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
1031765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // send events
1032765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    SelectionChangedEvent selectionEvent = new SelectionChangedEvent(this, getSelection());
1033765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    for (ISelectionChangedListener listener : m_selectionListeners) {
1034765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      listener.selectionChanged(selectionEvent);
1035765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
1036765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // re-draw
1037765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    redraw();
1038765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
1039765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1040765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
1041765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
1042765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // Painting
1043765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
1044765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
1045765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private boolean m_painting;
1046765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private Font m_baseFont;
1047765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private Font m_boldFont;
1048765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private Font m_italicFont;
1049765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1050765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
1051765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Handles {@link SWT#Paint} event.
1052765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
1053765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private void handlePaint(GC gc, int x, int y, int width, int height) {
1054765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // sometimes we disable Eclipse Shell to prevent user actions, but we do this for short time
1055765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (!isEnabled()) {
1056765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      return;
1057765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
1058765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // prevent recursion
1059765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    if (m_painting) {
1060765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      return;
1061765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
1062765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    m_painting = true;
1063765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    //
1064765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    try {
1065765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      setActiveEditorBounds();
1066765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // prepare buffered image
1067765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      if (m_bufferedImage == null || m_bufferedImage.isDisposed()) {
1068765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        Point size = getSize();
1069765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        m_bufferedImage = new Image(DesignerPlugin.getStandardDisplay(), size.x, size.y);
1070765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
1071765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // prepare buffered GC
1072765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      GC bufferedGC = null;
1073765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      try {
1074765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // perform some drawing
1075765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        {
1076765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          bufferedGC = new GC(m_bufferedImage);
1077765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          bufferedGC.setClipping(x, y, width, height);
1078765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          bufferedGC.setBackground(gc.getBackground());
1079765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          bufferedGC.setForeground(gc.getForeground());
1080765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          bufferedGC.setFont(gc.getFont());
1081765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          bufferedGC.setLineStyle(gc.getLineStyle());
1082765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          bufferedGC.setLineWidth(gc.getLineWidth());
1083765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
1084765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // fill client area
1085765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        {
1086765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          Rectangle clientArea = getClientArea();
1087765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          bufferedGC.setBackground(COLOR_BACKGROUND);
1088765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          bufferedGC.fillRectangle(clientArea);
1089765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
1090765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // draw content
1091765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        if (m_properties == null || m_properties.size() == 0) {
1092765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          drawEmptyContent(bufferedGC);
1093765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        } else {
1094765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          drawContent(bufferedGC);
1095765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
1096765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      } finally {
1097765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // flush image
1098765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        if (bufferedGC != null) {
1099765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          bufferedGC.dispose();
1100765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
1101765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
1102765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      gc.drawImage(m_bufferedImage, 0, 0);
1103765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    } finally {
1104765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_painting = false;
1105765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
1106765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
1107765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1108765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
1109765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Draws content when there are no properties.
1110765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
1111765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private void drawEmptyContent(GC gc) {
1112765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    Rectangle area = getClientArea();
1113765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // draw message
1114765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    gc.setForeground(COLOR_NO_PROPERTIES);
1115765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    DrawUtils.drawStringCHCV(
1116765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        gc,
1117765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        "<No properties>",
1118765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        0,
1119765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        0,
1120765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        area.width,
1121765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        area.height);
1122765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
1123765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1124765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
1125765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Draws all {@link PropertyInfo}'s, separators, etc.
1126765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
1127765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private void drawContent(GC gc) {
1128765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    Rectangle clientArea = getClientArea();
1129765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // prepare fonts
1130765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    m_baseFont = gc.getFont();
1131765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    m_boldFont = DrawUtils.getBoldFont(m_baseFont);
1132765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    m_italicFont = DrawUtils.getItalicFont(m_baseFont);
1133765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // show presentations
1134765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    int[] presentationsWidth = showPresentations(clientArea);
1135765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // draw properties
1136765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    {
1137765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      int y = clientArea.y - m_rowHeight * m_selection;
1138765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      for (int i = 0; i < m_properties.size(); i++) {
1139765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // skip, if not visible yet
1140765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        if (y + m_rowHeight < 0) {
1141765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          y += m_rowHeight;
1142765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          continue;
1143765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
1144765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // stop, if already invisible
1145765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        if (y > clientArea.height) {
1146765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          break;
1147765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
1148765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // draw single property
1149765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        {
1150765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          PropertyInfo propertyInfo = m_properties.get(i);
1151765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          drawProperty(gc, propertyInfo, y + 1, m_rowHeight - 1, clientArea.width
1152765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye              - presentationsWidth[i]);
1153765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          y += m_rowHeight;
1154765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
1155765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // draw row separator
1156765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        gc.setForeground(COLOR_LINE);
1157765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        gc.drawLine(0, y, clientArea.width, y);
1158765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
1159765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
1160765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // draw expand line
1161765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    drawExpandLines(gc, clientArea);
1162765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // draw rectangle around table
1163765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    gc.setForeground(COLOR_LINE);
1164765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    gc.drawRectangle(0, 0, clientArea.width - 1, clientArea.height - 1);
1165765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // draw splitter
1166765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    gc.setForeground(COLOR_LINE);
1167765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    gc.drawLine(m_splitter, 0, m_splitter, clientArea.height);
1168765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // dispose font
1169765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    m_boldFont.dispose();
1170765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    m_italicFont.dispose();
1171765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
1172765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1173765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
1174765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Shows {@link PropertyEditorPresentation}'s for all {@link Property}'s, i.e. updates also their
1175765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * bounds. So, some {@link PropertyEditorPresentation}'s become invisible because they are moved
1176765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * above or below visible client area.
1177765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   *
1178765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * @return the array of width for each {@link PropertyEditorPresentation}'s, consumed on the
1179765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   *         right.
1180765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
1181765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private int[] showPresentations(Rectangle clientArea) {
1182765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    int[] presentationsWidth = new int[m_properties.size()];
1183765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // prepare value rectangle
1184765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    int x = m_splitter + 4;
1185765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    int w = clientArea.width - x - MARGIN_RIGHT;
1186765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // show presentation's for all properties
1187765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    int y = clientArea.y - m_rowHeight * m_selection;
1188765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    for (int i = 0; i < m_properties.size(); i++) {
1189765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      PropertyInfo propertyInfo = m_properties.get(i);
1190765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      Property property = propertyInfo.getProperty();
1191765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      PropertyEditorPresentation presentation = property.getEditor().getPresentation();
1192765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      if (presentation != null) {
1193765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        presentationsWidth[i] = presentation.show(this, property, x, y + 1, w, m_rowHeight - 1);
1194765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
1195765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      y += m_rowHeight;
1196765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
1197765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    return presentationsWidth;
1198765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
1199765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1200765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
1201765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Draws lines from expanded complex property to its last sub-property.
1202765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
1203765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private void drawExpandLines(GC gc, Rectangle clientArea) {
1204765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    int height = m_rowHeight - 1;
1205765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    int xOffset = m_plusImage.getBounds().width / 2;
1206765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    int yOffset = (height - m_plusImage.getBounds().width) / 2;
1207765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    //
1208765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    int y = clientArea.y - m_selection * m_rowHeight;
1209765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    gc.setForeground(COLOR_COMPLEX_LINE);
1210765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    for (int i = 0; i < m_properties.size(); i++) {
1211765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      PropertyInfo propertyInfo = m_properties.get(i);
1212765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      //
1213765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      if (propertyInfo.isExpanded()) {
1214765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        int index = m_properties.indexOf(propertyInfo);
1215765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // prepare index of last sub-property
1216765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        int index2 = index;
1217765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        for (; index2 < m_properties.size(); index2++) {
1218765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          PropertyInfo nextPropertyInfo = m_properties.get(index2);
1219765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          if (nextPropertyInfo != propertyInfo
1220765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye              && nextPropertyInfo.getLevel() <= propertyInfo.getLevel()) {
1221765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            break;
1222765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          }
1223765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
1224765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        index2--;
1225765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // draw line if there are children
1226765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        if (index2 > index) {
1227765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          int x = getTitleX(propertyInfo) + xOffset;
1228765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          int y1 = y + height - yOffset;
1229765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          int y2 = y + m_rowHeight * (index2 - index) + m_rowHeight / 2;
1230765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          gc.drawLine(x, y1, x, y2);
1231765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          gc.drawLine(x, y2, x + m_rowHeight / 3, y2);
1232765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
1233765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
1234765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      //
1235765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      y += m_rowHeight;
1236765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
1237765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
1238765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1239765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
1240765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Draws single {@link PropertyInfo} in specified rectangle.
1241765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
1242765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private void drawProperty(GC gc, PropertyInfo propertyInfo, int y, int height, int width) {
1243765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // remember colors
1244765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    Color oldBackground = gc.getBackground();
1245765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    Color oldForeground = gc.getForeground();
1246765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // draw property
1247765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    try {
1248765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      Property property = propertyInfo.getProperty();
1249765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      boolean isActiveProperty =
1250765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          m_activePropertyInfo != null && m_activePropertyInfo.getProperty() == property;
1251765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // set background
1252765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    boolean modified = property.isModified();
1253765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    {
1254765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        if (isActiveProperty) {
1255765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          gc.setBackground(COLOR_PROPERTY_BG_SELECTED);
1256765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        } else {
1257765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          if (modified) {
1258765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            gc.setBackground(COLOR_PROPERTY_BG_MODIFIED);
1259765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          } else {
1260765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            gc.setBackground(COLOR_PROPERTY_BG);
1261765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          }
1262765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
1263765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        gc.fillRectangle(0, y, width, height);
1264765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
1265765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // draw state image
1266765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      if (propertyInfo.isShowComplex()) {
1267765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        Image stateImage = propertyInfo.isExpanded() ? m_minusImage : m_plusImage;
1268765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        DrawUtils.drawImageCV(gc, stateImage, getTitleX(propertyInfo), y, height);
1269765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
1270765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // draw title
1271765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      {
1272765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // configure GC
1273765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        {
1274765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          gc.setForeground(COLOR_PROPERTY_FG_TITLE);
1275765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          // check category
1276765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          if (getCategory(property).isAdvanced()) {
1277765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            gc.setForeground(COLOR_PROPERTY_FG_ADVANCED);
1278765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            gc.setFont(m_italicFont);
1279765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          } else if (getCategory(property).isPreferred() || getCategory(property).isSystem()) {
1280765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            gc.setFont(m_boldFont);
1281765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          }
1282765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          // check for active
1283765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          if (isActiveProperty) {
1284765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            gc.setForeground(COLOR_PROPERTY_FG_SELECTED);
1285765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          }
1286765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
1287765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // paint title
1288765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        int x = getTitleTextX(propertyInfo);
1289765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        DrawUtils.drawStringCV(gc, property.getTitle(), x, y, m_splitter - x, height);
1290765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
1291765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // draw value
1292765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      {
1293765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // configure GC
1294765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        gc.setFont(m_baseFont);
1295765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        if (!isActiveProperty) {
1296765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          gc.setForeground(COLOR_PROPERTY_FG_VALUE);
1297765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
1298765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // prepare value rectangle
1299765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        int x = m_splitter + 4;
1300765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        int w = width - x - MARGIN_RIGHT;
1301765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // paint value
1302765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1303765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // BEGIN ADT MODIFICATIONS
1304765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        if (!modified) {
1305765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            gc.setForeground(COLOR_PROPERTY_FG_DEFAULT);
1306765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
1307765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // END ADT MODIFICATIONS
1308765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1309765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        property.getEditor().paint(property, gc, x, y, w, height);
1310765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
1311765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    } catch (Throwable e) {
1312765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      DesignerPlugin.log(e);
1313765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    } finally {
1314765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // restore colors
1315765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      gc.setBackground(oldBackground);
1316765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      gc.setForeground(oldForeground);
1317765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
1318765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
1319765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1320765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
1321765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
1322765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // PropertyCategory
1323765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
1324765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
1325765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private PropertyCategoryProvider m_propertyCategoryProvider =
1326765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      PropertyCategoryProviders.fromProperty();
1327765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1328765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
1329765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Sets the {@link PropertyCategoryProvider} that can be used to tweak usual
1330765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * {@link PropertyCategory}.
1331765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
1332765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  public void setPropertyCategoryProvider(PropertyCategoryProvider propertyCategoryProvider) {
1333765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    m_propertyCategoryProvider = propertyCategoryProvider;
1334765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
1335765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1336765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
1337765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * @return the {@link PropertyCategory} that is used by this {@link PropertyTable} to display.
1338765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
1339765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private PropertyCategory getCategory(Property property) {
1340765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    return m_propertyCategoryProvider.getCategory(property);
1341765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
1342765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1343765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
1344765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
1345765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // PropertyInfo
1346765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  //
1347765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  ////////////////////////////////////////////////////////////////////////////
1348765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /**
1349765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * Class with information about single {@link Property}.
1350765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   *
1351765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   * @author scheglov_ke
1352765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye   */
1353765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  private final class PropertyInfo {
1354765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    private final String m_id;
1355765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    private final int m_level;
1356765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    private final Property m_property;
1357765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    private final boolean m_stateComplex;
1358765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    private boolean m_stateExpanded;
1359765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    private List<PropertyInfo> m_children;
1360765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1361765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    ////////////////////////////////////////////////////////////////////////////
1362765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    //
1363765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // Constructor
1364765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    //
1365765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    ////////////////////////////////////////////////////////////////////////////
1366765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    public PropertyInfo(Property property) {
1367765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      this(property, "", 0);
1368765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
1369765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1370765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    private PropertyInfo(Property property, String idPrefix, int level) {
1371765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // BEGIN ADT MODIFICATIONS
1372765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      //m_id = idPrefix + "|" + property.getTitle();
1373765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_id = idPrefix + "|" + property.getName();
1374765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // END ADT MODIFICATIONS
1375765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_level = level;
1376765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_property = property;
1377765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_stateComplex = property.getEditor() instanceof IComplexPropertyEditor;
1378765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
1379765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1380765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    ////////////////////////////////////////////////////////////////////////////
1381765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    //
1382765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // State
1383765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    //
1384765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    ////////////////////////////////////////////////////////////////////////////
1385765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    /**
1386765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye     * @return <code>true</code> if this property is complex.
1387765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye     */
1388765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    public boolean isComplex() {
1389765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      return m_stateComplex;
1390765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
1391765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1392765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    public boolean isShowComplex() throws Exception {
1393765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      if (m_stateComplex) {
1394765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        prepareChildren();
1395765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        return m_children != null && !m_children.isEmpty();
1396765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
1397765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      return false;
1398765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
1399765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1400765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    /**
1401765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye     * @return <code>true</code> if this complex property is expanded.
1402765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye     */
1403765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    public boolean isExpanded() {
1404765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      return m_stateExpanded;
1405765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
1406765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1407765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    ////////////////////////////////////////////////////////////////////////////
1408765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    //
1409765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // Access
1410765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    //
1411765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    ////////////////////////////////////////////////////////////////////////////
1412765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    /**
1413765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye     * @return the level of this property, i.e. on which level of complex property it is located.
1414765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye     */
1415765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    public int getLevel() {
1416765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      return m_level;
1417765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
1418765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1419765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    /**
1420765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye     * @return the {@link Property}.
1421765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye     */
1422765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    public Property getProperty() {
1423765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      return m_property;
1424765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
1425765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1426765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    /**
1427765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye     * Flips collapsed/expanded state and adds/removes sub-properties.
1428765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye     */
1429765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    public void flip() throws Exception {
1430765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      Assert.isTrue(m_stateComplex);
1431765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      if (m_stateExpanded) {
1432765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        collapse();
1433765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      } else {
1434765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        expand();
1435765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
1436765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
1437765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1438765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    /**
1439765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye     * Expands this property.
1440765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye     */
1441765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    public void expand() throws Exception {
1442765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      Assert.isTrue(m_stateComplex);
1443765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      Assert.isTrue(!m_stateExpanded);
1444765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      //
1445765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_stateExpanded = true;
1446765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_expandedIds.add(m_id);
1447765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // BEGIN ADT MODIFICATIONS
1448765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      if (m_collapsedIds != null) {
1449765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          m_collapsedIds.remove(m_id);
1450765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
1451765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // END ADT MODIFICATIONS
1452765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      prepareChildren();
1453765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      //
1454765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      int index = m_properties.indexOf(this);
1455765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      addChildren(index + 1);
1456765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
1457765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1458765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    /**
1459765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye     * Collapses this property.
1460765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye     */
1461765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    public void collapse() throws Exception {
1462765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      Assert.isTrue(m_stateComplex);
1463765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      Assert.isTrue(m_stateExpanded);
1464765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      //
1465765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_stateExpanded = false;
1466765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      m_expandedIds.remove(m_id);
1467765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // BEGIN ADT MODIFICATIONS
1468765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      if (m_collapsedIds != null) {
1469765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          m_collapsedIds.add(m_id);
1470765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
1471765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // END ADT MODIFICATIONS
1472765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      prepareChildren();
1473765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      //
1474765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      int index = m_properties.indexOf(this);
1475765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      removeChildren(index + 1);
1476765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
1477765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1478765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    ////////////////////////////////////////////////////////////////////////////
1479765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    //
1480765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // Internal
1481765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    //
1482765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    ////////////////////////////////////////////////////////////////////////////
1483765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    /**
1484765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye     * Adds children properties.
1485765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye     *
1486765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye     * @return the index for new properties to add.
1487765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye     */
1488765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    private int addChildren(int index) throws Exception {
1489765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      prepareChildren();
1490765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      for (PropertyInfo child : m_children) {
1491765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // skip if should not display raw Property
1492765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        if (!rawProperties_shouldShow(child.m_property)) {
1493765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          continue;
1494765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
1495765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // add child
1496765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        m_properties.add(index++, child);
1497765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // add children of current child
1498765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        if (child.isExpanded()) {
1499765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          index = child.addChildren(index);
1500765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
1501765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
1502765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      return index;
1503765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
1504765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1505765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    /**
1506765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye     * Removes children properties.
1507765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye     */
1508765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    private void removeChildren(int index) throws Exception {
1509765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      prepareChildren();
1510765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      for (PropertyInfo child : m_children) {
1511765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // skip if should not display raw Property
1512765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        if (!rawProperties_shouldShow(child.m_property)) {
1513765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          continue;
1514765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
1515765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // hide presentation
1516765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        {
1517765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          PropertyEditorPresentation presentation =
1518765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye              child.getProperty().getEditor().getPresentation();
1519765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          if (presentation != null) {
1520765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye            presentation.hide(PropertyTable.this, child.getProperty());
1521765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          }
1522765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
1523765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // remove child
1524765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        m_properties.remove(index);
1525765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        // remove children of current child
1526765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        if (child.isExpanded()) {
1527765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          child.removeChildren(index);
1528765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
1529765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
1530765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
1531765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1532765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    /**
1533765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye     * Prepares children {@link PropertyInfo}'s, for sub-properties.
1534765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye     */
1535765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    private void prepareChildren() throws Exception {
1536765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      if (m_children == null) {
1537765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        m_children = Lists.newArrayList();
1538765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        for (Property subProperty : getSubProperties()) {
1539765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          PropertyInfo subPropertyInfo = createSubPropertyInfo(subProperty);
1540765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          m_children.add(subPropertyInfo);
1541765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
1542765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
1543765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
1544765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1545765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    private PropertyInfo createSubPropertyInfo(Property subProperty) {
1546765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      return new PropertyInfo(subProperty, m_id, m_level + 1);
1547765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
1548765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1549765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    private Property[] getSubProperties() throws Exception {
1550765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      IComplexPropertyEditor complexEditor = (IComplexPropertyEditor) m_property.getEditor();
1551765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      List<Property> subProperties = Lists.newArrayList();
1552765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      for (Property subProperty : complexEditor.getProperties(m_property)) {
1553765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        if (getCategory(subProperty).isHidden() && !subProperty.isModified()) {
1554765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          // skip hidden properties
1555765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          continue;
1556765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        }
1557765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        subProperties.add(subProperty);
1558765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
1559765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      return subProperties.toArray(new Property[subProperties.size()]);
1560765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
1561765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1562765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    ////////////////////////////////////////////////////////////////////////////
1563765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    //
1564765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    // Persistent expanding support
1565765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    //
1566765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    ////////////////////////////////////////////////////////////////////////////
1567765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    /**
1568765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye     * @return <code>true</code> if this {@link PropertyInfo} was expanded from history.
1569765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye     */
1570765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    public boolean expandFromHistory() throws Exception {
1571765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      if (isComplex() && !isExpanded() && m_expandedIds.contains(m_id)) {
1572765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        expand();
1573765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye        return true;
1574765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
1575765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // BEGIN ADT MODIFICATIONS
1576765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      if (m_collapsedIds != null && isComplex() && !isExpanded()
1577765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye              && !m_collapsedIds.contains(m_id)) {
1578765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          expand();
1579765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          return true;
1580765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
1581765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      // END ADT MODIFICATIONS
1582765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      return false;
1583765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye    }
1584765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
1585765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1586765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // BEGIN ADT MODIFICATIONS
1587765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /** Collapse all top-level properties */
1588765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  public void collapseAll() {
1589765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      try {
1590765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          m_lastExpandCollapseTime = System.currentTimeMillis();
1591765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          if (m_collapsedIds != null) {
1592765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye              m_collapsedIds.addAll(m_expandedIds);
1593765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          }
1594765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          m_expandedIds.clear();
1595765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          setInput(m_rawProperties);
1596765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          redraw();
1597765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      } catch (Throwable e) {
1598765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          DesignerPlugin.log(e);
1599765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
1600765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
1601765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye
1602765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  /** Expand all top-level properties */
1603765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  public void expandAll() {
1604765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      try {
1605765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          m_lastExpandCollapseTime = System.currentTimeMillis();
1606765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          if (m_collapsedIds != null) {
1607765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye              m_collapsedIds.clear();
1608765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          }
1609765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          m_expandedIds.clear();
1610765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          for (PropertyInfo info : m_properties) {
1611765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye              if (info.m_stateComplex) {
1612765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye                  m_expandedIds.add(info.m_id);
1613765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye              }
1614765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          }
1615765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          setInput(m_rawProperties);
1616765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          redraw();
1617765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      } catch (Throwable e) {
1618765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye          DesignerPlugin.log(e);
1619765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye      }
1620765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  }
1621765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye  // END ADT MODIFICATIONS
1622765e52e2d30d0754625b8c7af6c36e93612f15beTor Norbye}