001: /*******************************************************************************
002: * Copyright (c) 2004, 2006 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.presentations;
011:
012: import java.util.ArrayList;
013:
014: import org.eclipse.jface.action.IMenuManager;
015: import org.eclipse.jface.action.MenuManager;
016: import org.eclipse.jface.preference.IPreferenceStore;
017: import org.eclipse.jface.util.Geometry;
018: import org.eclipse.swt.SWT;
019: import org.eclipse.swt.events.DisposeEvent;
020: import org.eclipse.swt.events.DisposeListener;
021: import org.eclipse.swt.events.MouseAdapter;
022: import org.eclipse.swt.events.MouseEvent;
023: import org.eclipse.swt.events.MouseListener;
024: import org.eclipse.swt.graphics.Image;
025: import org.eclipse.swt.graphics.Point;
026: import org.eclipse.swt.graphics.Rectangle;
027: import org.eclipse.swt.widgets.Composite;
028: import org.eclipse.swt.widgets.Control;
029: import org.eclipse.swt.widgets.Event;
030: import org.eclipse.swt.widgets.Listener;
031: import org.eclipse.swt.widgets.Menu;
032: import org.eclipse.swt.widgets.TabFolder;
033: import org.eclipse.swt.widgets.TabItem;
034: import org.eclipse.ui.IPropertyListener;
035: import org.eclipse.ui.internal.IPreferenceConstants;
036: import org.eclipse.ui.internal.WorkbenchPlugin;
037: import org.eclipse.ui.presentations.IPresentablePart;
038: import org.eclipse.ui.presentations.IStackPresentationSite;
039: import org.eclipse.ui.presentations.PresentationUtil;
040: import org.eclipse.ui.presentations.StackDropResult;
041: import org.eclipse.ui.presentations.StackPresentation;
042:
043: /**
044: * A stack presentation using native widgets.
045: * <p>
046: * EXPERIMENTAL
047: * </p>
048: *
049: * @since 3.0
050: */
051: public class NativeStackPresentation extends StackPresentation {
052:
053: private TabFolder tabFolder;
054:
055: private Listener dragListener;
056:
057: private IPresentablePart current;
058:
059: private MenuManager systemMenuManager = new MenuManager();
060:
061: private static IPreferenceStore preferenceStore = WorkbenchPlugin
062: .getDefault().getPreferenceStore();
063:
064: // don't reset this dynamically, so just keep the information static.
065: // see bug:
066: // 75422 [Presentations] Switching presentation to R21 switches immediately, but only partially
067: private static int tabPos = preferenceStore
068: .getInt(IPreferenceConstants.VIEW_TAB_POSITION);
069:
070: private final static String TAB_DATA = NativeStackPresentation.class
071: .getName()
072: + ".partId"; //$NON-NLS-1$
073:
074: private MouseListener mouseListener = new MouseAdapter() {
075: public void mouseDown(MouseEvent e) {
076: // // PR#1GDEZ25 - If selection will change in mouse up ignore mouse down.
077: // // Else, set focus.
078: // TabItem newItem = tabFolder.getItem(new Point(e.x, e.y));
079: // if (newItem != null) {
080: // TabItem oldItem = tabFolder.getSelection();
081: // if (newItem != oldItem)
082: // return;
083: // }
084: if (current != null) {
085: current.setFocus();
086: }
087: }
088: };
089:
090: private Listener menuListener = new Listener() {
091: /* (non-Javadoc)
092: * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)
093: */
094: public void handleEvent(Event event) {
095: Point pos = new Point(event.x, event.y);
096: // TabItem item = tabFolder.getItem(pos);
097: TabItem item = null;
098: IPresentablePart part = null;
099: if (item != null) {
100: part = getPartForTab(item);
101: }
102: showPaneMenu(part, pos);
103: }
104: };
105:
106: private Listener selectionListener = new Listener() {
107: public void handleEvent(Event e) {
108: IPresentablePart item = getPartForTab((TabItem) e.item);
109: if (item != null) {
110: getSite().selectPart(item);
111: // item.setFocus();
112: }
113: }
114: };
115:
116: private Listener resizeListener = new Listener() {
117: public void handleEvent(Event e) {
118: setControlSize();
119: }
120: };
121:
122: private IPropertyListener childPropertyChangeListener = new IPropertyListener() {
123: public void propertyChanged(Object source, int property) {
124:
125: if (isDisposed()) {
126: return;
127: }
128:
129: if (source instanceof IPresentablePart) {
130: IPresentablePart part = (IPresentablePart) source;
131: childPropertyChanged(part, property);
132: }
133: }
134: };
135:
136: private DisposeListener tabDisposeListener = new DisposeListener() {
137: public void widgetDisposed(DisposeEvent e) {
138: if (e.widget instanceof TabItem) {
139: TabItem item = (TabItem) e.widget;
140: IPresentablePart part = getPartForTab(item);
141: part
142: .removePropertyListener(childPropertyChangeListener);
143: }
144: }
145: };
146:
147: public NativeStackPresentation(Composite parent,
148: IStackPresentationSite stackSite) {
149: super (stackSite);
150:
151: tabFolder = new TabFolder(parent, tabPos);
152:
153: // listener to switch between visible tabItems
154: tabFolder.addListener(SWT.Selection, selectionListener);
155:
156: // listener to resize visible components
157: tabFolder.addListener(SWT.Resize, resizeListener);
158:
159: // listen for mouse down on tab to set focus.
160: tabFolder.addMouseListener(mouseListener);
161:
162: tabFolder.addListener(SWT.MenuDetect, menuListener);
163:
164: dragListener = new Listener() {
165: public void handleEvent(Event event) {
166: Point localPos = new Point(event.x, event.y);
167: // TabItem tabUnderPointer = tabFolder.getItem(localPos);
168: TabItem tabUnderPointer = null;
169:
170: if (tabUnderPointer == null) {
171: return;
172: }
173:
174: IPresentablePart part = getPartForTab(tabUnderPointer);
175:
176: if (getSite().isPartMoveable(part)) {
177: getSite().dragStart(part,
178: tabFolder.toDisplay(localPos), false);
179: }
180: }
181: };
182:
183: PresentationUtil.addDragListener(tabFolder, dragListener);
184:
185: }
186:
187: /**
188: * Returns the index of the tab for the given part, or returns tabFolder.getItemCount()
189: * if there is no such tab.
190: *
191: * @param part part being searched for
192: * @return the index of the tab for the given part, or the number of tabs
193: * if there is no such tab
194: */
195: private final int indexOf(IPresentablePart part) {
196: if (part == null) {
197: return tabFolder.getItemCount();
198: }
199:
200: TabItem[] items = tabFolder.getItems();
201:
202: for (int idx = 0; idx < items.length; idx++) {
203: IPresentablePart tabPart = getPartForTab(items[idx]);
204:
205: if (part == tabPart) {
206: return idx;
207: }
208: }
209:
210: return items.length;
211: }
212:
213: /**
214: * Returns the tab for the given part, or null if there is no such tab
215: *
216: * @param part the part being searched for
217: * @return the tab for the given part, or null if there is no such tab
218: */
219: protected final TabItem getTab(IPresentablePart part) {
220: TabItem[] items = tabFolder.getItems();
221:
222: int idx = indexOf(part);
223:
224: if (idx < items.length) {
225: return items[idx];
226: }
227:
228: return null;
229: }
230:
231: /**
232: * @param part
233: * @param property
234: */
235: protected void childPropertyChanged(IPresentablePart part,
236: int property) {
237: TabItem tab = getTab(part);
238: initTab(tab, part);
239: }
240:
241: protected final IPresentablePart getPartForTab(TabItem item) {
242: IPresentablePart part = (IPresentablePart) item
243: .getData(TAB_DATA);
244: return part;
245: }
246:
247: protected TabFolder getTabFolder() {
248: return tabFolder;
249: }
250:
251: public boolean isDisposed() {
252: return tabFolder == null || tabFolder.isDisposed();
253: }
254:
255: /**
256: * Set the size of a page in the folder.
257: */
258: private void setControlSize() {
259: if (current == null || tabFolder == null) {
260: return;
261: }
262: // Rectangle bounds;
263: // @issue as above, the mere presence of a theme should not change the behaviour
264: // if ((mapTabToPart.size() > 1)
265: // || ((tabThemeDescriptor != null) && (mapTabToPart.size() >= 1)))
266: // bounds = calculatePageBounds(tabFolder);
267: // else
268: // bounds = tabFolder.getBounds();
269: current.setBounds(calculatePageBounds(tabFolder));
270: //current.moveAbove(tabFolder);
271: }
272:
273: public static Rectangle calculatePageBounds(TabFolder folder) {
274: if (folder == null) {
275: return new Rectangle(0, 0, 0, 0);
276: }
277: Rectangle bounds = folder.getBounds();
278: Rectangle offset = folder.getClientArea();
279: bounds.x += offset.x;
280: bounds.y += offset.y;
281: bounds.width = offset.width;
282: bounds.height = offset.height;
283: return bounds;
284: }
285:
286: /* (non-Javadoc)
287: * @see org.eclipse.ui.internal.skins.Presentation#dispose()
288: */
289: public void dispose() {
290: if (isDisposed()) {
291: return;
292: }
293: PresentationUtil.removeDragListener(tabFolder, dragListener);
294:
295: //systemMenuManager.dispose();
296:
297: tabFolder.dispose();
298: tabFolder = null;
299: }
300:
301: private TabItem createPartTab(IPresentablePart part, int tabIndex) {
302: TabItem tabItem = new TabItem(tabFolder, SWT.NONE, tabIndex);
303: tabItem.setData(TAB_DATA, part);
304: part.addPropertyListener(childPropertyChangeListener);
305: tabItem.addDisposeListener(tabDisposeListener);
306: initTab(tabItem, part);
307: return tabItem;
308: }
309:
310: /**
311: * Initializes a tab for the given part. Sets the text, icon, tool tip,
312: * etc. This will also be called whenever a relevant property changes
313: * in the part to reflect those changes in the tab. Subclasses may override
314: * to change the appearance of tabs for a particular part.
315: *
316: * @param tabItem tab for the part
317: * @param part the part being displayed
318: */
319: protected void initTab(TabItem tabItem, IPresentablePart part) {
320: tabItem.setText(part.getName());
321: tabItem.setToolTipText(part.getTitleToolTip());
322:
323: Image tabImage = part.getTitleImage();
324: if (tabImage != tabItem.getImage()) {
325: tabItem.setImage(tabImage);
326: }
327: }
328:
329: /* (non-Javadoc)
330: * @see org.eclipse.ui.internal.skins.StackPresentation#addPart(org.eclipse.ui.internal.skins.IPresentablePart, org.eclipse.ui.internal.skins.IPresentablePart)
331: */
332: public void addPart(IPresentablePart newPart, Object cookie) {
333: createPartTab(newPart, tabFolder.getItemCount());
334: }
335:
336: /* (non-Javadoc)
337: * @see org.eclipse.ui.internal.skins.StackPresentation#removePart(org.eclipse.ui.internal.skins.IPresentablePart)
338: */
339: public void removePart(IPresentablePart oldPart) {
340: TabItem item = getTab(oldPart);
341: if (item == null) {
342: return;
343: }
344: oldPart.setVisible(false);
345:
346: item.dispose();
347: }
348:
349: /* (non-Javadoc)
350: * @see org.eclipse.ui.internal.skins.StackPresentation#selectPart(org.eclipse.ui.internal.skins.IPresentablePart)
351: */
352: public void selectPart(IPresentablePart toSelect) {
353: if (toSelect == current) {
354: return;
355: }
356:
357: if (current != null) {
358: current.setVisible(false);
359: }
360:
361: current = toSelect;
362:
363: if (current != null) {
364: tabFolder.setSelection(indexOf(current));
365: current.setVisible(true);
366: setControlSize();
367: }
368: }
369:
370: /* (non-Javadoc)
371: * @see org.eclipse.ui.internal.skins.Presentation#setBounds(org.eclipse.swt.graphics.Rectangle)
372: */
373: public void setBounds(Rectangle bounds) {
374: tabFolder.setBounds(bounds);
375: setControlSize();
376: }
377:
378: /* (non-Javadoc)
379: * @see org.eclipse.ui.internal.skins.Presentation#computeMinimumSize()
380: */
381: public Point computeMinimumSize() {
382: return Geometry.getSize(tabFolder.computeTrim(0, 0, 0, 0));
383: }
384:
385: /* (non-Javadoc)
386: * @see org.eclipse.ui.internal.skins.Presentation#setVisible(boolean)
387: */
388: public void setVisible(boolean isVisible) {
389: if (current != null) {
390: current.setVisible(isVisible);
391: }
392: tabFolder.setVisible(isVisible);
393: }
394:
395: /* (non-Javadoc)
396: * @see org.eclipse.ui.internal.skins.Presentation#setState(int)
397: */
398: public void setState(int state) {
399: // tabFolder.setMinimized(state == IPresentationSite.STATE_MINIMIZED);
400: // tabFolder.setMaximized(state == IPresentationSite.STATE_MAXIMIZED);
401: }
402:
403: /* (non-Javadoc)
404: * @see org.eclipse.ui.internal.skins.Presentation#getSystemMenuManager()
405: */
406: public IMenuManager getSystemMenuManager() {
407: return systemMenuManager;
408: }
409:
410: /**
411: * @param part
412: * @param point
413: */
414: protected void showPaneMenu(IPresentablePart part, Point point) {
415: systemMenuManager.update(false);
416: Menu aMenu = systemMenuManager.createContextMenu(tabFolder
417: .getParent());
418: aMenu.setLocation(point.x, point.y);
419: aMenu.setVisible(true);
420: }
421:
422: /* (non-Javadoc)
423: * @see org.eclipse.ui.internal.skins.Presentation#getControl()
424: */
425: public Control getControl() {
426: return tabFolder;
427: }
428:
429: /* (non-Javadoc)
430: * @see org.eclipse.ui.internal.skins.StackPresentation#dragOver(org.eclipse.swt.widgets.Control, org.eclipse.swt.graphics.Point)
431: */
432: public StackDropResult dragOver(Control currentControl,
433: Point location) {
434:
435: // Determine which tab we're currently dragging over
436: // Point localPos = tabFolder.toControl(location);
437: // final TabItem tabUnderPointer = tabFolder.getItem(localPos);
438: final TabItem tabUnderPointer = null;
439:
440: // This drop target only deals with tabs... if we're not dragging over
441: // a tab, exit.
442: if (tabUnderPointer == null) {
443: return null;
444: }
445:
446: // return new StackDropResult(Geometry.toDisplay(tabFolder, tabUnderPointer.getBounds()),
447: // tabFolder.indexOf(tabUnderPointer));
448: return null;
449: }
450:
451: /* (non-Javadoc)
452: * @see org.eclipse.ui.presentations.StackPresentation#showSystemMenu()
453: */
454: public void showSystemMenu() {
455: // TODO Auto-generated method stub
456:
457: }
458:
459: /* (non-Javadoc)
460: * @see org.eclipse.ui.presentations.StackPresentation#showPaneMenu()
461: */
462: public void showPaneMenu() {
463: // TODO Auto-generated method stub
464:
465: }
466:
467: /* (non-Javadoc)
468: * @see org.eclipse.ui.presentations.StackPresentation#getTabList(IPresentablePart)
469: */
470: public Control[] getTabList(IPresentablePart part) {
471: ArrayList list = new ArrayList();
472: if (getControl() != null) {
473: list.add(getControl());
474: }
475: if (part.getToolBar() != null) {
476: list.add(part.getToolBar());
477: }
478: if (part.getControl() != null) {
479: list.add(part.getControl());
480: }
481: return (Control[]) list.toArray(new Control[list.size()]);
482: }
483:
484: /* (non-Javadoc)
485: * @see org.eclipse.ui.presentations.StackPresentation#getCurrentPart()
486: */
487: public IPresentablePart getCurrentPart() {
488: return current;
489: }
490:
491: /* (non-Javadoc)
492: * @see org.eclipse.ui.presentations.StackPresentation#setActive(int)
493: */
494: public void setActive(int newState) {
495:
496: }
497:
498: }
|