~ubuntu-branches/ubuntu/saucy/libtggraphlayout-java/saucy

1 by Morten Sørensen
Import upstream version 122
1
/*
2
 * TouchGraph LLC. Apache-Style Software License
3
 *
4
 *
5
 * Copyright (c) 2001-2002 Alexander Shapiro. All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 *
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 *
14
 * 2. Redistributions in binary form must reproduce the above copyright
15
 *    notice, this list of conditions and the following disclaimer in
16
 *    the documentation and/or other materials provided with the
17
 *    distribution.
18
 *
19
 * 3. The end-user documentation included with the redistribution,
20
 *    if any, must include the following acknowledgment:
21
 *       "This product includes software developed by
22
 *        TouchGraph LLC (http://www.touchgraph.com/)."
23
 *    Alternately, this acknowledgment may appear in the software itself,
24
 *    if and wherever such third-party acknowledgments normally appear.
25
 *
26
 * 4. The names "TouchGraph" or "TouchGraph LLC" must not be used to endorse
27
 *    or promote products derived from this software without prior written
28
 *    permission.  For written permission, please contact
29
 *    alex@touchgraph.com
30
 *
31
 * 5. Products derived from this software may not be called "TouchGraph",
32
 *    nor may "TouchGraph" appear in their name, without prior written
33
 *    permission of alex@touchgraph.com.
34
 *
35
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38
 * DISCLAIMED.  IN NO EVENT SHALL TOUCHGRAPH OR ITS CONTRIBUTORS BE
39
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
40
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
41
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
42
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
43
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
44
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
45
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46
 * ====================================================================
47
 *
48
 */
49
50
package com.touchgraph.graphlayout;
51
52
import  com.touchgraph.graphlayout.graphelements.*;
53
54
import  java.util.*;
55
56
/** LocalityUtils:  Utilities for switching locality.  Animation effects
57
  * require a reference to TGPanel.
58
  *
59
  * @author   Alexander Shapiro
60
  * @version  1.22-jre1.1  $Id: LocalityUtils.java,v 1.2 2002/09/20 14:00:35 ldornbusch Exp $
61
  */
