comparison dwtx/jface/action/CoolBarManager.d @ 25:ca63e2bea4bf

CoolBarManager
author Frank Benoit <benoit@tionex.de>
date Thu, 03 Apr 2008 04:50:25 +0200
parents
children da5ad8eedf5d
comparison
equal deleted inserted replaced
24:eb6b3e6de869 25:ca63e2bea4bf
1 /*******************************************************************************
2 * Copyright (c) 2003, 2006 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 * 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 dwt.dwthelper.Integer;
45 import tango.io.Stdout;
46
47 /**
48 * A cool bar manager is a contribution manager which realizes itself and its
49 * items in a cool bar control.
50 * <p>
51 * This class may be instantiated; it may also be subclassed.
52 * </p>
53 *
54 * @since 3.0
55 */
56 public class CoolBarManager : ContributionManager,
57 ICoolBarManager {
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 */
214 protected bool allowItem(IContributionItem itemToAdd) {
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 IContributionItem[] items = getItems();
312 for (int i = 0; i < items.length; i++) {
313 // Disposes of the contribution item.
314 // If Contribution Item is a toolbar then it will dispose of
315 // all the nested
316 // contribution items.
317 items[i].dispose();
318 }
319 coolBar.dispose();
320 coolBar = null;
321 }
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 */
506 protected void itemAdded(IContributionItem item) {
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 */
534 protected void itemRemoved(IContributionItem item) {
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 }