001    /*
002     * Copyright 2002-2004 the original author or authors.
003     * 
004     * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005     * use this file except in compliance with the License. You may obtain a copy of
006     * the License at
007     * 
008     * http://www.apache.org/licenses/LICENSE-2.0
009     * 
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012     * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013     * License for the specific language governing permissions and limitations under
014     * the License.
015     */
016    package org.springframework.richclient.application;
017    
018    import java.awt.Window;
019    import java.util.ArrayList;
020    import java.util.Iterator;
021    import java.util.List;
022    import java.util.Observable;
023    import java.beans.PropertyChangeSupport;
024    import java.beans.PropertyChangeListener;
025    
026    import org.springframework.util.Assert;
027    import org.springframework.binding.value.PropertyChangePublisher;
028    
029    /**
030     * A manager for a group of windows. Window managers are needed in applications
031     * which create many different windows in addition to a main window. A window
032     * manager can be used to remember all the windows that an application has
033     * created (independent of whether they are presently open or closed). There can
034     * be several window managers, and they can be arranged into a tree. This kind
035     * of organization makes it simple to close whole subgroupings of windows.
036     * <p>
037     * Associating a window with a window manager is done with
038     * <code>WindowManager.add(Window)</code>. A window is automatically removed
039     * from its window manager as a side effect of closing the window.
040     * 
041     * @see Window
042     */
043    public class WindowManager extends Observable implements PropertyChangePublisher {
044    
045        /**
046         * List of windows managed by this window manager (element type:
047         * <code>Window</code>).
048         */
049        private List windows = new ArrayList();
050    
051        /**
052         * Parent window manager, or <code>null</code> if none.
053         */
054        private WindowManager parentManager;
055    
056        /**
057         * List of window managers who have this window manager as their parent
058         * (element type: <code>WindowManager</code>).
059         */
060        private List subManagers;
061        
062        /**
063         * Holds the currently active window.
064         */
065        private ApplicationWindow activeWindow;
066        
067        private final PropertyChangeSupport changeSupport = new PropertyChangeSupport(this);
068    
069        /**
070         * Creates an empty window manager without a parent window manager (that is,
071         * a root window manager).
072         */
073        public WindowManager() {
074        }
075    
076        /**
077         * Creates an empty window manager with the given window manager as parent.
078         * 
079         * @param parent
080         *            the parent window manager
081         */
082        public WindowManager(WindowManager parent) {
083            Assert.notNull(parent);
084            parent.addWindowManager(this);
085        }
086    
087        /**
088         * Adds the given window to the set of windows managed by this window
089         * manager. Does nothing is this window is already managed by this window
090         * manager.
091         * 
092         * @param window
093         *            the window
094         */
095        public void add(ApplicationWindow window) {
096            if (activeWindow == null) // first window will be set as activeWindow
097                setActiveWindow(window);
098            
099            if (!windows.contains(window)) {
100                windows.add(window);
101                window.setWindowManager(this);
102                setChanged();
103                notifyObservers();
104            }
105        }
106    
107        /**
108         * Adds the given window manager to the list of window managers that have
109         * this one as a parent.
110         * 
111         * @param wm
112         *            the child window manager
113         */
114        private void addWindowManager(WindowManager wm) {
115            if (subManagers == null) {
116                subManagers = new ArrayList();
117            }
118            if (!subManagers.contains(wm)) {
119                subManagers.add(wm);
120                wm.parentManager = this;
121            }
122        }
123    
124        /**
125         * Attempts to close all windows managed by this window manager, as well as
126         * windows managed by any descendent window managers.
127         * 
128         * @return <code>true</code> if all windows were sucessfully closed, and
129         *         <code>false</code> if any window refused to close
130         */
131        public boolean close() {
132            List t = (List)((ArrayList)windows).clone();
133            Iterator e = t.iterator();
134            while (e.hasNext()) {
135                ApplicationWindow window = (ApplicationWindow)e.next();
136                if (!window.close()) { return false; }
137            }
138            if (subManagers != null) {
139                e = subManagers.iterator();
140                while (e.hasNext()) {
141                    WindowManager wm = (WindowManager)e.next();
142                    if (!wm.close()) { return false; }
143                }
144            }
145            return true;
146        }
147    
148        /**
149         * Returns this window manager's set of windows.
150         * 
151         * @return a possibly empty list of window
152         */
153        public ApplicationWindow[] getWindows() {
154            ApplicationWindow managed[] = new ApplicationWindow[windows.size()];
155            windows.toArray(managed);
156            return managed;
157        }
158    
159        /**
160         * @return the parent of this WindowManager
161         */
162        public WindowManager getParent() {
163            return parentManager;
164        }
165    
166        /**
167         * Removes the given window from the set of windows managed by this window
168         * manager. Does nothing is this window is not managed by this window
169         * manager.
170         * 
171         * @param window
172         *            the window
173         */
174        public final void remove(ApplicationWindow window) {
175            if (windows.contains(window)) {
176                windows.remove(window);
177                window.setWindowManager(null);
178                setChanged();
179                notifyObservers();
180            }
181        }
182    
183        /**
184         * Set the currently active window. When a window gets focus, it will set itself
185         * as the current window of it's manager.
186         * 
187         * @param window
188         */
189        public final void setActiveWindow(ApplicationWindow window)
190        {
191            final ApplicationWindow old = this.activeWindow;
192            this.activeWindow = window;
193            if (getParent() != null) // let things ripple up
194                getParent().setActiveWindow(window);
195            getChangeSupport().firePropertyChange("activeWindow", old, window);
196        }
197        
198        /**
199         * @return the active window.
200         */
201        public final ApplicationWindow getActiveWindow()
202        {
203            return this.activeWindow;
204        }
205        
206        /**
207         * @return Number of windows managed by this instance.
208         */
209        public int size() {
210            return windows.size();
211        }
212        
213        
214        protected PropertyChangeSupport getChangeSupport() {
215            return changeSupport;
216        }
217    
218        
219        
220        
221        //
222        // METHODS FROM INTERFACE PropertyChangePublisher
223        //
224    
225    
226        public void addPropertyChangeListener(PropertyChangeListener listener) {
227            getChangeSupport().addPropertyChangeListener(listener);
228        }
229    
230        public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
231            getChangeSupport().addPropertyChangeListener(propertyName, listener);
232        }
233    
234        public void removePropertyChangeListener(PropertyChangeListener listener) {
235            getChangeSupport().removePropertyChangeListener(listener);
236        }
237    
238        public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
239            getChangeSupport().removePropertyChangeListener(propertyName, listener);
240        }
241    }