Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: df651a14a1a151faeb41096e30bd0122901f2eda (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
/*******************************************************************************
 * Copyright (c) 2000, 2010 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.jface.action;

import java.util.ArrayList;
import java.util.Iterator;

import org.eclipse.swt.SWT;
import org.eclipse.swt.accessibility.ACC;
import org.eclipse.swt.accessibility.AccessibleAdapter;
import org.eclipse.swt.accessibility.AccessibleEvent;
import org.eclipse.swt.accessibility.AccessibleListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.CoolBar;
import org.eclipse.swt.widgets.CoolItem;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;

/**
 * A tool bar manager is a contribution manager which realizes itself and its
 * items in a tool bar control.
 * <p>
 * This class may be instantiated; it may also be subclassed if a more
 * sophisticated layout is required.
 * </p>
 */
public class ToolBarManager extends ContributionManager implements
		IToolBarManager {

	/**
	 * The tool bar items style; <code>SWT.NONE</code> by default.
	 */
	private int itemStyle = SWT.NONE;

	/**
	 * The tool bar control; <code>null</code> before creation and after
	 * disposal.
	 */
	private ToolBar toolBar = null;

	/**
	 * The menu manager to the context menu associated with the toolbar.
	 * 
	 * @since 3.0
	 */
	private MenuManager contextMenuManager = null;

	/**
	 * Creates a new tool bar manager with the default SWT button style. Use the
	 * {@link #createControl(Composite)} method to create the tool bar control.
	 * 
	 */
	public ToolBarManager() {
		//Do nothing if there are no parameters
	}

	/**
	 * Creates a tool bar manager with the given SWT button style. Use the
	 * <code>createControl</code> method to create the tool bar control.
	 * 
	 * @param style
	 *            the tool bar item style
	 * @see org.eclipse.swt.widgets.ToolBar for valid style bits
	 */
	public ToolBarManager(int style) {
		itemStyle = style;
	}

	/**
	 * Creates a tool bar manager for an existing tool bar control. This manager
	 * becomes responsible for the control, and will dispose of it when the
	 * manager is disposed.
	 * <strong>NOTE</strong> When creating a ToolBarManager from an existing
	 * {@link ToolBar} you will not get the accessible listener provided by
	 * JFace.
	 * @see #ToolBarManager()
	 * @see #ToolBarManager(int)
	 * 
	 * @param toolbar
	 *            the tool bar control
	 */
	public ToolBarManager(ToolBar toolbar) {
		this();
		this.toolBar = toolbar;
	}

	/**
	 * Creates and returns this manager's tool bar control. Does not create a
	 * new control if one already exists. Also create an {@link AccessibleListener}
	 * for the {@link ToolBar}.
	 * 
	 * @param parent
	 *            the parent control
	 * @return the tool bar control
	 */
	public ToolBar createControl(Composite parent) {
		if (!toolBarExist() && parent != null) {
			toolBar = new ToolBar(parent, itemStyle);
			toolBar.setMenu(getContextMenuControl());
			update(true);
			
			toolBar.getAccessible().addAccessibleListener(getAccessibleListener());
		}

		return toolBar;
	}

	/**
	 * Get the accessible listener for the tool bar.
	 * 
	 * @return AccessibleListener
	 * 
	 * @since 3.1
	 */
	private AccessibleListener getAccessibleListener() {
		return new AccessibleAdapter() {
			@Override
			public void getName(AccessibleEvent e) {
				if (e.childID != ACC.CHILDID_SELF) {
					ToolItem item = toolBar.getItem(e.childID);
					if (item != null) {
						String toolTip = item.getToolTipText();
						if (toolTip != null) {
							e.result = toolTip;
						}
					}
				}
			}
		};

	}

	/**
	 * Disposes of this tool bar manager and frees all allocated SWT resources.
	 * Notifies all contribution items of the dispose. Note that this method
	 * does not clean up references between this tool bar manager and its
	 * associated contribution items. Use <code>removeAll</code> for that
	 * purpose.
	 */
	public void dispose() {

		if (toolBarExist()) {
			toolBar.dispose();
		}
		toolBar = null;

		IContributionItem[] items = getItems();
		for (int i = 0; i < items.length; i++) {
			items[i].dispose();
		}

		if (getContextMenuManager() != null) {
			getContextMenuManager().dispose();
			setContextMenuManager(null);
		}
	}

	/**
	 * Returns the tool bar control for this manager.
	 * 
	 * @return the tool bar control, or <code>null</code> if none (before
	 *         creating or after disposal)
	 */
	public ToolBar getControl() {
		return toolBar;
	}

	/**
	 * Re-lays out the tool bar.
	 * <p>
	 * The default implementation of this framework method re-lays out the
	 * parent when the number of items are different and the new count != 0
	 * 
	 * @param layoutBar
	 *            the tool bar control
	 * @param oldCount
	 *            the old number of items
	 * @param newCount
	 *            the new number of items
	 */
	protected void relayout(ToolBar layoutBar, int oldCount, int newCount) {
		if ((oldCount != newCount) && (newCount!=0)) {
			Point beforePack = layoutBar.getSize();
			layoutBar.pack(true);
			Point afterPack = layoutBar.getSize();
			
			// If the TB didn't change size then we're done
			if (beforePack.equals(afterPack))
				return;
			
			// OK, we need to re-layout the TB
			layoutBar.getParent().layout();
			
			// Now, if we're in a CoolBar then change the CoolItem size as well
			if (layoutBar.getParent() instanceof CoolBar) {
				CoolBar cb = (CoolBar) layoutBar.getParent();
				CoolItem[] items = cb.getItems();
				for (int i = 0; i < items.length; i++) {
					if (items[i].getControl() == layoutBar) {
						Point curSize = items[i].getSize();
						items[i].setSize(curSize.x+ (afterPack.x - beforePack.x),
									curSize.y+ (afterPack.y - beforePack.y));
						return;
					}
				}
			}
		}
	}

	/**
	 * Returns whether the tool bar control is created and not disposed.
	 * 
	 * @return <code>true</code> if the control is created and not disposed,
	 *         <code>false</code> otherwise
	 */
	private boolean toolBarExist() {
		return toolBar != null && !toolBar.isDisposed();
	}

	/*
	 * (non-Javadoc) Method declared on IContributionManager.
	 */
	public void update(boolean force) {

		//	long startTime= 0;
		//	if (DEBUG) {
		//		dumpStatistics();
		//		startTime= (new Date()).getTime();
		//	}

		if (isDirty() || force) {

			if (toolBarExist()) {

				int oldCount = toolBar.getItemCount();

				// clean contains all active items without double separators
				IContributionItem[] items = getItems();
				ArrayList<IContributionItem> clean = new ArrayList<IContributionItem>(items.length);
				IContributionItem separator = null;
				//			long cleanStartTime= 0;
				//			if (DEBUG) {
				//				cleanStartTime= (new Date()).getTime();
				//			}
				for (int i = 0; i < items.length; ++i) {
					IContributionItem ci = items[i];
					if (!isChildVisible(ci)) {
						continue;
					}
					if (ci.isSeparator()) {
						// delay creation until necessary
						// (handles both adjacent separators, and separator at
						// end)
						separator = ci;
					} else {
						if (separator != null) {
							if (clean.size() > 0) {
								clean.add(separator);
							}
							separator = null;
						}
						clean.add(ci);
					}
				}
				//			if (DEBUG) {
				//				System.out.println(" Time needed to build clean vector: " +
				// ((new Date()).getTime() - cleanStartTime));
				//			}

				// determine obsolete items (removed or non active)
				ToolItem[] mi = toolBar.getItems();
				ArrayList<ToolItem> toRemove = new ArrayList<ToolItem>(mi.length);
				for (int i = 0; i < mi.length; i++) {
					// there may be null items in a toolbar
					if (mi[i] == null)
						continue;
					
					Object data = mi[i].getData();
					if (data == null
							|| !clean.contains(data)
							|| (data instanceof IContributionItem && ((IContributionItem) data)
									.isDynamic())) {
						toRemove.add(mi[i]);
					}
				}

				// Turn redraw off if the number of items to be added
				// is above a certain threshold, to minimize flicker,
				// otherwise the toolbar can be seen to redraw after each item.
				// Do this before any modifications are made.
				// We assume each contribution item will contribute at least one
				// toolbar item.
				boolean useRedraw = (clean.size() - (mi.length - toRemove
						.size())) >= 3;
                try {
                    if (useRedraw) {
                        toolBar.setRedraw(false);
                    }

                    // remove obsolete items
                    for (int i = toRemove.size(); --i >= 0;) {
                        ToolItem item = toRemove.get(i);
                        if (!item.isDisposed()) {
                            Control ctrl = item.getControl();
                            if (ctrl != null) {
                                item.setControl(null);
                                ctrl.dispose();
                            }
                            item.dispose();
                        }
                    }

                    // add new items
                    IContributionItem src, dest;
                    mi = toolBar.getItems();
                    int srcIx = 0;
                    int destIx = 0;
                    for (Iterator<IContributionItem> e = clean.iterator(); e.hasNext();) {
                        src = e.next();

                        // get corresponding item in SWT widget
                        if (srcIx < mi.length) {
							dest = (IContributionItem) mi[srcIx].getData();
						} else {
							dest = null;
						}

                        if (dest != null && src.equals(dest)) {
                            srcIx++;
                            destIx++;
                            continue;
                        }

                        if (dest != null && dest.isSeparator()
                                && src.isSeparator()) {
                            mi[srcIx].setData(src);
                            srcIx++;
                            destIx++;
                            continue;
                        }

                        int start = toolBar.getItemCount();
                        src.fill(toolBar, destIx);
                        int newItems = toolBar.getItemCount() - start;
                        for (int i = 0; i < newItems; i++) {
                            ToolItem item = toolBar.getItem(destIx++);
                            item.setData(src);
                        }
                    }

                    // remove any old tool items not accounted for
                    for (int i = mi.length; --i >= srcIx;) {
                        ToolItem item = mi[i];
                        if (!item.isDisposed()) {
                            Control ctrl = item.getControl();
                            if (ctrl != null) {
                                item.setControl(null);
                                ctrl.dispose();
                            }
                            item.dispose();
                        }
                    }

                    setDirty(false);

                    // turn redraw back on if we turned it off above
                } finally {
                    if (useRedraw) {
                        toolBar.setRedraw(true);
                    }
                }

				int newCount = toolBar.getItemCount();
				
				// If we're forcing a change then ensure that we re-layout everything
				if (force)
					oldCount = newCount+1;
				
				relayout(toolBar, oldCount, newCount);
			}

		}

		//	if (DEBUG) {
		//		System.out.println(" Time needed for update: " + ((new
		// Date()).getTime() - startTime));
		//		System.out.println();
		//	}
	}

	/**
	 * Returns the control of the Menu Manager. If the menu manager does not
	 * have a control then one is created.
	 * 
	 * @return menu widget associated with manager
	 */
	private Menu getContextMenuControl() {
		if ((contextMenuManager != null) && (toolBar != null)) {
			Menu menuWidget = contextMenuManager.getMenu();
			if ((menuWidget == null) || (menuWidget.isDisposed())) {
				menuWidget = contextMenuManager.createContextMenu(toolBar);
			}
			return menuWidget;
		}
		return null;
	}

	/**
	 * Returns the context menu manager for this tool bar manager.
	 * 
	 * @return the context menu manager, or <code>null</code> if none
	 * @since 3.0
	 */
	public MenuManager getContextMenuManager() {
		return contextMenuManager;
	}

	/**
	 * Sets the context menu manager for this tool bar manager to the given menu
	 * manager. If the tool bar control exists, it also adds the menu control to
	 * the tool bar.
	 * 
	 * @param contextMenuManager
	 *            the context menu manager, or <code>null</code> if none
	 * @since 3.0
	 */
	public void setContextMenuManager(MenuManager contextMenuManager) {
		this.contextMenuManager = contextMenuManager;
		if (toolBar != null) {
			toolBar.setMenu(getContextMenuControl());
		}
	}

	private boolean isChildVisible(IContributionItem item) {
		Boolean v;
		
		IContributionManagerOverrides overrides = getOverrides();
		if(overrides == null) {
			v = null;
		} else {
			v = getOverrides().getVisible(item); 
		}
		
		if (v != null) {
			return v.booleanValue();
		}
		return item.isVisible();
	}
}

Back to the top