]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/FlagClassFactory.java
Bringing layers back to life
[simantics/platform.git] / bundles / org.simantics.diagram / src / org / simantics / diagram / adapter / FlagClassFactory.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.diagram.adapter;
13
14 import java.awt.Font;
15 import java.awt.Shape;
16 import java.awt.geom.AffineTransform;
17 import java.awt.geom.Rectangle2D;
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.Collections;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.regex.Pattern;
24 import java.util.regex.PatternSyntaxException;
25
26 import org.simantics.databoard.Bindings;
27 import org.simantics.databoard.binding.error.RuntimeBindingConstructionException;
28 import org.simantics.databoard.util.Bean;
29 import org.simantics.datatypes.literal.RGB;
30 import org.simantics.db.AsyncReadGraph;
31 import org.simantics.db.ReadGraph;
32 import org.simantics.db.Resource;
33 import org.simantics.db.Session;
34 import org.simantics.db.WriteGraph;
35 import org.simantics.db.common.procedure.adapter.TransientCacheListener;
36 import org.simantics.db.common.procedure.guarded.GuardedAsyncProcedureWrapper;
37 import org.simantics.db.common.request.ResourceRead;
38 import org.simantics.db.common.request.TernaryRead;
39 import org.simantics.db.common.request.WriteRequest;
40 import org.simantics.db.exception.DatabaseException;
41 import org.simantics.db.layer0.variable.Variable;
42 import org.simantics.db.layer0.variable.Variables;
43 import org.simantics.db.procedure.AsyncProcedure;
44 import org.simantics.diagram.content.ResourceTerminal;
45 import org.simantics.diagram.flag.AbstractFlagType;
46 import org.simantics.diagram.flag.BasicFlagType;
47 import org.simantics.diagram.flag.FlagSceneGraph;
48 import org.simantics.diagram.flag.FlagUtil;
49 import org.simantics.diagram.flag.IFlagType;
50 import org.simantics.diagram.flag.IFlagType.FlagInfo;
51 import org.simantics.diagram.flag.IFlagTypeReader;
52 import org.simantics.diagram.function.All;
53 import org.simantics.diagram.function.PredefinedVariables;
54 import org.simantics.diagram.query.DiagramRequests;
55 import org.simantics.diagram.query.FlagTables;
56 import org.simantics.diagram.query.FlagTypeFilter;
57 import org.simantics.diagram.query.FlagTypeFilters;
58 import org.simantics.diagram.query.FlagTypeVisual;
59 import org.simantics.diagram.query.FlagTypeVisuals;
60 import org.simantics.diagram.stubs.DiagramResource;
61 import org.simantics.diagram.synchronization.CompositeHintSynchronizer;
62 import org.simantics.diagram.synchronization.IHintSynchronizer;
63 import org.simantics.diagram.synchronization.SynchronizationHints;
64 import org.simantics.diagram.synchronization.graph.DiagramGraphUtil;
65 import org.simantics.diagram.synchronization.graph.FlagSynchronizer;
66 import org.simantics.diagram.synchronization.graph.TransformSynchronizer;
67 import org.simantics.diagram.ui.DiagramModelHints;
68 import org.simantics.g2d.canvas.ICanvasContext;
69 import org.simantics.g2d.diagram.IDiagram;
70 import org.simantics.g2d.diagram.handler.Topology.Terminal;
71 import org.simantics.g2d.element.ElementClass;
72 import org.simantics.g2d.element.ElementUtils;
73 import org.simantics.g2d.element.IElement;
74 import org.simantics.g2d.element.handler.TextEditor;
75 import org.simantics.g2d.element.handler.impl.StaticObjectAdapter;
76 import org.simantics.g2d.elementclass.FlagClass;
77 import org.simantics.g2d.elementclass.FlagClass.Mode;
78 import org.simantics.g2d.elementclass.FlagHandler;
79 import org.simantics.g2d.utils.Alignment;
80 import org.simantics.g2d.utils.geom.DirectionSet;
81 import org.simantics.layer0.Layer0;
82 import org.simantics.modeling.ModelingResources;
83 import org.simantics.modeling.template2d.ontology.Template2dResource;
84 import org.simantics.structural2.modelingRules.IModelingRules;
85 import org.simantics.utils.ui.ErrorLogger;
86
87 /**
88  * @author Tuukka Lehtonen
89  */
90 public class FlagClassFactory extends SyncElementFactory {
91
92     private static final Bean[] NO_BEANS = {};
93
94     private static final IHintSynchronizer HINT_SYNCHRONIZER = new CompositeHintSynchronizer(FlagSynchronizer.INSTANCE, TransformSynchronizer.INSTANCE);
95
96     public static ElementClass createFlagClass(Resource elementClass, Resource terminalResource) {
97         Terminal terminal = new ResourceTerminal(terminalResource, new AffineTransform(), DirectionSet.ANY);
98         return FlagClass.create(terminal, FlagSceneGraph.INSTANCE).newClassWith(new StaticObjectAdapter(elementClass));
99     }
100
101     @Override
102     public void create(AsyncReadGraph graph, ICanvasContext canvas, IDiagram diagram, Resource elementType, AsyncProcedure<ElementClass> procedure) {
103         DiagramResource DIA = graph.getService(DiagramResource.class);
104         procedure.execute(graph, createFlagClass(DIA.Flag, DIA.Flag_Terminal));
105     }
106
107     @Override
108     public void load(AsyncReadGraph graph, final ICanvasContext canvas, final IDiagram diagram,
109             final Resource elementResource, final IElement element, final AsyncProcedure<IElement> procedure) {
110         GuardedAsyncProcedureWrapper<IElement> guard = new GuardedAsyncProcedureWrapper<IElement>(procedure, 2);
111         super.load(graph, canvas, diagram, elementResource, element, guard);
112         ElementFactoryUtil.loadLayersForElement(graph, diagram, element, elementResource, guard);
113     }
114
115     @Override
116     public void load(ReadGraph g, ICanvasContext canvas, IDiagram diagram, Resource flag, IElement e) throws DatabaseException {
117         Layer0 l0 = g.getService(Layer0.class);
118         DiagramResource dr = g.getService(DiagramResource.class);
119
120         ElementClass ec = e.getElementClass();
121         final FlagHandler fh = ec.getSingleItem(FlagHandler.class);
122
123         fh.connectData(e, flag, FlagUtil.getPossibleCounterpart(g, flag));
124         fh.setExternal(e, FlagUtil.isExternal(g, flag));
125
126         TextEditor ed = ec.getAtMostOneItemOfClass(TextEditor.class);
127         if (ed != null) {
128             final Session session = g.getSession();
129             ed.setModifier(e, new TextEditor.Modifier() {
130                 @Override
131                 public String getValue(IElement element) {
132                     String s = ElementUtils.getText(element);
133                     return s != null ? s : "";
134                 }
135
136                 @Override
137                 public String isValid(IElement element, String text) {
138                     return null;
139                 }
140
141                 @Override
142                 public void modify(final IElement element, final String text) {
143                     final Resource flag = (Resource) ElementUtils.getObject(element);
144                     try {
145                         session.syncRequest(new WriteRequest() {
146                             @Override
147                             public void perform(WriteGraph graph) throws DatabaseException {
148                                 Layer0 l0 = Layer0.getInstance(graph);
149                                 DiagramGraphUtil.setRelatedValue(graph, flag, l0.HasLabel, l0.String, text, Bindings.STRING);
150                                 Resource otherFlag = FlagUtil.getPossibleCounterpart(graph, flag);
151                                 if (otherFlag != null)
152                                     DiagramGraphUtil.setRelatedValue(graph, otherFlag, l0.HasLabel, l0.String, text, Bindings.STRING);
153                             }
154                         });
155                     } catch (DatabaseException e) {
156                         ErrorLogger.defaultLogError("Flag label editing failed, see exception for details.", e);
157                     }
158                 }
159             });
160         }
161
162         Resource diagramRuntime = diagram.getHint(DiagramModelHints.KEY_DIAGRAM_RUNTIME_RESOURCE);
163         AffineTransform at = DiagramGraphUtil.getDynamicAffineTransform(g, diagramRuntime, flag);
164         ElementUtils.setTransform(e, at);
165
166         String label = g.getPossibleRelatedValue(flag, l0.HasLabel);
167         if (label == null)
168             label = "";
169         ElementUtils.setText(e, label);
170
171         boolean shapeIsSet = false;
172         boolean flagTextIsSet = false;
173         boolean flagTypeIsSet = false;
174         boolean textAreaIsSet = false;
175
176         // Defaults
177         e.setHint(FlagClass.KEY_TEXT_HORIZONTAL_ALIGN, Alignment.LEADING);
178         e.setHint(FlagClass.KEY_TEXT_VERTICAL_ALIGN, Alignment.CENTER);
179
180         IModelingRules modelingRules = diagram.getHint(DiagramModelHints.KEY_MODELING_RULES);
181         if (modelingRules != null) {
182             Resource connectionType = DiagramGraphUtil.getConnectionTypeForFlag(g, flag);
183             IFlagTypeReader ftr = null;
184             if (connectionType != null) {
185                 //System.out.println("FLAG " + NameUtils.getSafeName(g, flag) + ", CONNECTION TYPE " + NameUtils.getSafeName(g, connectionType));
186                 ftr = g.getPossibleAdapter(connectionType, IFlagTypeReader.class);
187             }
188             if (ftr == null) {
189                 //System.out.println("FLAG " + NameUtils.getSafeName(g, flag) + ", NO CONNECTION TYPE");
190                 ftr = g.getPossibleAdapter(flag, IFlagTypeReader.class);
191             }
192
193             if (ftr != null) {
194                 IFlagType ft = ftr.read(g, flag, modelingRules);
195
196                 FlagInfo info = ft.getInfo(g, canvas);
197
198                 Shape shape = info.getShape();
199                 if (shape != null) {
200                     e.setHint(FlagClass.KEY_SHAPE, shape);
201                     shapeIsSet = true;
202                 }
203
204                 FlagClass.Type type = info.getType();
205                 if (type != null) {
206                     e.setHint(FlagClass.KEY_FLAG_TYPE, type);
207                     flagTypeIsSet = true;
208                 }
209
210                 String[] flagText = info.getText();
211                 if (flagText != null) {
212                     e.setHint(FlagClass.KEY_FLAG_TEXT, flagText);
213                     flagTextIsSet = true;
214                 }
215                 
216                 Font flagFont = info.getFont();
217                 if(flagFont != null) {
218                     e.setHint(FlagClass.KEY_FLAG_FONT, flagFont);
219                 }
220
221                 if (info.getTextArea() != null) {
222                     e.setHint(FlagClass.KEY_FLAG_TEXT_AREA, info.getTextArea());
223                     textAreaIsSet = true;
224                 }
225
226                 if (info.getHorizontalAlignment() != null)
227                     e.setHint(FlagClass.KEY_TEXT_HORIZONTAL_ALIGN, info.getHorizontalAlignment());
228                 if (info.getVerticalAlignment() != null)
229                     e.setHint(FlagClass.KEY_TEXT_VERTICAL_ALIGN, info.getVerticalAlignment());
230             }
231         }
232
233         if (!flagTypeIsSet)
234             // Fall back to reading flag type from a property.
235             e.setHint(FlagClass.KEY_FLAG_TYPE, DiagramGraphUtil.toFlagType(dr, g.getPossibleObject(flag, dr.HasFlagType), FlagClass.Type.In));
236         if (!flagTextIsSet)
237 //            e.setHint(FlagClass.KEY_FLAG_TEXT, new String[] { label });
238             e.setHint(FlagClass.KEY_FLAG_TEXT, g.syncRequest(DiagramRequests.getFlagText(flag)));
239         if (!textAreaIsSet) {
240             FlagClass.Type type = e.getHint(FlagClass.KEY_FLAG_TYPE);
241             Mode mode = AbstractFlagType.getMode(g, flag);
242             e.setHint(FlagClass.KEY_FLAG_TEXT_AREA, BasicFlagType.getArea(type, mode));
243         }
244         if (!shapeIsSet) {
245             FlagClass.Type type = e.getHint(FlagClass.KEY_FLAG_TYPE);
246             Mode mode = AbstractFlagType.getMode(g, flag);
247             e.setHint(FlagClass.KEY_SHAPE, BasicFlagType.getShape(type, mode));
248         }
249
250         e.setHint(SynchronizationHints.HINT_SYNCHRONIZER, HINT_SYNCHRONIZER);
251         e.setHint(FlagSceneGraph.KEY_FLAG_VISUALS, NO_BEANS);
252
253         DiagramResource DIA = DiagramResource.getInstance(g);
254         Layer0 L0 = Layer0.getInstance(g);
255
256         Resource template = diagramRuntime != null ? All.getTemplate(g, diagramRuntime) : null;
257         Resource flagTable = getFlagTable(g, template, flag);
258
259         if (template != null && flagTable != null) {
260
261             Resource flagTypeVisual = getVisualOfFlag(g, template, flagTable, flag);
262             if (flagTypeVisual != null) {
263                 Template2dResource TEMPLATE2D = Template2dResource.getInstance(g);
264                 float tableWidth = g.getRelatedValue(flagTable, TEMPLATE2D.FlagTable_HasWidth, Bindings.FLOAT);
265                 Resource align = g.getPossibleObject(flagTable, TEMPLATE2D.FlagTable_HasAlignment);
266                 float height = g.getRelatedValue(flagTable, TEMPLATE2D.FlagTable_HasRowHeigth, Bindings.FLOAT);
267                 float halfHeight = height / 2;
268                 float horizontalOffset = tableWidth;
269
270                 if (align != null) {
271                     if (align.equals(TEMPLATE2D.FlagTable_Alignment_Left)) {
272                         horizontalOffset = 0.0f;
273                     } else if (align.equals(TEMPLATE2D.FlagTable_Alignment_Right)) {
274                         tableWidth = -tableWidth;
275                         horizontalOffset = -horizontalOffset;
276                     }
277                 }
278
279                 Collection<Resource> monitorsAndTexts = g.getObjects(flagTypeVisual, L0.ConsistsOf);
280                 List<Bean> flagVisuals = Collections.emptyList(); 
281                 if (!monitorsAndTexts.isEmpty()) {
282                     flagVisuals = new ArrayList<Bean>(monitorsAndTexts.size());
283
284                     ModelingResources MOD = ModelingResources.getInstance(g);
285                     Resource diagramResource = diagram.getHint(DiagramModelHints.KEY_DIAGRAM_RESOURCE);
286                     Resource compositeResource = g.getSingleObject(diagramResource, MOD.DiagramToComposite);
287                     Variable compositeVariable = Variables.getVariable(g, compositeResource);
288
289                     for (Resource visual : monitorsAndTexts) {
290                         if (!acceptVisual(g, flag, visual))
291                             continue;
292
293                         if (g.isInstanceOf(visual, DIA.Scenegraph_Monitor)) {
294                             FlagTextInfo i = g.syncRequest(new ReadFlagTextInfo(visual), TransientCacheListener.<FlagTextInfo>instance());
295                             FlagTextInfo monitorInfo = (FlagTextInfo) i.clone();
296                             if (monitorInfo.transform != null)
297                                 monitorInfo.transform[4] += horizontalOffset;
298
299                             String path = g.getRelatedValue(visual, DIA.Scenegraph_Monitor_reference, Bindings.STRING);
300                             String value = "";
301                             if (path != null && path.length() > 0) {
302                                 value = evaluatePath(g,flag,path);
303                             }
304                             monitorInfo.text = value;
305                             monitorInfo.id = Long.toString(visual.getResourceId());
306
307                             flagVisuals.add(monitorInfo);
308                         } else if (g.isInstanceOf(visual, DIA.Scenegraph_Text)) {
309                             FlagTextInfo i = g.syncRequest(new ReadFlagTextInfo(visual), TransientCacheListener.<FlagTextInfo>instance());
310                             FlagTextInfo info = (FlagTextInfo) i.clone();
311                             if (info.transform != null)
312                                 info.transform[4] += horizontalOffset;
313
314                             String path = g.getRelatedValue(visual, DIA.Scenegraph_Text_text, Bindings.STRING);
315                             if (path != null && path.length() > 0) {
316                                 info.text = path;
317                             }
318                             info.id = Long.toString(visual.getResourceId());
319
320                             flagVisuals.add(info);
321                         } else if (g.isInstanceOf(visual, DIA.Scenegraph_SVGImage)) {
322                             SVGImageInfo info = g.syncRequest(new ReadSVGImageInfo(visual, compositeResource, compositeVariable), TransientCacheListener.<SVGImageInfo>instance());
323                             flagVisuals.add(info);
324                         }
325                     }
326                 }
327
328                 if (flagVisuals.size() > 0) {
329                     // Make sure that the flag shape is set to something that
330                     // should contain the flag visual to make selection borders
331                     // work properly.
332                     Rectangle2D newShape = new Rectangle2D.Double();
333                     newShape.setFrameFromDiagonal(0, -halfHeight, tableWidth, halfHeight);
334                     e.setHint(FlagClass.KEY_SHAPE, newShape);
335                     e.setHint(FlagSceneGraph.KEY_FLAG_VISUALS, flagVisuals.toArray(NO_BEANS));
336                 }
337             }
338         }
339     }
340
341     private static String evaluatePath(ReadGraph graph, Resource resource, String path) throws DatabaseException{
342         Variable resourceVariable = Variables.getPossibleVariable(graph, resource);
343         if (resourceVariable == null)
344             return "";
345         return evaluatePath(graph, resource, resourceVariable, path);
346     }
347
348     private static String evaluatePath(ReadGraph graph, Resource resource, Variable resourceVariable, String path) throws DatabaseException{
349         PredefinedVariables vars = PredefinedVariables.getInstance();
350         Variable property = vars.getVariable(graph, path, resource, resourceVariable);
351         if (property == null)
352             return "";
353         Object value = property.getPossibleValue(graph);
354         if (value == null || !(value instanceof String))
355             return "";
356         return value.toString();
357     }
358
359     static class ReadSVGImageInfo extends TernaryRead<Resource, Resource, Variable, SVGImageInfo> {
360
361         public ReadSVGImageInfo(Resource svgImageNode, Resource composite, Variable compositeVariable) {
362             super(svgImageNode, composite, compositeVariable);
363         }
364
365         @Override
366         public SVGImageInfo perform(ReadGraph graph) throws DatabaseException {
367             SVGImageInfo info = new SVGImageInfo();
368             DiagramResource DIA = DiagramResource.getInstance(graph);
369             info.id = Long.toString(parameter.getResourceId());
370             Resource document = graph.getPossibleObject(parameter, DIA.Scenegraph_SVGImage_document);
371             if (document != null) {
372                 Template2dResource TMPL = Template2dResource.getInstance(graph);
373                 String path = graph.getPossibleRelatedValue(document, TMPL.Profiles_VariableReference_path, Bindings.STRING);
374                 if (path != null) {
375                     String svg = evaluatePath(graph, parameter2, parameter3, path);
376                     if (svg != null && !svg.isEmpty())
377                         info.svgDocument = svg;
378                     //System.out.println("svgDocument: " + info.svgDocument);
379                 }
380             }
381             info.transform = graph.getPossibleRelatedValue(parameter, DIA.Scenegraph_SVGImage_transform, Bindings.DOUBLE_ARRAY);
382             return info;
383         }
384
385     }
386
387     static class ReadFlagTextInfo extends ResourceRead<FlagTextInfo> {
388
389         public ReadFlagTextInfo(Resource textNode) {
390             super(textNode);
391         }
392
393         @Override
394         public FlagTextInfo perform(ReadGraph graph) throws DatabaseException {
395             return createTextInfo(graph, resource);
396         }
397
398     }
399
400     /**
401      * @param g
402      * @param visual
403      * @return
404      * @throws DatabaseException
405      * @throws RuntimeBindingConstructionException
406      */
407     private static FlagTextInfo createTextInfo(ReadGraph g, Resource visual) throws DatabaseException {
408         DiagramResource DIA = DiagramResource.getInstance(g);
409         //Template2d TEMPLATE2D = Template2d.getInstance(g);
410         //Layer0 L0 = Layer0.getInstance(g);
411
412         FlagTextInfo info = new FlagTextInfo();
413         info.id = Long.toString(visual.getResourceId());
414
415         info.font = g.getPossibleRelatedValue2(visual, DIA.Scenegraph_AbstractText_font, Bindings.getBindingUnchecked(Font.class));
416         info.color = g.getPossibleRelatedValue2(visual, DIA.Scenegraph_AbstractText_color, RGB.Integer.BINDING/*Bindings.getBindingUnchecked(RGB.Integer.class)*/);
417         info.borderColor = g.getPossibleRelatedValue2(visual, DIA.Scenegraph_AbstractText_borderColor, RGB.Integer.BINDING/*Bindings.getBindingUnchecked(RGB.Integer.class)*/);
418         info.backgroundColor = g.getPossibleRelatedValue2(visual, DIA.Scenegraph_AbstractText_backgroundColor, RGB.Integer.BINDING/*Bindings.getBindingUnchecked(RGB.Integer.class)*/);
419         Float width = g.getPossibleRelatedValue2(visual, DIA.Scenegraph_AbstractText_width, Bindings.getBindingUnchecked(Float.class));
420         if (width != null)
421             info.width = width;
422
423         Float borderWidth = g.getPossibleRelatedValue2(visual, DIA.Scenegraph_AbstractText_borderWidth, Bindings.getBindingUnchecked(Float.class));
424         if (borderWidth != null)
425             info.borderWidth = borderWidth;
426
427         Boolean wrapText = g.getRelatedValue2(visual, DIA.Scenegraph_AbstractText_wrapText, Bindings.BOOLEAN);
428         if (wrapText != null)
429             info.wrapText = wrapText; 
430
431         info.hAlignment = Alignment.LEADING;
432         Byte hAlignment = g.getPossibleRelatedValue2(visual, DIA.Scenegraph_AbstractText_horizontalAlignment, Bindings.BYTE);
433         if (hAlignment != null) {
434             if (hAlignment == 1)
435                 info.hAlignment = Alignment.TRAILING;
436             else if (hAlignment == 2)
437                 info.hAlignment = Alignment.CENTER;
438         }
439
440         info.vAlignment = Alignment.LEADING;
441         Byte vAlignment = g.getPossibleRelatedValue2(visual, DIA.Scenegraph_AbstractText_verticalAlignment, Bindings.BYTE);
442         if (vAlignment != null) {
443             if (vAlignment == 1)
444                 info.vAlignment = Alignment.TRAILING;
445             else if (vAlignment == 2)
446                 info.vAlignment = Alignment.CENTER;
447             else if (vAlignment == 3)
448                 info.vAlignment = Alignment.BASELINE;
449         }
450
451         info.transform = g.getPossibleRelatedValue2(visual, DIA.Scenegraph_AbstractText_transform, Bindings.getBindingUnchecked(double[].class));
452         return info;
453     }
454
455     private static Resource getFlagTable(ReadGraph g, Resource template, Resource flag) throws DatabaseException {
456         if (template == null || flag == null)
457             return null;
458
459         DiagramResource DIA = DiagramResource.getInstance(g);
460         String tableName = g.getPossibleRelatedValue(flag, DIA.Flag_HasIOTableBinding, Bindings.STRING);
461         if (tableName == null)
462             return null;
463
464         Map<String, Resource> flagTables = g.syncRequest(new FlagTables(template), TransientCacheListener.<Map<String, Resource>>instance());
465         return flagTables.get(tableName);
466     }
467
468     private Resource getVisualOfFlag(ReadGraph g, Resource template, Resource flagTable, Resource flag) throws DatabaseException {
469         if (template == null || flagTable == null || flag == null)
470             return null;
471
472         // First make sure that there are possible visuals.
473         // There's no point in proceeding if no visuals exist.
474         List<FlagTypeVisual> flagTypeVisuals = g.syncRequest( new FlagTypeVisuals(flagTable),
475                 TransientCacheListener.<List<FlagTypeVisual>>instance());
476         if (flagTypeVisuals == null || flagTypeVisuals.isEmpty())
477             return null;
478
479         Variable flagVariable = Variables.getPossibleVariable(g, flag);
480         if (flagVariable == null)
481             return null;
482
483         for (FlagTypeVisual visual : flagTypeVisuals) {
484             Resource visualComposite = visual.getVisualComposite();
485
486             String filterReference = visual.getFilteredPropertyReference();
487             if (filterReference == null || filterReference.isEmpty())
488                 return visualComposite;
489
490             String filterPattern = visual.getFilterPattern();
491             if (filterPattern == null || filterPattern.isEmpty())
492                 return visualComposite;
493
494             String value = evaluatePath(g, flag, flagVariable, filterReference);
495             if (value == null)
496                 return visualComposite;
497
498             try {
499                 if (!Pattern.matches(filterPattern, value)) {
500                     // filter is defined but property don't match
501                     continue;
502                 }
503             } catch (PatternSyntaxException ex) {
504                 ErrorLogger.defaultLogError(ex);
505                 continue;
506             }
507
508             return visualComposite;
509         }
510
511         return null;
512     }
513
514     /**
515      * @param graph
516      * @param flag the flag to which to apply the filter reference paths
517      * @param visual the visual to look for filters from
518      * @return <code>true</code> if filter passes, <code>false</code> if not
519      * @throws DatabaseException
520      */
521     private boolean acceptVisual(ReadGraph graph, Resource flag, Resource visual) throws DatabaseException {
522         List<FlagTypeFilter> filters = graph.syncRequest(new FlagTypeFilters(visual),
523                 TransientCacheListener.<List<FlagTypeFilter>>instance());
524         if (filters.isEmpty())
525             return true;
526
527         Variable flagVariable = Variables.getPossibleVariable(graph, flag);
528         if (flagVariable == null)
529             return false;
530
531         for (FlagTypeFilter filter : filters) {
532             String reference = filter.getReference();
533             if (reference == null || reference.isEmpty())
534                 continue;
535
536             String pattern = filter.getPattern();
537             if (pattern == null || pattern.isEmpty())
538                 continue;
539
540             String value = evaluatePath(graph, flag, flagVariable, reference);
541             if (value == null)
542                 continue;
543
544             try {
545                 if (Pattern.matches(pattern, value) == filter.isMatchRequired()) {
546                     return true;
547                 }
548             } catch (PatternSyntaxException ex) {
549                 ErrorLogger.defaultLogError(ex);
550                 continue;
551             }
552         }
553
554         return false;
555     }
556
557 }