/[svn]/jsampler/trunk/src/org/jsampler/view/InstrumentsDbTreeModel.java
ViewVC logotype

Contents of /jsampler/trunk/src/org/jsampler/view/InstrumentsDbTreeModel.java

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1729 - (show annotations) (download)
Tue Apr 29 22:22:40 2008 UTC (15 years, 11 months ago) by iliev
File size: 18947 byte(s)
* Added support for handling lost files in the Instruments Database
  (In the Instruments Database window choose Actions/Check For Lost Files)
* Fantasia: Added option to show the Instruments Database
  on the Right-Side Pane of the Fantasia's main window
  (choose Edit/Preferences, then click the `View' tab)
* Added new menu item in the Instruments Database window: Edit/Find
* Some minor bugfixes and enhancements

1 /*
2 * JSampler - a java front-end for LinuxSampler
3 *
4 * Copyright (C) 2005-2007 Grigor Iliev <grigor@grigoriliev.com>
5 *
6 * This file is part of JSampler.
7 *
8 * JSampler is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2
10 * as published by the Free Software Foundation.
11 *
12 * JSampler is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with JSampler; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20 * MA 02111-1307 USA
21 */
22
23 package org.jsampler.view;
24
25 import java.awt.event.ActionEvent;
26 import java.awt.event.ActionListener;
27
28 import java.util.Vector;
29
30 import javax.swing.SwingUtilities;
31
32 import javax.swing.event.TreeModelEvent;
33 import javax.swing.event.TreeModelListener;
34
35 import javax.swing.tree.TreeModel;
36 import javax.swing.tree.TreePath;
37
38 import net.sf.juife.event.TaskEvent;
39 import net.sf.juife.event.TaskListener;
40
41 import org.jsampler.CC;
42
43 import org.jsampler.task.InstrumentsDb;
44
45 import org.linuxsampler.lscp.DbDirectoryInfo;
46 import org.linuxsampler.lscp.DbInstrumentInfo;
47
48 import org.linuxsampler.lscp.event.InstrumentsDbEvent;
49 import org.linuxsampler.lscp.event.InstrumentsDbListener;
50
51 import static org.linuxsampler.lscp.Parser.*;
52
53
54 /**
55 *
56 * @author Grigor Iliev
57 */
58 public class InstrumentsDbTreeModel implements TreeModel {
59 private DbDirectoryTreeNode root = null;
60 private Vector<TreeModelListener> listeners = new Vector<TreeModelListener>();
61
62 /**
63 * Creates a new instance of <code>InstrumentsDbTreeModel</code>.
64 */
65 public
66 InstrumentsDbTreeModel() { this(null); }
67
68 /**
69 * Creates a new instance of <code>InstrumentsDbTreeModel</code>.
70 * @param l A listener that will be notified when the root
71 * directory content is loaded.
72 */
73 public
74 InstrumentsDbTreeModel(final ActionListener l) {
75 // TODO: This shouldn't be done in the event-dispatcing thread
76 CC.getClient().addInstrumentsDbListener(getHandler());
77 ///////
78
79 initDb(l);
80 }
81
82 /**
83 * Creates a new instance of <code>InstrumentsDbTreeModel</code>.
84 */
85 public
86 InstrumentsDbTreeModel(boolean dummy) {
87 if(dummy) return;
88 // TODO: This shouldn't be done in the event-dispatcing thread
89 CC.getClient().addInstrumentsDbListener(getHandler());
90 ///////
91
92 initDb(null);
93 }
94
95 private void
96 initDb(final ActionListener l) {
97 final InstrumentsDb.GetDrectory gdi = new InstrumentsDb.GetDrectory("/");
98 final InstrumentsDb.GetDrectories gd = new InstrumentsDb.GetDrectories("/");
99 final InstrumentsDb.GetInstruments gi = new InstrumentsDb.GetInstruments("/");
100
101 gdi.addTaskListener(new TaskListener() {
102 public void
103 taskPerformed(TaskEvent e) {
104 if(gdi.doneWithErrors()) return;
105 root = new DbDirectoryTreeNode(gdi.getResult());
106 fireNodeStructureChanged(root);
107
108 CC.getTaskQueue().add(gd);
109 CC.getTaskQueue().add(gi);
110 }
111 });
112
113 gd.addTaskListener(new TaskListener() {
114 public void
115 taskPerformed(TaskEvent e) {
116 root.setConnected(true);
117 if(gd.doneWithErrors()) return;
118 updateDirectoryContent(root, gd.getResult());
119
120 for(int i = 0; i < root.getChildCount(); i++) {
121 DbDirectoryTreeNode node = root.getChildAt(i);
122 node.setConnected(true);
123 updateDirectoryContent(node, "/" + toEscapedFileName(node));
124 }
125
126 if(l != null) l.actionPerformed(null);
127 }
128 });
129
130 gi.addTaskListener(new TaskListener() {
131 public void
132 taskPerformed(TaskEvent e) {
133 if(gi.doneWithErrors()) return;
134 updateDirectoryContent(root, gi.getResult());
135 }
136 });
137
138 CC.getTaskQueue().add(gdi);
139 }
140
141 public void
142 treeWillExpand(TreePath path) {
143 DbDirectoryTreeNode node = (DbDirectoryTreeNode)path.getLastPathComponent();
144
145 if(!node.isConnected()) {
146 node.setConnected(true);
147 updateDirectoryContent(node, node.getInfo().getDirectoryPath());
148 }
149
150 for(int i = 0; i < node.getChildCount(); i++) {
151 DbDirectoryTreeNode child = node.getChildAt(i);
152 if(child.isConnected()) continue;
153 child.setConnected(true);
154 String pathName = getPathName(path.getPath());
155 if(pathName.length() > 1) pathName += "/";
156 updateDirectoryContent(child, pathName + toEscapedFileName(child));
157 }
158 }
159
160 // Tree model methods
161 public void
162 addTreeModelListener(TreeModelListener l) {
163 listeners.add(l);
164 }
165
166 public void
167 removeTreeModelListener(TreeModelListener l) {
168 listeners.remove(l);
169 }
170
171 public Object
172 getChild(Object parent, int index) {
173 return ((DbDirectoryTreeNode)parent).getChildAt(index);
174 }
175
176 public int
177 getChildCount(Object parent) {
178 return ((DbDirectoryTreeNode)parent).getChildCount();
179 }
180
181 public Object
182 getRoot() { return root; }
183
184 public int
185 getIndexOfChild(Object parent, Object child) {
186 if(parent == null || child == null) return -1;
187 return ((DbDirectoryTreeNode)parent).getIndex((DbDirectoryTreeNode)child);
188 }
189
190 public boolean
191 isLeaf(Object node) { return ((DbDirectoryTreeNode)node).isLeaf(); }
192
193 public void
194 valueForPathChanged(TreePath path, Object newValue) {
195
196 }
197 ///////
198
199 /**
200 * Schedules an update of the directory content for the specified directory node.
201 */
202 private void
203 updateDirectoryContent(final DbDirectoryTreeNode dirNode, String dirPath) {
204 updateDirectoryContent(dirNode, dirPath, null);
205 }
206
207 /**
208 * Schedules an update of the directory content for the specified directory node.
209 * @param l A listener that will be notified when the subdirectory list is updated.
210 */
211 private void
212 updateDirectoryContent (
213 final DbDirectoryTreeNode dirNode, String dirPath, final ActionListener l
214 ) {
215 final InstrumentsDb.GetDrectories gd = new InstrumentsDb.GetDrectories(dirPath);
216
217 gd.addTaskListener(new TaskListener() {
218 public void
219 taskPerformed(TaskEvent e) {
220 if(gd.doneWithErrors()) {
221 if(l != null) l.actionPerformed(null);
222 return;
223 }
224 updateDirectoryContent(dirNode, gd.getResult());
225 if(l != null) l.actionPerformed(null);
226 }
227 });
228 CC.scheduleTask(gd);
229
230 final InstrumentsDb.GetInstruments gi = new InstrumentsDb.GetInstruments(dirPath);
231
232 gi.addTaskListener(new TaskListener() {
233 public void
234 taskPerformed(TaskEvent e) {
235 if(gi.doneWithErrors()) return;
236 updateDirectoryContent(dirNode, gi.getResult());
237 }
238 });
239 CC.scheduleTask(gi);
240 }
241
242 private void
243 updateDirectoryContent(DbDirectoryTreeNode parent, DbDirectoryInfo[] children) {
244 boolean found = false;
245 Vector<DbDirectoryTreeNode> removedNodes = new Vector<DbDirectoryTreeNode>();
246 for(int i = 0; i < parent.getChildCount(); i++) {
247 for(int j = 0; j < children.length; j++) {
248 if(children[j] == null) continue;
249 if(children[j].getName().equals(parent.getChildAt(i).toString())) {
250 children[j] = null;
251 found = true;
252 break;
253 }
254 }
255 if(!found) removedNodes.add(parent.getChildAt(i));
256 found = false;
257 }
258
259 for(DbDirectoryTreeNode node : removedNodes) {
260 int i = parent.getIndex(node);
261 parent.removeDirectory(i);
262 fireNodeRemoved(parent, node, i);
263 }
264
265 for(DbDirectoryInfo info : children) {
266 if(info == null) continue;
267 DbDirectoryTreeNode node = new DbDirectoryTreeNode(info);
268 parent.addDirectory(node);
269 fireNodeInserted(node, parent.getIndex(node));
270 if(parent.getParent() == null) {
271 node.setConnected(true);
272 updateDirectoryContent(node, info.getDirectoryPath());
273 } else if(parent.isConnected()) {
274 updateDirectoryContent(node, info.getDirectoryPath());
275 }
276 }
277 }
278
279 private void
280 updateDirectoryContent(DbDirectoryTreeNode parent, DbInstrumentInfo[] children) {
281 boolean found = false;
282 Vector<DbInstrumentInfo> removedNodes = new Vector<DbInstrumentInfo>();
283 for(int i = 0; i < parent.getInstrumentCount(); i++) {
284 String name = parent.getInstrumentAt(i).getName();
285
286 for(int j = 0; j < children.length; j++) {
287 if(children[j] == null) continue;
288 if(children[j].getName().equals(name)) {
289 children[j] = null;
290 found = true;
291 break;
292 }
293 }
294 if(!found) removedNodes.add(parent.getInstrumentAt(i));
295 found = false;
296 }
297
298 for(DbInstrumentInfo info : removedNodes) {
299 int i = parent.getInstrumentIndex(info);
300 parent.removeInstrument(i);
301 }
302
303 for(DbInstrumentInfo info : children) {
304 if(info == null) continue;
305 parent.addInstrument(info);
306 }
307 }
308
309 /**
310 * Schedules a task for refreshing the directory content of the specified directory.
311 * Note that the specified directory is expected to be connected.
312 * @param dir The absolute path name of the directory to refresh.
313 */
314 public void
315 refreshDirectoryContent(String dir) {
316 final DbDirectoryTreeNode node = getNodeByPath(dir);
317 if(node == null) return;
318
319 node.removeAllDirectories();
320 fireNodeStructureChanged(node);
321 node.removeAllInstruments();
322
323 final InstrumentsDb.GetDrectories gd = new InstrumentsDb.GetDrectories(dir);
324
325 gd.addTaskListener(new TaskListener() {
326 public void
327 taskPerformed(TaskEvent e) {
328 if(gd.doneWithErrors()) return;
329
330 for(DbDirectoryInfo info : gd.getResult()) {
331 DbDirectoryTreeNode n = new DbDirectoryTreeNode(info);
332 node.addDirectory(n);
333 fireNodeInserted(n, node.getIndex(n));
334 n.setConnected(true);
335 updateDirectoryContent(n, n.getInfo().getDirectoryPath());
336 }
337 }
338 });
339 CC.scheduleTask(gd);
340
341 final InstrumentsDb.GetInstruments gi = new InstrumentsDb.GetInstruments(dir);
342
343 gi.addTaskListener(new TaskListener() {
344 public void
345 taskPerformed(TaskEvent e) {
346 if(gi.doneWithErrors()) return;
347
348 for(DbInstrumentInfo info : gi.getResult()) {
349 node.addInstrument(info);
350 }
351 }
352 });
353 CC.scheduleTask(gi);
354 }
355
356 protected Object[]
357 getPathToRoot(DbDirectoryTreeNode node) {
358 Vector v = new Vector();
359
360 while(node != null) {
361 v.insertElementAt(node, 0);
362 if(node == getRoot()) break;
363 node = node.getParent();
364 }
365
366 return v.toArray(new Object[v.size()]);
367 }
368
369 protected String
370 getPathName(Object[] objs) {
371 if(objs.length == 1) return "/";
372
373 StringBuffer sb = new StringBuffer();
374 for(int i = 1; i < objs.length; i++) {
375 sb.append('/').append(toEscapedFileName(objs[i]));
376 }
377
378 return sb.toString();
379 }
380
381 private void
382 fireNodeInserted(DbDirectoryTreeNode node, int index) {
383 Object[] path = getPathToRoot(node.getParent());
384 int[] idxs = { index };
385 Object[] objs = { node };
386 TreeModelEvent e = new TreeModelEvent(this, path, idxs, objs);
387 for(TreeModelListener l : listeners) {
388 l.treeNodesInserted(e);
389 }
390 }
391
392 private void
393 fireNodeChanged(DbDirectoryTreeNode node, int index) {
394 Object[] path = getPathToRoot(node.getParent());
395 int[] idxs = { index };
396 Object[] objs = { node };
397 TreeModelEvent e = new TreeModelEvent(this, path, idxs, objs);
398 for(TreeModelListener l : listeners) {
399 l.treeNodesChanged(e);
400 }
401 }
402
403 private void
404 fireNodeRemoved(DbDirectoryTreeNode parent, DbDirectoryTreeNode node, int index) {
405 Object[] path = getPathToRoot(parent);
406 int[] idxs = { index };
407 Object[] objs = { node };
408 TreeModelEvent e = new TreeModelEvent(this, path, idxs, objs);
409 for(int i = listeners.size() - 1; i >=0; i--) {
410 listeners.get(i).treeNodesRemoved(e);
411 }
412 }
413
414 private void
415 fireNodeStructureChanged(DbDirectoryTreeNode node) {
416 Object[] path = getPathToRoot(node);
417 Object[] objs = { node };
418 TreeModelEvent e = new TreeModelEvent(this, path);
419 for(TreeModelListener l : listeners) {
420 l.treeStructureChanged(e);
421 }
422 }
423
424 public DbDirectoryTreeNode
425 getNodeByPath(String path) {
426 String[] dirs = getDirectoryList(path);
427 if(dirs == null) return null;
428 if(dirs.length == 1) return root;
429 if(root == null) return null;
430 DbDirectoryTreeNode node = root;
431 boolean found = false;
432 for(int i = 1; i < dirs.length; i++) {
433 for(int k = 0; k < node.getChildCount(); k++) {
434 String s = toNonEscapedFileName(dirs[i]);
435 if(s.equals(node.getChildAt(k).toString())) {
436 node = node.getChildAt(k);
437 found = true;
438 break;
439 }
440 }
441
442 if(!found) return null;
443 found = false;
444 }
445
446 return node;
447 }
448
449 public String
450 getPathByNode(DbDirectoryTreeNode node) {
451 if(node == null) return null;
452 return getPathName(getPathToRoot(node));
453 }
454
455 /**
456 * @param l A listener which will be notified when the operation is completed.
457 */
458 public void
459 loadPath(String path, final ActionListener l) {
460 // TODO: This method is lazily implemented. Should be optimized.
461 final String[] dirs = getDirectoryList(path);
462 if(dirs == null) {
463 l.actionPerformed(null);
464 return;
465 }
466
467 final ActionListener listener = new ActionListener() {
468 public void
469 actionPerformed(ActionEvent e) {
470 String s = "";
471 DbDirectoryTreeNode node = null;
472 for(int i = 0; i < dirs.length; i++) {
473 if(i > 1) s += "/" + dirs[i];
474 else s += dirs[i];
475 node = getNodeByPath(s);
476 if(node == null) {
477 if(l != null) l.actionPerformed(null);
478 return;
479 }
480
481 if(!node.isConnected()) {
482 node.setConnected(true);
483 updateDirectoryContent(node, s, this);
484 return;
485 }
486 }
487
488 if(l != null) l.actionPerformed(null);
489 }
490 };
491
492 listener.actionPerformed(null);
493 }
494
495 /** Resets this model. */
496 public void
497 reset() {
498 DbDirectoryTreeNode oldRoot = root;
499 root = null;
500 TreeModelEvent e = new TreeModelEvent(this, (TreePath)null);
501 for(TreeModelListener l : listeners) {
502 l.treeStructureChanged(e);
503 }
504 }
505
506 private final EventHandler eventHandler = new EventHandler();
507
508 private EventHandler
509 getHandler() { return eventHandler; }
510
511 private class EventHandler implements InstrumentsDbListener {
512 /**
513 * Invoked when the number of instrument
514 * directories in a specific directory has changed.
515 */
516 public void
517 directoryCountChanged(final InstrumentsDbEvent e) {
518 SwingUtilities.invokeLater(new Runnable() {
519 public void
520 run() { updateDirectoryCount(e); }
521 });
522 }
523
524 private void
525 updateDirectoryCount(InstrumentsDbEvent e) {
526 if(e.getPathName().equals("/") && root == null) {
527 /*
528 * If the directory tree failed to load due to a database
529 * corruption it may work now if the db has been formatted
530 */
531 initDb(null);
532 }
533
534 DbDirectoryTreeNode node = getNodeByPath(e.getPathName());
535 if(node == null) return;
536 if(!node.isConnected()) return;
537
538 updateDirectoryContent(node, e.getPathName());
539 }
540
541 /**
542 * Invoked when the settings of an instrument directory are changed.
543 */
544 public void
545 directoryInfoChanged(final InstrumentsDbEvent e) {
546 SwingUtilities.invokeLater(new Runnable() {
547 public void
548 run() { updateDirectoryInfo(e); }
549 });
550 }
551
552 private void
553 updateDirectoryInfo(InstrumentsDbEvent e) {
554 final DbDirectoryTreeNode node = getNodeByPath(e.getPathName());
555 if(node == null) return;
556
557 final InstrumentsDb.GetDrectory t =
558 new InstrumentsDb.GetDrectory(e.getPathName());
559
560 t.addTaskListener(new TaskListener() {
561 public void
562 taskPerformed(TaskEvent e) {
563 if(t.doneWithErrors()) return;
564 if(node.getParent() != null) {
565 node.getParent().updateDirectory(t.getResult());
566 fireNodeChanged(node, node.getParent().getIndex(node));
567 }
568 }
569 });
570
571 CC.getTaskQueue().add(t);
572 }
573
574 /**
575 * Invoked when an instrument directory is renamed.
576 */
577 public void
578 directoryNameChanged(final InstrumentsDbEvent e) {
579 SwingUtilities.invokeLater(new Runnable() {
580 public void
581 run() { directoryRenamed(e); }
582 });
583 }
584
585 private void
586 directoryRenamed(InstrumentsDbEvent e) {
587 DbDirectoryTreeNode node = getNodeByPath(e.getPathName());
588 if(node == null) {
589 // If the directory is renamed by this frontend the
590 // directory should already be with the new name
591 String s = getParentDirectory(e.getPathName());
592 if(s.length() == 1) s += toEscapedFileName(e.getNewName());
593 else s += "/" + toEscapedFileName(e.getNewName());
594 node = getNodeByPath(s);
595 }
596 if(node == null || node.getParent() == null) {
597 CC.getLogger().warning("Invalid path: " + e.getPathName());
598 return;
599 }
600
601 node.setName(e.getNewName());
602 DbDirectoryTreeNode parent = node.getParent();
603
604 int i = parent.getIndex(node);
605 parent.removeDirectory(i);
606 fireNodeRemoved(parent, node, i);
607
608 parent.addDirectory(node);
609 fireNodeInserted(node, parent.getIndex(node));
610 }
611
612 /**
613 * Invoked when the number of instruments
614 * in a specific directory has changed.
615 */
616 public void
617 instrumentCountChanged(final InstrumentsDbEvent e) {
618 SwingUtilities.invokeLater(new Runnable() {
619 public void
620 run() {
621 DbDirectoryTreeNode node = getNodeByPath(e.getPathName());
622 if(node == null) {
623 return;
624 }
625 if(!node.isConnected()) {
626 return;
627 }
628
629 updateDirectoryContent(node, e.getPathName());
630 }
631 });
632 }
633
634 /**
635 * Invoked when the settings of an instrument are changed.
636 */
637 public void
638 instrumentInfoChanged(final InstrumentsDbEvent e) {
639 SwingUtilities.invokeLater(new Runnable() {
640 public void
641 run() { updateInstrumentInfo(e); }
642 });
643 }
644
645 /**
646 * Invoked when an instrument is renamed.
647 */
648 public void
649 instrumentNameChanged(final InstrumentsDbEvent e) {
650 SwingUtilities.invokeLater(new Runnable() {
651 public void
652 run() { instrumentRenamed(e); }
653 });
654 }
655
656 private void
657 updateInstrumentInfo(InstrumentsDbEvent e) {
658 String dir = getParentDirectory(e.getPathName());
659 final DbDirectoryTreeNode node = getNodeByPath(dir);
660 if(node == null) return;
661 if(!node.isConnected()) return;
662
663 final InstrumentsDb.GetInstrument t =
664 new InstrumentsDb.GetInstrument(e.getPathName());
665
666 t.addTaskListener(new TaskListener() {
667 public void
668 taskPerformed(TaskEvent e) {
669 if(t.doneWithErrors()) return;
670 node.updateInstrument(t.getResult());
671 }
672 });
673
674 CC.getTaskQueue().add(t);
675 }
676
677 private void
678 instrumentRenamed(InstrumentsDbEvent e) {
679 String dir = getParentDirectory(e.getPathName());
680 DbDirectoryTreeNode node = getNodeByPath(dir);
681 if(node == null) return;
682
683 String instr = getFileName(e.getPathName());
684 if(instr == null) return;
685
686 DbInstrumentInfo info = node.getInstrument(toNonEscapedFileName(instr));
687
688 if(info == null) {
689 // If the instrument is renamed by this frontend the
690 // instrument should already be with the new name
691 info = node.getInstrument(e.getNewName());
692 }
693 if(info == null) {
694 CC.getLogger().warning("Invalid path: " + e.getPathName());
695 return;
696 }
697
698 info.setName(e.getNewName());
699 node.removeInstrument(node.getInstrumentIndex(info));
700 node.addInstrument(info);
701 }
702
703 /** Invoked when the status of particular job has changed. */
704 public void
705 jobStatusChanged(InstrumentsDbEvent e) { }
706 }
707 }

  ViewVC Help
Powered by ViewVC