001: /*******************************************************************************
002: * Copyright (c) 2004, 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: * Stefan Xenos, IBM; Chris Torrence, ITT Visual Information Solutions - bug 51580
011: *******************************************************************************/package org.eclipse.ui.internal.presentations;
012:
013: import java.util.ArrayList;
014: import java.util.List;
015:
016: import org.eclipse.core.runtime.ListenerList;
017: import org.eclipse.jface.util.IPropertyChangeListener;
018: import org.eclipse.jface.util.PropertyChangeEvent;
019: import org.eclipse.swt.graphics.Image;
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.ui.IPropertyListener;
025: import org.eclipse.ui.ISharedImages;
026: import org.eclipse.ui.PlatformUI;
027: import org.eclipse.ui.internal.PartPane;
028: import org.eclipse.ui.internal.WorkbenchPartReference;
029: import org.eclipse.ui.internal.dnd.SwtUtil;
030: import org.eclipse.ui.presentations.IPartMenu;
031: import org.eclipse.ui.presentations.IPresentablePart;
032:
033: /**
034: * This is a lightweight adapter that allows PartPanes to be used by a StackPresentation. All methods
035: * either redirect directly to PartPane or do trivial type conversions. All listeners registered by
036: * the presentation are kept here rather than registering them directly on the PartPane. This allows
037: * us to remove all listeners registered by a presentation that has been disposed, offering some
038: * protection against memory leaks.
039: */
040: public class PresentablePart implements IPresentablePart {
041:
042: private PartPane part;
043:
044: /**
045: * Local listener list -- we use this rather than registering listeners directly on the part
046: * in order to protect against memory leaks in badly behaved presentations.
047: */
048: private List listeners = new ArrayList();
049:
050: // Lazily initialized. Use getPropertyListenerProxy() to access.
051: private IPropertyListener lazyPropertyListenerProxy;
052:
053: private ListenerList partPropertyChangeListeners = new ListenerList();
054:
055: private IPropertyChangeListener lazyPartPropertyChangeListener;
056:
057: // Lazily initialized. Use getMenu() to access
058: private IPartMenu viewMenu;
059:
060: // True iff the "set" methods on this object are talking to the real part (disabled
061: // if the part is currently being managed by another presentation stack)
062: private boolean enableInputs = true;
063:
064: // True iff the "get" methods are returning up-to-date info from the real part (disabled
065: // for efficency if the presentation is invisible)
066: private boolean enableOutputs = true;
067: private Rectangle savedBounds = new Rectangle(0, 0, 0, 0);
068: private boolean isVisible = false;
069:
070: // Saved state (only used when the part is inactive)
071: private String name = ""; //$NON-NLS-1$
072: private String titleStatus = ""; //$NON-NLS-1$
073: private boolean isDirty = false;
074: private boolean isBusy = false;
075: private boolean hasViewMenu = false;
076:
077: /**
078: * Constructor
079: *
080: * @param part
081: */
082: public PresentablePart(PartPane part, Composite parent) {
083: this .part = part;
084: getPane().addPropertyListener(getPropertyListenerProxy());
085: getPane().addPartPropertyListener(
086: getPartPropertyListenerProxy());
087: }
088:
089: public PartPane getPane() {
090: return part;
091: }
092:
093: private IPropertyListener getPropertyListenerProxy() {
094: if (lazyPropertyListenerProxy == null) {
095: lazyPropertyListenerProxy = new IPropertyListener() {
096: public void propertyChanged(Object source, int propId) {
097: firePropertyChange(propId);
098: }
099: };
100: }
101:
102: return lazyPropertyListenerProxy;
103: }
104:
105: private IPropertyChangeListener getPartPropertyListenerProxy() {
106: if (lazyPartPropertyChangeListener == null) {
107: lazyPartPropertyChangeListener = new IPropertyChangeListener() {
108: public void propertyChange(PropertyChangeEvent event) {
109: PropertyChangeEvent e = new PropertyChangeEvent(
110: this , event.getProperty(), event
111: .getOldValue(), event.getNewValue());
112: firePartPropertyChange(e);
113: }
114: };
115: }
116: return lazyPartPropertyChangeListener;
117: }
118:
119: /**
120: * Detach this PresentablePart from the real part. No further methods should
121: * be invoked on this object.
122: */
123: public void dispose() {
124: // Ensure that the property listener is detached (necessary to prevent leaks)
125: getPane().removePropertyListener(getPropertyListenerProxy());
126: getPane().removePartPropertyListener(
127: getPartPropertyListenerProxy());
128:
129: // Null out the various fields to ease garbage collection (optional)
130: part = null;
131: listeners.clear();
132: listeners = null;
133: partPropertyChangeListeners.clear();
134: partPropertyChangeListeners = null;
135: }
136:
137: public void firePropertyChange(int propertyId) {
138: for (int i = 0; i < listeners.size(); i++) {
139: ((IPropertyListener) listeners.get(i)).propertyChanged(
140: this , propertyId);
141: }
142: }
143:
144: public void addPropertyListener(final IPropertyListener listener) {
145: listeners.add(listener);
146: }
147:
148: public void removePropertyListener(final IPropertyListener listener) {
149: listeners.remove(listener);
150: }
151:
152: protected void firePartPropertyChange(PropertyChangeEvent event) {
153: Object[] l = partPropertyChangeListeners.getListeners();
154: for (int i = 0; i < l.length; i++) {
155: ((IPropertyChangeListener) l[i]).propertyChange(event);
156: }
157: }
158:
159: public void addPartPropertyListener(IPropertyChangeListener listener) {
160: partPropertyChangeListeners.add(listener);
161: }
162:
163: public void removePartPropertyListener(
164: IPropertyChangeListener listener) {
165: partPropertyChangeListeners.remove(listener);
166: }
167:
168: /* (non-Javadoc)
169: * @see org.eclipse.ui.presentations.IPresentablePart#setBounds(org.eclipse.swt.graphics.Rectangle)
170: */
171: public void setBounds(Rectangle bounds) {
172: savedBounds = bounds;
173: if (enableInputs && !SwtUtil.isDisposed(part.getControl())) {
174: part.setBounds(bounds);
175: }
176: }
177:
178: /* (non-Javadoc)
179: * @see org.eclipse.ui.presentations.IPresentablePart#setVisible(boolean)
180: */
181: public void setVisible(boolean isVisible) {
182: this .isVisible = isVisible;
183: if (enableInputs) {
184: part.setVisible(isVisible);
185: }
186: }
187:
188: /* (non-Javadoc)
189: * @see org.eclipse.ui.presentations.IPresentablePart#setFocus()
190: */
191: public void setFocus() {
192: if (!SwtUtil.isDisposed(part.getControl())) {
193: if (part.getPage().getActivePart() == part
194: .getPartReference().getPart(false)) {
195: part.setFocus();
196: } else {
197: part.requestActivation();
198: }
199: }
200: }
201:
202: private WorkbenchPartReference getPartReference() {
203: return (WorkbenchPartReference) part.getPartReference();
204: }
205:
206: /* (non-Javadoc)
207: * @see org.eclipse.ui.presentations.IPresentablePart#getName()
208: */
209: public String getName() {
210: if (enableOutputs) {
211: return getPartReference().getPartName();
212: }
213: return name;
214: }
215:
216: /* (non-Javadoc)
217: * @see org.eclipse.ui.presentations.IPresentablePart#getTitle()
218: */
219: public String getTitle() {
220: return getPartReference().getTitle();
221: }
222:
223: /* (non-Javadoc)
224: * @see org.eclipse.ui.presentations.IPresentablePart#getTitleStatus()
225: */
226: public String getTitleStatus() {
227: if (enableOutputs) {
228: return getPartReference().getContentDescription();
229: }
230:
231: return titleStatus;
232: }
233:
234: /*
235: * (non-Javadoc)
236: *
237: * @see org.eclipse.ui.presentations.IPresentablePart#getTitleImage()
238: */
239: public Image getTitleImage() {
240: //
241: // return PlatformUI.getWorkbench().getSharedImages().getImage(
242: // ISharedImages.IMG_DEF_VIEW);
243: //
244: if (enableOutputs) {
245: return getPartReference().getTitleImage();
246: }
247:
248: return PlatformUI.getWorkbench().getSharedImages().getImage(
249: ISharedImages.IMG_DEF_VIEW);
250: }
251:
252: /*
253: * (non-Javadoc)
254: *
255: * @see org.eclipse.ui.presentations.IPresentablePart#getTitleToolTip()
256: */
257: public String getTitleToolTip() {
258: return getPartReference().getTitleToolTip();
259: }
260:
261: /* (non-Javadoc)
262: * @see org.eclipse.ui.presentations.IPresentablePart#isDirty()
263: */
264: public boolean isDirty() {
265: if (enableOutputs) {
266: return getPartReference().isDirty();
267: }
268: return isDirty;
269: }
270:
271: /*
272: * (non-Javadoc)
273: *
274: * @see org.eclipse.ui.presentations.IPresentablePart#isBusy()
275: */
276: public boolean isBusy() {
277: if (enableOutputs) {
278: return part.isBusy();
279: }
280: return isBusy;
281: }
282:
283: /*
284: * (non-Javadoc)
285: *
286: * @see org.eclipse.ui.presentations.IPresentablePart#getToolBar()
287: */
288: public Control getToolBar() {
289: if (enableOutputs) {
290: return getPane().getToolBar();
291: }
292: return null;
293: }
294:
295: /*
296: * (non-Javadoc)
297: *
298: * @see org.eclipse.ui.presentations.IPresentablePart#getMenu()
299: */
300: public IPartMenu getMenu() {
301: boolean hasMenu;
302:
303: if (enableOutputs) {
304: hasMenu = part.hasViewMenu();
305: } else {
306: hasMenu = this .hasViewMenu;
307: }
308:
309: if (!hasMenu) {
310: return null;
311: }
312:
313: if (viewMenu == null) {
314: viewMenu = new IPartMenu() {
315: public void showMenu(Point location) {
316: part.showViewMenu(location);
317: }
318: };
319: }
320:
321: return viewMenu;
322: }
323:
324: /* (non-Javadoc)
325: * @see org.eclipse.ui.presentations.IPresentablePart#isCloseable()
326: */
327: public boolean isCloseable() {
328: return part.isCloseable();
329: }
330:
331: /* (non-Javadoc)
332: * @see org.eclipse.ui.presentations.IPresentablePart#getControl()
333: */
334: public Control getControl() {
335: return part.getControl();
336: }
337:
338: public void enableOutputs(boolean isActive) {
339: if (isActive == this .enableOutputs) {
340: return;
341: }
342:
343: this .enableOutputs = isActive;
344:
345: if (isActive) {
346: if (isBusy != getPane().isBusy()) {
347: firePropertyChange(PROP_BUSY);
348: }
349: if (isDirty != isDirty()) {
350: firePropertyChange(PROP_DIRTY);
351: }
352: if (!name.equals(getName())) {
353: firePropertyChange(PROP_PART_NAME);
354: }
355: if (!titleStatus.equals(getTitleStatus())) {
356: firePropertyChange(PROP_CONTENT_DESCRIPTION);
357: }
358: if (hasViewMenu != getPane().hasViewMenu()) {
359: firePropertyChange(PROP_PANE_MENU);
360: }
361: // Always assume that the toolbar and title has changed (keeping track of this for real
362: // would be too expensive)
363: firePropertyChange(PROP_TOOLBAR);
364: firePropertyChange(PROP_TITLE);
365:
366: getPane().addPropertyListener(getPropertyListenerProxy());
367: } else {
368: getPane()
369: .removePropertyListener(getPropertyListenerProxy());
370:
371: WorkbenchPartReference ref = getPartReference();
372: isBusy = getPane().isBusy();
373: isDirty = ref.isDirty();
374: name = ref.getPartName();
375: titleStatus = ref.getContentDescription();
376: hasViewMenu = getPane().hasViewMenu();
377: firePropertyChange(PROP_TITLE);
378: firePropertyChange(PROP_TOOLBAR);
379: }
380: }
381:
382: public void enableInputs(boolean isActive) {
383: if (isActive == this .enableInputs) {
384: return;
385: }
386:
387: this .enableInputs = isActive;
388:
389: if (isActive) {
390: if (isActive && !SwtUtil.isDisposed(part.getControl())) {
391: part.setBounds(savedBounds);
392: }
393:
394: part.setVisible(isVisible);
395: }
396: }
397:
398: /* (non-Javadoc)
399: * @see org.eclipse.ui.presentations.IPresentablePart#getPartProperty(java.lang.String)
400: */
401: public String getPartProperty(String key) {
402: return getPartReference().getPartProperty(key);
403: }
404:
405: /* (non-Javadoc)
406: * @see org.eclipse.ui.ISizeProvider#computePreferredSize(boolean, int, int, int)
407: */
408: public int computePreferredSize(boolean width,
409: int availableParallel, int availablePerpendicular,
410: int preferredResult) {
411:
412: return getPane().computePreferredSize(width, availableParallel,
413: availablePerpendicular, preferredResult);
414: }
415:
416: /* (non-Javadoc)
417: * @see org.eclipse.ui.ISizeProvider#getSizeFlags(boolean)
418: */
419: public int getSizeFlags(boolean width) {
420: return getPane().getSizeFlags(width);
421: }
422:
423: }
|