62
public class LocalityUtils {
63
64
    TGPanel tgPanel;
65
    Locality locality;
66
67
    public static final int INFINITE_LOCALITY_RADIUS = Integer.MAX_VALUE;
68
69
    ShiftLocaleThread shiftLocaleThread;
70
    boolean fastFinishShift=false;  // If finish fast is true, quickly wrap up animation
71
72
    public LocalityUtils(Locality loc, TGPanel tgp) {
73
        locality = loc;
74
        tgPanel = tgp;
75
    }
76
77
    public void fastFinishAnimation() {
78
        fastFinishShift = true;
79
    }
80
81
    /** Mark for deletion nodes not contained within distHash. */
82
    private synchronized boolean markDistantNodes(final Hashtable subgraph) {//Collection subgraph) {
83
        final boolean[] someNodeWasMarked = new boolean[1];
84
        someNodeWasMarked[0] = false;
85
//        Boolean x;
86
        TGForEachNode fen = new TGForEachNode() {
87
            public void forEachNode(Node n) {
88
//							if(!subgraph.contains(n)) {
89
                if(!subgraph.containsKey(n)) {
90
                    n.markedForRemoval=true;
91
                    someNodeWasMarked[0] = true;
92
                }
93
            }
94
        };
95
96
        locality.forAllNodes(fen);
97
        return someNodeWasMarked[0];
98
    }
99
100
    private synchronized void removeMarkedNodes() {
101
        final Vector nodesToRemove = new Vector();
102
103
        TGForEachNode fen = new TGForEachNode() {
104
            public void forEachNode(Node n) {
105
                if(n.markedForRemoval)  {
106
                    nodesToRemove.addElement(n);
107
                    n.markedForRemoval=false;
108
                    n.massfade=1;
109
                }
110
            }
111
        };
112
        synchronized(locality) {
113
            locality.forAllNodes(fen);
114
            locality.removeNodes(nodesToRemove);
115
        }
116
    }
117
118
    /** Add to locale nodes within radius distance of a focal node. */
119
    private synchronized void addNearNodes(Hashtable distHash, int radius) throws TGException {
120
        for ( int r=0; r<radius+1; r++ ) {
121
            Enumeration localNodes = distHash.keys();
122
            while (localNodes.hasMoreElements()) {
123
                Node n = (Node)localNodes.nextElement();
124
                if(!locality.contains(n) && ((Integer)distHash.get(n)).intValue()<=r) {
125
                    n.massfade=1;
126
                    n.justMadeLocal = true;                    
127
                    locality.addNodeWithEdges(n);
128
                    if (!fastFinishShift) {                        
129
                        try { 
130
                        	if(radius==1) Thread.currentThread().sleep(50); 
131
                        	else Thread.currentThread().sleep(50); 
132
                        }
133
                        catch (InterruptedException ex) {}                        
134
                    }
135
                }
136
            }
137
        }
138
    }
139
140
    private synchronized void unmarkNewAdditions() {
141
        TGForEachNode fen = new TGForEachNode() {
142
            public void forEachNode(Node n) {
143
                n.justMadeLocal=false;
144
            }
145
        };
146
        locality.forAllNodes(fen);
147
    }
148
149
    /** The thread that gets instantiated for doing the locality shift animation. */
150
    class ShiftLocaleThread extends Thread {
151
        Hashtable distHash;
152
        Node focusNode;
153
        int radius;
154
        int maxAddEdgeCount;
155
        int maxExpandEdgeCount;
156
        boolean unidirectional;
157
158
        ShiftLocaleThread(Node n, int r, int maec, int meec, boolean unid) {
159
            focusNode = n;
160
            radius = r;
161
            maxAddEdgeCount = maec;
162
            maxExpandEdgeCount = meec;
163
            unidirectional = unid;
164
            start();
165
166
        }
167
168
        public void run() {        	
169
            synchronized (LocalityUtils.this) {            
170
                if (!locality.getCompleteEltSet().contains(focusNode)) return;
171
                tgPanel.stopDamper();
172
                distHash = GESUtils.calculateDistances(
173
                             locality.getCompleteEltSet(),focusNode,radius,maxAddEdgeCount,maxExpandEdgeCount,unidirectional);
174
                try {                	
175
                	if (radius==1) {
176
                		addNearNodes(distHash,radius);
177
                    	for (int i=0;i<4&&!fastFinishShift;i++) {
178
                        	Thread.currentThread().sleep(100);
179
                    	}                     	                   	
180
                		unmarkNewAdditions();
181
                		for (int i=0;i<4&&!fastFinishShift;i++) {
182
                        	Thread.currentThread().sleep(100);
183
                    	}
184
                	}
185
                    if (markDistantNodes(distHash)){//.keySet())) {// markDistantNodes will use a Collection..
186
                         for (int i=0;i<8&&!fastFinishShift;i++) {
187
                             Thread.currentThread().sleep(100);
188
                         }
189
                    }                    
190
                    removeMarkedNodes();                    
191
                    for (int i=0;i<1&&!fastFinishShift;i++) {
192
                        if(radius>1) Thread.currentThread().sleep(100);
193
                    }
194
                    if(radius!=1) {
195
                    	addNearNodes(distHash,radius);
196
                    	for (int i=0;i<4&&!fastFinishShift;i++) {
197
                        	Thread.currentThread().sleep(100);
198
                    	}
199
                    	unmarkNewAdditions();
200
                	}
201
                    
202
                } catch ( TGException tge ) {
203
                    System.err.println("TGException: " + tge.getMessage());
204
                } catch (InterruptedException ex) {}
205
                tgPanel.resetDamper();
206
            }
207
        }
208
    }
209
210
    public void setLocale(Node n, final int radius, final int maxAddEdgeCount, final int maxExpandEdgeCount,
211
                          final boolean unidirectional) throws TGException {
212
        if (n==null || radius<0) return;
213
        if(shiftLocaleThread!=null && shiftLocaleThread.isAlive()) {
214
            fastFinishShift=true; //This should cause last locale shift to finish quickly
215
            while(shiftLocaleThread.isAlive())
216
                try { Thread.currentThread().sleep(100); }
217
                catch (InterruptedException ex) {}
218
        }
219
        if (radius == INFINITE_LOCALITY_RADIUS || n==null) {
220
            addAllGraphElts();
221
            tgPanel.resetDamper();
222
            return;
223
        }
224
225
        fastFinishShift=false;
226
        shiftLocaleThread=new ShiftLocaleThread(n, radius, maxAddEdgeCount, maxExpandEdgeCount, unidirectional);
227
    }
228
229
    public void setLocale(Node n, final int radius) throws TGException {
230
        setLocale(n,radius,1000,1000, false);
231
    }
232
233
    public synchronized void addAllGraphElts() throws TGException {
234
        locality.addAll();
235
    }
236
237
   /** Add to locale nodes that are one edge away from a given node.
238
     * This method does not utilize "fastFinishShift" so it's likely that
239
     * synchronization errors will occur.
240
     */
241
    public void expandNode(final Node n) {
242
        new Thread() {
243
            public void run() {
244
                synchronized (LocalityUtils.this) {
245
                    if (!locality.getCompleteEltSet().contains(n)) return;
246
                    tgPanel.stopDamper();
247
                    for(int i=0;i<n.edgeCount();i++) {
248
                        Node newNode = n.edgeAt(i).getOtherEndpt(n);
249
                        if (!locality.contains(newNode)) {
250
                            newNode.justMadeLocal = true;
251
                            try {
252
                                locality.addNodeWithEdges(newNode);
253
                                Thread.currentThread().sleep(50);
254
                            } catch ( TGException tge ) {
255
                                System.err.println("TGException: " + tge.getMessage());
256
                            } catch ( InterruptedException ex ) {}
257
                        }
258
                        else if (!locality.contains(n.edgeAt(i))) {
259
                            locality.addEdge(n.edgeAt(i));
260
                        }
261
                    }
262
                    try { Thread.currentThread().sleep(200); }
263
                    catch (InterruptedException ex) {}
264
                    unmarkNewAdditions();
265
                    tgPanel.resetDamper();
266
                }
267
            }
268
        }.start();
269
    }
270
271
   /** Hides a node, and all the nodes attached to it. */
272
    public synchronized void hideNode( final Node hideNode ) {
273
        if (hideNode==null) return;
274
        new Thread() {
275
            public void run() {
276
                synchronized(LocalityUtils.this) {
277
                    if (!locality.getCompleteEltSet().contains(hideNode)) return;
278
279
                    locality.removeNode(hideNode); //Necessary so that node is ignored in distances calculation.
280
                    if (hideNode==tgPanel.getSelect()) {
281
                        tgPanel.clearSelect();
282
                    }
283
284
285
//									Collection subgraph = GESUtils.getLargestConnectedSubgraph(locality);
286
										Hashtable subgraph = GESUtils.getLargestConnectedSubgraph(locality);
287
                    markDistantNodes(subgraph);
288
                    tgPanel.repaint();                    
289
                    try { Thread.currentThread().sleep(200); }
290
                    catch (InterruptedException ex) {}
291
                    removeMarkedNodes();
292
293
                    tgPanel.resetDamper();
294
                }
295
            }
296
        }.start();
297
    }
298
299
   /** Opposite of expand node, works like hide node except that the selected node is not hidden.*/
300
    public synchronized void collapseNode( final Node collapseNode ) {
301
        if (collapseNode==null) return;
302
        new Thread() {
303
            public void run() {
304
                synchronized(LocalityUtils.this) {
305
                    if (!locality.getCompleteEltSet().contains(collapseNode)) return;
306
307
                    locality.removeNode(collapseNode); //Necessary so that node is ignored in distances calculation.
308
//										Collection subgraph = GESUtils.getLargestConnectedSubgraph(locality);
309
										Hashtable subgraph = GESUtils.getLargestConnectedSubgraph(locality);
310
                    markDistantNodes(subgraph);
311
                    try {
312
                        locality.addNodeWithEdges(collapseNode); // Add the collapsed node back in.
313
                    }
314
                    catch (TGException tge) { tge.printStackTrace(); }
315
                    tgPanel.repaint();
316
                    tgPanel.resetDamper();
317
                    try { Thread.currentThread().sleep(600); }
318
                    catch (InterruptedException ex) {}
319
                    removeMarkedNodes();
320
321
                    tgPanel.resetDamper();
322
                }
323
            }
324
        }.start();
325
    }
326
} // end com.touchgraph.graphlayout.LocalityUtils