Project

General

Profile

Download (11.8 KB) Statistics
| Branch: | Tag: | Revision:
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.gef.internal.ui.palette.editparts;
12

    
13
import java.beans.PropertyChangeEvent;
14
import java.util.Iterator;
15

    
16
import org.eclipse.swt.events.MenuEvent;
17
import org.eclipse.swt.events.MenuListener;
18
import org.eclipse.swt.graphics.Point;
19
import org.eclipse.swt.widgets.Display;
20
import org.eclipse.swt.widgets.Menu;
21

    
22
import org.eclipse.jface.action.MenuManager;
23

    
24
import org.eclipse.draw2d.ActionEvent;
25
import org.eclipse.draw2d.ActionListener;
26
import org.eclipse.draw2d.Border;
27
import org.eclipse.draw2d.BorderLayout;
28
import org.eclipse.draw2d.ButtonBorder;
29
import org.eclipse.draw2d.ButtonModel;
30
import org.eclipse.draw2d.ChangeEvent;
31
import org.eclipse.draw2d.ChangeListener;
32
import org.eclipse.draw2d.Clickable;
33
import org.eclipse.draw2d.ColorConstants;
34
import org.eclipse.draw2d.Figure;
35
import org.eclipse.draw2d.Graphics;
36
import org.eclipse.draw2d.IFigure;
37
import org.eclipse.draw2d.StackLayout;
38
import org.eclipse.draw2d.geometry.Dimension;
39
import org.eclipse.draw2d.geometry.Rectangle;
40

    
41
import org.eclipse.gef.GraphicalEditPart;
42
import org.eclipse.gef.Request;
43
import org.eclipse.gef.RequestConstants;
44
import org.eclipse.gef.palette.PaletteEntry;
45
import org.eclipse.gef.palette.PaletteListener;
46
import org.eclipse.gef.palette.PaletteStack;
47
import org.eclipse.gef.palette.ToolEntry;
48
import org.eclipse.gef.ui.actions.SetActivePaletteToolAction;
49
import org.eclipse.gef.ui.palette.PaletteViewer;
50
import org.eclipse.gef.ui.palette.editparts.PaletteEditPart;
51

    
52
/**
53
 * The EditPart for a PaletteStack to be used on the toolbar.
54
 * 
55
 * @author Whitney Sorenson
56
 * @since 3.0
57
 */
