001/*
002 * Copyright 2006 - 2013
003 *      Stefan Balev    <stefan.balev@graphstream-project.org>
004 *      Julien Baudry   <julien.baudry@graphstream-project.org>
005 *      Antoine Dutot   <antoine.dutot@graphstream-project.org>
006 *      Yoann Pigné         <yoann.pigne@graphstream-project.org>
007 *      Guilhelm Savin  <guilhelm.savin@graphstream-project.org>
008 *  
009 * GraphStream is a library whose purpose is to handle static or dynamic
010 * graph, create them from scratch, file or any source and display them.
011 * 
012 * This program is free software distributed under the terms of two licenses, the
013 * CeCILL-C license that fits European law, and the GNU Lesser General Public
014 * License. You can  use, modify and/ or redistribute the software under the terms
015 * of the CeCILL-C license as circulated by CEA, CNRS and INRIA at the following
016 * URL <http://www.cecill.info> or under the terms of the GNU LGPL as published by
017 * the Free Software Foundation, either version 3 of the License, or (at your
018 * option) any later version.
019 * 
020 * This program is distributed in the hope that it will be useful, but WITHOUT ANY
021 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
022 * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
023 * 
024 * You should have received a copy of the GNU Lesser General Public License
025 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
026 * 
027 * The fact that you are presently reading this means that you have had
028 * knowledge of the CeCILL-C and LGPL licenses and that you accept their terms.
029 */
030package org.graphstream.util;
031
032import org.graphstream.graph.Edge;
033import org.graphstream.graph.Graph;
034import org.graphstream.graph.Node;
035import org.graphstream.graph.implementations.AbstractElement.AttributeChangeEvent;
036import org.graphstream.stream.Pipe;
037import org.graphstream.stream.SourceBase;
038import org.graphstream.stream.sync.SinkTime;
039
040/**
041 * Helper object to handle events producted by a graph.
042 * 
043 */
044public class GraphListeners extends SourceBase implements Pipe {
045        SinkTime sinkTime;
046        boolean passYourWay;
047        Graph g;
048
049        public GraphListeners(Graph g) {
050                super(g.getId());
051
052                this.sinkTime = new SinkTime();
053                this.sourceTime.setSinkTime(sinkTime);
054                this.passYourWay = false;
055                this.g = g;
056        }
057
058        public long newEvent() {
059                return sourceTime.newEvent();
060        }
061
062        public void sendAttributeChangedEvent(String eltId, ElementType eltType,
063                        String attribute, AttributeChangeEvent event, Object oldValue,
064                        Object newValue) {
065                //
066                // Attributes with name beginnig with a dot are hidden.
067                //
068                if (passYourWay || attribute.charAt(0) == '.')
069                        return;
070
071                sendAttributeChangedEvent(sourceId, newEvent(), eltId, eltType,
072                                attribute, event, oldValue, newValue);
073        }
074
075        public void sendNodeAdded(String nodeId) {
076                if (passYourWay)
077                        return;
078
079                sendNodeAdded(sourceId, newEvent(), nodeId);
080        }
081
082        public void sendNodeRemoved(String nodeId) {
083                if (passYourWay)
084                        return;
085
086                sendNodeRemoved(sourceId, newEvent(), nodeId);
087        }
088
089        public void sendEdgeAdded(String edgeId, String source, String target,
090                        boolean directed) {
091                if (passYourWay)
092                        return;
093
094                sendEdgeAdded(sourceId, newEvent(), edgeId, source, target, directed);
095        }
096
097        public void sendEdgeRemoved(String edgeId) {
098                if (passYourWay)
099                        return;
100
101                sendEdgeRemoved(sourceId, newEvent(), edgeId);
102        }
103
104        public void sendGraphCleared() {
105                if (passYourWay)
106                        return;
107
108                sendGraphCleared(sourceId, newEvent());
109        }
110
111        public void sendStepBegins(double step) {
112                if (passYourWay)
113                        return;
114
115                sendStepBegins(sourceId, newEvent(), step);
116        }
117
118        /*
119         * (non-Javadoc)
120         * 
121         * @see org.graphstream.stream.AttributeSink#edgeAttributeAdded(java.lang
122         * .String, long, java.lang.String, java.lang.String, java.lang.Object)
123         */
124        public void edgeAttributeAdded(String sourceId, long timeId, String edgeId,
125                        String attribute, Object value) {
126                if (sinkTime.isNewEvent(sourceId, timeId)) {
127                        Edge edge = g.getEdge(edgeId);
128                        if (edge != null) {
129                                passYourWay = true;
130
131                                try {
132                                        edge.addAttribute(attribute, value);
133                                } finally {
134                                        passYourWay = false;
135                                }
136
137                                sendEdgeAttributeAdded(sourceId, timeId, edgeId, attribute,
138                                                value);
139                        }
140                }
141        }
142
143        /*
144         * (non-Javadoc)
145         * 
146         * @see org.graphstream.stream.AttributeSink#edgeAttributeChanged(java.lang
147         * .String, long, java.lang.String, java.lang.String, java.lang.Object,
148         * java.lang.Object)
149         */
150        public void edgeAttributeChanged(String sourceId, long timeId,
151                        String edgeId, String attribute, Object oldValue, Object newValue) {
152                if (sinkTime.isNewEvent(sourceId, timeId)) {
153                        Edge edge = g.getEdge(edgeId);
154                        if (edge != null) {
155                                passYourWay = true;
156
157                                if (oldValue == null)
158                                        oldValue = edge.getAttribute(attribute);
159
160                                try {
161                                        edge.changeAttribute(attribute, newValue);
162                                } finally {
163                                        passYourWay = false;
164                                }
165
166                                sendEdgeAttributeChanged(sourceId, timeId, edgeId, attribute,
167                                                oldValue, newValue);
168                        }
169                }
170        }
171
172        /*
173         * (non-Javadoc)
174         * 
175         * @see org.graphstream.stream.AttributeSink#edgeAttributeRemoved(java.lang
176         * .String, long, java.lang.String, java.lang.String)
177         */
178        public void edgeAttributeRemoved(String sourceId, long timeId,
179                        String edgeId, String attribute) {
180                if (sinkTime.isNewEvent(sourceId, timeId)) {
181                        Edge edge = g.getEdge(edgeId);
182                        if (edge != null) {
183                                sendEdgeAttributeRemoved(sourceId, timeId, edgeId, attribute);
184                                passYourWay = true;
185
186                                try {
187                                        edge.removeAttribute(attribute);
188                                } finally {
189                                        passYourWay = false;
190                                }
191
192                        }
193                }
194        }
195
196        /*
197         * (non-Javadoc)
198         * 
199         * @see org.graphstream.stream.AttributeSink#graphAttributeAdded(java.lang
200         * .String, long, java.lang.String, java.lang.Object)
201         */
202        public void graphAttributeAdded(String sourceId, long timeId,
203                        String attribute, Object value) {
204                if (sinkTime.isNewEvent(sourceId, timeId)) {
205                        passYourWay = true;
206
207                        try {
208                                g.addAttribute(attribute, value);
209                        } finally {
210                                passYourWay = false;
211                        }
212
213                        sendGraphAttributeAdded(sourceId, timeId, attribute, value);
214                }
215        }
216
217        /*
218         * (non-Javadoc)
219         * 
220         * @see org.graphstream.stream.AttributeSink#graphAttributeChanged(java.lang
221         * .String, long, java.lang.String, java.lang.Object, java.lang.Object)
222         */
223        public void graphAttributeChanged(String sourceId, long timeId,
224                        String attribute, Object oldValue, Object newValue) {
225                if (sinkTime.isNewEvent(sourceId, timeId)) {
226                        passYourWay = true;
227
228                        if (oldValue == null)
229                                oldValue = g.getAttribute(attribute);
230
231                        try {
232                                g.changeAttribute(attribute, newValue);
233                        } finally {
234                                passYourWay = false;
235                        }
236
237                        sendGraphAttributeChanged(sourceId, timeId, attribute, oldValue,
238                                        newValue);
239                }
240        }
241
242        /*
243         * (non-Javadoc)
244         * 
245         * @see org.graphstream.stream.AttributeSink#graphAttributeRemoved(java.lang
246         * .String, long, java.lang.String)
247         */
248        public void graphAttributeRemoved(String sourceId, long timeId,
249                        String attribute) {
250                if (sinkTime.isNewEvent(sourceId, timeId)) {
251                        sendGraphAttributeRemoved(sourceId, timeId, attribute);
252                        passYourWay = true;
253
254                        try {
255                                g.removeAttribute(attribute);
256                        } finally {
257                                passYourWay = false;
258                        }
259                }
260        }
261
262        /*
263         * (non-Javadoc)
264         * 
265         * @see org.graphstream.stream.AttributeSink#nodeAttributeAdded(java.lang
266         * .String, long, java.lang.String, java.lang.String, java.lang.Object)
267         */
268        public void nodeAttributeAdded(String sourceId, long timeId, String nodeId,
269                        String attribute, Object value) {
270                if (sinkTime.isNewEvent(sourceId, timeId)) {
271                        Node node = g.getNode(nodeId);
272                        if (node != null) {
273                                passYourWay = true;
274
275                                try {
276                                        node.addAttribute(attribute, value);
277                                } finally {
278                                        passYourWay = false;
279                                }
280
281                                sendNodeAttributeAdded(sourceId, timeId, nodeId, attribute,
282                                                value);
283                        }
284                }
285        }
286
287        /*
288         * (non-Javadoc)
289         * 
290         * @see org.graphstream.stream.AttributeSink#nodeAttributeChanged(java.lang
291         * .String, long, java.lang.String, java.lang.String, java.lang.Object,
292         * java.lang.Object)
293         */
294        public void nodeAttributeChanged(String sourceId, long timeId,
295                        String nodeId, String attribute, Object oldValue, Object newValue) {
296                if (sinkTime.isNewEvent(sourceId, timeId)) {
297                        Node node = g.getNode(nodeId);
298                        if (node != null) {
299                                passYourWay = true;
300
301                                if (oldValue == null)
302                                        oldValue = node.getAttribute(attribute);
303
304                                try {
305                                        node.changeAttribute(attribute, newValue);
306                                } finally {
307                                        passYourWay = false;
308                                }
309
310                                sendNodeAttributeChanged(sourceId, timeId, nodeId, attribute,
311                                                oldValue, newValue);
312                        }
313                }
314        }
315
316        /*
317         * (non-Javadoc)
318         * 
319         * @see org.graphstream.stream.AttributeSink#nodeAttributeRemoved(java.lang
320         * .String, long, java.lang.String, java.lang.String)
321         */
322        public void nodeAttributeRemoved(String sourceId, long timeId,
323                        String nodeId, String attribute) {
324                if (sinkTime.isNewEvent(sourceId, timeId)) {
325                        Node node = g.getNode(nodeId);
326                        if (node != null) {
327                                sendNodeAttributeRemoved(sourceId, timeId, nodeId, attribute);
328                                passYourWay = true;
329
330                                try {
331                                        node.removeAttribute(attribute);
332                                } finally {
333                                        passYourWay = false;
334                                }
335                        }
336                }
337        }
338
339        /*
340         * (non-Javadoc)
341         * 
342         * @see org.graphstream.stream.ElementSink#edgeAdded(java.lang.String, long,
343         * java.lang.String, java.lang.String, java.lang.String, boolean)
344         */
345        public void edgeAdded(String sourceId, long timeId, String edgeId,
346                        String fromNodeId, String toNodeId, boolean directed) {
347                if (sinkTime.isNewEvent(sourceId, timeId)) {
348                        passYourWay = true;
349
350                        try {
351                                g.addEdge(edgeId, fromNodeId, toNodeId, directed);
352                        } finally {
353                                passYourWay = false;
354                        }
355
356                        sendEdgeAdded(sourceId, timeId, edgeId, fromNodeId, toNodeId,
357                                        directed);
358                }
359        }
360
361        /*
362         * (non-Javadoc)
363         * 
364         * @see org.graphstream.stream.ElementSink#edgeRemoved(java.lang.String,
365         * long, java.lang.String)
366         */
367        public void edgeRemoved(String sourceId, long timeId, String edgeId) {
368                if (sinkTime.isNewEvent(sourceId, timeId)) {
369                        sendEdgeRemoved(sourceId, timeId, edgeId);
370                        passYourWay = true;
371
372                        try {
373                                g.removeEdge(edgeId);
374                        } finally {
375                                passYourWay = false;
376                        }
377                }
378        }
379
380        /*
381         * (non-Javadoc)
382         * 
383         * @see org.graphstream.stream.ElementSink#graphCleared(java.lang.String,
384         * long)
385         */
386        public void graphCleared(String sourceId, long timeId) {
387                if (sinkTime.isNewEvent(sourceId, timeId)) {
388                        sendGraphCleared(sourceId, timeId);
389                        passYourWay = true;
390
391                        try {
392                                g.clear();
393                        } finally {
394                                passYourWay = false;
395                        }
396                }
397        }
398
399        /*
400         * (non-Javadoc)
401         * 
402         * @see org.graphstream.stream.ElementSink#nodeAdded(java.lang.String, long,
403         * java.lang.String)
404         */
405        public void nodeAdded(String sourceId, long timeId, String nodeId) {
406                if (sinkTime.isNewEvent(sourceId, timeId)) {
407                        passYourWay = true;
408
409                        try {
410                                g.addNode(nodeId);
411                        } finally {
412                                passYourWay = false;
413                        }
414
415                        sendNodeAdded(sourceId, timeId, nodeId);
416                }
417        }
418
419        /*
420         * (non-Javadoc)
421         * 
422         * @see org.graphstream.stream.ElementSink#nodeRemoved(java.lang.String,
423         * long, java.lang.String)
424         */
425        public void nodeRemoved(String sourceId, long timeId, String nodeId) {
426                if (sinkTime.isNewEvent(sourceId, timeId)) {
427                        sendNodeRemoved(sourceId, timeId, nodeId);
428                        passYourWay = true;
429
430                        try {
431                                g.removeNode(nodeId);
432                        } finally {
433                                passYourWay = false;
434                        }
435                }
436        }
437
438        /*
439         * (non-Javadoc)
440         * 
441         * @see org.graphstream.stream.ElementSink#stepBegins(java.lang.String,
442         * long, double)
443         */
444        public void stepBegins(String sourceId, long timeId, double step) {
445                if (sinkTime.isNewEvent(sourceId, timeId)) {
446                        passYourWay = true;
447
448                        try {
449                                g.stepBegins(step);
450                        } finally {
451                                passYourWay = false;
452                        }
453
454                        sendStepBegins(sourceId, timeId, step);
455                }
456        }
457
458        @Override
459        public String toString() {
460                return String.format("GraphListeners of %s.%s", g.getClass()
461                                .getSimpleName(), g.getId());
462        }
463}