/[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 1204 - (show annotations) (download)
Thu May 24 21:43:45 2007 UTC (16 years, 11 months ago) by iliev
File size: 18907 byte(s)
upgrading to version 0.5a

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

  ViewVC Help
Powered by ViewVC