001: /*******************************************************************************
002: * Copyright (c) 2000, 2005 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;
011:
012: import java.util.Iterator;
013: import java.util.LinkedList;
014:
015: import org.eclipse.swt.events.DisposeEvent;
016: import org.eclipse.swt.events.DisposeListener;
017: import org.eclipse.swt.events.ShellAdapter;
018: import org.eclipse.swt.events.ShellEvent;
019: import org.eclipse.swt.events.ShellListener;
020: import org.eclipse.swt.widgets.Control;
021: import org.eclipse.swt.widgets.Shell;
022:
023: /**
024: * Manages a pool of shells. This can be used instead of creating and destroying
025: * shells. By reusing shells, they will never be disposed until the pool goes away.
026: * This is useful in situations where client code may have cached pointers to the
027: * shells to use as a parent for dialogs. It also works around bug 86226 (SWT menus
028: * cannot be reparented).
029: *
030: * @since 3.1
031: */
032: public class ShellPool {
033:
034: private int flags;
035:
036: /**
037: * Parent shell (or null if none)
038: */
039: private Shell parentShell;
040:
041: private LinkedList availableShells = new LinkedList();
042:
043: private final static String CLOSE_LISTENER = "close listener"; //$NON-NLS-1$
044:
045: private boolean isDisposed = false;
046:
047: private DisposeListener disposeListener = new DisposeListener() {
048: public void widgetDisposed(DisposeEvent e) {
049: WorkbenchPlugin.log(new RuntimeException(
050: "Widget disposed too early!")); //$NON-NLS-1$
051: }
052: };
053:
054: private ShellListener closeListener = new ShellAdapter() {
055:
056: public void shellClosed(ShellEvent e) {
057: if (isDisposed) {
058: return;
059: }
060:
061: if (e.doit) {
062: Shell s = (Shell) e.widget;
063: ShellListener l = (ShellListener) s
064: .getData(CLOSE_LISTENER);
065:
066: if (l != null) {
067: s.setData(CLOSE_LISTENER, null);
068: l.shellClosed(e);
069:
070: Control[] children = s.getChildren();
071: for (int i = 0; i < children.length; i++) {
072: Control control = children[i];
073:
074: control.dispose();
075: }
076: availableShells.add(s);
077: s.setVisible(false);
078: }
079: }
080: e.doit = false;
081: }
082: };
083:
084: /**
085: * Creates a shell pool that allocates shells that are children of the
086: * given parent and are created with the given flags.
087: *
088: * @param parentShell parent shell (may be null, indicating that this pool creates
089: * top-level shells)
090: * @param childFlags flags for all child shells
091: */
092: public ShellPool(Shell parentShell, int childFlags) {
093: this .parentShell = parentShell;
094: this .flags = childFlags;
095: }
096:
097: /**
098: * Returns a new shell. The shell must not be disposed directly, but it may be closed.
099: * Once the shell is closed, it will be returned to the shell pool. Note: callers must
100: * remove all listeners from the shell before closing it.
101: */
102: public Shell allocateShell(ShellListener closeListener) {
103: Shell result;
104: if (!availableShells.isEmpty()) {
105: result = (Shell) availableShells.removeFirst();
106: } else {
107: result = new Shell(parentShell, flags);
108: result.addShellListener(this .closeListener);
109: result.addDisposeListener(disposeListener);
110: }
111:
112: result.setData(CLOSE_LISTENER, closeListener);
113: return result;
114: }
115:
116: /**
117: * Disposes this pool. Any unused shells in the pool are disposed immediately,
118: * and any shells in use will be disposed once they are closed.
119: *
120: * @since 3.1
121: */
122: public void dispose() {
123: for (Iterator iter = availableShells.iterator(); iter.hasNext();) {
124: Shell next = (Shell) iter.next();
125: next.removeDisposeListener(disposeListener);
126:
127: next.dispose();
128: }
129:
130: availableShells.clear();
131: isDisposed = true;
132: }
133: }
|