1 package com.melloware.jukes.gui.tool;
2
3 import java.io.File;
4 import java.io.FileInputStream;
5 import java.io.IOException;
6 import java.util.Enumeration;
7 import java.util.prefs.Preferences;
8
9 import javax.swing.event.TreeSelectionEvent;
10 import javax.swing.event.TreeSelectionListener;
11 import javax.swing.tree.DefaultMutableTreeNode;
12 import javax.swing.tree.DefaultTreeModel;
13 import javax.swing.tree.DefaultTreeSelectionModel;
14 import javax.swing.tree.TreeModel;
15 import javax.swing.tree.TreeNode;
16 import javax.swing.tree.TreePath;
17 import javax.swing.tree.TreeSelectionModel;
18
19 import org.apache.commons.io.FilenameUtils;
20 import org.apache.commons.lang.StringUtils;
21 import org.apache.commons.lang.SystemUtils;
22 import org.apache.commons.logging.Log;
23 import org.apache.commons.logging.LogFactory;
24
25 import com.jgoodies.binding.beans.Model;
26 import com.jgoodies.uif.application.Application;
27 import com.jgoodies.uif.util.ResourceUtils;
28 import com.jgoodies.uifextras.convenience.SetupManager;
29 import com.melloware.jukes.db.orm.AbstractJukesObject;
30 import com.melloware.jukes.db.orm.Artist;
31 import com.melloware.jukes.db.orm.Catalog;
32 import com.melloware.jukes.db.orm.Disc;
33 import com.melloware.jukes.db.orm.Track;
34 import com.melloware.jukes.file.image.ImageFactory;
35 import com.melloware.jukes.file.tag.MusicTag;
36 import com.melloware.jukes.gui.view.MainFrame;
37 import com.melloware.jukes.gui.view.node.AbstractTreeNode;
38 import com.melloware.jukes.gui.view.node.ArtistNode;
39 import com.melloware.jukes.gui.view.node.DiscNode;
40 import com.melloware.jukes.gui.view.node.NavigationNode;
41 import com.melloware.jukes.gui.view.node.RootNode;
42 import com.melloware.jukes.gui.view.node.TrackNode;
43 import com.melloware.jukes.util.MessageUtil;
44
45
46
47
48
49
50
51
52
53
54
55
56 public final class MainModule extends Model {
57
58 private static final Log LOG = LogFactory.getLog(MainModule.class);
59
60 public static final String PROPERTYNAME_CATALOG = "catalog";
61 public static final String PROPERTYNAME_HIGHLIGHT = "highlight";
62 public static final String PROPERTYNAME_SELECTION = "selection";
63 public static final String PROPERTYNAME_SELECTION_TYPE = "selectionType";
64 public static final String PROPERTYNAME_NAVIGATION_TREE_MODEL = "navigationTreeModel";
65
66
67
68
69
70 public static final Settings SETTINGS = new Settings();
71
72
73
74
75
76
77 private Catalog catalog;
78
79
80
81
82
83
84 private Class selectionType;
85
86
87
88
89
90
91
92
93
94
95
96
97 private NavigationNode selectedNode;
98
99
100
101
102
103
104 private Object selection;
105
106
107
108
109
110
111
112 private TreeModel navigationTreeModel;
113
114
115
116
117
118
119
120 private final TreeSelectionModel navigationTreeSelectionModel = new DefaultTreeSelectionModel();
121
122
123
124
125
126 public MainModule() {
127 LOG.debug("MainModule created.");
128 restoreFromFile();
129 restoreState();
130 MusicTag.setSettings(SETTINGS);
131 ImageFactory.setSettings(SETTINGS);
132 Catalog.setSettings(SETTINGS);
133 }
134
135
136
137
138
139 public Catalog getCatalog() {
140 return catalog;
141 }
142
143
144
145
146
147 public TreeModel getNavigationTreeModel() {
148 return navigationTreeModel;
149 }
150
151
152
153
154
155 public TreeSelectionModel getNavigationTreeSelectionModel() {
156 return navigationTreeSelectionModel;
157 }
158
159
160
161
162
163
164 public NavigationNode getSelectedNode() {
165 return this.selectedNode;
166 }
167
168
169
170
171
172
173
174
175
176 public Object getSelection() {
177 return selection;
178 }
179
180
181
182
183
184
185 public Class getSelectionType() {
186 return selectionType;
187 }
188
189
190
191
192
193
194 public void setCatalog(final Catalog newCatalog) {
195 if (newCatalog == null) {
196 throw new IllegalArgumentException("The catalog must not be null.");
197 }
198
199 final Catalog oldCatalog = getCatalog();
200 catalog = newCatalog;
201 firePropertyChange(PROPERTYNAME_CATALOG, oldCatalog, newCatalog);
202 setNavigationTreeModel(createNavigationTreeModel(newCatalog));
203
204 }
205
206
207
208
209
210 public boolean isCatalogFilePathValid() {
211 return false;
212 }
213
214
215
216
217
218 public boolean hasCatalog() {
219 return getCatalog() != null;
220 }
221
222
223
224
225
226
227
228 public void refreshSelection(final Object domainObject, final String operation) {
229 if (selectedNode == null) {
230 return;
231 }
232 final DefaultTreeModel treeModel = ((DefaultTreeModel) getNavigationTreeModel());
233 if (Resources.NODE_CHANGED.equals(operation)) {
234 treeModel.nodeChanged(selectedNode);
235 LOG.debug("Tree Node changed.");
236 } else if (Resources.NODE_DELETED.equals(operation)) {
237 final TreeNode parent = selectedNode.getParent();
238 if (parent != null) {
239 LOG.debug("Tree Node Deleted");
240 treeModel.removeNodeFromParent((DefaultMutableTreeNode) selectedNode);
241 setSelectedNode((AbstractTreeNode) parent);
242 }
243 }
244 }
245
246
247
248
249
250
251 public void refreshTree() {
252 setCatalog(new Catalog(SETTINGS.getFilter()));
253 firePropertyChange(PROPERTYNAME_SELECTION, selection, null);
254 }
255
256
257
258
259
260
261 public void refreshTree(Object selectedObject) {
262 setCatalog(new Catalog(SETTINGS.getFilter()));
263 firePropertyChange(PROPERTYNAME_SELECTION, selection, selectedObject);
264 selectNodeInTree(selectedObject);
265 }
266
267
268
269
270 public void restoreState() {
271 SETTINGS.restoreFrom(Application.getUserPreferences());
272 }
273
274
275
276
277
278
279 public void selectNodeInTree(final Object newSelection) {
280 final AbstractJukesObject selection = (AbstractJukesObject) newSelection;
281 AbstractTreeNode node = null;
282 String artistName = null;
283 String discName = null;
284 String trackName = null;
285 if (selection instanceof Artist) {
286 artistName = selection.getName();
287 } else if (selection instanceof Disc) {
288 final Disc disc = (Disc) selection;
289 artistName = disc.getArtist().getName();
290 discName = selection.getName();
291 } else if (selection instanceof Track) {
292 final Track track = (Track) selection;
293 artistName = track.getDisc().getArtist().getName();
294 discName = track.getDisc().getName();
295 trackName = selection.getName();
296 }
297
298 final DefaultTreeModel treeModel = ((DefaultTreeModel) navigationTreeModel);
299 final AbstractTreeNode root = (AbstractTreeNode) treeModel.getRoot();
300
301
302 ArtistNode artistNode = null;
303 if (StringUtils.isNotBlank(artistName)) {
304 final Enumeration artistEnum = root.children();
305 while (artistEnum.hasMoreElements()) {
306 artistNode = (ArtistNode) artistEnum.nextElement();
307 if (StringUtils.equalsIgnoreCase(artistNode.toString(), artistName)) {
308 node = artistNode;
309 break;
310 }
311 }
312 }
313
314
315 DiscNode discNode = null;
316 if ((StringUtils.isNotBlank(discName)) && (artistNode != null)) {
317 final Enumeration discEnum = artistNode.children();
318 while (discEnum.hasMoreElements()) {
319 discNode = (DiscNode) discEnum.nextElement();
320 if (StringUtils.equalsIgnoreCase(discNode.toString(), discName)) {
321 node = discNode;
322 break;
323 }
324 }
325 }
326
327
328 TrackNode trackNode = null;
329 if ((StringUtils.isNotBlank(trackName)) && (discNode != null)) {
330 final Enumeration trackEnum = discNode.children();
331 while (trackEnum.hasMoreElements()) {
332 trackNode = (TrackNode) trackEnum.nextElement();
333 if (StringUtils.equalsIgnoreCase(trackNode.toString(), trackName)) {
334 node = trackNode;
335 break;
336 }
337 }
338 }
339
340 if (node != null) {
341
342 setSelectedNode(node);
343
344
345 firePropertyChange(PROPERTYNAME_HIGHLIGHT, null, "Highlight");
346 }
347 }
348
349
350
351
352 public void storeState() {
353 final Preferences prefs = Application.getUserPreferences();
354 SETTINGS.storeIn(prefs);
355 SetupManager.incrementUsageCounter();
356 }
357
358
359
360
361
362
363 private void setNavigationTreeModel(final TreeModel newModel) {
364 final TreeModel oldModel = getNavigationTreeModel();
365 navigationTreeModel = newModel;
366 firePropertyChange(PROPERTYNAME_NAVIGATION_TREE_MODEL, oldModel, newModel);
367 }
368
369
370
371
372
373
374
375
376
377 private void setSelectedNode(final NavigationNode newSelectedNode) {
378 final NavigationNode oldSelectedNode = selectedNode;
379 selectedNode = newSelectedNode;
380 setSelection(newSelectedNode.getModel());
381 ((DefaultTreeModel) getNavigationTreeModel()).nodeChanged(oldSelectedNode);
382 }
383
384
385
386
387
388
389
390
391 private void setSelection(final Object newSelection) {
392 final Object oldSelection = getSelection();
393 selection = newSelection;
394 setSelectionType(newSelection.getClass());
395 firePropertyChange(PROPERTYNAME_SELECTION, oldSelection, newSelection);
396 }
397
398
399
400
401
402
403
404 private void setSelectionType(final Class newSelectionType) {
405 final Class oldSelectionType = getSelectionType();
406 selectionType = newSelectionType;
407 if (equals(oldSelectionType, newSelectionType)) {
408 return;
409 }
410
411 firePropertyChange(PROPERTYNAME_SELECTION_TYPE, oldSelectionType, newSelectionType);
412 }
413
414
415
416
417
418
419
420 private TreeModel createNavigationTreeModel(final Catalog catalog) {
421 final RootNode rootNode = new RootNode(catalog);
422 rootNode.setSettings(SETTINGS);
423 final DefaultTreeModel model = new DefaultTreeModel(rootNode);
424 navigationTreeSelectionModel.setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
425 navigationTreeSelectionModel.addTreeSelectionListener(new NavigationTreeSelectionChangeHandler());
426 return model;
427 }
428
429
430
431 private class NavigationTreeSelectionChangeHandler implements TreeSelectionListener {
432
433
434
435
436
437
438
439
440 public void valueChanged(final TreeSelectionEvent evt) {
441 final TreePath path = evt.getPath();
442 final NavigationNode aSelectedNode = (NavigationNode) path.getLastPathComponent();
443 if (aSelectedNode != null) {
444 setSelectedNode(aSelectedNode);
445 }
446 }
447
448 }
449
450
451
452 private void restoreFromFile() {
453 LOG.info("Read Preferences from jukes.xml");
454 final String errorMessage = ResourceUtils.getString("messages.ErrorReadPrefsFile");
455 final MainFrame mainFrame = (MainFrame) Application.getDefaultParentFrame();
456 final File file = new File(FilenameUtils.normalizeNoEndSeparator(SystemUtils.USER_DIR
457 + SystemUtils.FILE_SEPARATOR + "jukes.xml"));
458
459 if (file.exists()) {
460 try {
461 final FileInputStream stream = new FileInputStream(file);
462 Preferences.importPreferences(stream);
463 } catch (IOException ex) {
464 MessageUtil.showError(mainFrame, errorMessage);
465 LOG.error(errorMessage + ex.getMessage(), ex);
466 } catch (Exception ex) {
467 MessageUtil.showError(mainFrame, errorMessage);
468 LOG.error(errorMessage, ex);
469 }
470 }
471 }
472 }