/[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 1355 - (show annotations) (download)
Mon Sep 17 23:55:27 2007 UTC (16 years, 7 months ago) by iliev
File size: 18396 byte(s)
* Added support for formatting the instruments database
* Now database instruments and directories can have multiline descriptions
* Fantasia: added detailed error dialog

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

  ViewVC Help
Powered by ViewVC