001: /*******************************************************************************
002: * Copyright (c) 2002, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.internal.cheatsheets.actions;
011:
012: import com.ibm.icu.text.Collator;
013: import java.util.ArrayList;
014: import java.util.Collections;
015: import java.util.Comparator;
016: import java.util.List;
017:
018: import org.eclipse.jface.action.ContributionItem;
019: import org.eclipse.swt.SWT;
020: import org.eclipse.swt.events.*;
021: import org.eclipse.swt.widgets.*;
022: import org.eclipse.ui.*;
023:
024: import org.eclipse.ui.cheatsheets.*;
025: import org.eclipse.ui.internal.cheatsheets.*;
026: import org.eclipse.ui.internal.cheatsheets.registry.*;
027: import org.eclipse.ui.internal.cheatsheets.views.CheatSheetView;
028:
029: /**
030: * A menu for cheatsheet selection.
031: * <p>
032: * A <code>CheatSheetMenu</code> is used to populate a menu with
033: * cheatsheet items. If the user selects one of these items
034: * an action is performed to launch the selected cheatsheet.
035: * </p><p>
036: * The visible cheatsheet items within the menu are dynamic and reflect the
037: * available set. The available set consists of a limited combination of
038: * the most recently used cheatsheet list and the currently available
039: * cheatsheet.
040: * </p>
041: */
042: public class CheatSheetMenu extends ContributionItem {
043: private static final int MAX_CHEATSHEET_ITEMS = 5;
044: private static CheatSheetRegistryReader reg;
045:
046: private boolean showActive = false;
047:
048: private IMenuContributor menuContributor;
049:
050: private Comparator comparator = new Comparator() {
051: private Collator collator = Collator.getInstance();
052:
053: public int compare(Object ob1, Object ob2) {
054: if (ob1 == null || ob2 == null) {
055: return -1;
056: }
057: CheatSheetElement d1 = (CheatSheetElement) ob1;
058: CheatSheetElement d2 = (CheatSheetElement) ob2;
059: return collator.compare(d1.getLabel(null), d2
060: .getLabel(null));
061: }
062: };
063:
064: /**
065: * Constructs a new instance of <code>CheatSheetMenu</code>.
066: */
067: public CheatSheetMenu() {
068: super ("LaunchCheatSheetMenu"); //$NON-NLS-1$
069:
070: if (reg == null)
071: reg = CheatSheetRegistryReader.getInstance();
072:
073: showActive(true);
074: }
075:
076: /* (non-Javadoc)
077: * Creates a menu item for a cheatsheet.
078: */
079: private void createMenuItem(Menu menu, int index,
080: final CheatSheetElement element, boolean bCheck) {
081:
082: MenuItem mi = new MenuItem(menu, bCheck ? SWT.RADIO : SWT.PUSH,
083: index);
084: mi.setText(element.getLabel(null));
085: String key;
086: if (element.isComposite()) {
087: key = ICheatSheetResource.COMPOSITE_OBJ;
088: } else {
089: key = ICheatSheetResource.CHEATSHEET_OBJ;
090: }
091: mi.setImage(CheatSheetPlugin.getPlugin().getImageRegistry()
092: .get(key));
093: mi.setSelection(bCheck);
094: mi.addSelectionListener(new SelectionAdapter() {
095: public void widgetSelected(SelectionEvent e) {
096: run(element, e);
097: }
098: });
099: }
100:
101: /* (non-Javadoc)
102: * Creates a menu item for "Other...".
103: */
104: private void createOtherItem(Menu menu, int index) {
105: MenuItem mi = new MenuItem(menu, SWT.PUSH, index);
106: mi.setText(Messages.CHEAT_SHEET_OTHER_MENU);
107: mi.addSelectionListener(new SelectionAdapter() {
108: public void widgetSelected(SelectionEvent e) {
109: runOther(e);
110: }
111: });
112: }
113:
114: /* (non-Javadoc)
115: * Fills the menu with cheatsheet items.
116: */
117: public void fill(Menu menu, int index) {
118: // Get the checked cheatsheet.
119: String checkID = null;
120: if (showActive) {
121: checkID = getActiveCheatSheetID();
122: }
123:
124: // Collect and sort cheatsheet items.
125: ArrayList cheatsheets = getCheatSheetItems();
126: Collections.sort(cheatsheets, comparator);
127:
128: // Add cheatsheet shortcuts
129: for (int i = 0; i < cheatsheets.size(); i++) {
130: CheatSheetElement element = (CheatSheetElement) cheatsheets
131: .get(i);
132: if (element != null) {
133: createMenuItem(menu, index++, element, element.getID()
134: .equals(checkID));
135: }
136: }
137:
138: // Add others item..
139: if (cheatsheets.size() > 0) {
140: new MenuItem(menu, SWT.SEPARATOR, index++);
141: }
142: createOtherItem(menu, index++);
143: if (menuContributor != null) {
144: menuContributor.contributeToViewMenu(menu, index);
145: }
146: }
147:
148: /**
149: * Method getActiveCheatSheetID returns the id of the active
150: * cheatsheet or null.
151: *
152: * @return String
153: */
154: private String getActiveCheatSheetID() {
155: //get the active cheatsheet view, if opened
156: IWorkbenchPage page = getActiveWorkbenchPage();
157:
158: if (page != null) {
159: CheatSheetView view = (CheatSheetView) page
160: .findView(ICheatSheetResource.CHEAT_SHEET_VIEW_ID);
161: if (view != null) {
162: CheatSheetElement content = view.getContent();
163: if (content != null) {
164: return content.getID();
165: }
166: }
167: }
168:
169: return null;
170: }
171:
172: /**
173: * Method getActiveWorkbenchPage returns the active
174: * workbench page or null.
175: *
176: * @return IWorkbenchPage
177: */
178: private IWorkbenchPage getActiveWorkbenchPage() {
179: IWorkbench workbench = CheatSheetPlugin.getPlugin()
180: .getWorkbench();
181: IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
182:
183: //get the active cheatsheet view, if opened
184: return window.getActivePage();
185: }
186:
187: /**
188: * Returns the available list of cheatsheets to display
189: * in the menu.
190: * <p>
191: * By default, the list contains the most recently used cheatsheets
192: * and then random cheatsheets until there are 5 present in the list.
193: * </p><p>
194: * Care should be taken to keep this list to a minimum (7 +/- 2 items
195: * is a good guideline to follow).
196: * </p>
197: *
198: * @return an <code>ArrayList<code> of cheatsheet items <code>CheatSheetElement</code>
199: */
200: protected ArrayList getCheatSheetItems() {
201: ArrayList list = new ArrayList(MAX_CHEATSHEET_ITEMS);
202: int emptySlots = MAX_CHEATSHEET_ITEMS;
203:
204: // Add cheatsheets from MRU list
205: if (emptySlots > 0) {
206: ArrayList mru = new ArrayList(MAX_CHEATSHEET_ITEMS);
207: int count = getCheatSheetMru(mru, 0, MAX_CHEATSHEET_ITEMS);
208: for (int i = 0; i < count && emptySlots > 0; i++) {
209: if (!list.contains(mru.get(i))) {
210: list.add(mru.get(i));
211: emptySlots--;
212: }
213: }
214: }
215:
216: // Add random cheatsheets until the list is filled.
217: CheatSheetCollectionElement cheatSheetsCollection = (CheatSheetCollectionElement) reg
218: .getCheatSheets();
219: emptySlots = addCheatSheets(list, cheatSheetsCollection,
220: emptySlots);
221:
222: return list;
223: }
224:
225: /**
226: * Method addCheatSheets fills a list with cheatsheet elements until there
227: * are no more empty slots.
228: *
229: * @param list - the list to file
230: * @param cheatSheetsCollection - the collection to get the elements from
231: * @param emptySlots - number of empty slots remaining
232: * @return int - number of empty slots remaining
233: */
234: private int addCheatSheets(ArrayList list,
235: CheatSheetCollectionElement cheatSheetsCollection,
236: int emptySlots) {
237: Object[] cheatSheets = cheatSheetsCollection.getCheatSheets();
238: for (int i = 0; i < cheatSheets.length && emptySlots > 0; i++) {
239: if (!list.contains(cheatSheets[i])) {
240: list.add(cheatSheets[i]);
241: emptySlots--;
242: }
243: }
244:
245: Object[] cheatSheetsFromCollection = cheatSheetsCollection
246: .getChildren();
247: for (int nX = 0; nX < cheatSheetsFromCollection.length
248: && emptySlots > 0; nX++) {
249: CheatSheetCollectionElement collection = (CheatSheetCollectionElement) cheatSheetsFromCollection[nX];
250: emptySlots = addCheatSheets(list, collection, emptySlots);
251: }
252:
253: return emptySlots;
254: }
255:
256: /* (non-Javadoc)
257: * Gets the most recently used (MRU) shortcut cheatsheets
258: * (<code>CheatSheetElement</code> items)
259: * <p>
260: * The list is formed from the global cheatsheet history.
261: * </p>
262: * @param dest destination list to contain the items
263: * @param destStart index in destination list to start copying items at
264: * @param count number of items to copy from history
265: * @return the number of items actually copied
266: */
267: private int getCheatSheetMru(List dest, int destStart, int count) {
268: CheatSheetHistory history = CheatSheetPlugin.getPlugin()
269: .getCheatSheetHistory();
270: return history.copyItems(dest, destStart, count);
271: }
272:
273: /**
274: * Returns whether the menu item representing the active cheatsheet
275: * will have a check mark.
276: *
277: * @return <code>true</code> if a check mark is shown, <code>false</code> otherwise
278: */
279: protected boolean getShowActive() {
280: return showActive;
281: }
282:
283: /* (non-Javadoc)
284: * Returns whether this menu is dynamic.
285: */
286: public boolean isDynamic() {
287: return true;
288: }
289:
290: /* (non-Javadoc)
291: * @see org.eclipse.jface.action.IContributionItem#isVisible()
292: */
293: public boolean isVisible() {
294: return getActiveWorkbenchPage() != null;
295: }
296:
297: /**
298: * Runs an action to launch the cheatsheet.
299: *
300: * @param element the selected cheatsheet
301: * @param event SelectionEvent - the event send along with the selection callback
302: */
303: protected void run(CheatSheetElement element, SelectionEvent event) {
304: new OpenCheatSheetAction(element.getID()).run();
305: }
306:
307: /* (non-Javadoc)
308: * Show the "other" dialog, select a cheatsheet, and launch it. Pass on the selection
309: * event should the meny need it.
310: */
311: private void runOther(SelectionEvent event) {
312: new CheatSheetCategoryBasedSelectionAction().run();
313: }
314:
315: /**
316: * Sets the showActive flag. If <code>showActive == true</code> then the
317: * active cheatsheet is hilighted with a check mark.
318: *
319: * @param the new showActive flag
320: */
321: protected void showActive(boolean b) {
322: showActive = b;
323: }
324:
325: /**
326: * Sets the menuContributor
327: * @param menuContributor an object which may add contributions to
328: * the menu.
329: */
330: public void setMenuContributor(IMenuContributor menuContributor) {
331: this.menuContributor = menuContributor;
332: }
333:
334: }
|