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.util;
011:
012: import java.util.ArrayList;
013: import java.util.Iterator;
014: import java.util.List;
015:
016: import org.eclipse.swt.SWT;
017: import org.eclipse.swt.events.MouseAdapter;
018: import org.eclipse.swt.events.MouseEvent;
019: import org.eclipse.swt.events.MouseListener;
020: import org.eclipse.swt.graphics.Point;
021: import org.eclipse.swt.graphics.Rectangle;
022: import org.eclipse.swt.widgets.Composite;
023: import org.eclipse.swt.widgets.Control;
024: import org.eclipse.swt.widgets.Event;
025: import org.eclipse.swt.widgets.Listener;
026: import org.eclipse.ui.presentations.IStackPresentationSite;
027: import org.eclipse.ui.presentations.PresentationUtil;
028:
029: /**
030: * @since 3.1
031: */
032: public abstract class AbstractTabFolder {
033:
034: private List listeners = new ArrayList(1);
035:
036: private Control toolbar;
037: private int state;
038:
039: public abstract Point computeSize(int widthHint, int heightHint);
040:
041: public abstract AbstractTabItem add(int index, int flags);
042:
043: public abstract Composite getContentParent();
044:
045: public abstract void setContent(Control newContent);
046:
047: public abstract AbstractTabItem[] getItems();
048:
049: public abstract AbstractTabItem getSelection();
050:
051: public abstract void setSelection(AbstractTabItem toSelect);
052:
053: public abstract void setSelectedInfo(PartInfo info);
054:
055: public abstract void enablePaneMenu(boolean enabled);
056:
057: private int activeState = IStackPresentationSite.STATE_RESTORED;
058:
059: private Listener menuListener = new Listener() {
060: /* (non-Javadoc)
061: * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)
062: */
063: public void handleEvent(Event event) {
064: Point globalPos = new Point(event.x, event.y);
065: handleContextMenu(globalPos, event);
066: }
067: };
068:
069: private Listener dragListener = new Listener() {
070: public void handleEvent(Event e) {
071: Point globalPos = ((Control) e.widget).toDisplay(e.x, e.y);
072: handleDragStarted(globalPos, e);
073: }
074: };
075:
076: private MouseListener mouseListener = new MouseAdapter() {
077:
078: // If we single-click on an empty space on the toolbar, move focus to the
079: // active control
080: public void mouseDown(MouseEvent e) {
081: Point p = ((Control) e.widget).toDisplay(e.x, e.y);
082:
083: handleMouseDown(p, e);
084: }
085:
086: // If we double-click on the toolbar, maximize the presentation
087: public void mouseDoubleClick(MouseEvent e) {
088: Point p = ((Control) e.widget).toDisplay(e.x, e.y);
089:
090: handleDoubleClick(p, e);
091: }
092: };
093:
094: public void setActive(int activeState) {
095: this .activeState = activeState;
096: }
097:
098: public int getActive() {
099: return activeState;
100: }
101:
102: /**
103: * Returns the location where the pane menu should be opened when activated
104: * by a keyboard shortcut (display coordinates)
105: *
106: * @return the location for the pane menu (display coordinates)
107: * @since 3.1
108: */
109: public Point getPaneMenuLocation() {
110: return getControl().toDisplay(new Point(0, 0));
111: }
112:
113: /**
114: * Returns the location where the part list should be opened when activated
115: * by a keyboard shortcut (display coordinates)
116: *
117: * @return the location for the part list (display coordinates)
118: * @since 3.1
119: */
120: public Point getPartListLocation() {
121: return getSystemMenuLocation();
122: }
123:
124: /**
125: * Returns the location where the pane menu should be opened when activated
126: * by a keyboard shortcut (display coordinates)
127: *
128: * @return the location for the pane menu (display coordinates)
129: * @since 3.1
130: */
131: public Point getSystemMenuLocation() {
132: return getControl().toDisplay(new Point(0, 0));
133: }
134:
135: /**
136: * Returns the parent composite that should be used for creating the toolbar.
137: * Any control passed into setToolbar must have this composite as its parent.
138: *
139: * @return the parent composite that should be used for creating the toolbar
140: *
141: * @since 3.1
142: */
143: public abstract Composite getToolbarParent();
144:
145: /**
146: * Returns the main control for this folder.
147: *
148: * @return the main control for the folder
149: * @since 3.1
150: */
151: public abstract Control getControl();
152:
153: public AbstractTabItem getItem(int idx) {
154: return getItems()[idx];
155: }
156:
157: public AbstractTabItem getItem(Point toFind) {
158: AbstractTabItem[] items = getItems();
159:
160: for (int i = 0; i < items.length; i++) {
161: AbstractTabItem item = items[i];
162:
163: if (item.getBounds().contains(toFind)) {
164: return item;
165: }
166: }
167:
168: return null;
169: }
170:
171: public AbstractTabItem findItem(Object dataToFind) {
172: AbstractTabItem[] items = getItems();
173:
174: for (int i = 0; i < items.length; i++) {
175: AbstractTabItem item = items[i];
176:
177: if (item.getData() == dataToFind) {
178: return item;
179: }
180: }
181:
182: return null;
183: }
184:
185: /**
186: * Returns the index of the given item, or -1 if the given item is
187: * not found in this tab folder. Subclasses should override this if
188: * the underlying SWT widget has an equivalent method
189: *
190: * @param item item to find
191: * @return the index of the given item or -1
192: */
193: public int indexOf(AbstractTabItem item) {
194: AbstractTabItem[] items = getItems();
195:
196: for (int idx = 0; idx < items.length; idx++) {
197: AbstractTabItem next = items[idx];
198:
199: if (next == item) {
200: return idx;
201: }
202: }
203:
204: return -1;
205: }
206:
207: public int getItemCount() {
208: return getItems().length;
209: }
210:
211: public void setToolbar(Control toolbarControl) {
212: this .toolbar = toolbarControl;
213: }
214:
215: public final Control getToolbar() {
216: return toolbar;
217: }
218:
219: /**
220: * Sets the current state for the folder
221: *
222: * @param state one of the IStackPresentationSite.STATE_* constants
223: */
224: public void setState(int state) {
225: this .state = state;
226: }
227:
228: /**
229: * Returns the title area for this control (in the control's coordinate system)
230: *
231: * @return
232: */
233: public abstract Rectangle getTabArea();
234:
235: /**
236: * Called when the tab folder's shell becomes active or inactive. Subclasses
237: * can override this to change the appearance of the tabs based on activation.
238: *
239: * @param isActive
240: */
241: public void shellActive(boolean isActive) {
242: }
243:
244: /**
245: * Adds the given listener to this AbstractTabFolder
246: *
247: * @param newListener the listener to add
248: */
249: public final void addListener(TabFolderListener newListener) {
250: listeners.add(newListener);
251: }
252:
253: /**
254: * Removes the given listener from this AbstractTabFolder
255: *
256: * @param toRemove the listener to remove
257: */
258: public final void removeListener(TabFolderListener toRemove) {
259: listeners.remove(toRemove);
260: }
261:
262: public void flushToolbarSize() {
263:
264: }
265:
266: protected final void fireEvent(TabFolderEvent e) {
267: for (Iterator iter = listeners.iterator(); iter.hasNext();) {
268: TabFolderListener next = (TabFolderListener) iter.next();
269:
270: next.handleEvent(e);
271: }
272: }
273:
274: protected final void fireEvent(int id) {
275: fireEvent(new TabFolderEvent(id));
276: }
277:
278: protected final void fireEvent(int id, AbstractTabItem w) {
279: fireEvent(new TabFolderEvent(id, w, 0, 0));
280: }
281:
282: protected final void fireEvent(int id, AbstractTabItem w, Point pos) {
283: fireEvent(new TabFolderEvent(id, w, pos));
284: }
285:
286: public void layout(boolean flushCache) {
287: }
288:
289: public void setTabPosition(int tabPosition) {
290: }
291:
292: public int getTabPosition() {
293: return SWT.TOP;
294: }
295:
296: public int getState() {
297: return state;
298: }
299:
300: protected void attachListeners(Control theControl, boolean recursive) {
301: theControl.addListener(SWT.MenuDetect, menuListener);
302: theControl.addMouseListener(mouseListener);
303: PresentationUtil.addDragListener(theControl, dragListener);
304:
305: if (recursive && theControl instanceof Composite) {
306: Composite composite = (Composite) theControl;
307: Control[] children = composite.getChildren();
308:
309: for (int i = 0; i < children.length; i++) {
310: Control control = children[i];
311:
312: attachListeners(control, recursive);
313: }
314: }
315: }
316:
317: protected void detachListeners(Control theControl, boolean recursive) {
318: theControl.removeListener(SWT.MenuDetect, menuListener);
319: theControl.removeMouseListener(mouseListener);
320: PresentationUtil.removeDragListener(theControl, dragListener);
321:
322: if (recursive && theControl instanceof Composite) {
323: Composite composite = (Composite) theControl;
324: Control[] children = composite.getChildren();
325:
326: for (int i = 0; i < children.length; i++) {
327: Control control = children[i];
328:
329: detachListeners(control, recursive);
330: }
331: }
332: }
333:
334: protected void handleContextMenu(Point displayPos, Event e) {
335: if (isOnBorder(displayPos)) {
336: return;
337: }
338:
339: AbstractTabItem tab = getItem(displayPos);
340:
341: fireEvent(TabFolderEvent.EVENT_SYSTEM_MENU, tab, displayPos);
342: }
343:
344: protected void handleMouseDown(Point displayPos, MouseEvent e) {
345: fireEvent(TabFolderEvent.EVENT_GIVE_FOCUS_TO_PART);
346: }
347:
348: protected void handleDoubleClick(Point displayPos, MouseEvent e) {
349: if (isOnBorder(displayPos)) {
350: return;
351: }
352:
353: if (getState() == IStackPresentationSite.STATE_MAXIMIZED) {
354: fireEvent(TabFolderEvent.EVENT_RESTORE);
355: } else {
356: fireEvent(TabFolderEvent.EVENT_MAXIMIZE);
357: }
358: }
359:
360: protected void handleDragStarted(Point displayPos, Event e) {
361:
362: if (isOnBorder(displayPos)) {
363: return;
364: }
365:
366: AbstractTabItem tab = getItem(displayPos);
367: fireEvent(TabFolderEvent.EVENT_DRAG_START, tab, displayPos);
368: }
369:
370: /**
371: * Returns true iff the given point is on the border of the folder.
372: * By default, double-clicking, context menus, and drag/drop are disabled
373: * on the folder's border.
374: *
375: * @param toTest a point (display coordinates)
376: * @return true iff the point is on the presentation border
377: * @since 3.1
378: */
379: public boolean isOnBorder(Point toTest) {
380: return false;
381: }
382:
383: /**
384: * Set the folder to visible. This can be extended to propogate the
385: * visibility request to other components in the subclass.
386: *
387: * @param visible
388: * <code>true</code> - the folder is visible.
389: * @since 3.2
390: */
391: public void setVisible(boolean visible) {
392: getControl().setVisible(visible);
393: }
394:
395: /**
396: * Cause the folder to hide or show its
397: * Minimize and Maximize affordances.
398: *
399: * @param show
400: * <code>true</code> - the min/max buttons are visible.
401: * @since 3.3
402: */
403: public void showMinMax(boolean show) {
404: }
405: }
|