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