Mercurial > projects > dwt-addons
annotate dwtx/jface/action/CoolBarManager.d @ 90:7ffeace6c47f
Update 3.4M7 to 3.4
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sun, 06 Jul 2008 23:30:07 +0200 |
parents | 46a6e0e6ccd4 |
children | 04b47443bb01 |
rev | line source |
---|---|
25 | 1 /******************************************************************************* |
90 | 2 * Copyright (c) 2003, 2008 IBM Corporation and others. |
25 | 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 * Port to the D programming language: | |
11 * Frank Benoit <benoit@tionex.de> | |
12 *******************************************************************************/ | |
13 module dwtx.jface.action.CoolBarManager; | |
14 | |
15 import dwtx.jface.action.ToolBarContributionItem; | |
16 import dwtx.jface.action.Separator; | |
17 | |
18 import dwtx.jface.action.ContributionManager; | |
19 import dwtx.jface.action.IContributionManager; | |
20 import dwtx.jface.action.IContributionItem; | |
21 import dwtx.jface.action.ICoolBarManager; | |
22 import dwtx.jface.action.IToolBarManager; | |
23 import dwtx.jface.action.IMenuManager; | |
24 import dwtx.jface.action.MenuManager; | |
25 | |
26 import tango.util.collection.ArraySeq; | |
27 import tango.util.collection.HashMap; | |
28 import tango.util.collection.model.Iterator; | |
29 // import java.util.HashMap; | |
30 // import java.util.Iterator; | |
31 // import java.util.List; | |
32 // import java.util.ListIterator; | |
33 | |
34 import dwt.DWT; | |
35 import dwt.widgets.Composite; | |
36 import dwt.widgets.Control; | |
37 import dwt.widgets.CoolBar; | |
38 import dwt.widgets.CoolItem; | |
39 import dwt.widgets.Menu; | |
40 import dwtx.core.runtime.Assert; | |
41 import dwtx.jface.util.Policy; | |
42 | |
43 import dwt.dwthelper.utils; | |
44 import tango.io.Stdout; | |
45 | |
46 /** | |
47 * A cool bar manager is a contribution manager which realizes itself and its | |
48 * items in a cool bar control. | |
49 * <p> | |
50 * This class may be instantiated; it may also be subclassed. | |
51 * </p> | |
52 * | |
53 * @since 3.0 | |
54 */ | |
55 public class CoolBarManager : ContributionManager, | |
56 ICoolBarManager { | |
43
ea8ff534f622
Fix override and super aliases
Frank Benoit <benoit@tionex.de>
parents:
40
diff
changeset
|
57 alias ContributionManager.add add; |
25 | 58 |
59 class ListIterator { | |
60 | |
61 ArraySeq!(Object) c; | |
62 int i; | |
63 | |
64 this( ArraySeq!(Object) c ){ | |
65 this.c = c; | |
66 } | |
67 | |
68 Object next(){ | |
69 return c.get(++i); | |
70 } | |
71 Object previous(){ | |
72 return c.get(--i); | |
73 } | |
74 | |
75 bool hasNext(){ | |
76 return i+1 < c.size(); | |
77 } | |
78 bool hasPrevious(){ | |
79 return i > 0; | |
80 } | |
81 | |
82 void remove(){ | |
83 c.removeAt(i); | |
84 if( i is c.size() ) i--; | |
85 } | |
86 int nextIndex(){ | |
87 return i+1; | |
88 } | |
89 } | |
90 | |
91 /** | |
92 * A separator created by the end user. | |
93 */ | |
94 public final static String USER_SEPARATOR = "UserSeparator"; //$NON-NLS-1$ | |
95 | |
96 /** | |
97 * The original creation order of the contribution items. | |
98 */ | |
99 private ArraySeq!(Object) cbItemsCreationOrder; | |
100 | |
101 /** | |
102 * MenuManager for cool bar pop-up menu, or null if none. | |
103 */ | |
104 private MenuManager contextMenuManager = null; | |
105 | |
106 /** | |
107 * The cool bar control; <code>null</code> before creation and after | |
108 * disposal. | |
109 */ | |
110 private CoolBar coolBar = null; | |
111 | |
112 /** | |
113 * The cool bar items style; <code>DWT.NONE</code> by default. | |
114 */ | |
115 private int itemStyle = DWT.NONE; | |
116 | |
117 /** | |
118 * Creates a new cool bar manager with the default style. Equivalent to | |
119 * <code>CoolBarManager(DWT.NONE)</code>. | |
120 */ | |
121 public this() { | |
122 cbItemsCreationOrder = new ArraySeq!(Object); | |
123 // do nothing | |
124 } | |
125 | |
126 /** | |
127 * Creates a cool bar manager for an existing cool bar control. This | |
128 * manager becomes responsible for the control, and will dispose of it when | |
129 * the manager is disposed. | |
130 * | |
131 * @param coolBar | |
132 * the cool bar control | |
133 */ | |
134 public this(CoolBar coolBar) { | |
135 this(); | |
136 Assert.isNotNull(coolBar); | |
137 this.coolBar = coolBar; | |
138 itemStyle = coolBar.getStyle(); | |
139 } | |
140 | |
141 /** | |
142 * Creates a cool bar manager with the given DWT style. Calling <code>createControl</code> | |
143 * will create the cool bar control. | |
144 * | |
145 * @param style | |
146 * the cool bar item style; see | |
147 * {@link dwt.widgets.CoolBar CoolBar}for for valid | |
148 * style bits | |
149 */ | |
150 public this(int style) { | |
151 cbItemsCreationOrder = new ArraySeq!(Object); | |
152 itemStyle = style; | |
153 } | |
154 | |
155 /* | |
156 * (non-Javadoc) | |
157 * | |
158 * @see dwtx.jface.action.ICoolBarManager#add(dwtx.jface.action.IToolBarManager) | |
159 */ | |
160 public void add(IToolBarManager toolBarManager) { | |
161 Assert.isNotNull(cast(Object)toolBarManager); | |
162 super.add(new ToolBarContributionItem(toolBarManager)); | |
163 } | |
164 | |
165 /** | |
166 * Collapses consecutive separators and removes a separator from the | |
167 * beginning and end of the list. | |
168 * | |
169 * @param contributionList | |
170 * the list of contributions; must not be <code>null</code>. | |
171 * @return The contribution list provided with extraneous separators | |
172 * removed; this value is never <code>null</code>, but may be | |
173 * empty. | |
174 */ | |
175 private ArraySeq!(Object) adjustContributionList(ArraySeq!(Object) contributionList) { | |
176 IContributionItem item; | |
177 // Fist remove a separator if it is the first element of the list | |
178 if (contributionList.size() !is 0) { | |
179 item = cast(IContributionItem) contributionList.get(0); | |
180 if (item.isSeparator()) { | |
181 contributionList.removeAt(0); | |
182 } | |
183 | |
184 auto iterator = new ListIterator( contributionList ); | |
185 // collapse consecutive separators | |
186 while (iterator.hasNext()) { | |
187 item = cast(IContributionItem) iterator.next(); | |
188 if (item.isSeparator()) { | |
189 while (iterator.hasNext()) { | |
190 item = cast(IContributionItem) iterator.next(); | |
191 if (item.isSeparator()) { | |
192 iterator.remove(); | |
193 } else { | |
194 break; | |
195 } | |
196 } | |
197 | |
198 } | |
199 } | |
200 // Now check last element to see if there is a separator | |
201 item = cast(IContributionItem) contributionList.get(contributionList | |
202 .size() - 1); | |
203 if (item.isSeparator()) { | |
204 contributionList.removeAt(contributionList.size() - 1); | |
205 } | |
206 } | |
207 return contributionList; | |
208 | |
209 } | |
210 | |
211 /* (non-Javadoc) | |
212 * @see dwtx.jface.action.ContributionManager#checkDuplication(dwtx.jface.action.IContributionItem) | |
213 */ | |
43
ea8ff534f622
Fix override and super aliases
Frank Benoit <benoit@tionex.de>
parents:
40
diff
changeset
|
214 protected override bool allowItem(IContributionItem itemToAdd) { |
25 | 215 /* We will allow as many null entries as they like, though there should |
216 * be none. | |
217 */ | |
218 if (itemToAdd is null) { | |
219 return true; | |
220 } | |
221 | |
222 /* Null identifiers can be expected in generic contribution items. | |
223 */ | |
224 String firstId = itemToAdd.getId(); | |
225 if (firstId is null) { | |
226 return true; | |
227 } | |
228 | |
229 // Cycle through the current list looking for duplicates. | |
230 IContributionItem[] currentItems = getItems(); | |
231 for (int i = 0; i < currentItems.length; i++) { | |
232 IContributionItem currentItem = currentItems[i]; | |
233 | |
234 // We ignore null entries. | |
235 if (currentItem is null) { | |
236 continue; | |
237 } | |
238 | |
239 String secondId = currentItem.getId(); | |
240 if (firstId.equals(secondId)) { | |
241 if (Policy.TRACE_TOOLBAR) { | |
242 Stdout.formatln("Trying to add a duplicate item."); //$NON-NLS-1$ | |
243 ExceptionPrintStackTrace(new Exception(null), Stdout ); | |
244 Stdout.formatln("DONE --------------------------"); //$NON-NLS-1$ | |
245 } | |
246 return false; | |
247 } | |
248 } | |
249 | |
250 return true; | |
251 } | |
252 | |
253 /** | |
254 * Positions the list iterator to the end of all the separators. Calling | |
255 * <code>next()</code> the iterator should return the immediate object | |
256 * following the last separator. | |
257 * | |
258 * @param iterator | |
259 * the list iterator. | |
260 */ | |
261 private void collapseSeparators(ListIterator iterator) { | |
262 | |
263 while (iterator.hasNext()) { | |
264 IContributionItem item = cast(IContributionItem) iterator.next(); | |
265 if (!item.isSeparator()) { | |
266 iterator.previous(); | |
267 return; | |
268 } | |
269 } | |
270 } | |
271 | |
272 /** | |
273 * Returns whether the cool bar control has been created and not yet | |
274 * disposed. | |
275 * | |
276 * @return <code>true</code> if the control has been created and not yet | |
277 * disposed, <code>false</code> otherwise | |
278 */ | |
279 private bool coolBarExist() { | |
280 return coolBar !is null && !coolBar.isDisposed(); | |
281 } | |
282 | |
283 /** | |
284 * Creates and returns this manager's cool bar control. Does not create a | |
285 * new control if one already exists. | |
286 * | |
287 * @param parent | |
288 * the parent control | |
289 * @return the cool bar control | |
290 */ | |
291 public CoolBar createControl(Composite parent) { | |
292 Assert.isNotNull(parent); | |
293 if (!coolBarExist()) { | |
294 coolBar = new CoolBar(parent, itemStyle); | |
295 coolBar.setMenu(getContextMenuControl()); | |
296 coolBar.setLocked(false); | |
297 update(false); | |
298 } | |
299 return coolBar; | |
300 } | |
301 | |
302 /** | |
303 * Disposes of this cool bar manager and frees all allocated DWT resources. | |
304 * Notifies all contribution items of the dispose. Note that this method | |
305 * does not clean up references between this cool bar manager and its | |
306 * associated contribution items. Use <code>removeAll</code> for that | |
307 * purpose. | |
308 */ | |
309 public void dispose() { | |
310 if (coolBarExist()) { | |
311 coolBar.dispose(); | |
312 coolBar = null; | |
313 } | |
70
46a6e0e6ccd4
Merge with d-fied sources of 3.4M7
Frank Benoit <benoit@tionex.de>
parents:
43
diff
changeset
|
314 IContributionItem[] items = getItems(); |
46a6e0e6ccd4
Merge with d-fied sources of 3.4M7
Frank Benoit <benoit@tionex.de>
parents:
43
diff
changeset
|
315 for (int i = 0; i < items.length; i++) { |
46a6e0e6ccd4
Merge with d-fied sources of 3.4M7
Frank Benoit <benoit@tionex.de>
parents:
43
diff
changeset
|
316 // Disposes of the contribution item. |
46a6e0e6ccd4
Merge with d-fied sources of 3.4M7
Frank Benoit <benoit@tionex.de>
parents:
43
diff
changeset
|
317 // If Contribution Item is a toolbar then it will dispose of |
46a6e0e6ccd4
Merge with d-fied sources of 3.4M7
Frank Benoit <benoit@tionex.de>
parents:
43
diff
changeset
|
318 // all the nested |
46a6e0e6ccd4
Merge with d-fied sources of 3.4M7
Frank Benoit <benoit@tionex.de>
parents:
43
diff
changeset
|
319 // contribution items. |
46a6e0e6ccd4
Merge with d-fied sources of 3.4M7
Frank Benoit <benoit@tionex.de>
parents:
43
diff
changeset
|
320 items[i].dispose(); |
46a6e0e6ccd4
Merge with d-fied sources of 3.4M7
Frank Benoit <benoit@tionex.de>
parents:
43
diff
changeset
|
321 } |
25 | 322 // If a context menu existed then dispose of it. |
323 if (contextMenuManager !is null) { | |
324 contextMenuManager.dispose(); | |
325 contextMenuManager = null; | |
326 } | |
327 | |
328 } | |
329 | |
330 /** | |
331 * Disposes the given cool item. | |
332 * | |
333 * @param item | |
334 * the cool item to dispose | |
335 */ | |
336 private void dispose(CoolItem item) { | |
337 if ((item !is null) && !item.isDisposed()) { | |
338 | |
339 item.setData(null); | |
340 Control control = item.getControl(); | |
341 // if the control is already disposed, setting the coolitem | |
342 // control to null will cause an DWT exception, workaround | |
343 // for 19630 | |
344 if ((control !is null) && !control.isDisposed()) { | |
345 item.setControl(null); | |
346 } | |
347 item.dispose(); | |
348 } | |
349 } | |
350 | |
351 /** | |
352 * Finds the cool item associated with the given contribution item. | |
353 * | |
354 * @param item | |
355 * the contribution item | |
356 * @return the associated cool item, or <code>null</code> if not found | |
357 */ | |
358 private CoolItem findCoolItem(IContributionItem item) { | |
359 CoolItem[] coolItems = (coolBar is null) ? null : coolBar.getItems(); | |
360 return findCoolItem(coolItems, item); | |
361 } | |
362 | |
363 private CoolItem findCoolItem(CoolItem[] items, IContributionItem item) { | |
364 if (items is null) { | |
365 return null; | |
366 } | |
367 | |
368 for (int i = 0; i < items.length; i++) { | |
369 CoolItem coolItem = items[i]; | |
370 IContributionItem data = cast(IContributionItem) coolItem.getData(); | |
371 if (data !is null && (cast(Object)data).opEquals(cast(Object)item)) { | |
372 return coolItem; | |
373 } | |
374 } | |
375 return null; | |
376 } | |
377 | |
378 /** | |
379 * Return a consistent set of wrap indices. The return value will always | |
380 * include at least one entry and the first entry will always be zero. | |
381 * CoolBar.getWrapIndices() is inconsistent in whether or not it returns an | |
382 * index for the first row. | |
383 * | |
384 * @param wraps | |
385 * the wrap indicies from the cool bar widget | |
386 * @return the adjusted wrap indicies. | |
387 */ | |
388 private int[] getAdjustedWrapIndices(int[] wraps) { | |
389 int[] adjustedWrapIndices; | |
390 if (wraps.length is 0) { | |
391 adjustedWrapIndices = [ 0 ]; | |
392 } else { | |
393 if (wraps[0] !is 0) { | |
394 adjustedWrapIndices = new int[wraps.length + 1]; | |
395 adjustedWrapIndices[0] = 0; | |
396 for (int i = 0; i < wraps.length; i++) { | |
397 adjustedWrapIndices[i + 1] = wraps[i]; | |
398 } | |
399 } else { | |
400 adjustedWrapIndices = wraps; | |
401 } | |
402 } | |
403 return adjustedWrapIndices; | |
404 } | |
405 | |
406 /** | |
407 * Returns the control of the Menu Manager. If the menu manager does not | |
408 * have a control then one is created. | |
409 * | |
410 * @return menu control associated with manager, or null if none | |
411 */ | |
412 private Menu getContextMenuControl() { | |
413 if ((contextMenuManager !is null) && (coolBar !is null)) { | |
414 Menu menuWidget = contextMenuManager.getMenu(); | |
415 if ((menuWidget is null) || (menuWidget.isDisposed())) { | |
416 menuWidget = contextMenuManager.createContextMenu(coolBar); | |
417 } | |
418 return menuWidget; | |
419 } | |
420 return null; | |
421 } | |
422 | |
423 /* | |
424 * (non-Javadoc) | |
425 * | |
426 * @see dwtx.jface.action.ICoolBarManager#isLayoutLocked() | |
427 */ | |
428 public IMenuManager getContextMenuManager() { | |
429 return contextMenuManager; | |
430 } | |
431 | |
432 /** | |
433 * Returns the cool bar control for this manager. | |
434 * | |
435 * @return the cool bar control, or <code>null</code> if none | |
436 */ | |
437 public CoolBar getControl() { | |
438 return coolBar; | |
439 } | |
440 | |
441 /** | |
442 * Returns an array list of all the contribution items in the manager. | |
443 * | |
444 * @return an array list of contribution items. | |
445 */ | |
446 private ArraySeq!(Object) getItemList() { | |
447 IContributionItem[] cbItems = getItems(); | |
448 ArraySeq!(Object) list = new ArraySeq!(Object); | |
449 list.capacity(cbItems.length); | |
450 for (int i = 0; i < cbItems.length; i++) { | |
451 list.append( cast(Object) cbItems[i]); | |
452 } | |
453 return list; | |
454 } | |
455 | |
456 /* | |
457 * (non-Javadoc) | |
458 * | |
459 * @see dwtx.jface.action.ICoolBarManager#isLayoutLocked() | |
460 */ | |
461 public bool getLockLayout() { | |
462 if (!coolBarExist()) { | |
463 return false; | |
464 } | |
465 return coolBar.getLocked(); | |
466 } | |
467 | |
468 /** | |
469 * Returns the number of rows that should be displayed visually. | |
470 * | |
471 * @param items | |
472 * the array of contributin items | |
473 * @return the number of rows | |
474 */ | |
475 private int getNumRows(IContributionItem[] items) { | |
476 int numRows = 1; | |
477 bool separatorFound = false; | |
478 for (int i = 0; i < items.length; i++) { | |
479 if (items[i].isSeparator()) { | |
480 separatorFound = true; | |
481 } | |
482 if ((separatorFound) && (items[i].isVisible()) | |
483 && (!items[i].isGroupMarker()) && (!items[i].isSeparator())) { | |
484 numRows++; | |
485 separatorFound = false; | |
486 } | |
487 } | |
488 return numRows; | |
489 } | |
490 | |
491 /* | |
492 * (non-Javadoc) | |
493 * | |
494 * @see dwtx.jface.action.ICoolBarManager#getStyle() | |
495 */ | |
496 public int getStyle() { | |
497 return itemStyle; | |
498 } | |
499 | |
500 /** | |
501 * Subclasses may extend this <code>ContributionManager</code> method, | |
502 * but must call <code>super.itemAdded</code>. | |
503 * | |
504 * @see dwtx.jface.action.ContributionManager#itemAdded(dwtx.jface.action.IContributionItem) | |
505 */ | |
43
ea8ff534f622
Fix override and super aliases
Frank Benoit <benoit@tionex.de>
parents:
40
diff
changeset
|
506 protected override void itemAdded(IContributionItem item) { |
25 | 507 Assert.isNotNull(cast(Object)item); |
508 super.itemAdded(item); | |
509 int insertedAt = indexOf(item); | |
510 bool replaced = false; | |
511 final int size = cbItemsCreationOrder.size(); | |
512 for (int i = 0; i < size; i++) { | |
513 IContributionItem created = cast(IContributionItem) cbItemsCreationOrder | |
514 .get(i); | |
515 if (created.getId() !is null && created.getId().equals(item.getId())) { | |
516 cbItemsCreationOrder.replaceAt(i, cast(Object) item); | |
517 replaced = true; | |
518 break; | |
519 } | |
520 } | |
521 | |
522 if (!replaced) { | |
523 cbItemsCreationOrder.addAt(Math.min(Math.max(insertedAt, 0), | |
524 cbItemsCreationOrder.size()), cast(Object) item); | |
525 } | |
526 } | |
527 | |
528 /** | |
529 * Subclasses may extend this <code>ContributionManager</code> method, | |
530 * but must call <code>super.itemRemoved</code>. | |
531 * | |
532 * @see dwtx.jface.action.ContributionManager#itemRemoved(dwtx.jface.action.IContributionItem) | |
533 */ | |
43
ea8ff534f622
Fix override and super aliases
Frank Benoit <benoit@tionex.de>
parents:
40
diff
changeset
|
534 protected override void itemRemoved(IContributionItem item) { |
25 | 535 Assert.isNotNull(cast(Object)item); |
536 super.itemRemoved(item); | |
537 CoolItem coolItem = findCoolItem(item); | |
538 if (coolItem !is null) { | |
539 coolItem.setData(null); | |
540 } | |
541 } | |
542 | |
543 /** | |
544 * Positions the list iterator to the starting of the next row. By calling | |
545 * next on the returned iterator, it will return the first element of the | |
546 * next row. | |
547 * | |
548 * @param iterator | |
549 * the list iterator of contribution items | |
550 * @param ignoreCurrentItem | |
551 * Whether the current item in the iterator should be considered | |
552 * (as well as subsequent items). | |
553 */ | |
554 private void nextRow(ListIterator iterator, bool ignoreCurrentItem) { | |
555 | |
556 IContributionItem currentElement = null; | |
557 if (!ignoreCurrentItem && iterator.hasPrevious()) { | |
558 currentElement = cast(IContributionItem) iterator.previous(); | |
559 iterator.next(); | |
560 } | |
561 | |
562 if ((currentElement !is null) && (currentElement.isSeparator())) { | |
563 collapseSeparators(iterator); | |
564 return; | |
565 } | |
566 | |
567 //Find next separator | |
568 while (iterator.hasNext()) { | |
569 IContributionItem item = cast(IContributionItem) iterator.next(); | |
570 if (item.isSeparator()) { | |
571 // we we find a separator, collapse any consecutive | |
572 // separators | |
573 // and return | |
574 collapseSeparators(iterator); | |
575 return; | |
576 } | |
577 } | |
578 } | |
579 | |
580 /* | |
581 * Used for debuging. Prints all the items in the internal structures. | |
582 */ | |
583 // private void printContributions(ArrayList contributionList) { | |
584 // int index = 0; | |
585 // System.out.println("----------------------------------\n"); //$NON-NLS-1$ | |
586 // for (Iterator i = contributionList.iterator(); i.hasNext(); index++) { | |
587 // IContributionItem item = (IContributionItem) i.next(); | |
588 // if (item.isSeparator()) { | |
589 // System.out.println("Separator"); //$NON-NLS-1$ | |
590 // } else { | |
591 // System.out.println(index + ". Item id: " + item.getId() //$NON-NLS-1$ | |
592 // + " - is Visible: " //$NON-NLS-1$ | |
593 // + item.isVisible()); | |
594 // } | |
595 // } | |
596 // } | |
597 /** | |
598 * Synchronizes the visual order of the cool items in the control with this | |
599 * manager's internal data structures. This method should be called before | |
600 * requesting the order of the contribution items to ensure that the order | |
601 * is accurate. | |
602 * <p> | |
603 * Note that <code>update()</code> and <code>refresh()</code> are | |
604 * converses: <code>update()</code> changes the visual order to match the | |
605 * internal structures, and <code>refresh</code> changes the internal | |
606 * structures to match the visual order. | |
607 * </p> | |
608 */ | |
609 public void refresh() { | |
610 if (!coolBarExist()) { | |
611 return; | |
612 } | |
613 | |
614 // Retreives the list of contribution items as an array list | |
615 auto contributionList = getItemList(); | |
616 | |
617 // Check the size of the list | |
618 if (contributionList.size() is 0) { | |
619 return; | |
620 } | |
621 | |
622 // The list of all the cool items in their visual order | |
623 CoolItem[] coolItems = coolBar.getItems(); | |
624 // The wrap indicies of the coolbar | |
625 int[] wrapIndicies = getAdjustedWrapIndices(coolBar.getWrapIndices()); | |
626 | |
627 int row = 0; | |
628 int coolItemIndex = 0; | |
629 | |
630 // Traverse through all cool items in the coolbar add them to a new | |
631 // data structure | |
632 // in the correct order | |
633 auto displayedItems = new ArraySeq!(Object); | |
634 displayedItems.capacity(coolBar.getItemCount()); | |
635 for (int i = 0; i < coolItems.length; i++) { | |
636 CoolItem coolItem = coolItems[i]; | |
637 if ( auto cbItem = cast(IContributionItem) coolItem.getData() ) { | |
638 displayedItems.addAt(Math.min(i, displayedItems.size()), cast(Object) cbItem); | |
639 } | |
640 } | |
641 | |
642 // Add separators to the displayed Items data structure | |
643 int offset = 0; | |
644 for (int i = 1; i < wrapIndicies.length; i++) { | |
645 int insertAt = wrapIndicies[i] + offset; | |
646 displayedItems.addAt(insertAt, new Separator(USER_SEPARATOR)); | |
647 offset++; | |
648 } | |
649 | |
650 // Determine which rows are invisible | |
651 auto existingVisibleRows = new ArraySeq!(Object); | |
652 existingVisibleRows.capacity(4); | |
653 ListIterator rowIterator = new ListIterator( contributionList ); | |
654 collapseSeparators(rowIterator); | |
655 int numRow = 0; | |
656 while (rowIterator.hasNext()) { | |
657 // Scan row | |
658 while (rowIterator.hasNext()) { | |
659 IContributionItem cbItem = cast(IContributionItem) rowIterator | |
660 .next(); | |
661 if (displayedItems.contains(cast(Object) cbItem)) { | |
662 existingVisibleRows.append(new Integer(numRow)); | |
663 break; | |
664 } | |
665 if (cbItem.isSeparator()) { | |
666 break; | |
667 } | |
668 } | |
669 nextRow(rowIterator, false); | |
670 numRow++; | |
671 } | |
672 | |
673 auto existingRows = new ListIterator( existingVisibleRows ); | |
674 // Adjust row number to the first visible | |
675 if (existingRows.hasNext()) { | |
676 row = (cast(Integer) existingRows.next()).intValue(); | |
677 } | |
678 | |
679 auto itemLocation = new HashMap!(Object,Object); | |
680 foreach( key; displayedItems ){ | |
681 IContributionItem item = cast(IContributionItem)key; | |
682 if (item.isSeparator()) { | |
683 if (existingRows.hasNext()) { | |
684 Integer value = cast(Integer) existingRows.next(); | |
685 row = value.intValue(); | |
686 } else { | |
687 row++; | |
688 } | |
689 } else { | |
690 itemLocation.add(cast(Object)item, new Integer(row)); | |
691 } | |
692 | |
693 } | |
694 | |
695 // Insert the contribution items in their correct location | |
696 foreach( key; displayedItems ){ | |
697 IContributionItem cbItem = cast(IContributionItem) key; | |
698 if (cbItem.isSeparator()) { | |
699 coolItemIndex = 0; | |
700 } else { | |
701 relocate(cbItem, coolItemIndex, contributionList, itemLocation); | |
702 cbItem.saveWidgetState(); | |
703 coolItemIndex++; | |
704 } | |
705 } | |
706 | |
707 if (contributionList.size() !is 0) { | |
708 contributionList = adjustContributionList(contributionList); | |
709 auto array = arraycast!(IContributionItem)( contributionList.toArray() ); | |
710 internalSetItems(array); | |
711 } | |
712 | |
713 } | |
714 | |
715 /** | |
716 * Relocates the given contribution item to the specified index. | |
717 * | |
718 * @param cbItem | |
719 * the conribution item to relocate | |
720 * @param index | |
721 * the index to locate this item | |
722 * @param contributionList | |
723 * the current list of conrtributions | |
724 * @param itemLocation | |
725 */ | |
726 private void relocate(IContributionItem cbItem, int index, | |
727 ArraySeq!(Object) contributionList, HashMap!(Object,Object) itemLocation) { | |
728 | |
729 if (!(cast(Integer)itemLocation.get(cast(Object)cbItem) )) { | |
730 return; | |
731 } | |
732 int targetRow = (cast(Integer) itemLocation.get(cast(Object)cbItem)).intValue(); | |
733 | |
734 int cbInternalIndex = -1; int idx; | |
735 foreach( el; contributionList ){ | |
736 if( el == cast(Object)cbItem){ | |
737 cbInternalIndex = idx; | |
738 break; | |
739 } | |
740 idx++; | |
741 } | |
742 | |
743 // by default add to end of list | |
744 int insertAt = contributionList.size(); | |
745 // Find the row to place this item in. | |
746 auto iterator = new ListIterator( contributionList ); | |
747 // bypass any separators at the begining | |
748 collapseSeparators(iterator); | |
749 int currentRow = -1; | |
750 while (iterator.hasNext()) { | |
751 | |
752 currentRow++; | |
753 if (currentRow is targetRow) { | |
754 // We found the row to insert the item | |
755 int virtualIndex = 0; | |
756 insertAt = iterator.nextIndex(); | |
757 // first check the position of the current element (item) | |
758 // then get the next element | |
759 while (iterator.hasNext()) { | |
760 IContributionItem item = cast(IContributionItem) iterator | |
761 .next(); | |
762 Integer itemRow = cast(Integer) itemLocation.get( cast(Object) item); | |
763 if (item.isSeparator()) { | |
764 break; | |
765 } | |
766 // if the item has an associate widget | |
767 if ((itemRow !is null) && (itemRow.intValue() is targetRow)) { | |
768 // if the next element is the index we are looking for | |
769 // then break | |
770 if (virtualIndex >= index) { | |
771 break; | |
772 } | |
773 virtualIndex++; | |
774 | |
775 } | |
776 insertAt++; | |
777 } | |
778 // If we don't need to move it then we return | |
779 if (cbInternalIndex is insertAt) { | |
780 return; | |
781 } | |
782 break; | |
783 } | |
784 nextRow(iterator, true); | |
785 } | |
786 contributionList.remove(cast(Object) cbItem); | |
787 | |
788 // Adjust insertAt index | |
789 if (cbInternalIndex < insertAt) { | |
790 insertAt--; | |
791 } | |
792 | |
793 // if we didn't find the row then add a new row | |
794 if (currentRow !is targetRow) { | |
795 contributionList.append(new Separator(USER_SEPARATOR)); | |
796 insertAt = contributionList.size(); | |
797 } | |
798 insertAt = Math.min(insertAt, contributionList.size()); | |
799 contributionList.addAt(insertAt, cast(Object) cbItem); | |
800 | |
801 } | |
802 | |
803 /** | |
804 * Restores the canonical order of this cool bar manager. The canonical | |
805 * order is the order in which the contribution items where added. | |
806 */ | |
807 public void resetItemOrder() { | |
808 auto iterator = new ListIterator( cbItemsCreationOrder ); | |
809 while( iterator.hasNext() ){ | |
810 IContributionItem item = cast(IContributionItem) iterator.next(); | |
811 // if its a user separator then do not include in original order. | |
812 if ((item.getId() !is null) && (item.getId().equals(USER_SEPARATOR))) { | |
813 iterator.remove(); | |
814 } | |
815 } | |
816 setItems( arraycast!(IContributionItem)(cbItemsCreationOrder.toArray)); | |
817 } | |
818 | |
819 /* | |
820 * (non-Javadoc) | |
821 * | |
822 * @see dwtx.jface.action.ICoolBarManager#setContextMenuManager(dwtx.jface.action.IMenuManager) | |
823 */ | |
824 public void setContextMenuManager(IMenuManager contextMenuManager) { | |
825 this.contextMenuManager = cast(MenuManager) contextMenuManager; | |
826 if (coolBar !is null) { | |
827 coolBar.setMenu(getContextMenuControl()); | |
828 } | |
829 } | |
830 | |
831 /** | |
832 * Replaces the current items with the given items. | |
833 * Forces an update. | |
834 * | |
835 * @param newItems the items with which to replace the current items | |
836 */ | |
837 public void setItems(IContributionItem[] newItems) { | |
838 // dispose of all the cool items on the cool bar manager | |
839 if (coolBar !is null) { | |
840 CoolItem[] coolItems = coolBar.getItems(); | |
841 for (int i = 0; i < coolItems.length; i++) { | |
842 dispose(coolItems[i]); | |
843 } | |
844 } | |
845 // Set the internal structure to this order | |
846 internalSetItems(newItems); | |
847 // Force and update | |
848 update(true); | |
849 } | |
850 | |
851 /* | |
852 * (non-Javadoc) | |
853 * | |
854 * @see dwtx.jface.action.ICoolBarManager#lockLayout(bool) | |
855 */ | |
856 public void setLockLayout(bool value) { | |
857 if (!coolBarExist()) { | |
858 return; | |
859 } | |
860 coolBar.setLocked(value); | |
861 } | |
862 | |
863 /** | |
864 * Subclasses may extend this <code>IContributionManager</code> method, | |
865 * but must call <code>super.update</code>. | |
866 * | |
867 * @see dwtx.jface.action.IContributionManager#update(bool) | |
868 */ | |
869 public void update(bool force) { | |
870 if ((!isDirty() && !force) || (!coolBarExist())) { | |
871 return; | |
872 } | |
873 | |
874 bool relock = false; | |
875 bool changed = false; | |
876 | |
877 try { | |
878 coolBar.setRedraw(false); | |
879 | |
880 // Refresh the widget data with the internal data structure. | |
881 refresh(); | |
882 | |
883 if (coolBar.getLocked()) { | |
884 coolBar.setLocked(false); | |
885 relock = true; | |
886 } | |
887 | |
888 /* | |
889 * Make a list of items including only those items that are | |
890 * visible. Separators should stay because they mark line breaks in | |
891 * a cool bar. | |
892 */ | |
893 IContributionItem[] items = getItems(); | |
894 auto visibleItems = new ArraySeq!(Object); | |
895 visibleItems.capacity(items.length); | |
896 for (int i = 0; i < items.length; i++) { | |
897 IContributionItem item = items[i]; | |
898 if (item.isVisible()) { | |
899 visibleItems.append(cast(Object)item); | |
900 } | |
901 } | |
902 | |
903 /* | |
904 * Make a list of CoolItem widgets in the cool bar for which there | |
905 * is no current visible contribution item. These are the widgets | |
906 * to be disposed. Dynamic items are also removed. | |
907 */ | |
908 CoolItem[] coolItems = coolBar.getItems(); | |
909 auto coolItemsToRemove = new ArraySeq!(Object); | |
910 coolItemsToRemove.capacity(coolItems.length); | |
911 for (int i = 0; i < coolItems.length; i++) { | |
912 Object data = coolItems[i].getData(); | |
913 if ((data is null) | |
914 || (!visibleItems.contains(data)) | |
915 || ((cast(IContributionItem)data ) && (cast(IContributionItem) data) | |
916 .isDynamic())) { | |
917 coolItemsToRemove.append(coolItems[i]); | |
918 } | |
919 } | |
920 | |
921 // Dispose of any items in the list to be removed. | |
922 for (int i = coolItemsToRemove.size() - 1; i >= 0; i--) { | |
923 CoolItem coolItem = cast(CoolItem) coolItemsToRemove.get(i); | |
924 if (!coolItem.isDisposed()) { | |
925 Control control = coolItem.getControl(); | |
926 if (control !is null) { | |
927 coolItem.setControl(null); | |
928 control.dispose(); | |
929 } | |
930 coolItem.dispose(); | |
931 } | |
932 } | |
933 | |
934 // Add any new items by telling them to fill. | |
935 coolItems = coolBar.getItems(); | |
936 IContributionItem sourceItem; | |
937 IContributionItem destinationItem; | |
938 int sourceIndex = 0; | |
939 int destinationIndex = 0; | |
940 auto visibleItemItr = new ListIterator( visibleItems ); | |
941 while (visibleItemItr.hasNext()) { | |
942 sourceItem = cast(IContributionItem) visibleItemItr.next(); | |
943 | |
944 // Retrieve the corresponding contribution item from DWT's | |
945 // data. | |
946 if (sourceIndex < coolItems.length) { | |
947 destinationItem = cast(IContributionItem) coolItems[sourceIndex] | |
948 .getData(); | |
949 } else { | |
950 destinationItem = null; | |
951 } | |
952 | |
953 // The items match is they are equal or both separators. | |
954 if (destinationItem !is null) { | |
955 if ((cast(Object)sourceItem).opEquals(cast(Object)destinationItem)) { | |
956 sourceIndex++; | |
957 destinationIndex++; | |
958 sourceItem.update(); | |
959 continue; | |
960 | |
961 } else if ((destinationItem.isSeparator()) | |
962 && (sourceItem.isSeparator())) { | |
963 coolItems[sourceIndex].setData(cast(Object)sourceItem); | |
964 sourceIndex++; | |
965 destinationIndex++; | |
966 sourceItem.update(); | |
967 continue; | |
968 | |
969 } | |
970 } | |
971 | |
972 // Otherwise, a new item has to be added. | |
973 int start = coolBar.getItemCount(); | |
974 sourceItem.fill(coolBar, destinationIndex); | |
975 int newItems = coolBar.getItemCount() - start; | |
976 for (int i = 0; i < newItems; i++) { | |
977 coolBar.getItem(destinationIndex++).setData(cast(Object)sourceItem); | |
978 } | |
979 changed = true; | |
980 } | |
981 | |
982 // Remove any old widgets not accounted for. | |
983 for (int i = coolItems.length - 1; i >= sourceIndex; i--) { | |
984 final CoolItem item = coolItems[i]; | |
985 if (!item.isDisposed()) { | |
986 Control control = item.getControl(); | |
987 if (control !is null) { | |
988 item.setControl(null); | |
989 control.dispose(); | |
990 } | |
991 item.dispose(); | |
992 changed = true; | |
993 } | |
994 } | |
995 | |
996 // Update wrap indices. | |
997 updateWrapIndices(); | |
998 | |
999 // Update the sizes. | |
1000 for (int i = 0; i < items.length; i++) { | |
1001 IContributionItem item = items[i]; | |
1002 item.update(SIZE); | |
1003 } | |
1004 | |
1005 // if the coolBar was previously locked then lock it | |
1006 if (relock) { | |
1007 coolBar.setLocked(true); | |
1008 } | |
1009 | |
1010 if (changed) { | |
1011 updateTabOrder(); | |
1012 } | |
1013 | |
1014 // We are no longer dirty. | |
1015 setDirty(false); | |
1016 } finally { | |
1017 coolBar.setRedraw(true); | |
1018 } | |
1019 } | |
1020 | |
1021 /** | |
1022 * Sets the tab order of the coolbar to the visual order of its items. | |
1023 */ | |
1024 /* package */void updateTabOrder() { | |
1025 if (coolBar !is null) { | |
1026 CoolItem[] items = coolBar.getItems(); | |
1027 if (items !is null) { | |
1028 auto children = new ArraySeq!(Object); | |
1029 children.capacity(items.length); | |
1030 for (int i = 0; i < items.length; i++) { | |
1031 if ((items[i].getControl() !is null) | |
1032 && (!items[i].getControl().isDisposed())) { | |
1033 children.append(items[i].getControl()); | |
1034 } | |
1035 } | |
1036 // Convert array | |
1037 Control[] childrenArray; | |
1038 childrenArray = arraycast!(Control)(children.toArray()); | |
1039 | |
1040 if (childrenArray !is null) { | |
1041 coolBar.setTabList(childrenArray); | |
1042 } | |
1043 | |
1044 } | |
1045 } | |
1046 } | |
1047 | |
1048 /** | |
1049 * Updates the indices at which the cool bar should wrap. | |
1050 */ | |
1051 private void updateWrapIndices() { | |
1052 final IContributionItem[] items = getItems(); | |
1053 final int numRows = getNumRows(items) - 1; | |
1054 | |
1055 // Generate the list of wrap indices. | |
1056 final int[] wrapIndices = new int[numRows]; | |
1057 bool foundSeparator = false; | |
1058 int j = 0; | |
1059 CoolItem[] coolItems = (coolBar is null) ? null : coolBar.getItems(); | |
1060 | |
1061 for (int i = 0; i < items.length; i++) { | |
1062 IContributionItem item = items[i]; | |
1063 CoolItem coolItem = findCoolItem(coolItems, item); | |
1064 if (item.isSeparator()) { | |
1065 foundSeparator = true; | |
1066 } | |
1067 if ((!item.isSeparator()) && (!item.isGroupMarker()) | |
1068 && (item.isVisible()) && (coolItem !is null) | |
1069 && (foundSeparator)) { | |
1070 wrapIndices[j] = coolBar.indexOf(coolItem); | |
1071 j++; | |
1072 foundSeparator = false; | |
1073 } | |
1074 } | |
1075 | |
1076 /* | |
1077 * Check to see if these new wrap indices are different than the old | |
1078 * ones. | |
1079 */ | |
1080 final int[] oldIndices = coolBar.getWrapIndices(); | |
1081 bool shouldUpdate = false; | |
1082 if (oldIndices.length is wrapIndices.length) { | |
1083 for (int i = 0; i < oldIndices.length; i++) { | |
1084 if (oldIndices[i] !is wrapIndices[i]) { | |
1085 shouldUpdate = true; | |
1086 break; | |
1087 } | |
1088 } | |
1089 } else { | |
1090 shouldUpdate = true; | |
1091 } | |
1092 | |
1093 if (shouldUpdate) { | |
1094 coolBar.setWrapIndices(wrapIndices); | |
1095 } | |
1096 } | |
1097 } |