001: /*******************************************************************************
002: * Copyright (c) 2004 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Common Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/cpl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.examples.presentation.sidewinder;
011:
012: import org.eclipse.jface.action.Action;
013: import org.eclipse.jface.action.IAction;
014: import org.eclipse.jface.action.MenuManager;
015: import org.eclipse.jface.action.Separator;
016: import org.eclipse.swt.SWT;
017: import org.eclipse.swt.custom.ViewForm;
018: import org.eclipse.swt.events.DisposeEvent;
019: import org.eclipse.swt.events.DisposeListener;
020: import org.eclipse.swt.events.MouseAdapter;
021: import org.eclipse.swt.events.MouseEvent;
022: import org.eclipse.swt.events.MouseListener;
023: import org.eclipse.swt.events.PaintEvent;
024: import org.eclipse.swt.events.PaintListener;
025: import org.eclipse.swt.graphics.Image;
026: import org.eclipse.swt.graphics.Point;
027: import org.eclipse.swt.graphics.Rectangle;
028: import org.eclipse.swt.layout.RowLayout;
029: import org.eclipse.swt.widgets.Composite;
030: import org.eclipse.swt.widgets.Control;
031: import org.eclipse.swt.widgets.Event;
032: import org.eclipse.swt.widgets.Listener;
033: import org.eclipse.swt.widgets.Menu;
034: import org.eclipse.swt.widgets.ToolItem;
035: import org.eclipse.ui.IPropertyListener;
036: import org.eclipse.ui.examples.presentation.wrappedtabs.ProxyControl;
037: import org.eclipse.ui.presentations.IPartMenu;
038: import org.eclipse.ui.presentations.IPresentablePart;
039: import org.eclipse.ui.presentations.IStackPresentationSite;
040: import org.eclipse.ui.presentations.PresentationUtil;
041: import org.eclipse.ui.presentations.StackDropResult;
042: import org.eclipse.ui.presentations.StackPresentation;
043:
044: public class SideWinderItemViewPresentation extends StackPresentation {
045:
046: private static final String PART_DATA = "part";
047:
048: private static final int TITLE_HEIGHT = 22;
049:
050: private boolean activeFocus = false;
051:
052: /**
053: * Main widget for the presentation
054: */
055: private Composite presentationControl;
056: private Composite titleArea;
057: private Composite clientArea;
058: private Composite statusLineArea;
059: private ViewForm contentArea;
060: private ProxyControl toolbarProxy;
061:
062: /**
063: * Currently selected part
064: */
065: private IPresentablePart current;
066:
067: /**
068: * close button
069: */
070: private ToolItem close;
071:
072: /**
073: * View menu button
074: */
075: private ToolItem viewMenu;
076:
077: /**
078: * Minimize button
079: */
080: private ToolItem minView;
081:
082: private int style = SWT.VERTICAL | SWT.LEFT;
083:
084: private boolean titleAreaHiden = false;
085:
086: /**
087: * This listener responds to selection events in all tool items.
088: */
089: private MouseListener mouseListener = new MouseAdapter() {
090: // If we single-click on an empty space on the toolbar, move focus to the
091: // active control
092: public void mouseDown(MouseEvent e) {
093: PartItem toolItem = (PartItem) e.widget;
094: IPresentablePart item = getPartForTab(toolItem);
095: if (item != null) {
096: // Clicking on the active tab should give focus to the current
097: // part
098: if (item == current) {
099: item.setFocus();
100: }
101: getSite().selectPart(item);
102: selectPart(item);
103: Point toDisplay = toolItem
104: .toDisplay(new Point(e.x, e.y));
105: if (e.button == 3) {
106: showSystemMenu(toDisplay);
107: } else {
108: Image image = toolItem.getImage();
109: if (image != null) {
110: if (image.getBounds().contains(e.x, e.y)) {
111: showPaneMenu(toDisplay);
112: }
113: }
114: }
115: }
116: }
117: };
118:
119: /**
120: * Listener attached to all child parts. It responds to changes in part properties
121: */
122: private IPropertyListener childPropertyChangeListener = new IPropertyListener() {
123: public void propertyChanged(Object source, int property) {
124: if (source instanceof IPresentablePart) {
125: IPresentablePart part = (IPresentablePart) source;
126: updatePartItem(getPartItem(part), part);
127: }
128: }
129: };
130:
131: /**
132: * Listener attached to all tool items. It removes listeners from the associated
133: * part when the tool item is destroyed. This is required to prevent memory leaks.
134: */
135: private DisposeListener tabDisposeListener = new DisposeListener() {
136: public void widgetDisposed(DisposeEvent e) {
137: if (e.widget instanceof ToolItem) {
138: PartItem item = (PartItem) e.widget;
139:
140: IPresentablePart part = getPartForTab(item);
141:
142: part
143: .removePropertyListener(childPropertyChangeListener);
144: }
145: }
146: };
147:
148: /**
149: * Drag listener for regions outside the toolbar
150: */
151: Listener dragListener = new Listener() {
152: public void handleEvent(Event event) {
153: Point loc = new Point(event.x, event.y);
154: Control ctrl = (Control) event.widget;
155:
156: getSite().dragStart(ctrl.toDisplay(loc), false);
157: }
158: };
159:
160: private Listener menuListener = new Listener() {
161: public void handleEvent(Event event) {
162: Point globalPos = new Point(event.x, event.y);
163: showSystemMenu(globalPos);
164: return;
165: }
166: };
167:
168: private boolean showText;
169:
170: private boolean showImage;
171:
172: private MenuManager systemMenuManager = new MenuManager();
173:
174: private Listener hideTitleListener = new Listener() {
175:
176: public void handleEvent(Event event) {
177: if (!titleAreaHiden) {
178: titleAreaHiden = true;
179: layout();
180: }
181: }
182: };
183: private Listener showTitleListener = new Listener() {
184:
185: public void handleEvent(Event event) {
186: if (titleAreaHiden) {
187: titleAreaHiden = false;
188: layout();
189: }
190: }
191: };
192:
193: public SideWinderItemViewPresentation(Composite parent,
194: IStackPresentationSite stackSite, boolean showText,
195: boolean showImage, int style) {
196: super (stackSite);
197: this .showText = showText;
198: this .showImage = showImage;
199: this .style = style;
200:
201: // Create a top-level control for the presentation.
202: presentationControl = new Composite(parent, SWT.NONE);
203: titleArea = new Composite(presentationControl, SWT.NONE);
204:
205: //statusLineArea = new Composite(titleArea, SWT.NONE);
206: //HeapStatusContributionItem item = new HeapStatusContributionItem(PlatformUI.getPreferenceStore());
207: //item.fill(statusLineArea);
208:
209: contentArea = new ViewForm(presentationControl, SWT.NONE);
210: clientArea = new Composite(contentArea, SWT.NONE);
211: clientArea.setVisible(false);
212:
213: contentArea.setContent(clientArea);
214: toolbarProxy = new ProxyControl(contentArea);
215:
216: PresentationUtil.addDragListener(titleArea, dragListener);
217: titleArea.addListener(SWT.MenuDetect, menuListener);
218: //titleArea.addListener(SWT.MouseEnter, showTitleListener);
219: //titleArea.addListener(SWT.MouseExit, hideTitleListener);
220:
221: RowLayout rowLayout = new RowLayout();
222: rowLayout.marginLeft = 0;
223: rowLayout.marginRight = 0;
224: rowLayout.marginTop = 0;
225: rowLayout.marginBottom = 0;
226: rowLayout.type = style;
227: //rowLayout.justify = true;
228: if ((style & SWT.VERTICAL) != 0) {
229: rowLayout.fill = true;
230: }
231: rowLayout.spacing = 0;
232: titleArea.setLayout(rowLayout);
233:
234: // Add a dispose listener. This will call the presentationDisposed()
235: // method when the widget is destroyed.
236: presentationControl.addDisposeListener(new DisposeListener() {
237: public void widgetDisposed(DisposeEvent e) {
238: presentationDisposed();
239: }
240: });
241:
242: presentationControl.addPaintListener(new PaintListener() {
243: public void paintControl(PaintEvent e) {
244: int borderWidth = getBorderWidth();
245: Rectangle clientArea = presentationControl
246: .getClientArea();
247: e.gc.setLineWidth(borderWidth);
248: if (activeFocus)
249: e.gc.setForeground(e.display
250: .getSystemColor(SWT.COLOR_BLUE));
251: else
252: e.gc.setForeground(e.display
253: .getSystemColor(SWT.COLOR_DARK_GRAY));
254: e.gc.drawRectangle(clientArea.x, clientArea.y,
255: clientArea.width, clientArea.height);
256: Rectangle contentAreaBounds = contentArea.getBounds();
257: int ypos = contentAreaBounds.y - 1;
258: //e.gc.drawLine(clientArea.x, ypos, clientArea.x + clientArea.width, ypos);
259: }
260: });
261: createSystemMenu();
262: update();
263: }
264:
265: public IPresentablePart getCurrent() {
266: return current;
267: }
268:
269: protected void presentationDisposed() {
270: // Remove any listeners that were attached to any
271: // global Eclipse resources. This is necessary in order to prevent
272: // memory leaks.
273: }
274:
275: protected int getBorderWidth() {
276: return 2;
277: }
278:
279: public void showSystemMenu(Point displayPos) {
280: Menu aMenu = systemMenuManager.createContextMenu(titleArea);
281: systemMenuManager.update(true);
282: aMenu.setLocation(displayPos.x, displayPos.y);
283: aMenu.setVisible(true);
284: }
285:
286: private final void createSystemMenu() {
287: getSite().addSystemActions(systemMenuManager);
288: // This example presentation includes the part list at the end of the system menu
289: systemMenuManager.add(new Separator());
290: systemMenuManager.add(new ClosePartContributionItem(this ));
291: systemMenuManager.add(new Separator());
292:
293: Action topAction = new Action("Top", IAction.AS_RADIO_BUTTON) {
294: public void run() {
295: SideWinderItemViewPresentation.this .style = SWT.TOP;
296: setChecked((SideWinderItemViewPresentation.this .style & SWT.TOP) != 0);
297: update();
298: }
299: };
300: topAction.setChecked((style & SWT.TOP) != 0);
301: systemMenuManager.add(topAction);
302:
303: Action bottomAction = new Action("Bottom",
304: IAction.AS_RADIO_BUTTON) {
305: public void run() {
306: SideWinderItemViewPresentation.this .style = SWT.BOTTOM;
307: setChecked((SideWinderItemViewPresentation.this .style & SWT.BOTTOM) != 0);
308: update();
309: }
310: };
311: bottomAction.setChecked((style & SWT.BOTTOM) != 0);
312: systemMenuManager.add(bottomAction);
313:
314: Action rightAction = new Action("Right",
315: IAction.AS_RADIO_BUTTON) {
316: public void run() {
317: SideWinderItemViewPresentation.this .style = SWT.RIGHT;
318: setChecked((SideWinderItemViewPresentation.this .style & SWT.RIGHT) != 0);
319: update();
320: }
321: };
322: rightAction.setChecked((style & SWT.RIGHT) != 0);
323: systemMenuManager.add(rightAction);
324:
325: Action leftAction = new Action("Left", IAction.AS_RADIO_BUTTON) {
326: public void run() {
327: SideWinderItemViewPresentation.this .style = SWT.LEFT;
328: setChecked((SideWinderItemViewPresentation.this .style & SWT.LEFT) != 0);
329: update();
330: }
331: };
332: leftAction.setChecked((style & SWT.VERTICAL) != 0);
333: systemMenuManager.add(leftAction);
334:
335: systemMenuManager.add(new Separator());
336: Action textAction = new Action("Text", IAction.AS_CHECK_BOX) {
337: public void run() {
338: SideWinderItemViewPresentation.this .showText = isChecked();
339: setChecked(SideWinderItemViewPresentation.this .showText);
340: update();
341: }
342: };
343: textAction.setChecked(showText);
344: systemMenuManager.add(textAction);
345: Action imageAction = new Action("Image", IAction.AS_CHECK_BOX) {
346: public void run() {
347: SideWinderItemViewPresentation.this .showImage = isChecked();
348: setChecked(isChecked());
349: update();
350: }
351: };
352: imageAction.setChecked(showImage);
353: systemMenuManager.add(imageAction);
354: }
355:
356: protected void update() {
357: Control[] items = titleArea.getChildren();
358: for (int idx = 0; idx < items.length; idx++) {
359: if (items[idx] instanceof PartItem) {
360: PartItem item = (PartItem) items[idx];
361: item.setShowImage(showImage);
362: item.setShowText(showText);
363: item.setFocus(activeFocus);
364: }
365: }
366: int type = SWT.VERTICAL;
367: if ((style & SWT.TOP) != 0 || (style & SWT.BOTTOM) != 0) {
368: type = SWT.HORIZONTAL;
369: }
370: RowLayout rowLayout = ((RowLayout) titleArea.getLayout());
371: rowLayout.type = type;
372: rowLayout.fill = type == SWT.VERTICAL;
373:
374: layout();
375: presentationControl.redraw();
376: //titleArea.redraw();
377: //titleArea.layout();
378: //contentArea.layout();
379: }
380:
381: public void close(IPresentablePart[] parts) {
382: getSite().close(parts);
383: }
384:
385: public void layout() {
386: // Determine the inner bounds of the presentation
387: Rectangle presentationClientArea = presentationControl
388: .getClientArea();
389: presentationClientArea.x += getBorderWidth();
390: presentationClientArea.width -= getBorderWidth() * 2;
391: presentationClientArea.y += getBorderWidth();
392: presentationClientArea.height -= getBorderWidth() * 2;
393:
394: if ((style & SWT.TOP) != 0 || (style & SWT.BOTTOM) != 0) {
395: Point p = titleArea.computeSize(
396: presentationClientArea.width, SWT.DEFAULT);
397: int yy = 0;
398: int x = 0;
399: int y = 0;
400: if ((style & SWT.TOP) != 0) {
401: x = presentationClientArea.x;
402: y = presentationClientArea.y;
403: yy = p.y + 1;
404: } else {
405: x = presentationClientArea.x;
406: y = presentationClientArea.height - p.y;
407: yy = presentationClientArea.y;
408: }
409: if (titleAreaHiden)
410: p.y = 3;
411: titleArea
412: .setBounds(x, y, presentationClientArea.width, p.y);
413: contentArea.setBounds(presentationClientArea.x, yy,
414: presentationClientArea.width,
415: presentationClientArea.height - p.y);
416: } else {
417: Point p = titleArea.computeSize(SWT.DEFAULT,
418: presentationClientArea.height);
419: int xx = 0;
420: int x = 0;
421: int y = 0;
422: if ((style & SWT.RIGHT) != 0) {
423: x = presentationClientArea.width - p.x;
424: y = presentationClientArea.y;
425: xx = presentationClientArea.x;
426: } else {
427: x = presentationClientArea.x;
428: y = presentationClientArea.y;
429: xx = p.x + 1;
430: }
431: if (titleAreaHiden)
432: p.x = 3;
433: titleArea.setBounds(x, y, p.x,
434: presentationClientArea.height);
435: contentArea.setBounds(xx, presentationClientArea.y,
436: presentationClientArea.width - p.x,
437: presentationClientArea.height);
438: }
439:
440: //Rectangle r = titleArea.getBounds();
441: //Point p = titleArea.computeSize(SWT.DEFAULT, r.height);
442: //statusLineArea.setBounds(r);
443:
444: titleArea.setBackground(titleArea.getDisplay().getSystemColor(
445: SWT.COLOR_GRAY));
446:
447: // Position the view's widgets
448: if (current != null) {
449: Control toolbar = current.getToolBar();
450: if (toolbar != null) {
451: toolbarProxy.setTargetControl(current.getToolBar());
452: contentArea.setTopCenter(toolbarProxy.getControl());
453: } else {
454: contentArea.setTopCenter(null);
455: }
456: contentArea.layout();
457:
458: Rectangle clientRectangle = clientArea.getBounds();
459: Point clientAreaStart = presentationControl.getParent()
460: .toControl(
461: contentArea.toDisplay(clientRectangle.x,
462: clientRectangle.y));
463: // current isn't parented by this widget hierarchy, the coordinates must be
464: // relative to the workbench window. The workbench window parents every
465: // part.
466: current.setBounds(new Rectangle(clientAreaStart.x,
467: clientAreaStart.y, clientRectangle.width,
468: clientRectangle.height));
469: }
470: }
471:
472: public void setBounds(Rectangle bounds) {
473: presentationControl.setBounds(bounds);
474: layout();
475: }
476:
477: public void dispose() {
478: }
479:
480: public void setActive(int newState) {
481: activeFocus = (newState == AS_ACTIVE_FOCUS);
482: Control[] items = titleArea.getChildren();
483: for (int idx = 0; idx < items.length; idx++) {
484: if (items[idx] instanceof PartItem) {
485: PartItem item = (PartItem) items[idx];
486: item.setFocus(activeFocus);
487: }
488: }
489: presentationControl.redraw();
490: }
491:
492: public void setVisible(boolean isVisible) {
493: presentationControl.setVisible(isVisible);
494:
495: // Make the currently visible part visible
496: if (current != null) {
497: current.setVisible(isVisible);
498: }
499:
500: if (isVisible) {
501: // Restore the bounds of the currently visible part.
502: // IPartPresentations can be used by multiple StackPresentations,
503: // although only one such presentation is ever visible at a time.
504: // It is possible that some other presentation has changed the
505: // bounds of the part since it was last visible, so we need to
506: // update the part's bounds when the presentation becomes visible.
507: layout();
508: }
509: }
510:
511: public void setState(int state) {
512: }
513:
514: public Control getControl() {
515: return presentationControl;
516: }
517:
518: public void addPart(IPresentablePart newPart, Object cookie) {
519: // Ignore the cookie for now, since we don't support drag-and-drop yet.
520: PartItem item = new PartItem(titleArea, newPart);
521:
522: // Attach the newPart pointer to the ToolItem. This is used for getPartForTab
523: // to determine which part is associated with the tool item
524: item.setData(PART_DATA, newPart);
525:
526: // Attach a property change listener to the part. This will update the ToolItem
527: // to reflect changes in the part.
528: newPart.addPropertyListener(childPropertyChangeListener);
529:
530: // Attach a dispose listener to the item. This removes the above property
531: // change listener from the part when the item is destroyed. This prevents
532: // memory leaks.
533: item.addDisposeListener(tabDisposeListener);
534:
535: // Listen to selection events in the new tool item
536: item.addMouseListener(mouseListener);
537:
538: PresentationUtil.addDragListener(item, new Listener() {
539: public void handleEvent(Event event) {
540: Point loc = new Point(event.x, event.y);
541: PartItem item = (PartItem) event.widget;
542: if (item != null) {
543: // Move the current part
544: IPresentablePart draggedItem = getPartForTab(item);
545: draggedItem.setFocus();
546: getSite().dragStart(draggedItem,
547: item.toDisplay(loc), false);
548: }
549: }
550: });
551:
552: // Initialize the tab for this part
553: updatePartItem(item, newPart);
554:
555: newPart.setBounds(clientArea.getBounds());
556: titleArea.layout();
557: titleArea.redraw();
558: update();
559: }
560:
561: protected void updatePartItem(PartItem item, IPresentablePart part) {
562: String tabName = part.getTitle();
563: if (item == null)
564: return;
565: if (!tabName.equals(item.getText())) {
566: item.setText(tabName);
567: }
568:
569: if (!(part.getTitleToolTip().equals(item.getToolTipText()))) {
570: item.setToolTipText(part.getTitleToolTip());
571: }
572:
573: item.setImage(part.getTitleImage());
574: item.setShowImage(showImage);
575: item.setShowText(showText);
576: titleArea.layout(true);
577: titleArea.redraw();
578: item.redraw();
579: }
580:
581: protected final PartItem getPartItem(IPresentablePart part) {
582: if (!titleArea.isDisposed()) {
583: Control[] items = titleArea.getChildren();
584: for (int idx = 0; idx < items.length; idx++) {
585: Control item = items[idx];
586: if (!item.isDisposed() && getPartForTab(item) == part) {
587: return (PartItem) item;
588: }
589: }
590: }
591: return null;
592: }
593:
594: protected final IPresentablePart getPartForTab(Control item) {
595: return (IPresentablePart) item.getData(PART_DATA);
596: }
597:
598: public void removePart(IPresentablePart oldPart) {
599: PartItem item = getPartItem(oldPart);
600: if (item != null) {
601: item.dispose();
602: titleArea.layout();
603: titleArea.redraw();
604: }
605: }
606:
607: public void selectPart(IPresentablePart toSelect) {
608: if (toSelect == current) {
609: return;
610: }
611:
612: if (current != null) {
613: current.setVisible(false);
614: }
615:
616: // Select the new part
617: current = toSelect;
618:
619: // Ordering is important here. We need to make the part
620: // visible before updating its bounds, or the call to setBounds
621: // may be ignored.
622:
623: if (current != null) {
624: // Make the newly selected part visible
625: current.setVisible(true);
626: Control[] items = titleArea.getChildren();
627: for (int idx = 0; idx < items.length; idx++) {
628: if (items[idx] instanceof PartItem) {
629: PartItem item = (PartItem) items[idx];
630: item.setSelected(getPartForTab(item) == current);
631: }
632: }
633: }
634: // Update the bounds of the newly selected part
635: layout();
636: }
637:
638: public StackDropResult dragOver(Control currentControl,
639: Point location) {
640: return null;
641: }
642:
643: public void showSystemMenu() {
644: }
645:
646: public void showPaneMenu() {
647:
648: }
649:
650: public void showPaneMenu(Point location) {
651: if (current == null) {
652: return;
653: }
654:
655: IPartMenu menu = current.getMenu();
656:
657: if (menu == null) {
658: return;
659: }
660:
661: menu.showMenu(location);
662: }
663:
664: public Control[] getTabList(IPresentablePart part) {
665: if (current != null) {
666: return new Control[] { current.getControl() };
667: } else {
668: return new Control[0];
669: }
670: }
671: }
|