1 /*
2  * @(#)LineConnection.java 5.1
3  *
4  */
5 
6 package CH.ifa.draw.figures;
7 
8 import java.awt.*;
9 import java.util.*;
10 import java.io.*;
11 import CH.ifa.draw.framework.*;
12 import CH.ifa.draw.standard.*;
13 import CH.ifa.draw.util.*;
14 
15 /**
16  * A LineConnection is a standard implementation of the
17  * ConnectionFigure interface. The interface is implemented with PolyLineFigure.
18  * @see ConnectionFigure
19  */
20 public  class LineConnection extends PolyLineFigure implements ConnectionFigure {
21 
22     protected Connector    fStart = null;
23     protected Connector    fEnd = null;
24 
25     /*
26      * Serialization support.
27      */
28     private static final long serialVersionUID = 6883731614578414801L;
29     private int lineConnectionSerializedDataVersion = 1;
30 
31     /**
32      * Constructs a LineConnection. A connection figure has
33      * an arrow decoration at the start and end.
34      */
LineConnection()35     public LineConnection() {
36         super(4);
37         setStartDecoration(new ArrowTip());
38         setEndDecoration(new ArrowTip());
39     }
40 
41     /**
42      * Tests whether a figure can be a connection target.
43      * ConnectionFigures cannot be connected and return false.
44      */
canConnect()45     public boolean canConnect() {
46         return false;
47     }
48 
49     /**
50      * Ensures that a connection is updated if the connection
51      * was moved.
52      */
basicMoveBy(int dx, int dy)53     protected void basicMoveBy(int dx, int dy) {
54         // don't move the start and end point since they are connected
55         for (int i = 1; i < fPoints.size()-1; i++)
56             ((Point) fPoints.elementAt(i)).translate(dx, dy);
57 
58         updateConnection(); // make sure that we are still connected
59     }
60 
61     /**
62      * Sets the start figure of the connection.
63      */
connectStart(Connector start)64     public void connectStart(Connector start) {
65         fStart = start;
66         startFigure().addFigureChangeListener(this);
67     }
68 
69     /**
70      * Sets the end figure of the connection.
71      */
connectEnd(Connector end)72     public void connectEnd(Connector end) {
73         fEnd = end;
74         endFigure().addFigureChangeListener(this);
75         handleConnect(startFigure(), endFigure());
76     }
77 
78     /**
79      * Disconnects the start figure.
80      */
disconnectStart()81     public void disconnectStart() {
82         startFigure().removeFigureChangeListener(this);
83         fStart = null;
84     }
85 
86     /**
87      * Disconnects the end figure.
88      */
disconnectEnd()89     public void disconnectEnd() {
90         handleDisconnect(startFigure(), endFigure());
91         endFigure().removeFigureChangeListener(this);
92         fEnd = null;
93     }
94 
95     /**
96      * Tests whether a connection connects the same figures
97      * as another ConnectionFigure.
98      */
connectsSame(ConnectionFigure other)99     public boolean connectsSame(ConnectionFigure other) {
100         return other.start() == start() && other.end() == end();
101     }
102 
103     /**
104      * Handles the disconnection of a connection.
105      * Override this method to handle this event.
106      */
handleDisconnect(Figure start, Figure end)107     protected void handleDisconnect(Figure start, Figure end) {}
108 
109     /**
110      * Handles the connection of a connection.
111      * Override this method to handle this event.
112      */
handleConnect(Figure start, Figure end)113     protected void handleConnect(Figure start, Figure end) {}
114 
115     /**
116      * Gets the start figure of the connection.
117      */
startFigure()118     public Figure startFigure() {
119         if (start() != null)
120             return start().owner();
121         return null;
122     }
123 
124     /**
125      * Gets the end figure of the connection.
126      */
endFigure()127     public Figure endFigure() {
128         if (end() != null)
129             return end().owner();
130         return null;
131     }
132 
133     /**
134      * Gets the start figure of the connection.
135      */
start()136     public Connector start() {
137         return fStart;
138     }
139 
140     /**
141      * Gets the end figure of the connection.
142      */
end()143     public Connector end() {
144         return fEnd;
145     }
146 
147     /**
148      * Tests whether two figures can be connected.
149      */
canConnect(Figure start, Figure end)150     public boolean canConnect(Figure start, Figure end) {
151         return true;
152     }
153 
154     /**
155      * Sets the start point.
156      */
startPoint(int x, int y)157     public void startPoint(int x, int y) {
158         willChange();
159         if (fPoints.size() == 0)
160             fPoints.addElement(new Point(x, y));
161         else
162             fPoints.setElementAt(new Point(x, y), 0);
163         changed();
164     }
165 
166     /**
167      * Sets the end point.
168      */
endPoint(int x, int y)169     public void endPoint(int x, int y) {
170         willChange();
171         if (fPoints.size() < 2)
172             fPoints.addElement(new Point(x, y));
173         else
174             fPoints.setElementAt(new Point(x, y), fPoints.size()-1);
175         changed();
176     }
177 
178     /**
179      * Gets the start point.
180      */
startPoint()181     public Point startPoint(){
182         Point p = (Point)fPoints.firstElement();
183         return new Point(p.x, p.y);
184     }
185 
186     /**
187      * Gets the end point.
188      */
endPoint()189     public Point endPoint() {
190         Point p = (Point)fPoints.lastElement();
191         return new Point(p.x, p.y);
192     }
193 
194     /**
195      * Gets the handles of the figure. It returns the normal
196      * PolyLineHandles but adds ChangeConnectionHandles at the
197      * start and end.
198      */
handles()199     public Vector handles() {
200         Vector handles = new Vector(fPoints.size());
201         handles.addElement(new ChangeConnectionStartHandle(this));
202         for (int i = 1; i < fPoints.size()-1; i++)
203             handles.addElement(new PolyLineHandle(this, locator(i), i));
204         handles.addElement(new ChangeConnectionEndHandle(this));
205         return handles;
206     }
207 
208     /**
209      * Sets the point and updates the connection.
210      */
setPointAt(Point p, int i)211     public void setPointAt(Point p, int i) {
212         super.setPointAt(p, i);
213         layoutConnection();
214     }
215 
216     /**
217      * Inserts the point and updates the connection.
218      */
insertPointAt(Point p, int i)219     public void insertPointAt(Point p, int i) {
220         super.insertPointAt(p, i);
221         layoutConnection();
222     }
223 
224     /**
225      * Removes the point and updates the connection.
226      */
removePointAt(int i)227     public void removePointAt(int i) {
228         super.removePointAt(i);
229         layoutConnection();
230     }
231 
232     /**
233      * Updates the connection.
234      */
updateConnection()235     public void updateConnection() {
236         if (fStart != null) {
237             Point start = fStart.findStart(this);
238             startPoint(start.x, start.y);
239         }
240         if (fEnd != null) {
241             Point end = fEnd.findEnd(this);
242             endPoint(end.x, end.y);
243         }
244     }
245 
246     /**
247      * Lays out the connection. This is called when the connection
248      * itself changes. By default the connection is recalculated
249      */
layoutConnection()250     public void layoutConnection() {
251         updateConnection();
252     }
253 
figureChanged(FigureChangeEvent e)254     public void figureChanged(FigureChangeEvent e) {
255         updateConnection();
256     }
257 
figureRemoved(FigureChangeEvent e)258     public void figureRemoved(FigureChangeEvent e) {
259         if (listener() != null)
260             listener().figureRequestRemove(new FigureChangeEvent(this));
261     }
262 
figureRequestRemove(FigureChangeEvent e)263     public void figureRequestRemove(FigureChangeEvent e) {}
figureInvalidated(FigureChangeEvent e)264     public void figureInvalidated(FigureChangeEvent e) {}
figureRequestUpdate(FigureChangeEvent e)265     public void figureRequestUpdate(FigureChangeEvent e) {}
266 
release()267     public void release() {
268         super.release();
269         handleDisconnect(startFigure(), endFigure());
270         if (fStart != null) startFigure().removeFigureChangeListener(this);
271         if (fEnd   != null) endFigure().removeFigureChangeListener(this);
272     }
273 
write(StorableOutput dw)274     public void write(StorableOutput dw) {
275         super.write(dw);
276         dw.writeStorable(fStart);
277         dw.writeStorable(fEnd);
278     }
279 
read(StorableInput dr)280     public void read(StorableInput dr) throws IOException {
281         super.read(dr);
282         Connector start = (Connector)dr.readStorable();
283         if (start != null)
284             connectStart(start);
285         Connector end = (Connector)dr.readStorable();
286         if (end != null)
287             connectEnd(end);
288         if (start != null && end != null)
289             updateConnection();
290     }
291 
readObject(ObjectInputStream s)292     private void readObject(ObjectInputStream s)
293         throws ClassNotFoundException, IOException {
294 
295         s.defaultReadObject();
296 
297         if (fStart != null)
298             connectStart(fStart);
299         if (fEnd != null)
300             connectEnd(fEnd);
301     }
302 }
303