1 package de.fzi.wim.guibase.graphview.layout;
2
3 import java.util.Collection;
4
5 import de.fzi.wim.guibase.graphview.graph.*;
6
7 /***
8 * The layouter applies the layout strategy to the graph in a separate thread,
9 */
10 public class Layouter {
11 /*** The graph that this layouter takes care of. */
12 protected Graph m_graph;
13 /*** The layout strategy for this layouter. */
14 protected LayoutStrategy m_layoutStrategy;
15 /*** The thread of the layouter. */
16 protected Thread m_layouterThread;
17
18 /***
19 * Creates the layouter.
20 *
21 * @param layoutStrategy the layout strategy
22 */
23 public Layouter(LayoutStrategy layoutStrategy) {
24 m_layoutStrategy=layoutStrategy;
25 m_graph=m_layoutStrategy.getGraph();
26 m_graph.addGraphListener(new GraphHandler());
27 }
28 /***
29 * Starts the layouter thread.
30 */
31 public synchronized void start() {
32 if (m_layouterThread==null) {
33 m_layouterThread=new LayouterThread();
34 m_layouterThread.start();
35 }
36 }
37 /***
38 * Stops the layouter thread.
39 */
40 public void stop() {
41 Thread layouterThread;
42 synchronized (this) {
43 layouterThread=m_layouterThread;
44 m_layouterThread=null;
45 }
46 if (layouterThread!=null) {
47 layouterThread.interrupt();
48 try {
49 layouterThread.join();
50 }
51 catch (InterruptedException ignored) {
52 }
53 }
54 }
55
56 /***
57 * The layouter thread.
58 */
59 protected class LayouterThread extends Thread {
60 public LayouterThread() {
61 super("GraphLayouter");
62 setDaemon(true);
63 }
64 public void run() {
65 synchronized (m_graph) {
66 m_layoutStrategy.graphContentsChanged();
67 m_layoutStrategy.notifyGraphLayoutUpdated();
68 }
69 while (true) {
70 try {
71 boolean hasMoreSteps=false;
72 synchronized (m_graph) {
73 hasMoreSteps=m_layoutStrategy.shouldExecuteStep();
74 if (hasMoreSteps) {
75 m_layoutStrategy.executeGraphLayoutStep();
76 m_graph.notifyLayoutUpdated();
77 }
78 }
79 if (hasMoreSteps)
80 Thread.sleep(20);
81 else
82 synchronized (Layouter.this) {
83 Layouter.this.wait();
84 }
85 }
86 catch (InterruptedException e) {
87 break;
88 }
89 catch (Throwable shouldntHappen) {
90 shouldntHappen.printStackTrace();
91 }
92 }
93 }
94 }
95
96 /***
97 * The handler for graph events.
98 */
99 protected class GraphHandler implements GraphListener {
100 public void graphLayoutUpdated(Graph graph) {
101 synchronized (m_graph) {
102 synchronized (Layouter.this) {
103 if (m_layouterThread!=Thread.currentThread()) {
104 m_layoutStrategy.notifyGraphLayoutUpdated();
105 Layouter.this.notifyAll();
106 }
107 }
108 }
109 }
110 public void graphUpdated(Graph graph) {
111 }
112 public void graphContentsChanged(Graph graph) {
113 synchronized (m_graph) {
114 m_layoutStrategy.graphContentsChanged();
115 notifyGraphChanged();
116 }
117 }
118 public void elementsAdded(Graph graph,Collection nodes,Collection edges) {
119 synchronized (m_graph) {
120 m_layoutStrategy.elementsAdded(nodes,edges);
121 notifyGraphChanged();
122 }
123 }
124 public void elementsRemoved(Graph graph,Collection nodes,Collection edges) {
125 synchronized (m_graph) {
126 m_layoutStrategy.elementsRemoved(nodes,edges);
127 notifyGraphChanged();
128 }
129 }
130 protected void notifyGraphChanged() {
131 synchronized (Layouter.this) {
132 m_layoutStrategy.notifyGraphLayoutUpdated();
133 Layouter.this.notifyAll();
134 }
135 }
136 }
137 }