001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.uml.ui.swing.testbed.addin.menu;
043:
044: import java.awt.Point;
045: import java.util.ArrayList;
046: import java.util.Hashtable;
047: import java.util.Iterator;
048: import java.util.List;
049:
050: import javax.swing.JMenu;
051: import javax.swing.JMenuBar;
052: import javax.swing.JToolBar;
053:
054: import org.netbeans.modules.uml.ui.products.ad.application.IMenuManager;
055: import org.netbeans.modules.uml.ui.products.ad.application.action.ContributionManager;
056: import org.netbeans.modules.uml.ui.products.ad.application.action.IContributionManager;
057: import java.util.HashMap;
058: import javax.swing.JSeparator;
059: import org.netbeans.modules.uml.ui.products.ad.application.action.BaseAction;
060:
061: /**
062: *
063: * @author Trey Spiva
064: */
065: //public class TestBedMenuManager extends ContributionManager implements IMenuManager
066: public class TestBedMenuManager implements IMenuManager {
067: private JMenuBar m_MenuBar = null;
068: private Hashtable<String, IMenuManager> m_SubMenus = new Hashtable<String, IMenuManager>();
069: private Point m_Point = null;
070: private Object m_ObjectClickedOn = null;
071:
072: private List m_Contributions = new ArrayList();
073:
074: private boolean isDirty = true;
075:
076: // private int dynamicItems = 0;
077:
078: /**
079: * The mnemonic character of the the menu.
080: */
081: private char m_Mnemonic = 0;
082:
083: /**
084: * The menu id.
085: */
086: private String m_Id = "";
087:
088: /**
089: * The menu item widget; <code>null</code> before
090: * creation and after disposal. This field is used
091: * when this menu manager is a sub-menu.
092: */
093: JMenu m_MenuItem = null;
094:
095: /**
096: * The text for a sub-menu.
097: */
098: private String m_MenuText = "";
099:
100: /**
101: * Indicates whether <code>removeAll</code> should be
102: * called just before the menu is displayed.
103: */
104: private boolean m_RemoveAllWhenShown = false;
105:
106: /**
107: * The parent contribution manager.
108: */
109: private IMenuManager m_Parent;
110:
111: /**
112: * Indicates this item is visible in its manager; <code>true</code>
113: * by default.
114: */
115: private boolean m_Visible = true;
116:
117: /**
118: * The overrides for items of this manager
119: */
120:
121: public TestBedMenuManager() {
122: this (true);
123: }
124:
125: public TestBedMenuManager(IMenuManager mgr) {
126: this ();
127: m_Parent = mgr;
128: setVisible(mgr.isVisible());
129: }
130:
131: public TestBedMenuManager(String text, String id) {
132: setId(id);
133: setMenuText(text);
134: }
135:
136: public TestBedMenuManager(IMenuManager mgr, String text, String id) {
137: setId(id);
138: setMenuText(text);
139:
140: m_Parent = mgr;
141: }
142:
143: protected TestBedMenuManager(boolean addAdditions) {
144: }
145:
146: /**
147: * Creates and returns an SWT menu bar control for this menu, for use in the
148: * given <code>Shell</code>, and installs all registered contributions. Does not
149: * create a new control if one already exists. This implementation simply calls
150: * the <code>createMenuBar(Decorations)</code> method
151: *
152: * @return the menu control
153: */
154: public JMenuBar createMenuBar() {
155: if (menuExist() == false) {
156: setMenuBar(new JMenuBar());
157: }
158:
159: update(false);
160:
161: return getMenuBar();
162: }
163:
164: public JMenuBar getMenuBar() {
165: return m_MenuBar;
166: }
167:
168: public void setMenuBar(JMenuBar bar) {
169: m_MenuBar = bar;
170: }
171:
172: public void setMenuItem(JMenu menu) {
173: m_MenuItem = menu;
174: }
175:
176: public JMenu getMenuItem() {
177: return m_MenuItem;
178: }
179:
180: //**************************************************
181: // IMenuManager Implementation
182: //**************************************************
183:
184: /* (non-Javadoc)
185: * @see org.netbeans.modules.uml.core.addinframework.ui.application.IMenuManager#findMenuUsingPath(java.lang.String)
186: */
187: public IMenuManager findMenuUsingPath(String path) {
188: IMenuManager retVal = null;
189:
190: Object item = findUsingPath(path);
191: if (item instanceof IMenuManager) {
192: retVal = (IMenuManager) item;
193: }
194:
195: return retVal;
196: }
197:
198: /* (non-Javadoc)
199: * @see org.netbeans.modules.uml.core.addinframework.ui.application.IMenuManager#findUsingPath(java.lang.String)
200: */
201: public Object findUsingPath(String path) {
202: String id = path;
203: String rest = null;
204: int separator = path.indexOf('/');
205:
206: if (separator != -1) {
207: id = path.substring(0, separator);
208: rest = path.substring(separator + 1);
209: } else {
210: return find(path);
211: }
212:
213: Object item = find(id);
214: if (item instanceof IMenuManager) {
215: IMenuManager manager = (IMenuManager) item;
216: return manager.findUsingPath(rest);
217: }
218: return null;
219: }
220:
221: /* (non-Javadoc)
222: * @see org.netbeans.modules.uml.core.addinframework.ui.application.IMenuManager#getRemoveAllWhenShown()
223: */
224: public boolean getRemoveAllWhenShown() {
225: return m_RemoveAllWhenShown;
226: }
227:
228: /* (non-Javadoc)
229: * @see org.netbeans.modules.uml.core.addinframework.ui.application.IMenuManager#isEnabled()
230: */
231: public boolean isEnabled() {
232: return true;
233: }
234:
235: /* (non-Javadoc)
236: * @see org.netbeans.modules.uml.core.addinframework.ui.application.IMenuManager#setRemoveAllWhenShown(boolean)
237: */
238: public void setRemoveAllWhenShown(boolean removeAll) {
239: m_RemoveAllWhenShown = removeAll;
240: }
241:
242: /* (non-Javadoc)
243: * @see org.netbeans.modules.uml.core.addinframework.ui.application.IMenuManager#updateAll(boolean)
244: */
245: public void updateAll(boolean force) {
246: update(force, true);
247: }
248:
249: /* (non-Javadoc)
250: * @see org.netbeans.modules.uml.core.addinframework.ui.action.IContributionManager#update(boolean)
251: */
252: public void update(boolean force) {
253: update(force, false);
254: }
255:
256: /* (non-Javadoc)
257: * @see org.netbeans.modules.uml.core.addinframework.ui.action.IContributionItem#update()
258: */
259: public void update() {
260: updateMenuItem();
261: }
262:
263: /* (non-Javadoc)
264: * @see org.netbeans.modules.uml.core.addinframework.ui.action.IContributionItem#fill(java.awt.Container)
265: */
266: public void fill(JMenu parent, int index) {
267: if (isSeparator() == true) {
268: parent.add(new JSeparator());
269: return;
270: }
271:
272: if (index >= 0) {
273: m_MenuItem = new JMenu(getMenuText());
274:
275: if (getMnemonic() > 0) {
276: m_MenuItem.setMnemonic(getMnemonic());
277: }
278: parent.add(m_MenuItem);
279: } else {
280: m_MenuItem = new JMenu(getMenuText());
281: parent.add(m_MenuItem);
282: }
283:
284: initializeMenu();
285:
286: // populate the submenu, in order to enable accelerators
287: // and to set enabled state on the menuItem properly
288: update(true);
289:
290: }
291:
292: /* (non-Javadoc)
293: * @see org.netbeans.modules.uml.core.addinframework.ui.action.IContributionItem#fill(org.netbeans.modules.uml.core.addinframework.ui.application.IMenu, int)
294: */
295: public void fill(JMenuBar parent, int index) {
296: if (m_MenuItem == null) {
297: if (index >= 0) {
298: m_MenuItem = new JMenu(getMenuText());
299:
300: if (getMnemonic() > 0) {
301: m_MenuItem.setMnemonic(getMnemonic());
302: }
303: parent.add(m_MenuItem);
304: } else {
305: m_MenuItem = new JMenu(getMenuText());
306: parent.add(m_MenuItem);
307: }
308:
309: initializeMenu();
310:
311: // populate the submenu, in order to enable accelerators
312: // and to set enabled state on the menuItem properly
313: update(true);
314: }
315: }
316:
317: /* (non-Javadoc)
318: * @see org.netbeans.modules.uml.core.addinframework.ui.action.IContributionItem#getId()
319: */
320: public String getId() {
321: return m_Id;
322: }
323:
324: public void setId(String id) {
325: m_Id = id;
326: }
327:
328: public String getMenuText() {
329: String retVal = m_MenuText;
330:
331: if ((retVal == null) || (retVal.length() <= 0)) {
332: retVal = ((TestBedMenuManager) getParent()).getMenuText();
333: }
334:
335: return retVal;
336: }
337:
338: public void setMenuText(String text) {
339: StringBuffer name = new StringBuffer();
340: for (int index = 0; index < text.length(); index++) {
341: char curChar = text.charAt(index);
342: if ((curChar == '&') && ((index + 1) < text.length())) {
343: index++;
344: curChar = text.charAt(index);
345: setMnemonic(curChar);
346: }
347:
348: name.append(curChar);
349: }
350:
351: m_MenuText = name.toString();
352: }
353:
354: public void setMnemonic(char ch) {
355: m_Mnemonic = ch;
356: }
357:
358: public char getMnemonic() {
359: char retVal = m_Mnemonic;
360:
361: if (retVal > 0) {
362: retVal = ((TestBedMenuManager) getParent()).getMnemonic();
363: }
364:
365: return retVal;
366: }
367:
368: /* (non-Javadoc)
369: * @see org.netbeans.modules.uml.core.addinframework.ui.action.IContributionItem#isDynamic()
370: */
371: // public boolean isDynamic()
372: // {
373: // return false;
374: // }
375:
376: /* (non-Javadoc)
377: * @see org.netbeans.modules.uml.core.addinframework.ui.action.IContributionItem#isSeparator()
378: */
379: public boolean isSeparator() {
380: return false;
381: }
382:
383: /* (non-Javadoc)
384: * @see org.netbeans.modules.uml.core.addinframework.ui.action.IContributionItem#isVisible()
385: */
386: public boolean isVisible() {
387: return m_Visible;
388: }
389:
390: /* (non-Javadoc)
391: * @see org.netbeans.modules.uml.core.addinframework.ui.action.IContributionItem#setParent(org.netbeans.modules.uml.core.addinframework.ui.action.IContributionManager)
392: */
393: public void setParent(IMenuManager parent) {
394: m_Parent = parent;
395: }
396:
397: /* (non-Javadoc)
398: * @see org.netbeans.modules.uml.core.addinframework.ui.action.IContributionItem#setVisible(boolean)
399: */
400: public void setVisible(boolean visible) {
401: m_Visible = visible;
402: }
403:
404: /* (non-Javadoc)
405: * @see org.netbeans.modules.uml.core.addinframework.ui.application.IMenuManager#createSubMenu(java.lang.String, java.lang.String)
406: */
407: public IMenuManager createSubMenu(String label, String id) {
408: IMenuManager subManager = new TestBedMenuManager(label, id);
409: subManager.setVisible(true);
410: subManager.setParent(this );
411:
412: IMenuManager retVal = new SubMenuManager(subManager);
413: retVal.setLabel(label);
414: retVal.setVisible(true);
415: m_SubMenus.put(label, retVal);
416:
417: // add(retVal);
418:
419: return retVal;
420: }
421:
422: public IMenuManager createOrGetSubMenu(String label, String id) {
423: IMenuManager retVal = null;
424: IMenuManager subManager = m_SubMenus.get(label);
425: if (subManager == null) {
426: retVal = createSubMenu(label, id);
427: add(retVal);
428: } else {
429: retVal = subManager;
430: }
431: return retVal;
432: }
433:
434: //**************************************************
435: // Helper Methods
436: //**************************************************
437:
438: /**
439: * Incrementally builds the menu from the contribution items.
440: * This method leaves out double separators and separators in the first
441: * or last position.
442: *
443: * @param force <code>true</code> means update even if not dirty,
444: * and <code>false</code> for normal incremental updating
445: * @param recursive <code>true</code> means recursively update
446: * all submenus, and <code>false</code> means just this menu
447: */
448: protected void update(boolean force, boolean recursive) {
449: if (isDirty() || force) {
450: if (menuExist() == true) {
451: // clean contains all active items without double separators
452: Object[] items = getItems();
453: List clean = new ArrayList(items.length);
454: IMenuManager separator = null;
455: for (int i = 0; i < items.length; ++i) {
456: Object ci = items[i];
457: if (ci instanceof IMenuManager) {
458: IMenuManager currmm = (IMenuManager) ci;
459: if (!currmm.isVisible()) {
460: continue;
461: }
462:
463: if (currmm.isSeparator()) {
464: // delay creation until necessary
465: // (handles both adjacent separators, and separator at end)
466: separator = currmm;
467: } else {
468: if (separator != null) {
469: if (clean.size() > 0) // no separator if first item
470: clean.add(separator);
471: separator = null;
472: }
473: clean.add(ci);
474: }
475: } else if (ci instanceof BaseAction) {
476: if (separator != null) {
477: if (clean.size() > 0) // no separator if first item
478: clean.add(separator);
479: separator = null;
480: }
481: clean.add(ci);
482: }
483:
484: }
485:
486: // remove obsolete (removed or nonactive)
487: updateMenu(force, recursive, clean);
488: }
489: } else {
490: // I am not dirty. Check if I must recursivly walk down the hierarchy.
491: if (recursive) {
492: Object[] items = getItems();
493: for (int i = 0; i < items.length; ++i) {
494: Object ci = items[i];
495: if (ci instanceof IMenuManager) {
496: IMenuManager mm = (IMenuManager) ci;
497: if (mm.isVisible()) {
498: mm.updateAll(force);
499: }
500: } else if (ci instanceof BaseAction) {
501: updateAll(force);
502: }
503: }
504: }
505: }
506: updateMenuItem();
507: }
508:
509: protected void updateMenu(boolean force, boolean recursive,
510: List clean) {
511:
512: int index = 0;
513:
514: for (Iterator e = clean.iterator(); e.hasNext();) {
515: Object obj = e.next();
516: if (obj instanceof IMenuManager) {
517: IMenuManager src = (IMenuManager) obj;
518:
519: if (m_MenuBar != null) {
520: src.fill(m_MenuBar, index);
521: } else if (m_MenuItem != null) {
522: src.fill(m_MenuItem, index);
523: }
524: } else if (obj instanceof BaseAction) {
525: if (m_MenuBar != null) {
526: } else if (m_MenuItem != null) {
527: m_MenuItem.add(((BaseAction) obj)
528: .getActionComponent());
529: // m_MenuItem.add((BaseAction)obj);
530: }
531: }
532: index++;
533: }
534: }
535:
536: /**
537: * Updates the menu item for this sub menu.
538: * The menu item is disabled if this sub menu is empty.
539: * Does nothing if this menu is not a submenu.
540: */
541: protected void updateMenuItem() {
542: /*
543: * Commented out until proper solution to enablement of
544: * menu item for a sub-menu is found. See bug 30833 for
545: * more details.
546: *
547: if (menuItem != null && !menuItem.isDisposed() && menuExist()) {
548: IContributionItem items[] = getItems();
549: boolean enabled = false;
550: for (int i = 0; i < items.length; i++) {
551: IContributionItem item = items[i];
552: enabled = item.isEnabled();
553: if(enabled) break;
554: }
555: // Workaround for 1GDDCN2: SWT:Linux - MenuItem.setEnabled() always causes a redraw
556: if (menuItem.getEnabled() != enabled)
557: menuItem.setEnabled(enabled);
558: }
559: */
560: }
561:
562: /**
563: * Returns whether the menu control is created
564: * and not disposed.
565: *
566: * @return <code>true</code> if the control is created
567: * and not disposed, <code>false</code> otherwise
568: */
569: private boolean menuExist() {
570: boolean retVal = false;
571:
572: if (m_MenuBar != null) {
573: retVal = true;
574: } else if (m_MenuItem != null) {
575: retVal = true;
576: }
577:
578: return retVal;
579: }
580:
581: /**
582: * Initializes the menu control.
583: */
584: private void initializeMenu() {
585: markDirty();
586: // Don't do an update(true) here, in case menu is never opened.
587: // Always do it lazily in handleAboutToShow().
588: }
589:
590: public void setLocation(Point p) {
591: m_Point = p;
592: }
593:
594: public Point getLocation() {
595: if (null == m_Point) {
596: if (m_Parent instanceof IMenuManager) {
597: IMenuManager parentMenu = (IMenuManager) m_Parent;
598: m_Point = parentMenu.getLocation();
599: }
600: }
601:
602: return m_Point;
603: }
604:
605: public void setContextObject(Object obj) {
606: m_ObjectClickedOn = obj;
607: }
608:
609: public Object getContextObject() {
610: return m_ObjectClickedOn;
611: }
612:
613: //override removeAll to clear the sub menus too.
614: public void removeAll() {
615: m_Contributions.clear();
616: // dynamicItems = 0;
617: markDirty();
618: m_SubMenus.clear();
619: }
620:
621: /* (non-Javadoc)
622: * @see org.netbeans.modules.uml.ui.products.ad.application.action.IContributionItem#getLabel()
623: */
624: public String getLabel() {
625: return m_Label;
626: }
627:
628: /* (non-Javadoc)
629: * @see org.netbeans.modules.uml.ui.products.ad.application.action.IContributionItem#setLabel(java.lang.String)
630: */
631: public void setLabel(String label) {
632: m_Label = label;
633: setMenuText(label);
634: }
635:
636: public Object remove(String ID) {
637: Object ci = find(ID);
638: if (ci == null)
639: throw new IllegalArgumentException("can't find ID"); //$NON-NLS-1$
640: return remove(ci);
641: }
642:
643: /* (non-Javadoc)
644: * Method declared on IContributionManager.
645: */
646: public Object remove(Object item) {
647: if (m_Contributions.remove(item)) {
648: itemRemoved(item);
649: return item;
650: }
651: return null;
652: }
653:
654: public Object find(String id) {
655: //search in the hash map with the id and return it..
656: Object item = itemMap.get(id);
657: if (item == null) {
658: Iterator e = m_Contributions.iterator();
659: while (e.hasNext()) {
660: Object obj = e.next();
661: if (obj instanceof IMenuManager) {
662: IMenuManager curItem = (IMenuManager) obj;
663: String itemId = curItem.getId();
664: if (itemId != null && itemId.equalsIgnoreCase(id)) {
665: item = curItem;
666: break;
667: }
668: } else if (obj instanceof BaseAction) {
669: BaseAction action = (BaseAction) obj;
670: String itemId = action.getId();
671: if (itemId != null && itemId.equalsIgnoreCase(id)) {
672: item = action;
673: break;
674: }
675: }
676: }
677: }
678:
679: return item;
680: }
681:
682: public Object[] getItems() {
683: Object[] items = new Object[m_Contributions.size()];
684: m_Contributions.toArray(items);
685: return items;
686: }
687:
688: // protected boolean hasDynamicItems()
689: // {
690: // return (dynamicItems > 0);
691: // }
692:
693: public boolean isDirty() {
694: if (isDirty)
695: return true;
696: // if (hasDynamicItems())
697: // {
698: // for (Iterator iter = m_Contributions.iterator(); iter.hasNext();)
699: // {
700: // IMenuManager item = (IMenuManager)iter.next();
701: // if (item.isDirty())
702: // return true;
703: // }
704: // }
705: return false;
706: }
707:
708: public boolean isEmpty() {
709: return m_Contributions.isEmpty();
710: }
711:
712: public void markDirty() {
713: setDirty(true);
714: }
715:
716: protected void itemRemoved(Object item) {
717: markDirty();
718: // if (item.isDynamic())
719: // dynamicItems--;
720: }
721:
722: protected void setDirty(boolean d) {
723: isDirty = d;
724: }
725:
726: public void add(IMenuManager item) {
727: m_Contributions.add(item);
728: item.setVisible(visible);
729: itemAdded(item);
730: item.setParent(this );
731: }
732:
733: protected void itemAdded(IMenuManager item) {
734: markDirty();
735: // if (item.isDynamic())
736: // dynamicItems++;
737: }
738:
739: public void fill(JToolBar parent, int index) {
740: }
741:
742: public IMenuManager getParent() {
743: return m_Parent;
744: }
745:
746: public void add(BaseAction action) {
747: m_Contributions.add(action);
748: action.setMenuManager(this );
749: }
750:
751: public void add(Separator sep, String key) {
752: add(sep);
753: itemMap.put(key, sep);
754: }
755:
756: private java.util.HashMap itemMap = new java.util.HashMap();
757: private boolean visible = true;
758: private String m_Label = null;
759: private IMenuManager parent;
760: private BaseAction m_Action;
761:
762: }
|