View Javadoc

1   /*
2    * Copyright 2006-2016 The JGUIraffe Team.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License")
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package net.sf.jguiraffe.examples.tutorial.mainwnd;
17  
18  import java.io.File;
19  import java.util.ArrayList;
20  import java.util.Collections;
21  import java.util.HashMap;
22  import java.util.List;
23  import java.util.Map;
24  
25  import net.sf.jguiraffe.examples.tutorial.model.DirectoryData;
26  import net.sf.jguiraffe.examples.tutorial.model.FileData;
27  import net.sf.jguiraffe.examples.tutorial.viewset.ViewSettings;
28  import net.sf.jguiraffe.gui.app.Application;
29  import net.sf.jguiraffe.gui.builder.action.ActionStore;
30  import net.sf.jguiraffe.gui.builder.components.WidgetHandler;
31  import net.sf.jguiraffe.gui.builder.components.model.TableHandler;
32  import net.sf.jguiraffe.gui.builder.components.model.TreeHandler;
33  import net.sf.jguiraffe.gui.builder.components.model.TreeNodePath;
34  
35  import org.apache.commons.configuration.HierarchicalConfiguration;
36  import org.apache.commons.configuration.tree.ConfigurationNode;
37  import org.apache.commons.configuration.tree.DefaultConfigurationNode;
38  
39  /**
40   * <p>
41   * The controller class for the main window.
42   * </p>
43   * <p>
44   * This class implements logic related to the GUI of the main window of the
45   * JGUIraffe tutorial application.
46   * </p>
47   *
48   * @author Oliver Heger
49   * @version $Id: MainWndController.java 205 2012-01-29 18:29:57Z oheger $
50   */
51  public class MainWndController
52  {
53      /** Constant for the action group to be enabled for a single file selection. */
54      static final String ACTGRP_SINGLE_FILE = "SINGLE_FILE";
55  
56      /** Constant for the action group to be enabled for a single selection. */
57      static final String ACTGRP_SINGLE = "SINGLE_SEL";
58  
59      /** Constant for the action group to be enabled for a non-null selection. */
60      static final String ACTGRP_SELECTION = "SELECTION";
61  
62      /** A reference to the main application object. */
63      private final Application application;
64  
65      /** The handler for the tree component. */
66      private final TreeHandler tree;
67  
68      /** The handler for the table component. */
69      private final TableHandler table;
70  
71      /** The widget handler for the table. */
72      private final WidgetHandler widgetTable;
73  
74      /** Stores the model used by the tree component. */
75      private final HierarchicalConfiguration treeModel;
76  
77      /** A map with the data of the file systems. */
78      private final Map<File, ConfigurationNode> fileSystems;
79  
80      /** A map for storing view settings for directories. */
81      private final Map<File, ViewSettings> viewSettings;
82  
83      /** The icon for directories. */
84      private Object iconDirectory;
85  
86      /** The icon for files. */
87      private Object iconFile;
88  
89      /**
90       * Creates a new instance of {@code MainWndController} and initializes it
91       * with references to its dependencies.
92       *
93       * @param app the main {@code Application} object
94       * @param treeHandler the handler for the tree component
95       * @param tabHandler the handler for the table component
96       */
97      public MainWndController(Application app, TreeHandler treeHandler,
98              TableHandler tabHandler, WidgetHandler widgetTab)
99      {
100         application = app;
101         tree = treeHandler;
102         table = tabHandler;
103         widgetTable = widgetTab;
104         treeModel = tree.getModel();
105         fileSystems = new HashMap<File, ConfigurationNode>();
106         viewSettings = new HashMap<File, ViewSettings>();
107     }
108 
109     /**
110      * Returns the central {@code Application} object.
111      *
112      * @return the {@code Application}
113      */
114     public Application getApplication()
115     {
116         return application;
117     }
118 
119     /**
120      * Returns the handler for the tree component.
121      *
122      * @return the tree handler
123      */
124     public TreeHandler getTree()
125     {
126         return tree;
127     }
128 
129     /**
130      * Returns the handler for the table component.
131      *
132      * @return the table handler
133      */
134     public TableHandler getTable()
135     {
136         return table;
137     }
138 
139     /**
140      * Returns the configuration acting a model for the tree component.
141      *
142      * @return the tree model
143      */
144     public HierarchicalConfiguration getTreeModel()
145     {
146         return treeModel;
147     }
148 
149     /**
150      * Returns the icon for directories.
151      *
152      * @return the icon for directories
153      */
154     public Object getIconDirectory()
155     {
156         return iconDirectory;
157     }
158 
159     /**
160      * Sets the icon for directories.
161      *
162      * @param iconDirectory the icon for directories
163      */
164     public void setIconDirectory(Object iconDirectory)
165     {
166         this.iconDirectory = iconDirectory;
167     }
168 
169     /**
170      * Returns the icon for files.
171      *
172      * @return the icon for files
173      */
174     public Object getIconFile()
175     {
176         return iconFile;
177     }
178 
179     /**
180      * Sets the icon for files.
181      *
182      * @param iconFile the icon for files
183      */
184     public void setIconFile(Object iconFile)
185     {
186         this.iconFile = iconFile;
187     }
188 
189     /**
190      * Returns a list with the {@code File} objects that are selected in the
191      * current directory. The list can contain plain files and directories as
192      * well.
193      *
194      * @return the list with the selected {@code File} objects
195      */
196     public List<File> getSelectedFiles()
197     {
198         int[] indices = getTable().getSelectedIndices();
199         List<File> files = new ArrayList<File>(indices.length);
200         List<Object> model = getTable().getModel();
201 
202         for (int idx : indices)
203         {
204             FileData data = (FileData) model.get(idx);
205             files.add(data.getFile());
206         }
207 
208         return files;
209     }
210 
211     /**
212      * Selects the specified directory in the tree view. The passed in directory
213      * must be a sub directory of the current directory.
214      *
215      * @param dir the directory to be selected
216      */
217     public void selectSubDirectory(File dir)
218     {
219         TreeNodePath currentPath = tree.getSelectedPath();
220         TreeNodePath newPath = currentPath.append(dir.getName());
221         tree.setSelectedPath(newPath);
222     }
223 
224     /**
225      * Reads the content of the specified directory and adds it to the model of
226      * the tree view. This method is called whenever the selection of the tree
227      * view changes to a directory that has not yet been scanned.
228      *
229      * @param path the path in the tree model
230      */
231     void readDirectory(TreeNodePath path)
232     {
233         widgetTable.setVisible(false);
234         application.execute(new ReadDirectoryCommand(this, path));
235     }
236 
237     /**
238      * The user has selected another file system. This method is called when the
239      * selection of the combobox with the file systems changes. If data for this
240      * file system is already available, it is installed in the tree model.
241      * Otherwise, a new node structure for the file system has to be created.
242      *
243      * @param root the root of the file system
244      */
245     void fileSystemChanged(File root)
246     {
247         boolean load = false;
248         ConfigurationNode node = fileSystems.get(root);
249 
250         if (node == null)
251         {
252             // first access to this file system => create initial nodes
253             node = new DefaultConfigurationNode(root.getPath(),
254                     new DirectoryData(root));
255             fileSystems.put(root, node);
256             load = true;
257         }
258 
259         // Update tree model
260         treeModel.setRootNode(new DefaultConfigurationNode());
261         treeModel.addNodes(null, Collections.singleton(node));
262 
263         if (load)
264         {
265             // load initial data
266             readDirectory(new TreeNodePath(node));
267         }
268     }
269 
270     /**
271      * The selection of the tree view has changed. This method is called by the
272      * event listener for the tree control. It reads in the data of the newly
273      * selected directory if this has not been done yet. It ensures that the
274      * table view is up-to-date.
275      *
276      * @param path the path to the selected tree node
277      */
278     void treeSelectionChanged(TreeNodePath path)
279     {
280         if (path != null)
281         {
282             DirectoryData dirData = (DirectoryData) path.getTargetNode()
283                     .getValue();
284             if (!dirData.isInitialized())
285             {
286                 readDirectory(path);
287             }
288             else
289             {
290                 fillTable(dirData, viewSettings.get(dirData.getDirectory()));
291             }
292         }
293     }
294 
295     /**
296      * Fills the table component with the data for the current directory.
297      *
298      * @param dirData the data object for the current directory
299      * @param settings the current view settings
300      */
301     void fillTable(DirectoryData dirData, ViewSettings settings)
302     {
303         getTable().clearSelection();
304         List<Object> model = getTable().getModel();
305         int size = model.size();
306         if (size > 0)
307         {
308             model.clear();
309             table.rowsDeleted(0, size - 1);
310         }
311 
312         model.addAll(dirData.getContent());
313         getTable().rowsInserted(0, dirData.getContent().size() - 1);
314         if (!dirData.getContent().isEmpty())
315         {
316             getTable().setSelectedIndex(0);
317         }
318 
319         // store current directory and settings in global properties
320         getApplication().getApplicationContext().setTypedProperty(
321                 DirectoryData.class, dirData);
322         if (settings != null)
323         {
324             // may be null when the file system was changed
325             getApplication().getApplicationContext().setTypedProperty(
326                     ViewSettings.class, settings);
327             viewSettings.put(dirData.getDirectory(), settings);
328 
329             applyViewSettings(settings);
330             widgetTable.setVisible(true);
331         }
332 
333         tableSelectionChanged();
334     }
335 
336     /**
337      * Sets the graphical properties according to the specified {@code
338      * ViewSettings} object. This method is called every time a new directory is
339      * listed. The properties of the table component have to be adjusted.
340      *
341      * @param settings the {@code ViewSettings} object
342      */
343     void applyViewSettings(ViewSettings settings)
344     {
345         widgetTable.setBackgroundColor(settings.getBackgroundColor());
346         widgetTable.setForegroundColor(settings.getForegroundColor());
347         table.setSelectionBackground(settings.getSelectionBackground());
348         table.setSelectionForeground(settings.getSelectionForeground());
349     }
350 
351     /**
352      * Notifies this controller about a change of the selection of the table.
353      * This method updates the enabled state of the actions that depend on the
354      * selection of files.
355      */
356     void tableSelectionChanged()
357     {
358         ActionStore as = getApplication().getApplicationContext()
359                 .getActionStore();
360         int[] indices = getTable().getSelectedIndices();
361         as.enableGroup(ACTGRP_SELECTION, indices.length > 0);
362         as.enableGroup(ACTGRP_SINGLE, indices.length == 1);
363 
364         boolean singleFile = false;
365         if (indices.length == 1)
366         {
367             List<File> files = getSelectedFiles();
368             if (files.get(0).isFile())
369             {
370                 singleFile = true;
371             }
372         }
373         as.enableGroup(ACTGRP_SINGLE_FILE, singleFile);
374     }
375 
376     /**
377      * Performs a refresh. The content of the current directory is read again.
378      */
379     void refresh()
380     {
381         TreeNodePath path = tree.getSelectedPath();
382         if (path != null)
383         {
384             DirectoryData dirData = (DirectoryData) path.getTargetNode()
385                     .getValue();
386             dirData.setContent(null); // remove content
387             treeSelectionChanged(path);
388         }
389     }
390 }