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.views;
011:
012: import java.util.ArrayList;
013: import java.util.Iterator;
014:
015: import org.eclipse.help.HelpSystem;
016: import org.eclipse.help.IContext;
017: import org.eclipse.jface.action.Action;
018: import org.eclipse.swt.SWT;
019: import org.eclipse.swt.events.FocusEvent;
020: import org.eclipse.swt.events.FocusListener;
021: import org.eclipse.swt.events.SelectionAdapter;
022: import org.eclipse.swt.events.SelectionEvent;
023: import org.eclipse.swt.graphics.Color;
024: import org.eclipse.swt.graphics.Font;
025: import org.eclipse.swt.graphics.FontData;
026: import org.eclipse.swt.graphics.Image;
027: import org.eclipse.swt.graphics.Point;
028: import org.eclipse.swt.layout.GridData;
029: import org.eclipse.swt.layout.GridLayout;
030: import org.eclipse.swt.widgets.Composite;
031: import org.eclipse.swt.widgets.Control;
032: import org.eclipse.swt.widgets.Label;
033: import org.eclipse.swt.widgets.Widget;
034: import org.eclipse.ui.PlatformUI;
035: import org.eclipse.ui.cheatsheets.AbstractItemExtensionElement;
036: import org.eclipse.ui.forms.events.ExpansionAdapter;
037: import org.eclipse.ui.forms.events.ExpansionEvent;
038: import org.eclipse.ui.forms.events.HyperlinkAdapter;
039: import org.eclipse.ui.forms.events.HyperlinkEvent;
040: import org.eclipse.ui.forms.widgets.ExpandableComposite;
041: import org.eclipse.ui.forms.widgets.FormText;
042: import org.eclipse.ui.forms.widgets.FormToolkit;
043: import org.eclipse.ui.forms.widgets.ImageHyperlink;
044: import org.eclipse.ui.forms.widgets.TableWrapData;
045: import org.eclipse.ui.forms.widgets.TableWrapLayout;
046: import org.eclipse.ui.internal.cheatsheets.CheatSheetPlugin;
047: import org.eclipse.ui.internal.cheatsheets.CheatSheetStopWatch;
048: import org.eclipse.ui.internal.cheatsheets.ICheatSheetResource;
049: import org.eclipse.ui.internal.cheatsheets.Messages;
050: import org.eclipse.ui.internal.cheatsheets.data.IParserTags;
051: import org.eclipse.ui.internal.cheatsheets.data.Item;
052:
053: public abstract class ViewItem {
054:
055: public final static byte VIEWITEM_ADVANCE = 0;
056: public final static byte VIEWITEM_DONOT_ADVANCE = 1;
057: private Composite bodyComp;
058:
059: protected FormText bodyText;
060: protected FormText completionText;
061: // protected Label bodyText;
062: protected Composite bodyWrapperComposite;
063: protected Composite buttonComposite;
064: protected Composite completionComposite;
065:
066: private boolean buttonExpanded = true;
067: private boolean completionMessageExpanded = false;
068: private Label checkDoneLabel;
069: private boolean completed = false;
070:
071: protected Item item;
072:
073: // Colors
074: protected Color itemColor;
075:
076: private boolean isSkipped = false;
077: private ExpandableComposite mainItemComposite;
078:
079: private Composite parent;
080: protected CheatSheetViewer viewer;
081: protected CheatSheetPage page;
082: private Composite titleComposite;
083: private boolean bold = true;
084: private Font boldFont;
085: private Font regularFont;
086: private boolean initialized = false;
087: protected ArrayList listOfSubItemCompositeHolders;
088:
089: /**
090: * Constructor for ViewItem.
091: */
092: public ViewItem(CheatSheetPage page, Item item, Color itemColor,
093: CheatSheetViewer viewer) {
094: super ();
095: this .page = page;
096: this .parent = page.getForm().getBody();
097: this .item = item;
098: this .itemColor = itemColor;
099: this .viewer = viewer;
100: addItem();
101: }
102:
103: //Adds the item to the main composite.
104: private void addItem() {
105: CheatSheetStopWatch.startStopWatch("ViewItem.addItem()"); //$NON-NLS-1$
106: CheatSheetStopWatch
107: .printLapTime(
108: "ViewItem.addItem()", "Time in addItem() after getBannerBackground: "); //$NON-NLS-1$ //$NON-NLS-2$
109:
110: // Set up the main composite for the item.******************************************
111: checkDoneLabel = page.getToolkit().createLabel(parent, " "); //$NON-NLS-1$
112: CheatSheetStopWatch
113: .printLapTime(
114: "ViewItem.addItem()", "Time in addItem() after create checkDoneLabel: "); //$NON-NLS-1$ //$NON-NLS-2$
115:
116: mainItemComposite = page.getToolkit().createSection(
117: parent,
118: ExpandableComposite.TWISTIE
119: | ExpandableComposite.COMPACT);
120: mainItemComposite.setBackground(itemColor);
121: mainItemComposite.setLayoutData(new TableWrapData(
122: TableWrapData.FILL_GRAB));
123: String title = item.getTitle();
124: if (title != null) {
125: mainItemComposite.setText(ViewUtilities
126: .escapeForLabel(title));
127: }
128: CheatSheetStopWatch
129: .printLapTime(
130: "ViewItem.addItem()", "Time in addItem() after create mainItemComposite: "); //$NON-NLS-1$ //$NON-NLS-2$
131:
132: mainItemComposite.addExpansionListener(new ExpansionAdapter() {
133: public void expansionStateChanged(ExpansionEvent e) {
134: page.getForm().reflow(true);
135: }
136: });
137: CheatSheetStopWatch
138: .printLapTime(
139: "ViewItem.addItem()", "Time in addItem() after addExpansionListener: "); //$NON-NLS-1$ //$NON-NLS-2$
140:
141: // handle item extensions here
142: // check number of extensions for this item and adjust layout accordingly
143: int number = 0;
144: ArrayList itemExts = item.getItemExtensions();
145:
146: if ((itemExts != null && itemExts.size() > 0)
147: || item.getContextId() != null
148: || item.getHref() != null) {
149: // Set up the title composite for the item.
150: titleComposite = page.getToolkit().createComposite(
151: mainItemComposite);
152: titleComposite.setBackground(itemColor);
153: }
154:
155: if (itemExts != null) {
156: for (int g = 0; g < itemExts.size(); g++) {
157: AbstractItemExtensionElement[] eea = (AbstractItemExtensionElement[]) itemExts
158: .get(g);
159: number += eea.length;
160: for (int x = 0; x < eea.length; x++) {
161: eea[x].createControl(titleComposite);
162: }
163: }
164: }
165: CheatSheetStopWatch
166: .printLapTime(
167: "ViewItem.addItem()", "Time in addItem() after create item extensions: "); //$NON-NLS-1$ //$NON-NLS-2$
168:
169: // don't add the help icon unless there is a context id or help link
170: if (item.getContextId() != null || item.getHref() != null) {
171: // adjust the layout count
172: number++;
173: ImageHyperlink helpButton = createButton(titleComposite,
174: CheatSheetPlugin.getPlugin().getImage(
175: ICheatSheetResource.CHEATSHEET_ITEM_HELP),
176: this , itemColor, Messages.HELP_BUTTON_TOOLTIP);
177: helpButton.addHyperlinkListener(new HyperlinkAdapter() {
178: public void linkActivated(HyperlinkEvent e) {
179: // If we have a context id, handle this first and ignore an hrefs
180: if (item.getContextId() != null) {
181: openInfopop(e.widget);
182: } else {
183: // We only have an href, so let's open it in the help system
184: openHelpTopic();
185: }
186: }
187: });
188: }
189: CheatSheetStopWatch
190: .printLapTime(
191: "ViewItem.addItem()", "Time in addItem() after create help button: "); //$NON-NLS-1$ //$NON-NLS-2$
192:
193: if (number > 0) {
194: mainItemComposite.setTextClient(titleComposite);
195: GridLayout layout = new GridLayout(number, false);
196: GridData data = new GridData(GridData.FILL_BOTH);
197:
198: titleComposite.setLayout(layout);
199: titleComposite.setLayoutData(data);
200: layout.marginWidth = 0;
201: layout.marginHeight = 0;
202: layout.verticalSpacing = 0;
203: }
204: CheatSheetStopWatch
205: .printLapTime(
206: "ViewItem.addItem()", "Time in addItem() after setTextClient: "); //$NON-NLS-1$ //$NON-NLS-2$
207:
208: //Body wrapper here. this composite will be hidden and shown as appropriate.
209: bodyWrapperComposite = page.getToolkit().createComposite(
210: mainItemComposite);
211: mainItemComposite.setClient(bodyWrapperComposite);
212: TableWrapLayout wrapperLayout = new TableWrapLayout();
213: bodyWrapperComposite.setLayout(wrapperLayout);
214: bodyWrapperComposite.setBackground(itemColor);
215: CheatSheetStopWatch
216: .printLapTime(
217: "ViewItem.addItem()", "Time in addItem() after create bodyWrapperComposite: "); //$NON-NLS-1$ //$NON-NLS-2$
218:
219: bodyText = page.getToolkit().createFormText(
220: bodyWrapperComposite, false);
221: bodyText.addSelectionListener(new SelectionAdapter() {
222: public void widgetSelected(SelectionEvent e) {
223: Action copyAction = viewer.getCopyAction();
224: if (copyAction != null)
225: copyAction.setEnabled(bodyText.canCopy());
226: }
227: });
228: bodyText.addFocusListener(new FocusListener() {
229: public void focusGained(FocusEvent e) {
230: Action copyAction = viewer.getCopyAction();
231: if (copyAction != null)
232: copyAction.setEnabled(bodyText.canCopy());
233: }
234:
235: public void focusLost(FocusEvent e) {
236: Action copyAction = viewer.getCopyAction();
237: if (copyAction != null)
238: copyAction.setEnabled(false);
239: }
240: });
241: // bodyText = toolkit.createLabel(bodyWrapperComposite, item.getDescription(), SWT.WRAP);
242: bodyText.setText(item.getDescription(), item.getDescription()
243: .startsWith(IParserTags.FORM_START_TAG), false);
244:
245: //Set up the body text portion here.
246: bodyText.setBackground(itemColor);
247: bodyText.setLayoutData(new TableWrapData(
248: TableWrapData.FILL_GRAB));
249: CheatSheetStopWatch
250: .printLapTime(
251: "ViewItem.addItem()", "Time in addItem() after create FormText: "); //$NON-NLS-1$ //$NON-NLS-2$
252:
253: //Handle the sub-steps and regular buttons here.
254: //First Check to see if there is sub steps. If there is, don't create the button comp,
255: //As it will be handled by the CoreItemWithSubs.
256: //If there is no sub steps, create a button composite and Pass it to CoreItem using the handleButtons.
257:
258: if (!item.isDynamic()) {
259: handleButtons();
260: }
261: CheatSheetStopWatch
262: .printLapTime(
263: "ViewItem.addItem()", "Time in addItem() after handleButtons(): "); //$NON-NLS-1$ //$NON-NLS-2$
264:
265: setButtonsVisible(false);
266: setCollapsed();
267: CheatSheetStopWatch
268: .printLapTime(
269: "ViewItem.addItem()", "Time in addItem() after setting buttons and item collapsed: "); //$NON-NLS-1$ //$NON-NLS-2$
270:
271: boldFont = mainItemComposite.getFont();
272: FontData[] fontDatas = boldFont.getFontData();
273: for (int i = 0; i < fontDatas.length; i++) {
274: fontDatas[i].setStyle(fontDatas[i].getStyle() ^ SWT.BOLD);
275: }
276: regularFont = new Font(mainItemComposite.getDisplay(),
277: fontDatas);
278: CheatSheetStopWatch
279: .printLapTime(
280: "ViewItem.addItem()", "Time in addItem() after font initlization: "); //$NON-NLS-1$ //$NON-NLS-2$
281:
282: setBold(false);
283: CheatSheetStopWatch
284: .printLapTime(
285: "ViewItem.addItem()", "Time in addItem() after setBold: "); //$NON-NLS-1$ //$NON-NLS-2$
286: }
287:
288: protected ImageHyperlink createButtonWithText(Composite parent,
289: Image image, ViewItem item, Color color, String linkText) {
290: ImageHyperlink button = page.getToolkit().createImageHyperlink(
291: parent, SWT.NULL);
292: button.setImage(image);
293: button.setData(item);
294: button.setBackground(color);
295: button.setText(linkText);
296: button.setToolTipText(linkText);
297: return button;
298: }
299:
300: protected ImageHyperlink createButton(Composite parent,
301: Image image, ViewItem item, Color color, String toolTipText) {
302: ImageHyperlink button = new ImageHyperlink(parent, SWT.NULL);
303: page.getToolkit().adapt(button, true, true);
304: button.setImage(image);
305: button.setData(item);
306: button.setBackground(color);
307: button.setToolTipText(toolTipText);
308: // button.setFAccessibleDescription(bodyText.getText());
309: // button.setFAccessibleName(button.getToolTipText());
310:
311: return button;
312: }
313:
314: public void dispose() {
315: if (checkDoneLabel != null)
316: checkDoneLabel.dispose();
317: if (bodyText != null)
318: bodyText.dispose();
319: if (buttonComposite != null)
320: buttonComposite.dispose();
321: if (completionComposite != null)
322: completionComposite.dispose();
323: if (bodyComp != null)
324: bodyComp.dispose();
325: if (bodyWrapperComposite != null)
326: bodyWrapperComposite.dispose();
327: if (mainItemComposite != null)
328: mainItemComposite.dispose();
329: if (titleComposite != null)
330: titleComposite.dispose();
331: if (regularFont != null)
332: regularFont.dispose();
333:
334: ArrayList itemExts = item.getItemExtensions();
335: if (itemExts != null) {
336: for (int g = 0; g < itemExts.size(); g++) {
337: AbstractItemExtensionElement[] eea = (AbstractItemExtensionElement[]) itemExts
338: .get(g);
339: for (int x = 0; x < eea.length; x++) {
340: eea[x].dispose();
341: }
342: }
343: }
344: }
345:
346: /**
347: * @return
348: */
349: /*package*/
350: Image getCompleteImage() {
351: return CheatSheetPlugin.getPlugin().getImage(
352: ICheatSheetResource.CHEATSHEET_ITEM_COMPLETE);
353: }
354:
355: /**
356: * @return
357: */
358: public Item getItem() {
359: return item;
360: }
361:
362: /**
363: * Returns the mainItemComposite.
364: * @return Composite
365: */
366: /*package*/
367: Composite getMainItemComposite() {
368: return mainItemComposite;
369: }
370:
371: /**
372: * @return
373: */
374: /*package*/
375: Image getSkipImage() {
376: return CheatSheetPlugin.getPlugin().getImage(
377: ICheatSheetResource.CHEATSHEET_ITEM_SKIP);
378: }
379:
380: //Adds the buttons to the buttonComposite.
381: /*package*/
382: abstract void handleButtons();
383:
384: /*package*/
385: boolean isBold() {
386: return bold;
387: }
388:
389: /**
390: * Returns the completed.
391: * @return boolean
392: */
393: public boolean isCompleted() {
394: return completed;
395: }
396:
397: public boolean isExpanded() {
398: return mainItemComposite.isExpanded();
399: }
400:
401: public boolean isCompletionMessageExpanded() {
402: return completionMessageExpanded;
403: }
404:
405: /**
406: * Returns whether or not cheat sheet viewer containing this item is in
407: * a modal dialog.
408: *
409: * @return whether the cheat sheet viewer is in a modal dialog
410: */
411: public boolean isInDialogMode() {
412: return viewer.isInDialogMode();
413: }
414:
415: /*package*/
416: boolean isSkipped() {
417: return isSkipped;
418: }
419:
420: /**
421: * Open a help topic
422: */
423: private void openHelpTopic() {
424: if (item == null || item.getHref() == null) {
425: return;
426: }
427:
428: PlatformUI.getWorkbench().getHelpSystem().displayHelpResource(
429: item.getHref());
430: }
431:
432: /**
433: * Open an infopop
434: */
435: private void openInfopop(Widget widget) {
436: if (item == null || item.getContextId() == null) {
437: return;
438: }
439:
440: IContext context = HelpSystem.getContext(item.getContextId());
441:
442: if (context != null) {
443: // determine a location in the upper right corner of the widget
444: Point point = widget.getDisplay().getCursorLocation();
445: point = new Point(point.x + 15, point.y);
446: // display the help
447: PlatformUI.getWorkbench().getHelpSystem().displayContext(
448: context, point.x, point.y);
449: }
450: }
451:
452: public void setAsCurrentActiveItem() {
453: setColorAsCurrent(true);
454: setButtonsVisible(true);
455: setBold(true);
456: setExpanded();
457: setFocus();
458: }
459:
460: protected void setFocus() {
461: mainItemComposite.setFocus();
462: FormToolkit.ensureVisible(getMainItemComposite());
463: }
464:
465: /*package*/
466: void setAsNormalCollapsed() {
467: setBold(false);
468: setColorAsCurrent(false);
469: if (mainItemComposite.isExpanded())
470: setCollapsed();
471: }
472:
473: /*package*/
474: void setAsNormalNonCollapsed() {
475: setColorAsCurrent(false);
476: setBold(false);
477: }
478:
479: private void setBodyColor(Color color) {
480: mainItemComposite.setBackground(color);
481: setBackgroundColor(bodyWrapperComposite, color);
482: setBackgroundColor(buttonComposite, color);
483: setBackgroundColor(completionComposite, color);
484: }
485:
486: /*
487: * Set the background color of this composite and its children.
488: * If the composite is null do nothing.
489: */
490: protected void setBackgroundColor(Composite composite, Color color) {
491: if (composite != null) {
492: composite.setBackground(color);
493: Control[] children = composite.getChildren();
494: for (int i = 0; i < children.length; i++) {
495: children[i].setBackground(color);
496: }
497: }
498: }
499:
500: /*package*/
501: void setBold(boolean value) {
502: if (value) {
503: mainItemComposite.setFont(boldFont);
504: if (initialized)
505: mainItemComposite.layout();
506: } else {
507: mainItemComposite.setFont(regularFont);
508: if (initialized)
509: mainItemComposite.layout();
510: }
511: bold = value;
512: }
513:
514: //collapse or expand the item
515: /*package*/
516: void setButtonsVisible(boolean isVisible) {
517: if (buttonExpanded != isVisible) {
518: if (listOfSubItemCompositeHolders != null) {
519: for (Iterator iter = listOfSubItemCompositeHolders
520: .iterator(); iter.hasNext();) {
521: ((SubItemCompositeHolder) iter.next())
522: .setButtonsVisible(isVisible);
523: }
524: } else if (buttonComposite != null) {
525: buttonComposite.setVisible(isVisible);
526: }
527: }
528:
529: if (isVisible && initialized) {
530: FormToolkit.ensureVisible(getMainItemComposite());
531: }
532: buttonExpanded = isVisible;
533: }
534:
535: protected void setCompletionMessageExpanded(boolean isFinalItem) {
536: if (hasCompletionMessage()) {
537: if (completionComposite == null) {
538: createCompletionComposite(isFinalItem);
539: }
540: if (!completionMessageExpanded) {
541: completionComposite.setVisible(true);
542: completionMessageExpanded = true;
543: }
544: }
545: }
546:
547: abstract void createCompletionComposite(boolean isFinalItem);
548:
549: protected void setCompletionMessageCollapsed() {
550: if (completionComposite != null) {
551: if (completionMessageExpanded) {
552: completionComposite.dispose();
553: completionComposite = null;
554: page.getForm().reflow(true);
555: }
556: }
557: completionMessageExpanded = false;
558: }
559:
560: //collapses the item
561: /*package*/
562: void setCollapsed() {
563: if (mainItemComposite.isExpanded()) {
564: mainItemComposite.setExpanded(false);
565: if (initialized) {
566: page.getForm().reflow(true);
567: FormToolkit.ensureVisible(getMainItemComposite());
568: }
569: }
570: }
571:
572: private void setColorAsCurrent(boolean active) {
573: if (active) {
574: setTitleColor(page.getActiveColor());
575: setBodyColor(page.getActiveColor());
576: } else {
577: setTitleColor(itemColor);
578: setBodyColor(itemColor);
579: }
580: }
581:
582: //marks the item as complete.
583: /*package*/
584: void setComplete() {
585: completed = true;
586: checkDoneLabel.setImage(getCompleteImage());
587:
588: if (initialized) {
589: checkDoneLabel.getParent().layout();
590: }
591: }
592:
593: //expands the item
594: /*package*/
595: void setExpanded() {
596: if (!mainItemComposite.isExpanded()) {
597: mainItemComposite.setExpanded(true);
598: if (initialized) {
599: page.getForm().reflow(true);
600: FormToolkit.ensureVisible(getMainItemComposite());
601: }
602: }
603: }
604:
605: /*package*/
606: void setIncomplete() {
607: checkDoneLabel.setImage(null);
608: completed = false;
609: setStartImage();
610: }
611:
612: /**
613: * Sets the itemColor.
614: * @param itemColor The itemColor to set
615: */
616: /*package*/
617: void setItemColor(Color itemColor) {
618: this .itemColor = itemColor;
619: }
620:
621: /*package*/
622: void setOriginalColor() {
623: setTitleColor(itemColor);
624: setBodyColor(itemColor);
625: setBold(false);
626: }
627:
628: /*package*/
629: abstract void setRestartImage();
630:
631: /*package*/
632: void setSkipped() {
633: isSkipped = true;
634: checkDoneLabel.setImage(getSkipImage());
635:
636: if (initialized) {
637: checkDoneLabel.getParent().layout();
638: }
639: }
640:
641: /*package*/
642: abstract void setStartImage();
643:
644: private void setTitleColor(Color bg) {
645: if (titleComposite != null) {
646: titleComposite.setBackground(bg);
647:
648: Control[] titlechildren = titleComposite.getChildren();
649: for (int i = 0; i < titlechildren.length; i++) {
650: titlechildren[i].setBackground(bg);
651: }
652: }
653: }
654:
655: public void initialized() {
656: initialized = true;
657: }
658:
659: public boolean canCopy() {
660: return (bodyText != null && !bodyText.isDisposed()) ? bodyText
661: .canCopy() : false;
662: }
663:
664: public void copy() {
665: if (bodyText != null && !bodyText.isDisposed())
666: bodyText.copy();
667: }
668:
669: abstract boolean hasCompletionMessage();
670:
671: }
|