58
public class PaletteStackEditPart extends PaletteEditPart implements
59
		IPaletteStackEditPart {
60

    
61
	private static final Dimension EMPTY_DIMENSION = new Dimension(0, 0);
62

    
63
	// listen to changes of clickable tool figure
64
	private ChangeListener clickableListener = new ChangeListener() {
65
		public void handleStateChanged(ChangeEvent event) {
66
			if (event.getPropertyName().equals(ButtonModel.MOUSEOVER_PROPERTY))
67
				arrowFigure.getModel().setMouseOver(
68
						activeFigure.getModel().isMouseOver());
69
			else if (event.getPropertyName().equals(ButtonModel.ARMED_PROPERTY))
70
				arrowFigure.getModel().setArmed(
71
						activeFigure.getModel().isArmed());
72
		}
73
	};
74

    
75
	// listen to changes of arrow figure
76
	private ChangeListener clickableArrowListener = new ChangeListener() {
77
		public void handleStateChanged(ChangeEvent event) {
78
			if (event.getPropertyName().equals(ButtonModel.MOUSEOVER_PROPERTY))
79
				activeFigure.getModel().setMouseOver(
80
						arrowFigure.getModel().isMouseOver());
81
			if (event.getPropertyName().equals(ButtonModel.ARMED_PROPERTY))
82
				activeFigure.getModel().setArmed(
83
						arrowFigure.getModel().isArmed());
84
		}
85
	};
86

    
87
	// listen to see if arrow is pressed
88
	private ActionListener actionListener = new ActionListener() {
89
		public void actionPerformed(ActionEvent event) {
90
			openMenu();
91
		}
92
	};
93

    
94
	// listen to see if active tool is changed in palette
95
	private PaletteListener paletteListener = new PaletteListener() {
96
		public void activeToolChanged(PaletteViewer palette, ToolEntry tool) {
97
			if (getStack().getChildren().contains(tool)) {
98
				if (!arrowFigure.getModel().isSelected())
99
					arrowFigure.getModel().setSelected(true);
100
				if (!getStack().getActiveEntry().equals(tool))
101
					getStack().setActiveEntry(tool);
102
			} else
103
				arrowFigure.getModel().setSelected(false);
104
		}
105
	};
106

    
107
	private Clickable activeFigure;
108
	private RolloverArrow arrowFigure;
109
	private Figure contentsFigure;
110
	private Menu menu;
111

    
112
	/**
113
	 * Creates a new PaletteStackEditPart with the given PaletteStack as its
114
	 * model.
115
	 * 
116
	 * @param model
117
	 *            the PaletteStack to associate with this EditPart.
118
	 */
119
	public PaletteStackEditPart(PaletteStack model) {
120
		super(model);
121
	}
122

    
123
	/**
124
	 * @see org.eclipse.gef.EditPart#activate()
125
	 */
126
	public void activate() {
127
		// in case the model is out of sync
128
		checkActiveEntrySync();
129
		getPaletteViewer().addPaletteListener(paletteListener);
130
		super.activate();
131
	}
132

    
133
	/**
134
	 * Called when the active entry has changed.
135
	 * 
136
	 * @param oldValue
137
	 *            the old model value (can be null)
138
	 * @param newValue
139
	 *            the new model value (can be null)
140
	 */
141
	private void activeEntryChanged(Object oldValue, Object newValue) {
142
		GraphicalEditPart part = null;
143
		Clickable clickable = null;
144

    
145
		if (newValue != null) {
146
			part = (GraphicalEditPart) getViewer().getEditPartRegistry().get(
147
					newValue);
148
			clickable = (Clickable) part.getFigure();
149
			clickable.setVisible(true);
150
			clickable.addChangeListener(clickableListener);
151
			activeFigure = clickable;
152
		} else {
153
			activeFigure = null;
154
		}
155

    
156
		if (oldValue != null) {
157
			part = (GraphicalEditPart) getViewer().getEditPartRegistry().get(
158
					oldValue);
159
			// if part is null, its no longer a child.
160
			if (part != null) {
161
				clickable = (Clickable) part.getFigure();
162
				clickable.setVisible(false);
163
				clickable.removeChangeListener(clickableListener);
164
			}
165
		}
166
	}
167

    
168
	private void checkActiveEntrySync() {
169
		if (activeFigure == null)
170
			activeEntryChanged(null, getStack().getActiveEntry());
171
	}
172

    
173
	/**
174
	 * @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#createFigure()
175
	 */
176
	public IFigure createFigure() {
177

    
178
		Figure figure = new Figure() {
179
			public Dimension getPreferredSize(int wHint, int hHint) {
180
				if (PaletteStackEditPart.this.getChildren().isEmpty())
181
					return EMPTY_DIMENSION;
182
				return super.getPreferredSize(wHint, hHint);
183
			}
184
		};
185
		figure.setLayoutManager(new BorderLayout());
186

    
187
		contentsFigure = new Figure();
188
		StackLayout stackLayout = new StackLayout();
189
		// make it so the stack layout does not allow the invisible figures to
190
		// contribute
191
		// to its bounds
192
		stackLayout.setObserveVisibility(true);
193
		contentsFigure.setLayoutManager(stackLayout);
194
		figure.add(contentsFigure, BorderLayout.CENTER);
195

    
196
		arrowFigure = new RolloverArrow();
197
		arrowFigure.addChangeListener(clickableArrowListener);
198
		arrowFigure.addActionListener(actionListener);
199
		figure.add(arrowFigure, BorderLayout.RIGHT);
200

    
201
		return figure;
202
	}
203

    
204
	/**
205
	 * @see org.eclipse.gef.EditPart#deactivate()
206
	 */
207
	public void deactivate() {
208
		if (activeFigure != null)
209
			activeFigure.removeChangeListener(clickableListener);
210
		arrowFigure.removeActionListener(actionListener);
211
		arrowFigure.removeChangeListener(clickableArrowListener);
212
		getPaletteViewer().removePaletteListener(paletteListener);
213
		super.deactivate();
214
	}
215

    
216
	/**
217
	 * @see org.eclipse.gef.EditPart#eraseTargetFeedback(org.eclipse.gef.Request)
218
	 */
219
	public void eraseTargetFeedback(Request request) {
220
		Iterator children = getChildren().iterator();
221

    
222
		while (children.hasNext()) {
223
			PaletteEditPart part = (PaletteEditPart) children.next();
224
			part.eraseTargetFeedback(request);
225
		}
226
		super.eraseTargetFeedback(request);
227
	}
228

    
229
	/**
230
	 * @see org.eclipse.gef.GraphicalEditPart#getContentPane()
231
	 */
232
	public IFigure getContentPane() {
233
		return contentsFigure;
234
	}
235

    
236
	private PaletteStack getStack() {
237
		return (PaletteStack) getModel();
238
	}
239

    
240
	/**
241
	 * Opens the menu to display the choices for the active entry.
242
	 */
243
	public void openMenu() {
244
		MenuManager menuManager = new MenuManager();
245

    
246
		Iterator children = getChildren().iterator();
247
		PaletteEditPart part = null;
248
		PaletteEntry entry = null;
249
		while (children.hasNext()) {
250
			part = (PaletteEditPart) children.next();
251
			entry = (PaletteEntry) part.getModel();
252

    
253
			menuManager
254
					.add(new SetActivePaletteToolAction(getPaletteViewer(),
255
							entry.getLabel(), entry.getSmallIcon(), getStack()
256
									.getActiveEntry().equals(entry),
257
							(ToolEntry) entry));
258
		}
259

    
260
		menu = menuManager.createContextMenu(getPaletteViewer().getControl());
261

    
262
		// make the menu open below the figure
263
		Rectangle figureBounds = getFigure().getBounds().getCopy();
264
		getFigure().translateToAbsolute(figureBounds);
265

    
266
		Point menuLocation = getPaletteViewer().getControl().toDisplay(
267
				figureBounds.getBottomLeft().x, figureBounds.getBottomLeft().y);
268

    
269
		// remove feedback from the arrow Figure and children figures
270
		arrowFigure.getModel().setMouseOver(false);
271
		eraseTargetFeedback(new Request(RequestConstants.REQ_SELECTION));
272

    
273
		menu.setLocation(menuLocation);
274
		menu.addMenuListener(new StackMenuListener(menu, getViewer()
275
				.getControl().getDisplay()));
276
		menu.setVisible(true);
277
	}
278

    
279
	/**
280
	 * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
281
	 */
282
	public void propertyChange(PropertyChangeEvent event) {
283
		if (event.getPropertyName().equals(PaletteStack.PROPERTY_ACTIVE_ENTRY))
284
			activeEntryChanged(event.getOldValue(), event.getNewValue());
285
		else
286
			super.propertyChange(event);
287
	}
288

    
289
	/**
290
	 * @see org.eclipse.gef.editparts.AbstractEditPart#refreshChildren()
291
	 */
292
	protected void refreshChildren() {
293
		super.refreshChildren();
294
		checkActiveEntrySync();
295
		Iterator children = getChildren().iterator();
296
		while (children.hasNext()) {
297
			PaletteEditPart editPart = (PaletteEditPart) children.next();
298
			if (!editPart.getFigure().equals(activeFigure))
299
				editPart.getFigure().setVisible(false);
300
		}
301
	}
302

    
303
	/**
304
	 * @see org.eclipse.gef.EditPart#showTargetFeedback(org.eclipse.gef.Request)
305
	 */
306
	public void showTargetFeedback(Request request) {
307
		// if menu is showing, don't show feedback. this is a fix
308
		// for the occasion when show is called after forced erase
309
		if (menu != null && !menu.isDisposed() && menu.isVisible())
310
			return;
311

    
312
		Iterator children = getChildren().iterator();
313
		while (children.hasNext()) {
314
			PaletteEditPart part = (PaletteEditPart) children.next();
315
			part.showTargetFeedback(request);
316
		}
317

    
318
		super.showTargetFeedback(request);
319
	}
320

    
321
	public PaletteEditPart getActiveEntry() {
322
		return (PaletteEditPart) getViewer().getEditPartRegistry().get(
323
				getStack().getActiveEntry());
324
	}
325

    
326
}
327

    
328
class StackMenuListener implements MenuListener {
329

    
330
	private Menu menu;
331
	private Display d;
332

    
333
	/**
334
	 * Creates a new listener to listen to the menu that it used to select the
335
	 * active tool on a stack. Disposes the stack with an asyncExec after hidden
336
	 * is called.
337
	 */
338
	StackMenuListener(Menu menu, Display d) {
339
		this.menu = menu;
340
		this.d = d;
341
	}
342

    
343
	/**
344
	 * @see org.eclipse.swt.events.MenuListener#menuShown(org.eclipse.swt.events.MenuEvent)
345
	 */
346
	public void menuShown(MenuEvent e) {
347
	}
348

    
349
	/**
350
	 * @see org.eclipse.swt.events.MenuListener#menuHidden(org.eclipse.swt.events.MenuEvent)
351
	 */
352
	public void menuHidden(MenuEvent e) {
353
		d.asyncExec(new Runnable() {
354
			public void run() {
355
				if (menu != null) {
356
					if (!menu.isDisposed())
357
						menu.dispose();
358
					menu = null;
359
				}
360
			}
361
		});
362
	}
363

    
364
}
365

    
366
class RolloverArrow extends Clickable {
367

    
368
	private static final Border BORDER_TOGGLE = new ButtonBorder(
369
			ButtonBorder.SCHEMES.TOOLBAR);
370

    
371
	/**
372
	 * Creates a new Clickable that paints a triangle figure.
373
	 */
374
	RolloverArrow() {
375
		super();
376
		setRolloverEnabled(true);
377
		setBorder(BORDER_TOGGLE);
378
		setBackgroundColor(ColorConstants.black);
379
		setOpaque(false);
380
		setPreferredSize(11, -1);
381
	}
382

    
383
	/**
384
	 * @return false so that the focus rectangle is not drawn.
385
	 */
386
	public boolean hasFocus() {
387
		return false;
388
	}
389

    
390
	public void paintFigure(Graphics graphics) {
391
		Rectangle rect = getClientArea();
392

    
393
		graphics.translate(getLocation());
394

    
395
		// fill the arrow
396
		int[] points = new int[8];
397

    
398
		points[0] = 3;
399
		points[1] = rect.height / 2;
400
		points[2] = 8;
401
		points[3] = rect.height / 2;
402
		points[4] = 5;
403
		points[5] = 3 + rect.height / 2;
404
		points[6] = 3;
405
		points[7] = rect.height / 2;
406

    
407
		graphics.fillPolygon(points);
408

    
409
		graphics.translate(getLocation().getNegated());
410
	}
411

    
412
}
(12-12/22)