001: // The contents of this file are subject to the Mozilla Public License Version
002: // 1.1
003: //(the "License"); you may not use this file except in compliance with the
004: //License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
005: //
006: //Software distributed under the License is distributed on an "AS IS" basis,
007: //WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
008: //for the specific language governing rights and
009: //limitations under the License.
010: //
011: //The Original Code is "The Columba Project"
012: //
013: //The Initial Developers of the Original Code are Frederik Dietz and Timo
014: // Stich.
015: //Portions created by Frederik Dietz and Timo Stich are Copyright (C) 2003.
016: //
017: //All Rights Reserved.
018:
019: package org.columba.core.gui.frame;
020:
021: import java.util.Enumeration;
022: import java.util.HashMap;
023: import java.util.Iterator;
024: import java.util.LinkedList;
025: import java.util.List;
026: import java.util.Map;
027: import java.util.logging.Logger;
028:
029: import javax.swing.JFrame;
030:
031: import org.columba.api.gui.frame.IContainer;
032: import org.columba.api.gui.frame.IFrameManager;
033: import org.columba.api.gui.frame.IFrameMediator;
034: import org.columba.api.plugin.IExtension;
035: import org.columba.api.plugin.IExtensionHandler;
036: import org.columba.api.plugin.IExtensionHandlerKeys;
037: import org.columba.api.plugin.PluginException;
038: import org.columba.api.plugin.PluginHandlerNotFoundException;
039: import org.columba.api.plugin.PluginLoadingFailedException;
040: import org.columba.core.config.Config;
041: import org.columba.core.config.ViewItem;
042: import org.columba.core.logging.Logging;
043: import org.columba.core.plugin.PluginManager;
044: import org.columba.core.shutdown.ShutdownManager;
045: import org.columba.core.xml.XmlElement;
046:
047: /**
048: * FrameManager manages all frames. It keeps a list of every controller. Its
049: * also the place to create a new frame, or save and close all frames at once.
050: *
051: * Frame controllers are plugins.
052: *
053: * @see FrameExtensionHandler
054: *
055: * @author fdietz
056: */
057: public class FrameManager implements IFrameManager {
058:
059: private static final Logger LOG = Logger
060: .getLogger("org.columba.core.gui.frame");
061:
062: /** list of frame controllers */
063: protected List activeFrameCtrls = new LinkedList();
064:
065: /** viewlist xml treenode */
066: protected XmlElement viewList = Config.getInstance().get("views")
067: .getElement("/views/viewlist");
068:
069: /** Default view specifications to be used when opening a new view */
070: protected XmlElement defaultViews = Config.getInstance().get(
071: "views").getElement("/views/defaultviews");
072:
073: protected IExtensionHandler handler;
074:
075: private static FrameManager instance = new FrameManager();
076:
077: /**
078: * we cache instances for later re-use
079: */
080: protected Map frameMediatorCache;
081:
082: /**
083: * Obtains a reference to the frame plugin handler and registers a shutdown
084: * hook with the ShutdownManager.
085: */
086: public FrameManager() {
087:
088: frameMediatorCache = new HashMap();
089:
090: // get plugin handler for handling frames
091: try {
092: handler = PluginManager.getInstance().getExtensionHandler(
093: IExtensionHandlerKeys.ORG_COLUMBA_CORE_FRAME);
094: } catch (PluginHandlerNotFoundException ex) {
095: throw new RuntimeException(ex);
096: }
097:
098: // this is executed on shutdown: store all open frames so that they
099: // can be restored on the next start
100: ShutdownManager.getInstance().register(new Runnable() {
101: public void run() {
102: storeViews();
103: }
104: });
105: }
106:
107: public static FrameManager getInstance() {
108: return instance;
109: }
110:
111: /**
112: * Check if frame mediator with given id is a managed frame.
113: *
114: * @param frameMediatorId
115: * @return
116: */
117: public boolean isManaged(String frameMediatorId) {
118: Enumeration _enum = handler.getExtensionEnumeration();
119: while (_enum.hasMoreElements()) {
120: IExtension extension = (IExtension) _enum.nextElement();
121: String managed = extension.getMetadata().getAttribute(
122: "managed");
123: if (managed == null)
124: managed = "false";
125:
126: if ((extension.getMetadata().getId()
127: .equals(frameMediatorId))
128: && managed.equals("true"))
129: return true;
130: }
131:
132: return false;
133: }
134:
135: /**
136: * Close all frames and re-open them again.
137: * <p>
138: * This is necessary when updating translations, adding new plugins which
139: * extend the menu and probably also look and feel changes.
140: *
141: */
142: public void refresh() {
143: storeViews();
144: openStoredViews();
145: }
146:
147: /**
148: * Store all open frames so that they can be restored on next startup.
149: *
150: */
151: public void storeViews() {
152: // used to temporarily store the values while the original
153: // viewList gets modified by the close method
154: List newViewList = new LinkedList();
155:
156: ViewItem v;
157:
158: // we cannot use an iterator here because the close method
159: // manipulates the list
160: while (activeFrameCtrls.size() > 0) {
161: DefaultContainer c = (DefaultContainer) activeFrameCtrls
162: .get(0);
163: v = c.getViewItem();
164:
165: // store every open frame in our temporary list
166: newViewList.add(v.getRoot());
167:
168: // close every open frame
169: c.close();
170: }
171:
172: // if not we haven't actually closed a frame, leave viewList as is
173: if (newViewList.size() > 0) {
174: // the close method manipulates the viewList so we have to
175: // remove the existing element and fill in our temporarily
176: // stored ones
177: viewList.removeAllElements();
178:
179: for (Iterator it = newViewList.iterator(); it.hasNext();) {
180: viewList.addElement((XmlElement) it.next());
181: }
182: }
183: }
184:
185: /**
186: * Opens all views stored in the configuration.
187: */
188: public void openStoredViews() {
189: // load all frames from configuration file
190: for (int i = 0; i < viewList.count(); i++) {
191: // get element from view list
192: XmlElement view = viewList.getElement(i);
193: try {
194: createFrameMediator(new ViewItem(view));
195: } catch (PluginLoadingFailedException plfe) {
196: // should not occur
197: continue;
198: }
199:
200: }
201:
202: }
203:
204: /**
205: * Returns an array of all open frames.
206: */
207: public IContainer[] getOpenFrames() {
208: return (IContainer[]) activeFrameCtrls
209: .toArray(new IContainer[0]);
210: }
211:
212: /*
213: * (non-Javadoc)
214: *
215: * @see org.columba.core.gui.frame.IFrameManager#getActiveFrameMediator()
216: */
217: public IContainer getActiveFrameMediator() {
218: Iterator it = activeFrameCtrls.iterator();
219: while (it.hasNext()) {
220: IContainer m = (IContainer) it.next();
221: JFrame frame = m.getFrame();
222: if (frame.isActive())
223: return m;
224: }
225:
226: return null;
227: }
228:
229: /**
230: * Get active/focused JFrame.
231: *
232: * @return active frame
233: */
234: public JFrame getActiveFrame() {
235: IContainer m = getActiveFrameMediator();
236: if (m != null)
237: return m.getFrame();
238:
239: // fall-back
240: return new JFrame();
241: }
242:
243: /**
244: * @param viewItem
245: * @param id
246: * @return
247: * @throws PluginLoadingFailedException
248: */
249: private IFrameMediator instanciateFrameMediator(ViewItem viewItem)
250: throws PluginLoadingFailedException {
251: String id = viewItem.get("id");
252:
253: IFrameMediator frame = null;
254: if (frameMediatorCache.containsKey(id)) {
255: LOG.fine("use cached instance " + id);
256:
257: // found cached instance
258: // -> re-use this instance and remove it from cache
259: frame = (IFrameMediator) frameMediatorCache.remove(id);
260: } else {
261: LOG.fine("create new instance " + id);
262: Object[] args = { viewItem };
263: // create new instance
264: // -> get frame controller using the plugin handler found above
265:
266: try {
267: IExtension extension = handler.getExtension(id);
268: frame = (IFrameMediator) extension
269: .instanciateExtension(args);
270: } catch (PluginException e) {
271: LOG.severe(e.getMessage());
272: if (Logging.DEBUG)
273: // TODO Auto-generated catch block
274: e.printStackTrace();
275: }
276: }
277: return frame;
278: }
279:
280: protected IFrameMediator createFrameMediator(ViewItem viewItem)
281: throws PluginLoadingFailedException {
282:
283: IFrameMediator frame = instanciateFrameMediator(viewItem);
284:
285: IContainer c = new DefaultContainer(
286: (DefaultFrameController) frame);
287:
288: activeFrameCtrls.add(c);
289:
290: return frame;
291: }
292:
293: /*
294: * (non-Javadoc)
295: *
296: * @see org.columba.core.gui.frame.IFrameManager#openView(java.lang.String)
297: */
298: public IFrameMediator openView(String id)
299: throws PluginLoadingFailedException {
300: // look for default view settings (if not found, null is returned)
301: ViewItem view = loadDefaultView(id);
302:
303: if (view == null)
304: view = ViewItem.createDefault(id);
305:
306: // Create a frame controller for this view
307: // view = null => defaults specified by frame controller is used
308: IFrameMediator controller = createFrameMediator(view);
309:
310: return controller;
311: }
312:
313: /*
314: * (non-Javadoc)
315: *
316: * @see org.columba.core.gui.frame.IFrameManager#switchView(org.columba.core.gui.frame.IContainer,
317: * java.lang.String)
318: */
319: public IFrameMediator switchView(IContainer c, String id)
320: throws PluginLoadingFailedException {
321: // look for default view settings (if not found, null is returned)
322: ViewItem view = loadDefaultView(id);
323:
324: if (view == null)
325: view = ViewItem.createDefault(id);
326:
327: // cancel, if we show already correct frame mediator
328: if (c.getFrameMediator().getId().equals(id))
329: return c.getFrameMediator();
330:
331: // Create a frame controller for this view
332:
333: // save old framemediator in cache (use containers's old id)
334: frameMediatorCache.put(((DefaultContainer) c).getViewItem()
335: .get("id"), c.getFrameMediator());
336:
337: IFrameMediator frame = instanciateFrameMediator(view);
338:
339: c.switchFrameMediator(frame);
340:
341: return frame;
342: }
343:
344: /**
345: * Gets default view settings for a given view type
346: *
347: * @param id
348: * id specifying view type
349: * @return View settings
350: */
351: protected ViewItem loadDefaultView(String id) {
352: // If defaultViews doesn't exist, create it (backward compatibility)
353: if (defaultViews == null) {
354: XmlElement gui = Config.getInstance().get("views")
355: .getElement("/views");
356: defaultViews = new XmlElement("defaultviews");
357: gui.addElement(defaultViews);
358: }
359:
360: // search through defaultViews to get settings for given id
361: ViewItem view = null;
362:
363: for (int i = 0; i < defaultViews.count(); i++) {
364: XmlElement child = defaultViews.getElement(i);
365: String childId = child.getAttribute("id");
366:
367: if ((childId != null) && childId.equals(id)) {
368: view = new ViewItem(child);
369:
370: break;
371: }
372: }
373:
374: return view;
375: }
376:
377: /**
378: * Saves default view settings for given view type. These will be used as
379: * startup values next a view of this type is opened. Though, views opened
380: * at startup will use settings from viewlist instead.
381: *
382: * Only one set of settings are stored for each view id.
383: *
384: * @param view
385: * view settings to be stored
386: */
387: protected void saveDefaultView(ViewItem view) {
388: if (view == null) {
389: return; // nothing to save
390: }
391:
392: String id = view.get("id");
393:
394: // removed previous default values
395: ViewItem oldView = loadDefaultView(id);
396:
397: if (oldView != null) {
398: defaultViews.removeElement(oldView.getRoot());
399: }
400:
401: // store current view settings
402: defaultViews.addElement(view.getRoot());
403: }
404:
405: /**
406: * Called when a frame is closed. The reference is removed from the list of
407: * active (shown) frames. If it's the last open view, the view settings are
408: * stored in the view list.
409: *
410: * @param c
411: * Reference to frame controller for the view which is closed
412: */
413: public void close(IContainer c) {
414:
415: // Check if the frame controller has been registered, else do nothing
416: if (activeFrameCtrls.contains(c)) {
417: ViewItem v = ((DefaultContainer) c).getViewItem();
418:
419: // save in cache
420: frameMediatorCache.put(v.get("id"), c.getFrameMediator());
421:
422: saveDefaultView(v);
423: activeFrameCtrls.remove(c);
424:
425: if (activeFrameCtrls.size() == 0) {
426: // this is the last frame so store its data in the viewList
427: viewList.removeAllElements();
428: viewList.addElement(v.getRoot());
429: }
430: }
431:
432: if (activeFrameCtrls.size() == 0) {
433: // shutdown Columba if no frame exists anymore
434: if (getOpenFrames().length == 0) {
435:
436: ShutdownManager.getInstance().shutdown(0);
437: }
438: }
439: }
440:
441: public ViewItem createCustomViewItem(String id) {
442: XmlElement parent = Config.getInstance().get("views")
443: .getElement("views");
444: XmlElement custom = parent.getElement("custom");
445: if (custom == null)
446: custom = parent.addSubElement("custom");
447:
448: for (int i = 0; i < custom.count(); i++) {
449: XmlElement child = custom.getElement(i);
450: String name = child.getAttribute("id");
451: if (name.equals(id))
452: return new ViewItem(child);
453: }
454:
455: ViewItem viewItem = ViewItem.createDefault(id);
456: custom.addElement(viewItem.getRoot());
457:
458: return viewItem;
459: }
460: }
|