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.r21.widgets;
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.Color;
021: import org.eclipse.swt.graphics.Point;
022: import org.eclipse.swt.graphics.Rectangle;
023: import org.eclipse.swt.widgets.Composite;
024: import org.eclipse.swt.widgets.Control;
025: import org.eclipse.ui.internal.layout.SizeCache;
026: import org.eclipse.ui.internal.presentations.util.ProxyControl;
027: import org.eclipse.ui.presentations.IStackPresentationSite;
028:
029: /**
030: * This class implements the tab folders that contains can contain two toolbars and
031: * status text. Wherever possible, the toolbars are aligned with the tabs.
032: * If there is not enough room beside the tabs, the toolbars are aligned with the status text. This
033: * is the same tab folder that is used to arrange views and editors in Eclipse.
034: * <p>
035: * This is closely related to DefaultPartPresentation, but they have different responsibilities. This
036: * is essentially a CTabFolder that can manage a toolbar. It should not depend on
037: * data structures from the workbench, and its public interface should only use SWT objects or
038: * listeners. DefaultPartPresentation uses a PaneFolder to arrange views or editors. Knowledge
039: * of higher-level data structures should go there.
040: * </p>
041: * <p>
042: * Although it is not actually a control, the public interface is much like
043: * an SWT control. Implementation-wise, this is actually a combination of a CTabFolder and
044: * a ViewForm. It encapsulates the details of moving the toolbar between the CTabFolder and
045: * the ViewForm, and provides a simpler interface to the ViewForm/CTabFolder.
046: * </p>
047: *
048: * @since 3.0
049: */
050: public final class R21PaneFolder {
051: // Tab folder and associated proxy controls
052: private CTabFolder tabFolder;
053:
054: // private Control titleAreaProxy;
055:
056: // View form and associated proxy controls
057: private ViewForm viewForm;
058:
059: private ProxyControl contentProxy;
060:
061: private ProxyControl viewFormTopLeftProxy;
062:
063: private ProxyControl viewFormTopRightProxy;
064:
065: private ProxyControl viewFormTopCenterProxy;
066:
067: // Cached sizes of the top-right and top-center controls
068: private SizeCache topRightCache = new SizeCache();
069:
070: private SizeCache topCenterCache = new SizeCache();
071:
072: private SizeCache topLeftCache = new SizeCache();
073:
074: private int tabPos;
075:
076: private boolean putTrimOnTop = false;
077:
078: /**
079: * List of PaneFolderButtonListener
080: */
081: private List buttonListeners = new ArrayList(1);
082:
083: private int state = IStackPresentationSite.STATE_RESTORED;
084:
085: /**
086: * State of the folder at the last mousedown event. This is used to prevent
087: * a mouseup over the minimize or maximize buttons from undoing a state change
088: * that was caused by the mousedown.
089: */
090: private int mousedownState = -1;
091:
092: // // CTabFolder listener
093: // private CTabFolder2Adapter expandListener = new CTabFolder2Adapter() {
094: // public void minimize(CTabFolderEvent event) {
095: // event.doit = false;
096: // notifyButtonListeners(IStackPresentationSite.STATE_MINIMIZED);
097: // }
098: //
099: // public void restore(CTabFolderEvent event) {
100: // event.doit = false;
101: // notifyButtonListeners(IStackPresentationSite.STATE_RESTORED);
102: // }
103: //
104: // public void maximize(CTabFolderEvent event) {
105: // event.doit = false;
106: // notifyButtonListeners(IStackPresentationSite.STATE_MAXIMIZED);
107: // }
108: //
109: // /* (non-Javadoc)
110: // * @see org.eclipse.swt.custom.CTabFolder2Adapter#close(org.eclipse.swt.custom.CTabFolderEvent)
111: // */
112: // public void close(CTabFolderEvent event) {
113: // event.doit = false;
114: // notifyCloseListeners((CTabItem)event.item);
115: // }
116: //
117: // public void showList(CTabFolderEvent event) {
118: // notifyShowListeners(event);
119: // }
120: //
121: // };
122: //
123: private MouseListener mouseListener = new MouseAdapter() {
124: public void mouseDown(MouseEvent e) {
125: mousedownState = getState();
126: }
127:
128: public void mouseDoubleClick(MouseEvent e) {
129: }
130: };
131:
132: /**
133: * Creates a pane folder. This will create exactly one child control in the
134: * given parent.
135: *
136: * @param parent
137: * @param flags
138: */
139: public R21PaneFolder(Composite parent, int flags) {
140: // Initialize tab folder
141: {
142: tabFolder = new CTabFolder(parent, flags);
143:
144: // // Create a proxy control to measure the title area of the tab folder
145: // titleAreaProxy = new Composite(tabFolder, SWT.NONE);
146: // titleAreaProxy.setVisible(false);
147: // tabFolder.setTopRight(titleAreaProxy, SWT.FILL);
148:
149: // tabFolder.addCTabFolder2Listener(expandListener);
150: //
151: tabFolder.addMouseListener(mouseListener);
152: }
153:
154: // Initialize view form
155: {
156: viewForm = new ViewForm(tabFolder, SWT.NONE);
157:
158: // Only attach these to the viewForm when there's actuall a control to display
159: viewFormTopLeftProxy = new ProxyControl(viewForm);
160: viewFormTopCenterProxy = new ProxyControl(viewForm);
161: viewFormTopRightProxy = new ProxyControl(viewForm);
162:
163: contentProxy = new ProxyControl(viewForm);
164: viewForm.setContent(contentProxy.getControl());
165: }
166: }
167:
168: /**
169: * Return the main control for this pane folder
170: *
171: * @return Composite the control
172: */
173: public Composite getControl() {
174: return tabFolder;
175: }
176:
177: /**
178: * Sets the top-center control (usually a toolbar), or null if none.
179: * Note that the control can have any parent.
180: *
181: * @param topCenter the top-center control or null if none
182: */
183: public void setTopCenter(Control topCenter) {
184: topCenterCache.setControl(topCenter);
185: if (topCenter != null) {
186: if (!putTrimOnTop) {
187: viewFormTopCenterProxy.setTarget(topCenterCache);
188: viewForm.setTopCenter(viewFormTopCenterProxy
189: .getControl());
190: }
191: } else {
192: if (!putTrimOnTop) {
193: viewForm.setTopCenter(null);
194: }
195: }
196: }
197:
198: /**
199: * Sets the top-right control (usually a dropdown), or null if none
200: *
201: * @param topRight
202: */
203: public void setTopRight(Control topRight) {
204: topRightCache.setControl(topRight);
205: if (topRight != null) {
206: if (!putTrimOnTop) {
207: viewFormTopRightProxy.setTarget(topRightCache);
208: viewForm
209: .setTopRight(viewFormTopRightProxy.getControl());
210: }
211: } else {
212: if (!putTrimOnTop) {
213: viewForm.setTopRight(null);
214: }
215: }
216: }
217:
218: /**
219: * Sets the top-left control (usually a title label), or null if none
220: *
221: * @param topLeft
222: */
223: public void setTopLeft(Control topLeft) {
224: if (topLeftCache.getControl() != topLeft) {
225: topLeftCache.setControl(topLeft);
226: // The top-left control always goes directly in the ViewForm
227: if (topLeft != null) {
228: viewFormTopLeftProxy.setTarget(topLeftCache);
229: viewForm.setTopLeft(viewFormTopLeftProxy.getControl());
230: } else {
231: viewFormTopLeftProxy.setTargetControl(null);
232: viewForm.setTopLeft(null);
233: }
234: }
235: }
236:
237: /**
238: * Flush all of this folder's size caches to ensure they will be re-computed
239: * on the next layout.
240: */
241: public void flush() {
242: topLeftCache.flush();
243: topRightCache.flush();
244: topCenterCache.flush();
245: }
246:
247: /**
248: * Layout the receiver, flusing the cache if needed.
249: *
250: * @param flushCache
251: */
252: public void layout(boolean flushCache) {
253: // Flush the cached sizes if necessary
254: if (flushCache) {
255: flush();
256: }
257:
258: Rectangle tabFolderClientArea = tabFolder.getClientArea();
259:
260: // Hide tabs if there is only one
261: if (tabFolder.getItemCount() < 2) {
262: //Rectangle tabFolderBounds = tabFolder.getBounds();
263:
264: int delta = getTabHeight() + 1;
265: tabFolderClientArea.height += delta;
266:
267: if (getTabPosition() == SWT.TOP) {
268: tabFolderClientArea.y -= delta;
269: }
270: }
271:
272: viewForm.setBounds(tabFolderClientArea);
273: viewFormTopRightProxy.layout();
274: viewFormTopLeftProxy.layout();
275: viewFormTopCenterProxy.layout();
276: }
277:
278: /**
279: * Returns the client area for this PaneFolder, relative to the pane folder's control.
280: *
281: * @return Rectangle the client area
282: */
283: public Rectangle getClientArea() {
284: Rectangle bounds = contentProxy.getControl().getBounds();
285:
286: Rectangle formArea = viewForm.getBounds();
287:
288: bounds.x += formArea.x;
289: bounds.y += formArea.y;
290:
291: return bounds;
292: }
293:
294: /**
295: * Returns the current state of the folder (as shown on the button icons)
296: *
297: * @return one of the IStackPresentationSite.STATE_* constants
298: */
299: public int getState() {
300: return state;
301: }
302:
303: /**
304: * @param buttonId one of the IStackPresentationSite.STATE_* constants
305: */
306: protected void notifyButtonListeners(int buttonId) {
307: if (mousedownState == getState()) {
308: Iterator iter = buttonListeners.iterator();
309:
310: while (iter.hasNext()) {
311: R21PaneFolderButtonListener listener = (R21PaneFolderButtonListener) iter
312: .next();
313:
314: listener.stateButtonPressed(buttonId);
315: }
316: }
317: }
318:
319: /**
320: * Notifies all listeners that the user clicked on the chevron
321: *
322: * @param event
323: */
324: protected void notifyShowListeners(CTabFolderEvent event) {
325: Iterator iter = buttonListeners.iterator();
326:
327: while (iter.hasNext()) {
328: R21PaneFolderButtonListener listener = (R21PaneFolderButtonListener) iter
329: .next();
330:
331: listener.showList(event);
332: }
333: }
334:
335: /**
336: * Notifies all listeners that the close button was pressed
337: *
338: * @param tabItem
339: */
340: protected void notifyCloseListeners(CTabItem tabItem) {
341: Iterator iter = buttonListeners.iterator();
342:
343: while (iter.hasNext()) {
344: R21PaneFolderButtonListener listener = (R21PaneFolderButtonListener) iter
345: .next();
346:
347: listener.closeButtonPressed(tabItem);
348: }
349: }
350:
351: /**
352: * @param listener
353: */
354: public void addButtonListener(R21PaneFolderButtonListener listener) {
355: buttonListeners.add(listener);
356: }
357:
358: /**
359: * @param listener
360: */
361: public void removeButtonListener(
362: R21PaneFolderButtonListener listener) {
363: buttonListeners.remove(listener);
364: }
365:
366: /**
367: * @param newTabPosition
368: */
369: public void setTabPosition(int newTabPosition) {
370: tabPos = newTabPosition;
371: tabFolder.setTabPosition(tabPos);
372: }
373:
374: /**
375: * @return int the postion of the tab
376: */
377: public int getTabPosition() {
378: return tabPos;
379: }
380:
381: /**
382: * @return boolean <code>true</code> if the receiver has been disposed
383: */
384: public boolean isDisposed() {
385: return tabFolder == null || tabFolder.isDisposed();
386: }
387:
388: /**
389: * @param style
390: * @param index
391: * @return CTabItem the created item
392: */
393: public CTabItem createItem(int style, int index) {
394: return new CTabItem(tabFolder, style, index);
395: }
396:
397: // The remainder of the methods in this class redirect directly to CTabFolder methods
398:
399: /**
400: * @param selection
401: */
402: public void setSelection(int selection) {
403: tabFolder.setSelection(selection);
404: }
405:
406: /**
407: * @param i
408: * @param j
409: * @param k
410: * @param l
411: * @return Rectangle the trim rectangle
412: */
413: public Rectangle computeTrim(int i, int j, int k, int l) {
414: return tabFolder.computeTrim(i, j, k, l);
415: }
416:
417: /**
418: * @param fgColor
419: */
420: public void setSelectionForeground(Color fgColor) {
421: tabFolder.setSelectionForeground(fgColor);
422: }
423:
424: /**
425: * @param idx
426: * @return CTabItem the indexed item
427: */
428: public CTabItem getItem(int idx) {
429: return tabFolder.getItem(idx);
430: }
431:
432: /**
433: * @return int the selected items index
434: */
435: public int getSelectionIndex() {
436: return tabFolder.getSelectionIndex();
437: }
438:
439: /**
440: * @return int the height of the tabs
441: */
442: public int getTabHeight() {
443: return tabFolder.getTabHeight();
444: }
445:
446: /**
447: * @param toFind
448: * @return int the index of the item to find
449: */
450: public int indexOf(CTabItem toFind) {
451: return tabFolder.indexOf(toFind);
452: }
453:
454: /**
455: * @param height
456: */
457: public void setTabHeight(int height) {
458: tabFolder.setTabHeight(height);
459: }
460:
461: /**
462: * @return int the item count
463: */
464: public int getItemCount() {
465: return tabFolder.getItemCount();
466: }
467:
468: /**
469: * @return CTabItem the items
470: */
471: public CTabItem[] getItems() {
472: return tabFolder.getItems();
473: }
474:
475: /**
476: * @param toGet
477: * @return CTabItem the indexed item
478: */
479: public CTabItem getItem(Point toGet) {
480: return tabFolder.getItem(toGet);
481: }
482:
483: /**
484: * @return CTabItem the selected item
485: */
486: public CTabItem getSelection() {
487: return tabFolder.getSelection();
488: }
489: }
|