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 }