View Javadoc

1   // $Id: MyDoggyApplicationPage.java 165 2009-05-28 21:46:38Z agony $
2   /*
3    * xsAnalyzer - XML schema analyzing tool. Copyright (C) 2008 Michael Engelhardt
4    * 
5    * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public
6    * License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later
7    * version.
8    * 
9    * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
10   * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
11   * 
12   * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free
13   * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
14   */
15  /**
16   * 
17   */
18  package de.mindcrimeilab.xsanalyzer.ui.support.mydoggy;
19  
20  import java.io.File;
21  import java.io.FileInputStream;
22  import java.io.FileOutputStream;
23  import java.io.IOException;
24  import java.util.HashMap;
25  import java.util.Iterator;
26  import java.util.Map;
27  import java.util.Map.Entry;
28  
29  import javax.swing.JComponent;
30  import javax.swing.JPanel;
31  import javax.swing.SwingUtilities;
32  
33  import org.noos.xing.mydoggy.AggregationPosition;
34  import org.noos.xing.mydoggy.Content;
35  import org.noos.xing.mydoggy.ContentManager;
36  import org.noos.xing.mydoggy.ContentManagerUIListener;
37  import org.noos.xing.mydoggy.Dockable;
38  import org.noos.xing.mydoggy.MultiSplitConstraint;
39  import org.noos.xing.mydoggy.MultiSplitContentManagerUI;
40  import org.noos.xing.mydoggy.TabbedContentManagerUI;
41  import org.noos.xing.mydoggy.ToolWindow;
42  import org.noos.xing.mydoggy.event.ContentManagerUIEvent;
43  import org.noos.xing.mydoggy.plaf.MyDoggyToolWindowManager;
44  import org.noos.xing.mydoggy.plaf.ui.cmp.ExtendedTableLayout;
45  import org.noos.xing.mydoggy.plaf.ui.content.MyDoggyMultiSplitContentManagerUI;
46  import org.springframework.richclient.application.ApplicationWindow;
47  import org.springframework.richclient.application.PageComponent;
48  import org.springframework.richclient.application.PageDescriptor;
49  import org.springframework.richclient.application.PageLayoutBuilder;
50  import org.springframework.richclient.application.ViewDescriptor;
51  import org.springframework.richclient.application.support.AbstractApplicationPage;
52  import org.springframework.util.Assert;
53  
54  /**
55   * Credits go to Peter Karich, peat_hal ‘at’ users ‘dot’ sourceforge ‘dot’ net for the mydoggy swing-rcp integration
56   * 
57   * @author Michael Engelhardt<me@mindcrime-ilab.de>
58   * @author $Author: agony $
59   * @version $Revision: 165 $
60   * 
61   */
62  public class MyDoggyApplicationPage extends AbstractApplicationPage implements PageLayoutBuilder {
63  
64      private JPanel rootComponent;
65  
66      private final MyDoggyToolWindowManager toolWindowManager;
67  
68      private final ContentManager contentManager;
69  
70      private final MultiSplitContentManagerUI contentManagerUI;
71  
72      private final Map<String, Entry<Dockable, PageComponent>> contentAndPageComponentById;
73  
74      MyDoggyApplicationPage(ApplicationWindow window, PageDescriptor pageDescriptor) {
75          super(window, pageDescriptor);
76          contentAndPageComponentById = new HashMap<String, Entry<Dockable, PageComponent>>();
77          toolWindowManager = new MyDoggyToolWindowManager();
78          contentManager = toolWindowManager.getContentManager();
79          contentManagerUI = new MyDoggyMultiSplitContentManagerUI();
80          contentManager.setContentManagerUI(contentManagerUI);
81  
82          assert SwingUtilities.isEventDispatchThread();
83  
84          contentManagerUI.setTabPlacement(TabbedContentManagerUI.TabPlacement.TOP);
85          contentManagerUI.setShowAlwaysTab(true);
86          contentManagerUI.setCloseable(true);
87          contentManagerUI.setDetachable(true);
88          // contentManagerUI.setMinimizable(true);
89  
90          contentManagerUI.addContentManagerUIListener(new MyDoggyContentListener());
91      }
92  
93      /*
94       * (non-Javadoc)
95       * 
96       * @see org.springframework.richclient.application.support.AbstractApplicationPage #
97       * doAddPageComponent(org.springframework.richclient.application.PageComponent )
98       */
99      @Override
100     protected void doAddPageComponent(PageComponent pageComponent) {
101         Assert.notNull(pageComponent);
102 
103         // If we have at least one content, then dock into that one!
104         MultiSplitConstraint constraint;
105         final Iterator<Entry<Dockable, PageComponent>> iterator = contentAndPageComponentById.values().iterator();
106         if (iterator.hasNext()) {
107             Dockable dock = iterator.next().getKey();
108             if (dock instanceof Content) {
109                 constraint = new MultiSplitConstraint((Content) dock);
110             }
111             else {
112                 constraint = new MultiSplitConstraint(AggregationPosition.DEFAULT);
113             }
114         }
115         else {
116             constraint = new MultiSplitConstraint(AggregationPosition.DEFAULT);
117         }
118         final Dockable dockable;
119 
120         ViewDescriptor viewDescriptor = getViewDescriptor(pageComponent.getId());
121 
122         if (viewDescriptor instanceof MyDoggyToolWindowViewDescriptor) {
123             final MyDoggyToolWindowViewDescriptor toolPageComponent = (MyDoggyToolWindowViewDescriptor) viewDescriptor;
124             ToolWindow tw = toolWindowManager.registerToolWindow(pageComponent.getId(), pageComponent.getDisplayName(), pageComponent.getIcon(), pageComponent.getControl(), toolPageComponent.getAnchor());
125 
126             tw.setType(toolPageComponent.getType());
127             tw.setAvailable(toolPageComponent.isAvailable());
128             tw.setActive(toolPageComponent.isActive());
129             dockable = tw;
130         }
131         else {
132             // Create and register a new content to the mydoggy layout manager
133             Content c = contentManager.addContent(pageComponent.getId(), pageComponent.getDisplayName(), // tabName
134                     pageComponent.getIcon(), pageComponent.getControl(), pageComponent.getDisplayName(), // toolTip
135                     constraint);
136             dockable = c;
137         }
138         Assert.notNull(dockable);
139         Assert.isTrue(dockable.getId().equals(pageComponent.getId()));
140         contentAndPageComponentById.put(pageComponent.getId(), new DoggyEntry<Dockable, PageComponent>(dockable, pageComponent));
141 
142         // trigger the createControl method of the PageComponent, so if a
143         // PageComponentListener is added
144         // in the createControl method, the componentOpened event is
145         // received.
146         pageComponent.getControl();
147     }
148 
149     /*
150      * (non-Javadoc)
151      * 
152      * @see org.springframework.richclient.application.support.AbstractApplicationPage
153      * #doRemovePageComponent(org.springframework.richclient.application. PageComponent)
154      */
155     @Override
156     protected void doRemovePageComponent(PageComponent pageComponent) {
157         Entry<Dockable, PageComponent> e = contentAndPageComponentById.remove(pageComponent.getId());
158         Assert.notNull(e);
159         Dockable dock = e.getKey();
160         final boolean ret;
161         if (dock instanceof Content) {
162             ret = contentManager.removeContent((Content) dock);
163         }
164         else {
165             toolWindowManager.unregisterToolWindow(dock.getId());
166             ret = true;
167         }
168         Assert.isTrue(ret);
169     }
170 
171     /*
172      * (non-Javadoc)
173      * 
174      * @see org.springframework.richclient.application.support.AbstractApplicationPage
175      * #giveFocusTo(org.springframework.richclient.application.PageComponent)
176      */
177     @Override
178     protected boolean giveFocusTo(PageComponent pageComponent) {
179         return pageComponent.getControl().requestFocusInWindow();
180     }
181 
182     @Override
183     public void setActiveComponent(PageComponent pageComponent) {
184         if (pageComponent != null) {
185             // really necessary?
186             Content c = getContent(pageComponent.getId());
187             if (c != null) {
188                 // c.ensureVisible();
189             }
190             setActive(pageComponent.getId());
191         }
192         super.setActiveComponent(pageComponent);
193     }
194 
195     /*
196      * (non-Javadoc)
197      * 
198      * @see org.springframework.richclient.factory.AbstractControlFactory#createControl ()
199      */
200     @Override
201     protected JComponent createControl() {
202         // At startup create the main component and set the mydoggy specific
203         // layout manager.
204         Assert.isNull(rootComponent, "Should not being initialized twice.");
205         rootComponent = new JPanel();
206         rootComponent.setLayout(new ExtendedTableLayout(new double[][] { { 0, -1, 0}, { 0, -1, 0}}));
207         rootComponent.add(toolWindowManager, "1,1,");
208 
209         return rootComponent;
210     }
211 
212     /*
213      * (non-Javadoc)
214      * 
215      * @see org.springframework.richclient.application.PageLayoutBuilder#addView( java.lang.String)
216      */
217     @Override
218     public void addView(String viewDescriptorId) {
219         // called from pageDescriptor.buildInitialLayout (then
220         // pageBuilder.addView)
221         showView(viewDescriptorId);
222     }
223 
224     /* Now some helper methods and classes */
225     private Content getContent(String id) {
226         return contentManager.getContent(id);
227     }
228 
229     private PageComponent getPageComponent(String id) {
230         Entry<Dockable, PageComponent> entry = contentAndPageComponentById.get(id);
231         if (entry == null) { return null; }
232 
233         return entry.getValue();
234     }
235 
236     void buildInitialLayout() {
237         // add all the specified views (List of views)
238         getPageDescriptor().buildInitialLayout(this);
239     }
240 
241     /**
242      * This method displays the component with specified key
243      * 
244      * @return true if it was successful.
245      */
246     private boolean setActive(final String id) {
247         Assert.isTrue(SwingUtilities.isEventDispatchThread());
248 
249         Content c = getContent(id);
250         if (c != null) {
251             c.setSelected(true);
252             return true;
253         }
254         return false;
255     }
256 
257     @Override
258     public boolean close() {
259         try {
260             saveLayout();
261         }
262         catch (IOException ex) {
263             logger.warn("IO Error while saving layout!", ex);
264         }
265         return super.close();
266     }
267 
268     boolean loadLayout() throws IOException {
269         File file = getLayoutFile();
270         if (file != null && file.canRead()) {
271             Assert.isTrue(SwingUtilities.isEventDispatchThread());
272             Assert.isTrue(rootComponent.isVisible());
273 
274             FileInputStream inputStream = new FileInputStream(file);
275 
276             // load layout, but add the requested content before (via callback)!
277             // toolWindowManager.getPersistenceDelegate().merge(inputStream,
278             // MergePolicy.UNION, new PersistenceDelegateCallback() {
279             //
280             // public Content contentNotFound(
281             // ToolWindowManager toolWindow, String id) {
282             // addView(id);
283             // return contentAndPageComponentById.get(id).getKey();
284             // }
285             // });
286             inputStream.close();
287 
288             // logger.info("Loaded layout from file " + file);
289             logger.info("Loaded " + contentManager.getContentCount() + " view(s).");
290             return true;
291         }
292         return false;
293     }
294 
295     void saveLayout() throws IOException {
296         File file = getLayoutFile();
297         if (file != null) {
298             if (!file.exists()) {
299                 file.createNewFile();
300             }
301             if (file.canWrite()) {
302                 FileOutputStream output = new FileOutputStream(file);
303                 toolWindowManager.getPersistenceDelegate().save(output);
304 
305                 output.close();
306                 // logger.info("Successfully saved layout.");
307                 logger.info("Saved " + contentManager.getContentCount() + " view(s).");
308             }
309         }
310     }
311 
312     private File getLayoutFile() throws IOException {
313         PageDescriptor pageDescriptor = getPageDescriptor();
314 
315         if (pageDescriptor instanceof MyDoggyPageDescriptor) {
316             return ((MyDoggyPageDescriptor) pageDescriptor).getInitialLayout().getFile();
317         }
318         else {
319             throw new IOException("Couldn't return the layout file. Wrong PageDescriptorType:" + pageDescriptor.getClass());
320         }
321     }
322 
323     /**
324      * SpringRC should be informed of a MyDoggy closing event.
325      */
326     private class MyDoggyContentListener implements ContentManagerUIListener {
327 
328         public boolean contentUIRemoving(ContentManagerUIEvent cmEvent) {
329             Content content = cmEvent.getContentUI().getContent();
330             Assert.notNull(content);
331             PageComponent pc = getPageComponent(content.getId());
332             Assert.notNull(pc);
333             close(pc);
334 
335             // let mydoggy remove the page ! (don't no for sure if this is the
336             // reason of the NPE in mydoggy if we return close(pc))
337             return false;
338         }
339 
340         public void contentUIDetached(ContentManagerUIEvent cmEvent) {
341         }
342     }
343 
344     private static class DoggyEntry<K, V> implements Map.Entry<K, V> {
345 
346         private final K key;
347 
348         private V innerValue;
349 
350         DoggyEntry(K key, V value) {
351             this.key = key;
352             this.innerValue = value;
353         }
354 
355         public K getKey() {
356             return key;
357         }
358 
359         public V getValue() {
360             return innerValue;
361         }
362 
363         public V setValue(V value) {
364             V old = this.innerValue;
365             this.innerValue = value;
366             return old;
367         }
368     }
369 }