Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.swing / org.gvsig.fmap.dal.swing.impl / src / main / java / org / gvsig / fmap / dal / swing / impl / searchpanel / SearchConditionFieldController.java @ 47784

History | View | Annotate | Download (82.2 KB)

1
package org.gvsig.fmap.dal.swing.impl.searchpanel;
2

    
3
import java.awt.Cursor;
4
import java.awt.Dimension;
5
import java.awt.event.ActionEvent;
6
import java.awt.event.ItemEvent;
7
import java.awt.event.ItemListener;
8
import java.awt.event.MouseAdapter;
9
import java.awt.event.MouseEvent;
10
import java.text.DateFormat;
11
import java.util.ArrayList;
12
import java.util.Arrays;
13
import java.util.Collections;
14
import java.util.Comparator;
15
import java.util.Date;
16
import java.util.HashMap;
17
import java.util.Iterator;
18
import java.util.List;
19
import java.util.Locale;
20
import java.util.Map;
21
import java.util.Objects;
22
import java.util.function.Supplier;
23
import javax.json.JsonArray;
24
import javax.json.JsonObject;
25
import javax.swing.ComboBoxModel;
26
import javax.swing.DefaultComboBoxModel;
27
import javax.swing.ImageIcon;
28
import javax.swing.JButton;
29
import javax.swing.JComboBox;
30
import javax.swing.JLabel;
31
import javax.swing.JOptionPane;
32
import javax.swing.JTextField;
33
import javax.swing.SwingUtilities;
34
import javax.swing.text.JTextComponent;
35
import org.apache.commons.lang3.StringUtils;
36
import org.apache.commons.lang3.mutable.MutableBoolean;
37
import org.cresques.cts.IProjection;
38
import org.gvsig.expressionevaluator.ExpressionBuilder;
39
import org.gvsig.expressionevaluator.GeometryExpressionBuilder;
40
import org.gvsig.fmap.dal.DALLocator;
41
import org.gvsig.fmap.dal.DataManager;
42
import org.gvsig.fmap.dal.DataStore;
43
import org.gvsig.fmap.dal.DataTypes;
44
import org.gvsig.fmap.dal.SQLBuilder;
45
import org.gvsig.fmap.dal.StoresRepository;
46
import org.gvsig.fmap.dal.complements.Search;
47
import org.gvsig.fmap.dal.exception.DataException;
48
import org.gvsig.fmap.dal.expressionevaluator.DALExpressionBuilder;
49
import org.gvsig.fmap.dal.feature.Feature;
50
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
51
import org.gvsig.fmap.dal.feature.FeatureQuery;
52
import org.gvsig.fmap.dal.feature.FeatureReference;
53
import org.gvsig.fmap.dal.feature.FeatureSet;
54
import org.gvsig.fmap.dal.feature.FeatureStore;
55
import org.gvsig.fmap.dal.feature.FeatureType;
56
import org.gvsig.fmap.dal.feature.ForeingKey;
57
import org.gvsig.fmap.dal.swing.DALSwingLocator;
58
import org.gvsig.fmap.dal.swing.DataSwingManager;
59
import org.gvsig.fmap.dal.swing.impl.featuretype.DefaultFeatureAttributeSelectionPanel;
60
import static org.gvsig.fmap.dal.swing.impl.searchpanel.SearchConditionPanelSimplified.PANEL_NAME;
61
import static org.gvsig.fmap.dal.swing.searchpanel.FeatureStoreSearchPanel.NOT_HANDLE_NULL;
62
import static org.gvsig.fmap.dal.swing.searchpanel.FeatureStoreSearchPanel.NULL_AS_FALSE;
63
import static org.gvsig.fmap.dal.swing.searchpanel.FeatureStoreSearchPanel.NULL_AS_TRUE;
64
import org.gvsig.fmap.dal.swing.searchpanel.SearchParameters;
65
import org.gvsig.fmap.geom.Geometry;
66
import org.gvsig.fmap.geom.GeometryUtils;
67
import org.gvsig.fmap.geom.primitive.Envelope;
68
import org.gvsig.json.Json;
69
import org.gvsig.json.JsonArrayBuilder;
70
import org.gvsig.json.JsonObjectBuilder;
71
import org.gvsig.tools.ToolsLocator;
72
import org.gvsig.tools.dataTypes.Coercion;
73
import org.gvsig.tools.dataTypes.CoercionException;
74
import org.gvsig.tools.dataTypes.DataTypeUtils;
75
import org.gvsig.tools.dispose.DisposeUtils;
76
import org.gvsig.tools.dynobject.DynField;
77
import org.gvsig.tools.i18n.I18nManager;
78
import org.gvsig.tools.swing.api.DropDown;
79
import org.gvsig.tools.swing.api.ToolsSwingLocator;
80
import org.gvsig.tools.swing.api.ToolsSwingManager;
81
import org.gvsig.tools.swing.api.pickercontroller.DatePickerController;
82
import org.gvsig.tools.swing.api.threadsafedialogs.ThreadSafeDialogsManager;
83
import org.gvsig.tools.swing.api.windowmanager.Dialog;
84
import org.gvsig.tools.swing.api.windowmanager.WindowManager;
85
import org.gvsig.tools.swing.api.windowmanager.WindowManager_v2;
86
import org.gvsig.tools.swing.icontheme.IconTheme;
87
import org.gvsig.tools.task.CancellableTask;
88
import org.gvsig.tools.util.CompareUtils;
89
import org.gvsig.tools.util.LabeledValue;
90
import org.gvsig.tools.util.LabeledValueImpl;
91
import org.gvsig.tools.visitor.VisitCanceledException;
92
import org.slf4j.Logger;
93
import org.slf4j.LoggerFactory;
94

    
95
/**
96
 *
97
 * @author jjdelcerro
98
 */
99
@SuppressWarnings("UseSpecificCatch")
100
public class SearchConditionFieldController {
101

    
102
    private static final Logger LOGGER = LoggerFactory.getLogger(SearchConditionFieldController.class);
103
    private static final Class LOAD_MORE_ELEMENTS = SearchConditionFieldController.class;
104

    
105
    private static final int MAXLEN_IN_COMBOS = 70;
106

    
107
    /*friend*/ static final String FUNCTION_ISNOTVALID = "IsNotValid";
108
    /*friend*/ static final String FUNCTION_INTERSECTSWITHBBOX = "IntersectsWithBBox";
109
    
110
    /*friend*/ static final int GEOM_OPERAND_MODE_EMPTY = 0;
111
    /*friend*/ static final int GEOM_OPERAND_MODE_CLIPBOARD = 1;
112
    /*friend*/ static final int GEOM_OPERAND_MODE_LAYER_SELECTION = 2;
113
    /*friend*/ static final int GEOM_OPERAND_MODE_CONSTANT = 3;
114
    /*friend*/ static final int GEOM_OPERAND_MODE_CURRENT_BOUNDINGBOX = 4;
115
    
116
    private static final String OPERATOR_CONTAINS = "CONTAINS";
117

    
118
    private class UpdateValueList implements Runnable, CancellableTask {
119

    
120
        private final Field field;
121
        private boolean cancelled;
122

    
123
        public UpdateValueList(Field field) {
124
            this.field = field;
125
        }
126
        
127
        @Override
128
        public void run() {
129
            if (isCancellationRequested()) {
130
                return;
131
            }
132
            final FeatureStore theStore = field.getFeatureStore();
133
            final FeatureQuery query;
134
            query = theStore.createFeatureQuery();
135
            query.addAttributeName(field.getDescriptor().getName());
136
            query.setFilter("");
137
    //        query.getExtraColumns().copyFrom(this.parameters.getQuery().getExtraColumns());
138
            query.setLimit(updateValuesFeaturesLimit);
139
            query.getGroupByColumns().clear();
140
            query.getAggregateFunctions().clear();     
141
            
142
            FeatureSet set = null;
143
            final List<Object> values = new ArrayList<>();
144
            final DefaultComboBoxModel model = new DefaultComboBoxModel();
145
            MutableBoolean canHasMoreElements = new MutableBoolean();
146
            
147
            try {
148
                canHasMoreElements.setFalse();
149
                if (isCancellationRequested()) {
150
                    return;
151
                }
152
                set = theStore.getFeatureSet(query);
153
                if (set.size() >= updateValuesFeaturesLimit) {
154
                    canHasMoreElements.setTrue();
155
                }
156
                final long timeLimit = System.currentTimeMillis() + updateValuesTimeLimit * 1000;
157
                set.accept((Object o) -> {
158
                    if (isCancellationRequested()) {
159
                        throw new VisitCanceledException();
160
                    }
161
                    Object value = ((Feature) o).get(field.getDescriptor().getName());
162
                    if (value != null && !values.contains(value)) {
163
                        values.add(value);
164
                    }
165
                    if (System.currentTimeMillis() > timeLimit) {
166
                        canHasMoreElements.setTrue();
167
                        throw new VisitCanceledException();
168
                    }
169
                    if (values.size() > updateValuesFeaturesLimit) {
170
                        canHasMoreElements.setTrue();
171
                        throw new VisitCanceledException();
172
                    }
173
                });
174
            } catch (VisitCanceledException ex) {
175
                canHasMoreElements.setTrue();
176
            } catch (Exception ex) {
177
                canHasMoreElements.setFalse();
178
                LOGGER.warn("Can't update list of values of '" + field.getLabel() + "'.", ex);
179
            } finally {
180
                DisposeUtils.disposeQuietly(set);
181
            }
182
            if (isCancellationRequested()) {
183
                return;
184
            }
185
            List<LabeledValue> elements = new ArrayList<>();
186
            if (!values.isEmpty()) {
187
                LabeledValue[] availableValues = field.getDescriptor().getAvailableValues();
188
                Map<String, String> availableValuesMap = new HashMap<>();
189
                if (availableValues != null) {
190
                    for (LabeledValue availableValue : availableValues) {
191
                        availableValuesMap.put(
192
                                Objects.toString(availableValue.getValue()),
193
                                availableValue.getLabel()
194
                        );
195
                    }
196
                }
197
                elements.add(new LabeledValueImpl("", null, MAXLEN_IN_COMBOS));
198
                for (Object value : values) {
199
                    String key;
200
                    key = DataTypeUtils.toString(value);
201
                    String label = availableValuesMap.getOrDefault(key, key);
202
                    elements.add(new LabeledValueImpl(label, value, MAXLEN_IN_COMBOS));
203
                }
204
                Comparator comparator = null;
205
                if (availableValues == null) {
206
                    switch (field.getDescriptor().getType()) {
207
                        case DataTypes.DATE:
208
                        case DataTypes.TIME:
209
                        case DataTypes.TIMESTAMP:
210
                            comparator = new CompareUtils.NullSafeComparator() {
211
                                @Override
212
                                public int safeCompare(Object o1, Object o2) {
213
                                    Comparable v1 = (Comparable) ((LabeledValue) o1).getValue();
214
                                    Comparable v2 = (Comparable) ((LabeledValue) o2).getValue();
215
                                    if (v1 == v2) {
216
                                        return 0;
217
                                    }
218
                                    if (v1 == null) {
219
                                        return -1;
220
                                    }
221
                                    if (v2 == null) {
222
                                        return 1;
223
                                    }
224
                                    return v1.compareTo(v2);
225
                                }
226
                            };
227
                    }
228
                }
229
                elements.sort(comparator);
230

    
231
            }
232
            for (LabeledValue element : elements) {
233
                model.addElement(element);
234
            }
235
            if (canHasMoreElements.isTrue()) {
236
                model.addElement(new LabeledValueImpl("...", LOAD_MORE_ELEMENTS));
237
            }
238
            if (isCancellationRequested()) {
239
                return;
240
            }
241
            SwingUtilities.invokeLater(new Runnable() {
242
                @Override
243
                public void run() {
244
                    if (isCancellationRequested()) {
245
                        return;
246
                    }
247
                    setEnabled(false);
248
                    Dimension sz = cboValue.getPreferredSize();
249
                    cboValue.setModel(model);
250
                    cboValue.setPreferredSize(sz);
251
                    if (valueAssigned != null) {
252
                        cboValue.setSelectedItem(valueAssigned);
253
                        valueAssigned = null;
254
                    }
255
                    setEnabled(true);
256
                }
257
            });
258
        }
259

    
260
        @Override
261
        public boolean isCancellationRequested() {
262
            return this.cancelled;
263
        }
264

    
265
        @Override
266
        public void cancelRequest() {
267
            this.cancelled = true;
268
        }
269
        
270
    }
271
    
272
    private static class Field extends LabeledValueImpl<String> {
273

    
274
        FeatureAttributeDescriptor attrdesc;
275
        private final FeatureStore store;
276
        private final int presentationMode;
277
        private final boolean showStoreName;
278
        private final FeatureAttributeDescriptor[] path;
279

    
280
        public Field(FeatureAttributeDescriptor[] path, FeatureStore store, FeatureAttributeDescriptor attrdesc, int presentationMode) {
281
            this(path, store, attrdesc, presentationMode, false);
282
        }
283

    
284
        public Field(
285
                FeatureAttributeDescriptor[] path,
286
                FeatureStore store,
287
                FeatureAttributeDescriptor attrdesc,
288
                int presentationMode,
289
                boolean showStoreName
290
        ) {
291
            super(
292
                    DALSwingLocator.getDataSwingManager().getAttributeDescriptorLabel(attrdesc, store.getName()),
293
                    attrdesc.getName()
294
            );
295
            this.path = path;
296
            this.store = store;
297
            this.attrdesc = attrdesc;
298
            this.presentationMode = presentationMode;
299
            this.showStoreName = showStoreName;
300
        }
301

    
302
        public FeatureAttributeDescriptor[] getPath() {
303
            return this.path;
304
        }
305

    
306
        @Override
307
        public String getLabel() {
308
            DataSwingManager dataSwingManager = DALSwingLocator.getDataSwingManager();
309
            String theLabel;
310
            FeatureAttributeDescriptor parentDescriptor = this.getParentDescriptor();
311
            if( parentDescriptor==null ) {
312
                theLabel = dataSwingManager.getAttributeDescriptorLabel(attrdesc, showStoreName ? store.getName() : null);
313
            } else {
314
                switch (parentDescriptor.getRelationType()) {
315
                    case DynField.RELATION_TYPE_COLLABORATION:
316
                    case DynField.RELATION_TYPE_IDENTITY:
317
                        theLabel = dataSwingManager.getAttributeDescriptorLabel(attrdesc)+" de "+store.getName();
318
                        break; // "_XFieldNameX_of_XTableNameX"
319

    
320
                    case DynField.RELATION_TYPE_AGGREGATE:
321
                    case DynField.RELATION_TYPE_COMPOSITION:
322
                        theLabel = "\u2203 "+store.getName()+" que "+dataSwingManager.getAttributeDescriptorLabel(attrdesc);
323
                        break; // "_With_some_XTableNameX_that_XFieldNameX". U+2203 -> Exsite alguno
324
                    default:
325
                        theLabel = dataSwingManager.getAttributeDescriptorLabel(attrdesc, showStoreName ? store.getName() : null);                        
326
                }
327
            }
328
            switch (this.presentationMode) {
329
                case Search.OrderedAttribute.TYPE_REGURAL:
330
                    break;
331
                case Search.OrderedAttribute.TYPE_FAVORITE:
332
                    theLabel = "<html><b>" + theLabel + "</b></html>";
333
                    break;
334
                case Search.OrderedAttribute.TYPE_RECENT:
335
                    theLabel = "<html><i><b>" + theLabel + "</b></i></html>";
336
                    break;
337
            }
338
            return theLabel;
339
        }
340

    
341
        public FeatureAttributeDescriptor getParentDescriptor() {
342
            int l = this.path.length;
343
            if (l < 2) {
344
                return null;
345
            }
346
            return this.path[l - 2];
347
        }
348

    
349
        public FeatureAttributeDescriptor getDescriptor() {
350
            return this.attrdesc;
351
        }
352

    
353
        public FeatureStore getFeatureStore() {
354
            return this.store;
355
        }
356

    
357
    }
358

    
359
    private FeatureStore store;
360
    private SearchParameters parameters;
361
    private final JLabel lblFields;
362
    private final JLabel lblExtraFields;
363
    private final JLabel lblLogicalOperators;
364
    private final JLabel lblRelationalOperators;
365
    private final JComboBox cboValue;
366
    private final JTextField txtValue;
367
    private final JButton btnValue;
368
    private final JLabel lblNull;
369
    private Object valueAssigned = null;
370

    
371
    private DropDown ddnFields;
372
    private DropDown ddnLogicalOperators;
373
    private DropDown ddnRelationalOperators;
374
    private DropDown ddnNullBehavior;
375

    
376
    private LabeledValue[] relationalOperators;
377
    private LabeledValue[] logicalOperators;
378
    private LabeledValue[] nullBehaviors;
379
    private ArrayList<ImageIcon> nullOperatorsIcons;
380

    
381
    private final int SIZE_ORDERED_ATTRIBUTES = 20;
382
    private DatePickerController dateController = null;
383

    
384
    private int updateValuesTimeLimit;
385
    private int updateValuesFeaturesLimit;
386

    
387
    private UpdateValueList updateValueListTask;
388
    private LabeledValue[] geometryRelationalOperators;
389
    private DefaultComboBoxModel modelRelationalOperators;
390
    private DefaultComboBoxModel modelGeometryRelationalOperators;
391
    
392
    private int geometryOperandMode;
393
    private boolean useBox2dInGeometryOperand = false;
394
    private String geometryOperandStoreId;
395
    private Geometry geometryOperandConstant;
396
    
397
    public SearchConditionFieldController(
398
            SearchParameters parameters,
399
            FeatureStore store,
400
            SearchConditionFieldView view           
401
    ) {
402
        this.parameters = parameters;
403
        this.store = store;
404
        this.lblFields = view.lblFields;
405
        this.lblExtraFields = view.lblExtraFields;
406
        this.lblRelationalOperators = view.lblRelationalOperators;
407
        this.cboValue = view.cboValue;
408
        this.txtValue = view.txtValue;
409
        this.btnValue = view.btnValue;
410
        this.lblNull = view.lblNull;
411
        this.lblLogicalOperators = view.lblLogicalOperators;
412
        this.updateValuesTimeLimit = 60;
413
        this.updateValuesFeaturesLimit = 1000;
414
        this.initComponents();
415
    }
416

    
417
    public boolean isAValidRelationOperator(String name) {
418
        for (LabeledValue relationalOperator : relationalOperators) {
419
            if (StringUtils.equalsIgnoreCase(name, (CharSequence) relationalOperator.getValue())) {
420
                return true;
421
            }
422
        }
423
        return false;
424
    }
425

    
426
    @SuppressWarnings("Convert2Lambda")
427
    private void initComponents() {
428
        try {
429
            I18nManager i18n = ToolsLocator.getI18nManager();
430
            ToolsSwingManager toolsSwingManager = ToolsSwingLocator.getToolsSwingManager();
431

    
432
            relationalOperators = new LabeledValue[]{
433
                new LabeledValueImpl(i18n.getTranslation("_Contains"), OPERATOR_CONTAINS),
434
                new LabeledValueImpl(i18n.getTranslation("_Equals_to"), ExpressionBuilder.OPERATOR_EQ),
435
                new LabeledValueImpl(i18n.getTranslation("_Like_to"), ExpressionBuilder.OPERATOR_ILIKE),
436
                new LabeledValueImpl(i18n.getTranslation("_Not_equals_to"), ExpressionBuilder.OPERATOR_NE),
437
                new LabeledValueImpl(i18n.getTranslation("_Greater_than"), ExpressionBuilder.OPERATOR_GT),
438
                new LabeledValueImpl(i18n.getTranslation("_Greater_or_equal_to"), ExpressionBuilder.OPERATOR_GE),
439
                new LabeledValueImpl(i18n.getTranslation("_Less_than"), ExpressionBuilder.OPERATOR_LT),
440
                new LabeledValueImpl(i18n.getTranslation("_Less_or_equal_to"), ExpressionBuilder.OPERATOR_LE),
441
                new LabeledValueImpl(i18n.getTranslation("_Is_null"), ExpressionBuilder.OPERATOR_IS_NULL),
442
                new LabeledValueImpl(i18n.getTranslation("_Is_not_null"), ExpressionBuilder.OPERATOR_IS_NOT_NULL)
443
            };
444

    
445
            this.geometryRelationalOperators = new LabeledValue[]{
446
                new LabeledValueImpl(i18n.getTranslation("_Is_covered_by"), GeometryExpressionBuilder.FUNCTION_ST_COVEREDBY),
447
                new LabeledValueImpl(i18n.getTranslation("_Covers_to"), GeometryExpressionBuilder.FUNCTION_ST_COVERS),
448
                new LabeledValueImpl(i18n.getTranslation("_Contains_to"), GeometryExpressionBuilder.FUNCTION_ST_CONTAINS),
449
                new LabeledValueImpl(i18n.getTranslation("_Crosses_to"), GeometryExpressionBuilder.FUNCTION_ST_CROSSES),
450
                new LabeledValueImpl(i18n.getTranslation("_Is_disjoint_with"), GeometryExpressionBuilder.FUNCTION_ST_DISJOINT),
451
                new LabeledValueImpl(i18n.getTranslation("_Intersects_with"), GeometryExpressionBuilder.FUNCTION_ST_INTERSECTS),
452
                new LabeledValueImpl(i18n.getTranslation("_Intersects_with_boundingbox"), FUNCTION_INTERSECTSWITHBBOX),
453
//                new LabeledValueImpl(i18n.getTranslation("_Is_closed"), GeometryExpressionBuilder.FUNCTION_ST_ISCLOSED),
454
                new LabeledValueImpl(i18n.getTranslation("_Overlaps_with"), GeometryExpressionBuilder.FUNCTION_ST_OVERLAPS),
455
                new LabeledValueImpl(i18n.getTranslation("_Touches_with"), GeometryExpressionBuilder.FUNCTION_ST_TOUCHES),
456
                new LabeledValueImpl(i18n.getTranslation("_Is_within_of"), GeometryExpressionBuilder.FUNCTION_ST_WITHIN),
457
                new LabeledValueImpl(i18n.getTranslation("_Is_equals_to"), GeometryExpressionBuilder.FUNCTION_ST_EQUALS),
458
                new LabeledValueImpl(i18n.getTranslation("_Is_null"), ExpressionBuilder.OPERATOR_IS_NULL),
459
                new LabeledValueImpl(i18n.getTranslation("_Is_not_null"), ExpressionBuilder.OPERATOR_IS_NOT_NULL),
460
                new LabeledValueImpl(i18n.getTranslation("_Is_valid"), GeometryExpressionBuilder.FUNCTION_ST_ISVALID),
461
                new LabeledValueImpl(i18n.getTranslation("_Is_not_valid"), FUNCTION_ISNOTVALID)
462
            };
463

    
464
            logicalOperators = new LabeledValue[]{
465
                new LabeledValueImpl(i18n.getTranslation("_Or"), ExpressionBuilder.OPERATOR_OR),
466
                new LabeledValueImpl(i18n.getTranslation("_And"), ExpressionBuilder.OPERATOR_AND)
467
            };
468

    
469
            nullBehaviors = new LabeledValue[]{
470
                new LabeledValueImpl(i18n.getTranslation("_Not_handle_null_values"), NOT_HANDLE_NULL),
471
                new LabeledValueImpl(i18n.getTranslation("_Null_values_as_true"), NULL_AS_TRUE),
472
                new LabeledValueImpl(i18n.getTranslation("_Null_values_as_false"), NULL_AS_FALSE)
473
            };
474

    
475
            nullOperatorsIcons = new ArrayList<ImageIcon>();
476
            nullOperatorsIcons.add(ToolsSwingLocator.getIconThemeManager().getCurrent().get("search-nullbehavior-null"));
477
            nullOperatorsIcons.add(ToolsSwingLocator.getIconThemeManager().getCurrent().get("search-nullbehavior-true"));
478
            nullOperatorsIcons.add(ToolsSwingLocator.getIconThemeManager().getCurrent().get("search-nullbehavior-false"));
479

    
480
            this.lblExtraFields.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
481

    
482
            this.ddnFields = toolsSwingManager.createDropDown(lblFields);
483
            this.ddnFields.setVisibleDropdownArrow(false);
484
            this.ddnRelationalOperators = toolsSwingManager.createDropDown(lblRelationalOperators);
485
            this.ddnRelationalOperators.setVisibleDropdownArrow(false);
486
            if (lblLogicalOperators != null) {
487
                this.ddnLogicalOperators = toolsSwingManager.createDropDown(lblLogicalOperators);
488
                this.ddnLogicalOperators.setVisibleDropdownArrow(false);
489
            }
490

    
491
            this.modelRelationalOperators = new DefaultComboBoxModel();
492
            for (LabeledValue op : relationalOperators) {
493
                modelRelationalOperators.addElement(op);
494
            }
495
            this.modelGeometryRelationalOperators = new DefaultComboBoxModel();
496
            for (LabeledValue op : geometryRelationalOperators) {
497
                modelGeometryRelationalOperators.addElement(op);
498
            }
499
            this.ddnRelationalOperators.setModel(modelRelationalOperators);
500
            this.ddnRelationalOperators.addItemListener(new ItemListener() {
501
                @Override
502
                public void itemStateChanged(ItemEvent ie) {
503
                    doUpdateControllerByRelationalOperator();
504
                }
505
            });
506

    
507
            if (this.ddnLogicalOperators != null) {
508
                DefaultComboBoxModel modelLogicalOperators = new DefaultComboBoxModel();
509
                for (LabeledValue op : logicalOperators) {
510
                    modelLogicalOperators.addElement(op);
511
                }
512
                this.ddnLogicalOperators.setModel(modelLogicalOperators);
513
                this.ddnLogicalOperators.setSelectedIndex(1);
514
            }
515

    
516
            this.ddnNullBehavior = toolsSwingManager.createDropDownIcon(lblNull);
517
            this.ddnNullBehavior.setVisibleDropdownArrow(false);
518
            DefaultComboBoxModel modelNullOperators = new DefaultComboBoxModel();
519
            for (LabeledValue op : nullBehaviors) {
520
                modelNullOperators.addElement(op);
521
            }
522
            this.ddnNullBehavior.setModel(modelNullOperators);
523
            this.ddnNullBehavior.setIcons(nullOperatorsIcons);
524
            this.ddnNullBehavior.setSelectedIndex(0);
525
            FeatureType featureType = parameters.getFeatureType(store);
526
            Search search = (Search) ToolsLocator.getComplementsManager().get(
527
                    Search.COMPLEMENT_MANE, featureType
528
            );
529
            List<Search.OrderedAttribute> orderedAttributes = search.getOrderedAttributes(
530
//                    Search.BASIC_TYPES_FILTER,
531
                    Search.BASIC_TYPES_FILTER
532
                        .or((FeatureAttributeDescriptor t) -> t.getType()==DataTypes.GEOMETRY),
533
                    Search.STR_INT_LONG_LABEL_ORDER,
534
                    SIZE_ORDERED_ATTRIBUTES
535
            );
536
            List<ImageIcon> icons = new ArrayList<>();
537
//            DataTypesManager dataTypeManager = ToolsLocator.getDataTypesManager();
538
            IconTheme iconTheme = ToolsSwingLocator.getIconThemeManager().getCurrent();
539
            DefaultComboBoxModel model = new DefaultComboBoxModel();
540
            for (Search.OrderedAttribute attr : orderedAttributes) {
541
                FeatureAttributeDescriptor attrdesc = attr.getDescriptor();
542
                Field field = new Field(
543
                        new FeatureAttributeDescriptor[]{attrdesc},
544
                        this.store,
545
                        attrdesc,
546
                        attr.getType()
547
                );
548
                model.addElement(field);
549
                String iconName = attrdesc.getDataType().getIconName();
550
                if (iconTheme.exists(iconName)) {
551
                    icons.add(iconTheme.get(iconName));
552
                } else {
553
                    icons.add(null);
554
                }
555
            }
556

    
557
            this.ddnFields.setIcons(icons);
558
            this.ddnFields.setModel(model);
559
            this.ddnFields.addItemListener(new ItemListener() {
560
                @Override
561
                public void itemStateChanged(ItemEvent e) {
562
                    if (e.getStateChange() == ItemEvent.SELECTED) {
563
                        doUpdateValuesList();
564
                    }
565

    
566
                }
567
            });
568

    
569
            this.cboValue.addItemListener(new ItemListener() {
570
                @Override
571
                public void itemStateChanged(ItemEvent e) {
572
                    if (e.getStateChange() == ItemEvent.SELECTED) {
573
                        if (cboValue.getSelectedItem() != null && cboValue.getSelectedItem() instanceof LabeledValue) {
574
                            if (Objects.equals(((LabeledValue) cboValue.getSelectedItem()).getValue(), LOAD_MORE_ELEMENTS)) {
575
                                setUpdateValuesLimits(updateValuesTimeLimit + 10, updateValuesFeaturesLimit + 1000);
576
                            }
577
                        }
578
                    }
579
                }
580
            });
581

    
582
            this.lblExtraFields.addMouseListener(new MouseAdapter() {
583
                @Override
584
                public void mouseClicked(MouseEvent e) {
585
                    doSelectMoreFields();
586
                }
587
            });
588
            this.txtValue.setVisible(false);
589
            this.btnValue.setVisible(false);
590
            this.geometryOperandMode = GEOM_OPERAND_MODE_EMPTY;
591
            this.geometryOperandStoreId = null;
592
            this.geometryOperandConstant = null;
593
            this.useBox2dInGeometryOperand = false;
594
            this.btnValue.addActionListener((ActionEvent e) -> {doSelectGeometryOperand(); });
595

    
596
            doUpdateControllerByRelationalOperator();
597
//      clear();
598
        } catch (Exception ex) {
599
            throw new RuntimeException(ex);
600
        }
601
    }
602

    
603
    private void doUpdateControllerByRelationalOperator() {
604
        Object item = ((LabeledValue) ddnRelationalOperators.getSelectedItem()).getValue();
605
        if (ExpressionBuilder.OPERATOR_IS_NULL.equals(item) || ExpressionBuilder.OPERATOR_IS_NOT_NULL.equals(item)) {
606
            lblNull.setEnabled(false);
607
            cboValue.setEnabled(false);
608
            cboValue.setSelectedIndex(-1);
609
        } else {
610
            lblNull.setEnabled(true);
611
            cboValue.setEnabled(true);
612
        }
613
        doUpdateCurrentValue();
614
    }
615

    
616
    private void doUpdateCurrentValue() {
617
        Field field = this.getCurrentField();
618
        if( field!=null ) {
619
            FeatureAttributeDescriptor desc = field.getDescriptor();
620
            int type = desc==null? DataTypes.INT:desc.getType();
621
            switch(type) {
622
                case DataTypes.GEOMETRY:
623
                    this.cboValue.setVisible(false);
624
                    this.txtValue.setVisible(true);
625
                    this.btnValue.setVisible(true);
626
                    switch(this.geometryOperandMode) {
627
                        case GEOM_OPERAND_MODE_CONSTANT:
628
                            if( this.geometryOperandConstant == null ) {
629
                                this.txtValue.setText("");
630
                            } else {
631
                                this.txtValue.setText(Objects.toString(GeometryUtils.toWKT(this.geometryOperandConstant), ""));
632
                            }
633
                            break;
634
                        case GEOM_OPERAND_MODE_LAYER_SELECTION:
635
                            if( this.geometryOperandStoreId!=null ) {
636
                                StoresRepository repo = DALLocator.getDataManager().getStoresRepository();
637
                                this.txtValue.setText(repo.getLabelOrName(this.geometryOperandStoreId));
638
                                break;
639
                            }
640
                            this.geometryOperandMode = GEOM_OPERAND_MODE_CLIPBOARD;
641
                        case GEOM_OPERAND_MODE_CLIPBOARD:
642
                            this.txtValue.setText("Contenido del portapapeles"); // i18n.getTranslation("_Clipboard_content"));
643
                            break;
644
                        case GEOM_OPERAND_MODE_CURRENT_BOUNDINGBOX:
645
                            DataSwingManager dataSwingManager = DALSwingLocator.getDataSwingManager();
646
                            Supplier<Envelope> bbox = dataSwingManager.getCurrentBoundingBox();
647
                            if( bbox!=null ) {
648
                                Envelope env = bbox.get();
649
                                if( env != null && !env.isEmpty() && !env.isCollapsed() ) {
650
                                    this.txtValue.setText(Objects.toString(GeometryUtils.toWKT(env.getGeometry()), ""));
651
                                } else {
652
                                    this.txtValue.setText("");
653
                                }
654
                            } else {
655
                                this.txtValue.setText("");
656
                            }
657
                            break;
658
                    }
659
                    break;
660
                default:
661
                    if( this.txtValue.isVisible() ) {
662
                        this.ddnRelationalOperators.setSelectedIndex(1);
663
                    }
664
                    this.cboValue.setVisible(true);
665
                    this.txtValue.setVisible(false);
666
                    this.btnValue.setVisible(false);
667
            }
668
        }
669
    }
670

    
671
    private FeatureType getFeatureType() {
672
        try {
673
            return this.store.getDefaultFeatureType();
674
        } catch (DataException ex) {
675
            return null;
676
        }
677
    }
678

    
679
    private void doSelectMoreFields() {
680
        DefaultFeatureAttributeSelectionPanel panel = new DefaultFeatureAttributeSelectionPanel(
681
                store, 
682
                parameters.getFeatureType(store),
683
                parameters.getQuery()
684
        );
685
        WindowManager_v2 winManager = (WindowManager_v2) ToolsSwingLocator.getWindowManager();
686
        final Dialog dialog = winManager.createDialog(
687
                panel,
688
                "Select attribute",
689
                null,
690
                WindowManager_v2.BUTTONS_OK_CANCEL
691
        );
692
        dialog.addActionListener((ActionEvent e) -> {
693
            if (dialog.getAction() == WindowManager_v2.BUTTONS_OK) {
694
                doAddAndSelect(
695
                        panel.getSelectedStore(),
696
                        panel.getSelectedAttributeDescriptor(),
697
                        panel.getSelectedPath()
698
                );
699
            }
700
        });
701
        dialog.show(WindowManager.MODE.DIALOG);
702

    
703
    }
704

    
705
    private void doAddAndSelect(FeatureStore theStore, FeatureAttributeDescriptor attrdesc, FeatureAttributeDescriptor[] path) {
706
        ThreadSafeDialogsManager dialogManager = ToolsSwingLocator.getThreadSafeDialogsManager();
707
        I18nManager i18n = ToolsLocator.getI18nManager();
708
        DefaultComboBoxModel<Field> model = (DefaultComboBoxModel) this.ddnFields.getModel();
709
        if (attrdesc == null) {
710
            dialogManager.messageDialog(
711
                    i18n.getTranslation("_It_is_not_supported_to_search_through_this_field") + "\n"
712
                    + i18n.getTranslation("_Field_not_found"),
713
                    "_Warning",
714
                    JOptionPane.WARNING_MESSAGE
715
            );
716
            return;
717
        }
718

    
719
        for (int i = 0; i < model.getSize(); i++) {
720
            Field field = model.getElementAt(i);
721
            FeatureAttributeDescriptor attrdescN = field.getDescriptor();
722
            if (theStore!=null && attrdescN.getStore()!=null && isTheSameStore(theStore, attrdescN.getStore())
723
                    && StringUtils.equalsIgnoreCase(attrdesc.getName(), attrdescN.getName())) {
724
                this.setAttribute(i);
725
                return;
726
            }
727
        }
728
        Field field = new Field(
729
                path,
730
                theStore,
731
                attrdesc,
732
                Search.OrderedAttribute.TYPE_REGURAL,
733
                !isTheSameStore(store, theStore)
734
        );
735
        if (field.getPath().length > 2) {
736
            dialogManager.messageDialog(
737
                    i18n.getTranslation("_It_is_not_supported_to_search_through_this_field") + "\n"
738
                    + i18n.getTranslation("_To_many_links"),
739
                    "_Warning",
740
                    JOptionPane.WARNING_MESSAGE
741
            );
742
            return;
743
        }
744
        FeatureAttributeDescriptor parentDescriptor = field.getParentDescriptor();
745
        if (parentDescriptor != null) {
746
            switch (parentDescriptor.getRelationType()) {
747
                case DynField.RELATION_TYPE_AGGREGATE:
748
                case DynField.RELATION_TYPE_COMPOSITION:
749
                    if (getForeingKeyName(field.getFeatureStore(), this.store) == null) {
750
                        dialogManager.messageDialog(
751
                                "It not supported to search through this field." + "\n"
752
                                + "The link field was not found.",
753
                                "_Warning",
754
                                JOptionPane.WARNING_MESSAGE
755
                        );
756
                        return;
757
                    }
758
                    if (getPrimaryKeyName(this.store) == null) {
759
                        dialogManager.messageDialog(
760
                                "It not supported to search through this field." + "\n"
761
                                + "A simple primary key was not found.",
762
                                "_Warning",
763
                                JOptionPane.WARNING_MESSAGE
764
                        );
765
                        return;
766
                    }
767
            }
768
        }
769
        model.addElement(field);
770
        IconTheme iconTheme = ToolsSwingLocator.getIconThemeManager().getCurrent();
771
        this.ddnFields.getIcons().add(iconTheme.get(attrdesc.getDataType().getIconName()));
772
        this.setAttribute(model.getSize() - 1);
773
    }
774

    
775
    public void clear() {
776
        this.ddnRelationalOperators.setSelectedIndex(0);
777
        if (this.ddnLogicalOperators != null) {
778
            this.ddnLogicalOperators.setSelectedIndex(1);
779
        }
780
        this.cboValue.setSelectedIndex(-1);
781
        this.ddnNullBehavior.setSelectedIndex(0);
782
        this.geometryOperandStoreId = null;
783
        this.geometryOperandMode = GEOM_OPERAND_MODE_EMPTY;
784
        doUpdateControllerByRelationalOperator();
785
    }
786

    
787
    private String lastNameInUpdateValuesList = null;
788
    private int lastUpdateValuesFeaturesLimit = -1;
789
    private int lastUpdateValuesTimeLimit = -1;
790
    
791
    private void doUpdateValuesList() {
792
        final Field field = (Field) this.ddnFields.getSelectedItem();
793
        if (field == null) {
794
            return;
795
        }
796
        FeatureAttributeDescriptor descriptor = field.getDescriptor();
797
        if(StringUtils.equalsIgnoreCase(lastNameInUpdateValuesList, descriptor.getName()) && 
798
                updateValuesFeaturesLimit == lastUpdateValuesFeaturesLimit && 
799
                updateValuesTimeLimit == lastUpdateValuesTimeLimit
800
                ){
801
            return;
802
        }
803
        lastNameInUpdateValuesList = descriptor.getName();
804
        lastUpdateValuesFeaturesLimit = updateValuesFeaturesLimit;
805
        lastUpdateValuesTimeLimit = updateValuesTimeLimit;
806
        
807
        if(this.updateValueListTask != null){
808
            this.updateValueListTask.cancelRequest();
809
        }
810
        Thread updateTask;
811
        switch(descriptor.getType()) {
812
            case DataTypes.GEOMETRY:
813
                this.ddnRelationalOperators.setModel(modelGeometryRelationalOperators);
814
                if( !this.txtValue.isVisible() ) {
815
                    this.ddnRelationalOperators.setSelectedIndex(0);
816
                }
817
                this.cboValue.setVisible(false);
818
                this.txtValue.setVisible(true);
819
                this.btnValue.setVisible(true);
820
                break;
821
            case DataTypes.DATE:
822
                if (this.dateController == null) {
823
                    this.dateController = ToolsSwingLocator.getToolsSwingManager().createDatePickerController(
824
                            (JTextComponent) this.cboValue.getEditor().getEditorComponent(),
825
                            null
826
                    );
827
                }
828
                this.ddnRelationalOperators.setModel(modelRelationalOperators);
829
                if( this.txtValue.isVisible() ) {
830
                    this.ddnRelationalOperators.setSelectedIndex(0);
831
                }
832
                this.cboValue.setVisible(true);
833
                this.txtValue.setVisible(false);
834
                this.btnValue.setVisible(false);
835
                this.updateValueListTask = new UpdateValueList(field);
836
                updateTask = new Thread(updateValueListTask);
837
                updateTask.start();
838
                break;
839
            default:
840
                this.ddnRelationalOperators.setModel(modelRelationalOperators);
841
                if( this.txtValue.isVisible() ) {
842
                    this.ddnRelationalOperators.setSelectedIndex(0);
843
                }
844
                this.cboValue.setVisible(true);
845
                this.txtValue.setVisible(false);
846
                this.btnValue.setVisible(false);
847
                if (this.dateController != null) {
848
                    this.dateController.uninstall();
849
                    this.dateController = null;
850
                }
851
                this.updateValueListTask = new UpdateValueList(field);
852
                updateTask = new Thread(updateValueListTask);
853
                updateTask.start();
854
        }
855
    }
856

    
857
    public void setEnabled(boolean enabled) {
858
        ddnFields.setEnabled(enabled);
859
        if (ddnLogicalOperators != null) {
860
            ddnLogicalOperators.setEnabled(enabled);
861
        }
862
        ddnRelationalOperators.setEnabled(enabled);
863
        lblExtraFields.setEnabled(enabled);
864
        cboValue.setEnabled(enabled);
865
        doUpdateControllerByRelationalOperator();
866
    }
867

    
868
    public String getRelationalOperator() {
869
        LabeledValue<String> op = (LabeledValue) this.ddnRelationalOperators.getSelectedItem();
870
        if (op == null) {
871
            return null;
872
        }
873
        return op.getValue();
874
    }
875

    
876
    public int setRelationalOperator(String name) {
877
        int n = 0;
878
        for (LabeledValue relationalOperator : relationalOperators) {
879
            if (StringUtils.equalsIgnoreCase(name, (CharSequence) relationalOperator.getValue())) {
880
                break;
881
            }
882
            n++;
883
        }
884
        if (this.relationalOperators.length <= n) {
885
            return -1;
886
        }
887
        this.ddnRelationalOperators.setSelectedIndex(n);
888
        doUpdateControllerByRelationalOperator();
889
        return n;
890
    }
891

    
892
    public String getLogicalOperator() {
893
        if (this.ddnLogicalOperators == null) {
894
            return null;
895
        }
896
        LabeledValue<String> rel = (LabeledValue) this.ddnLogicalOperators.getSelectedItem();
897
        if (rel == null) {
898
            return null;
899
        }
900
        return rel.getValue();
901
    }
902

    
903
    public void setLogicalOperator(String operator) {
904
        if (this.ddnLogicalOperators == null) {
905
            return;
906
        }
907
        ComboBoxModel model = this.ddnLogicalOperators.getModel();
908
        for (int i = 0; i < model.getSize(); i++) {
909
            LabeledValue modelValue = (LabeledValue) model.getElementAt(i);
910
            String value = (String) modelValue.getValue();
911
            if (StringUtils.equals(value, operator)) {
912
                this.ddnLogicalOperators.setSelectedIndex(i);
913
                break;
914
            }
915
        }
916
    }
917
    
918
    public Object getValue() {
919
        return this.getValue(true);
920
    }
921

    
922
    public Object getValue(boolean coerce) {
923
        final Field field = (Field) this.ddnFields.getSelectedItem();
924
        if (field == null) {
925
            return null;
926
        }
927
        Object v;
928
        if (this.dateController == null) {
929
            v = this.cboValue.getSelectedItem();
930
        } else {
931
            if(this.dateController.isValid()) {
932
                v = this.dateController.get();
933
            } else {
934
                v = null;
935
            }
936
        }
937
        if (v == null) {
938
            return null;
939
        }
940
        if (v instanceof LabeledValue) {
941
            v = ((LabeledValue) v).getValue();
942
            if (v == null || v == LOAD_MORE_ELEMENTS) {
943
                return null;
944
            }
945
        }
946
        if (v instanceof CharSequence) {
947
            if (StringUtils.isBlank((CharSequence) v)) {
948
                return null;
949
            }
950
        }
951
        if( coerce ) {
952
            Coercion coercion = field.getDescriptor().getDataType().getCoercion();
953
            try {
954
                return coercion.coerce(v);
955
            } catch (CoercionException ex) {
956
                return null;
957
            }
958
        }
959
        return v;
960
        
961
    }
962

    
963
    public void setValue(Object value) {
964
        //this.cboValue.setSelectedItem(value);
965
        SwingUtilities.invokeLater(new Runnable() {
966
            @Override
967
            public void run() {
968
                DefaultComboBoxModel model = (DefaultComboBoxModel) cboValue.getModel();
969
                for (int i = 0; i < model.getSize(); i++) {
970
                    Object item = model.getElementAt(i);
971
                    if (item.equals(value)) {
972
                        cboValue.setSelectedIndex(i);
973
                        valueAssigned = value;
974
                        return;
975
                    }
976
                }
977
                // si no lo encuentra en el modelo lo a?ade
978
                final Field field = (Field) ddnFields.getSelectedItem();
979
                if (field != null) {
980
                    LabeledValue[] availableValues = field.getDescriptor().getAvailableValues();
981
                    Map<String, String> availableValuesMap = new HashMap<>();
982
                    if (availableValues != null) {
983
                        for (LabeledValue availableValue : availableValues) {
984
                            availableValuesMap.put(
985
                                    Objects.toString(availableValue.getValue()),
986
                                    availableValue.getLabel()
987
                            );
988
                        }
989
                    }
990
                    String key;
991
                    if (value instanceof Date) {
992
                        DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault());
993
                        df.setLenient(false);
994
                        key = df.format(value);
995
                    } else {
996
                        key = Objects.toString(value);
997
                    }
998
                    String label = availableValuesMap.getOrDefault(key, key);
999
                    LabeledValueImpl newItem = new LabeledValueImpl(label, value);
1000
                    model.addElement(newItem);
1001
                    cboValue.setSelectedItem(newItem);
1002
                    valueAssigned = newItem;
1003
                }
1004
            }
1005
        });
1006
    }
1007

    
1008
    private Field getCurrentField() {
1009
        final Field field = (Field) this.ddnFields.getSelectedItem();
1010
        return field;
1011
    }
1012

    
1013
    public int setAttribute(String name) {
1014
        ComboBoxModel<Field> model = this.ddnFields.getModel();
1015
        for (int i = 0; i < model.getSize(); i++) {
1016
            Field x = model.getElementAt(i);
1017
            if (StringUtils.equalsIgnoreCase(name, x.getValue())) {
1018
                this.setAttribute(i);
1019
                return i;
1020
            }
1021
        }
1022
        this.setAttribute(-1);
1023
        return -1;
1024
    }
1025

    
1026
    public void setAttribute(int index) {
1027
        try {
1028
            this.ddnFields.setSelectedIndex(index);
1029
        } catch (Exception ex) {
1030
            this.ddnFields.setSelectedIndex(-1);
1031
        }
1032
        doUpdateValuesList();
1033
    }
1034

    
1035
    public int setAttributePath(String[][] pathNames) {
1036
        // [[attributeName, storeName],...]
1037
        try {
1038
            if (pathNames.length == 1) {
1039
                String[] path = pathNames[pathNames.length - 1];
1040
                String name = path[0];
1041
                int index = this.setAttribute(name);
1042
                if (index == -1) {
1043
                    try {
1044
                        FeatureAttributeDescriptor attrDescriptor = store.getDefaultFeatureType().getAttributeDescriptorFromAll(name);
1045
                        if (attrDescriptor == null) {
1046
                            FeatureQuery query = this.parameters.getQuery();
1047
                            if(query != null){
1048
                                attrDescriptor = query.getExtraColumns().get(name);
1049
                            }
1050
                        }
1051
                        if (attrDescriptor == null) {
1052
                            I18nManager i18n = ToolsLocator.getI18nManager();
1053
                            ThreadSafeDialogsManager dialogManager = ToolsSwingLocator.getThreadSafeDialogsManager();
1054
                            dialogManager.messageDialog(
1055
                                    i18n.getTranslation("_It_is_not_supported_to_search_through_this_field") + ":\n " + name + "\n"
1056
                                    + i18n.getTranslation("_Field_not_found_in_this_table"),
1057
                                    "_Warning",
1058
                                    JOptionPane.WARNING_MESSAGE
1059
                            );
1060
                            this.cboValue.setModel(new DefaultComboBoxModel());
1061
                        } else {
1062
                            FeatureAttributeDescriptor[] attributePath = new FeatureAttributeDescriptor[]{attrDescriptor};
1063
                            doAddAndSelect(store, attrDescriptor, attributePath);
1064
                        }
1065
                    } catch (Exception ex) {
1066
                        LOGGER.warn("Not able to set single path into controller", ex);
1067
                        return -1;
1068
                    }
1069
                }
1070
                return index;
1071
            } else {
1072
                ComboBoxModel<Field> model = this.ddnFields.getModel();
1073
                String[] singleArrayPathNameDescriptors = new String[pathNames.length];
1074
                for (int i = 0; i < pathNames.length; i++) {
1075
                    singleArrayPathNameDescriptors[i] = pathNames[i][0];
1076
                }
1077
                // check the drop
1078
                for (int i = 0; i < model.getSize(); i++) {
1079
                    Field x = model.getElementAt(i);
1080
                    String[] arrayDescriptors = new String[x.getPath().length];
1081
                    FeatureAttributeDescriptor[] path = x.getPath();
1082
                    for (int j = 0; j < path.length; j++) {
1083
                        arrayDescriptors[j] = path[j].getName();
1084
                    }
1085
                    if (Arrays.equals(singleArrayPathNameDescriptors, arrayDescriptors)) {
1086
                        this.setAttribute(i);
1087
                        return i;
1088
                    }
1089
                }
1090
                // if not, addit to the drop
1091
                DataManager dataManager = DALLocator.getDataManager();
1092
                String tableName = pathNames[pathNames.length - 1][1]; // del ultimo path, coger el nombre tabla
1093
                FeatureStore theStore = (FeatureStore) dataManager.getStoresRepository().getStore(tableName);
1094
                String attributeName = pathNames[pathNames.length - 1][0]; // del ultimo path, coger el nombre attribute
1095
                if (theStore != null) {
1096
                    FeatureAttributeDescriptor attr;
1097
                    try {
1098
                        attr = theStore.getDefaultFeatureType().getAttributeDescriptor(attributeName);
1099
                        FeatureAttributeDescriptor[] attributePath = new FeatureAttributeDescriptor[2];
1100
                        String firstAttrName = pathNames[0][0];
1101
                        FeatureAttributeDescriptor firstAttr = store.getDefaultFeatureType().getAttributeDescriptor(firstAttrName);
1102
                        attributePath[0] = firstAttr;
1103

    
1104
                        attributePath[1] = attr;
1105
                        doAddAndSelect(theStore, attr, attributePath);
1106
                        return SIZE_ORDERED_ATTRIBUTES - 1;
1107
                    } catch (Exception ex) {
1108
                        LOGGER.warn("Not able to set foreign path into controller", ex);
1109
                    }
1110

    
1111
                }
1112

    
1113
            }
1114
        } catch (Exception ex) {
1115
            LOGGER.warn("Controller not set.", ex);
1116
        }
1117
        this.setAttribute(-1);
1118
        return -1;
1119
    }
1120

    
1121
    private boolean isTheSameStore(DataStore store1, DataStore store2) {
1122
        String store1FullName = store1.getFullName();
1123
        String store2FullName = store2.getFullName();
1124
        return StringUtils.equalsIgnoreCase(store1FullName, store2FullName);
1125
    }
1126

    
1127
    private String getPrimaryKeyName(FeatureStore store) {
1128
        try {
1129
            FeatureAttributeDescriptor[] pk = store.getDefaultFeatureType().getPrimaryKey();
1130
            if (pk == null || pk.length != 1) {
1131
                return null;
1132
            }
1133
            return pk[0].getName();
1134
        } catch (DataException ex) {
1135
            return null;
1136
        }
1137
    }
1138

    
1139
    private String getForeingKeyName(FeatureStore store, FeatureStore foreingStore) {
1140
        try {
1141
            for (FeatureAttributeDescriptor descriptor : store.getDefaultFeatureType()) {
1142
                if (descriptor.isForeingKey()) {
1143
                    ForeingKey foreingKey = descriptor.getForeingKey();
1144
                    if (isTheSameStore(foreingStore, foreingKey.getFeatureStore(null))) {
1145
                        return descriptor.getName();
1146
                    }
1147
                }
1148
            }
1149
        } catch (DataException ex) {
1150
            return null;
1151
        }
1152
        return null;
1153
    }
1154

    
1155
    public boolean isValid(StringBuilder message) {
1156
        try {
1157
            Object value = this.getValue();
1158
            if (value == null) {
1159
                return true;
1160
            }
1161
            Field field = this.getCurrentField();
1162
            if (field == null) {
1163
                return true;
1164
            }
1165
            if (field.getPath().length > 2) {
1166
                message.append("Invalid field '").append(field.getLabel()).append("'.\n");
1167
                return false;
1168
            }
1169
            FeatureAttributeDescriptor descriptor = field.getDescriptor();
1170
            switch (this.getRelationalOperator()) {
1171
                case ExpressionBuilder.OPERATOR_EQ:
1172
                case ExpressionBuilder.OPERATOR_NE:
1173
                case ExpressionBuilder.OPERATOR_GT:
1174
                case ExpressionBuilder.OPERATOR_GE:
1175
                case ExpressionBuilder.OPERATOR_LT:
1176
                case ExpressionBuilder.OPERATOR_LE:
1177
        try {
1178
                    descriptor.getDataType().coerce(value);
1179
                } catch (CoercionException ex) {
1180
                    message.append("Invalid value '")
1181
                            .append(Objects.toString(value))
1182
                            .append("' for field '")
1183
                            .append(descriptor.getLabel())
1184
                            .append("'.");
1185
                    message.append("\n");
1186
                    message.append(ex.getMessage());
1187
                    message.append("\n");
1188
                    return false;
1189
                }
1190
                break;
1191

    
1192
                default:
1193
                case ExpressionBuilder.OPERATOR_ILIKE:
1194
                case OPERATOR_CONTAINS:
1195
                    break;
1196
            }
1197
            return true;
1198
        } catch (Exception ex) {
1199
            message.append("Invalid values '").append(ex.toString());
1200
            return false;
1201
        }
1202
    }
1203

    
1204
    public ExpressionBuilder.Value getFilter() {
1205
        StringBuilder warns = new StringBuilder();
1206
        return this.getFilter(warns);
1207
    }
1208

    
1209
    public ExpressionBuilder.Value getFilter(StringBuilder warnings) {
1210
        ExpressionBuilder.Value filter = null;
1211

    
1212
        Field field = this.getCurrentField();
1213
        if (field == null) {
1214
            return null;
1215
        }
1216
        if (field.getPath().length > 2) {
1217
            // No soportado
1218
            warnings.append("Lookups are only supported on directly related tables.");
1219
            return null;
1220
        }
1221
        DataManager dataManager = DALLocator.getDataManager();
1222
        DALExpressionBuilder builder = dataManager.createDALExpressionBuilder();
1223
        FeatureAttributeDescriptor parentDescriptor = field.getParentDescriptor();
1224
        FeatureAttributeDescriptor descriptor = field.getDescriptor();
1225
        
1226
        switch(descriptor.getType()) {
1227
            case DataTypes.GEOMETRY:
1228
                filter = this.createGeometryFilter(builder, parentDescriptor, descriptor, field, warnings);
1229
                if( filter == null ) {
1230
                    return null;
1231
                }
1232
                filter = builder.expression().group(filter);
1233
                return filter;
1234
            case DataTypes.DATE:
1235
            default:
1236
        }        
1237
        Object value = null;
1238
        ExpressionBuilder.Constant value_constant = null;
1239

    
1240
        String operator = this.getRelationalOperator();
1241
        switch (operator) {
1242
            case ExpressionBuilder.OPERATOR_IS_NULL:
1243
                value = this.getValue();
1244
                filter = getFilterForOperatorNull(parentDescriptor, descriptor, builder, field);
1245
                return filter;
1246
            case ExpressionBuilder.OPERATOR_IS_NOT_NULL:
1247
                value = this.getValue();
1248
                filter = getFilterForOperatorNotNull(parentDescriptor, descriptor, builder, field);
1249
                return filter;
1250
            case ExpressionBuilder.OPERATOR_EQ:
1251
            case ExpressionBuilder.OPERATOR_NE:
1252
            case ExpressionBuilder.OPERATOR_GT:
1253
            case ExpressionBuilder.OPERATOR_GE:
1254
            case ExpressionBuilder.OPERATOR_LT:
1255
            case ExpressionBuilder.OPERATOR_LE:
1256
                value = this.getValue();
1257
                if (value == null ) {
1258
                    return null;
1259
                }
1260
                try {
1261
                    value_constant = builder.expression().constant(
1262
                            descriptor.getDataType().coerce(value)
1263
                    );
1264
                } catch (CoercionException ex) {
1265
                    return null;
1266
                }
1267
                break;
1268

    
1269
            case ExpressionBuilder.OPERATOR_ILIKE:                
1270
                value = this.getValue(false);
1271
                if (value == null ) {
1272
                    return null;
1273
                }
1274
                value_constant = builder.expression().constant(value);
1275
                break;
1276
            default:
1277
            case OPERATOR_CONTAINS:
1278
                value = this.getValue(false);
1279
                if (value == null ) {
1280
                    return null;
1281
                }
1282
                value_constant = builder.expression().constant("%" + value + "%");
1283
                operator = ExpressionBuilder.OPERATOR_ILIKE;
1284
                break;                
1285
        }
1286

    
1287
        ExpressionBuilder.Value fieldOp = null;
1288
        if (parentDescriptor == null) {
1289
            fieldOp = builder.expression().column(this.store.getName(), descriptor.getName());
1290
            if (StringUtils.equalsIgnoreCase(operator, ExpressionBuilder.OPERATOR_ILIKE) && descriptor.getType() != DataTypes.STRING) {
1291
                fieldOp = builder.expression().cast(fieldOp,DataTypes.STRING);
1292
            }
1293

    
1294

    
1295
            // Se busca en campos de la misma tabla.
1296
            filter = builder.expression().binaryOperator(
1297
                    operator,
1298
                    fieldOp,
1299
                    value_constant
1300
            );
1301

    
1302
            ExpressionBuilder.Value nullValue = builder.expression().column(this.store.getName(), descriptor.getName());
1303
            filter = addNullBehavior(builder, filter, nullValue);
1304

    
1305
        } else {
1306
            // Se busca en campos de una tabla relacionada.
1307
            switch (parentDescriptor.getRelationType()) {
1308
                case DynField.RELATION_TYPE_COLLABORATION:
1309
                case DynField.RELATION_TYPE_IDENTITY:
1310
                    fieldOp = builder.foreing_value(
1311
                            parentDescriptor.getName(),
1312
                            descriptor.getName()
1313
                    );
1314
                    if (StringUtils.equalsIgnoreCase(operator, ExpressionBuilder.OPERATOR_ILIKE) && descriptor.getType() != DataTypes.STRING) {
1315
                        fieldOp = builder.expression().cast(fieldOp,DataTypes.STRING);
1316
                    }
1317

    
1318
                    filter = builder.expression().binaryOperator(
1319
                            operator,
1320
                            fieldOp,
1321
                            value_constant
1322
                    );
1323
                    ExpressionBuilder.Value nullValue = builder.foreing_value(
1324
                            parentDescriptor.getName(),
1325
                            descriptor.getName()
1326
                    );
1327
                    filter = addNullBehavior(builder, filter, nullValue);
1328
                    break;
1329

    
1330
                case DynField.RELATION_TYPE_AGGREGATE:
1331
                case DynField.RELATION_TYPE_COMPOSITION:
1332
                    ExpressionBuilder.Value op_composition = null;
1333
                    fieldOp = builder.expression().column(
1334
                            field.getFeatureStore().getName(),
1335
                            descriptor.getName()
1336
                    );
1337
                    if (StringUtils.equalsIgnoreCase(operator, ExpressionBuilder.OPERATOR_ILIKE) && descriptor.getType() != DataTypes.STRING) {
1338
                        fieldOp = builder.expression().cast(fieldOp,DataTypes.STRING);
1339
                    }
1340
                    op_composition = builder.expression().binaryOperator(
1341
                            operator,
1342
                            fieldOp,
1343
                            value_constant
1344
                    );
1345
                    ExpressionBuilder.Value null_value = builder.expression().column(
1346
                            field.getFeatureStore().getName(),
1347
                            descriptor.getName()
1348
                    );
1349
                    op_composition = addNullBehavior(builder, op_composition, null_value);
1350

    
1351
                    filter = buildExists(builder, field, op_composition);
1352
                    break;
1353
            }
1354
        }
1355

    
1356
        filter = builder.expression().group(filter);
1357
        return filter;
1358
    }
1359

    
1360
    private ExpressionBuilder.Value buildExists(DALExpressionBuilder builder, Field field, ExpressionBuilder.Value op_composition) {
1361
        ExpressionBuilder.Value filter;
1362
        SQLBuilder.SelectBuilder select = builder.select();
1363
        select.from().table().name(field.getFeatureStore().getName());
1364
        //select.column().name(parentDescriptor.getFeatureType().getPrimaryKey()[0].getName());
1365
        select.column().value(builder.expression().constant(1));
1366
        select.limit(1);
1367
        select.where().value(
1368
                builder.expression().and(
1369
                        builder.expression().eq(
1370
                                builder.expression().column(
1371
                                        field.getFeatureStore().getName(),
1372
                                        getForeingKeyName(field.getFeatureStore(), this.store)
1373
                                ),
1374
                                builder.expression().column(
1375
                                        this.store.getName(),
1376
                                        getPrimaryKeyName(this.store)
1377
                                )
1378
                        ),
1379
                        op_composition
1380
                )
1381
        );
1382
        filter = builder.exists(select);
1383
        return filter;
1384
    }
1385

    
1386
    public JsonObject toJson() {
1387
        JsonObjectBuilder fieldBuilder = Json.createObjectBuilder();
1388

    
1389
        JsonArrayBuilder arrayBuilder = Json.createArrayBuilder();
1390
        Field currentField = this.getCurrentField();
1391
//        if(currentField == null){
1392
//            return null;
1393
//        }
1394
        FeatureAttributeDescriptor[] path = currentField.getPath();
1395
        for (int i = 0; i < path.length; i++) {
1396
            FeatureAttributeDescriptor featureAttributeDescriptor = path[i];
1397
            JsonArrayBuilder pathArray = Json.createArrayBuilder();
1398

    
1399
            //first value: name field
1400
            String fieldName = featureAttributeDescriptor.getName();
1401
            pathArray.add(fieldName);
1402
            //second value: name store
1403
            if(i==0){
1404
                pathArray.add(this.store.getName());
1405
            } else {
1406
                FeatureType featureType = featureAttributeDescriptor.getFeatureType();
1407
                String storeName = featureType.getStore().getName();
1408
                pathArray.add(storeName);
1409
                }
1410
            arrayBuilder.add(pathArray);
1411
        }
1412
        String relational = this.getRelationalOperator();
1413
        Object value = this.getValue(false);
1414
        String strValue = DataTypeUtils.toString(value);
1415
        String logical = this.getLogicalOperator();
1416

    
1417
        fieldBuilder.add("fieldPath", arrayBuilder);
1418
        fieldBuilder.add("relational", relational);
1419
        if (!StringUtils.isEmpty(strValue)) {
1420
            fieldBuilder.add("strValue", strValue);
1421
        }
1422
        if (!StringUtils.isEmpty(logical)) {
1423
            fieldBuilder.add("logical", logical);
1424
        }
1425
        int nullBehavior = this.getNullBehavior();
1426
        fieldBuilder.add("nullBehavior", nullBehavior);
1427
        
1428
        fieldBuilder.add("geometryOperandMode", this.geometryOperandMode);
1429
        fieldBuilder.add("geometryOperandStoreName", this.geometryOperandStoreId);
1430
        fieldBuilder.add("geometryOperandConstant", this.geometryOperandConstant);
1431
        fieldBuilder.add("useBox2dInGeometryOperand", this.useBox2dInGeometryOperand);
1432
        return fieldBuilder.build();
1433
    }
1434
    
1435
    public void put(SearchParameters params, int index) {
1436
        this.parameters = params;
1437
        Map<String, JsonObject> values = params.getValues();
1438
        if( values == null ) {
1439
            return;
1440
        }
1441
        JsonObject panelState = values.getOrDefault(PANEL_NAME, null);
1442
        if( panelState == null ) {
1443
            return;
1444
        }
1445
        String name = DataTypeUtils.toString(index);
1446
        this.fromJson(panelState.getJsonObject(name));
1447
    }
1448
    
1449
    public void fromJson(JsonObject jsonState) {
1450
        if (jsonState == null) {
1451
            return;
1452
        }
1453

    
1454
        JsonArray fieldPath = jsonState.getJsonArray("fieldPath");
1455

    
1456
        // array of arrays
1457
        String[][] arrayNew = new String[fieldPath.size()][2];
1458
        for (int i = 0; i < fieldPath.size(); i++) {
1459
            String[] arrayField = new String[2];
1460
            arrayField[0] = fieldPath.getJsonArray(i).getString(0);
1461
            arrayField[1] = fieldPath.getJsonArray(i).getString(1);
1462
            arrayNew[i] = arrayField;
1463
        }
1464
        this.setAttributePath(arrayNew);  //usar el doAddAndSelect
1465

    
1466
        String relational = jsonState.getString("relational");
1467
        this.setRelationalOperator(relational);
1468

    
1469
        if (jsonState.containsKey("strValue")) {
1470
            String strValue = jsonState.getString("strValue");
1471
//        SwingUtilities.invokeLater(new Runnable() {
1472
//            @Override
1473
//            public void run() {
1474
            setValue(strValue);
1475
//            }
1476
//        });
1477
        }
1478
        if (jsonState.containsKey("logical")) {
1479
            String logical = jsonState.getString("logical");
1480
            this.setLogicalOperator(logical);
1481
        }
1482
        if (jsonState.containsKey("nullBehavior")) {
1483
            int nullBehavior = jsonState.getInt("nullBehavior");
1484
            this.setNullBehavior(nullBehavior);
1485
        }
1486

    
1487
        this.geometryOperandMode = jsonState.getInt("geometryOperandMode", GEOM_OPERAND_MODE_CLIPBOARD);
1488
        this.geometryOperandStoreId = jsonState.getString("geometryOperandStoreName", null);
1489
        this.geometryOperandConstant = (Geometry) Json.toObject(jsonState,"geometryOperandConstant");
1490
        this.useBox2dInGeometryOperand = jsonState.getBoolean("geometryOperandStoreName", false);
1491
    }
1492

    
1493
    public void setUpdateValuesLimits(int limit, int featuresLimit) {
1494
        this.updateValuesTimeLimit = limit;
1495
        this.updateValuesFeaturesLimit = featuresLimit;
1496
        doUpdateValuesList();
1497
    }
1498

    
1499
    public int getNullBehavior() {
1500
        return (int) ((LabeledValue) this.ddnNullBehavior.getSelectedItem()).getValue();
1501
    }
1502

    
1503
    public int setNullBehavior(int nullBehaviorValue) {
1504
        int n = 0;
1505
        for (LabeledValue nullBehavior : nullBehaviors) {
1506
            int toInt = (int) nullBehavior.getValue();
1507
            if (nullBehaviorValue == toInt) {
1508
                break;
1509
            }
1510
            n++;
1511
        }
1512
        if (this.nullBehaviors.length <= n) {
1513
            return -1;
1514
        }
1515
        this.ddnNullBehavior.setSelectedIndex(n);
1516
        return n;
1517
    }
1518

    
1519
    private ExpressionBuilder.Value addNullBehavior(DALExpressionBuilder builder, ExpressionBuilder.Value filter, ExpressionBuilder.Value nullValue) {
1520
        if (this.getRelationalOperator() != ExpressionBuilder.OPERATOR_IS_NULL && this.getRelationalOperator() != ExpressionBuilder.OPERATOR_IS_NOT_NULL) {
1521
            if (this.getNullBehavior() == NULL_AS_TRUE) {
1522
                ExpressionBuilder.Function null_function = builder.expression().is_null(nullValue);
1523
                filter = builder.expression().or(null_function, filter);
1524
            } else if (this.getNullBehavior() == NULL_AS_FALSE) {
1525
                ExpressionBuilder.Function null_function = builder.expression().not_is_null(nullValue);
1526
                filter = builder.expression().and(null_function, filter);
1527
            }
1528
        }
1529
        return filter;
1530
    }
1531

    
1532
    private ExpressionBuilder.Value getFilterForOperatorNull(
1533
            FeatureAttributeDescriptor parentDescriptor,
1534
            FeatureAttributeDescriptor descriptor,
1535
            DALExpressionBuilder builder,
1536
            Field field) {
1537

    
1538
        ExpressionBuilder.Value filter = null;
1539
        if (parentDescriptor == null) {
1540
            filter = builder.expression().is_null(builder.expression().column(this.store.getName(), descriptor.getName()));
1541
        } else {
1542
            // Se busca en campos de una tabla relacionada.
1543
            switch (parentDescriptor.getRelationType()) {
1544
                case DynField.RELATION_TYPE_COLLABORATION:
1545
                case DynField.RELATION_TYPE_IDENTITY:
1546
                    filter = builder.expression().is_null(builder.foreing_value(
1547
                            parentDescriptor.getName(),
1548
                            descriptor.getName()
1549
                    ));
1550
                    break;
1551
                case DynField.RELATION_TYPE_AGGREGATE:
1552
                case DynField.RELATION_TYPE_COMPOSITION:
1553
                    ExpressionBuilder.Value op_composition = null;
1554
                    op_composition = builder.expression().is_null(builder.expression().column(
1555
                            field.getFeatureStore().getName(),
1556
                            descriptor.getName()
1557
                    ));
1558
                    filter = buildExists(builder, field, op_composition);
1559
            }
1560
        }
1561

    
1562
        filter = builder.expression().group(filter);
1563
        return filter;
1564
    }
1565

    
1566
    private ExpressionBuilder.Value getFilterForOperatorNotNull(
1567
            FeatureAttributeDescriptor parentDescriptor,
1568
            FeatureAttributeDescriptor descriptor,
1569
            DALExpressionBuilder builder,
1570
            Field field) {
1571

    
1572
        ExpressionBuilder.Value filter = null;
1573
        if (parentDescriptor == null) {
1574
            filter = builder.expression().not_is_null(builder.expression().column(this.store.getName(), descriptor.getName()));
1575
        } else {
1576
            // Se busca en campos de una tabla relacionada.
1577
            switch (parentDescriptor.getRelationType()) {
1578
                case DynField.RELATION_TYPE_COLLABORATION:
1579
                case DynField.RELATION_TYPE_IDENTITY:
1580
                    filter = builder.expression().not_is_null(builder.foreing_value(
1581
                            parentDescriptor.getName(),
1582
                            descriptor.getName()
1583
                    ));
1584
                    break;
1585
                case DynField.RELATION_TYPE_AGGREGATE:
1586
                case DynField.RELATION_TYPE_COMPOSITION:
1587
                    ExpressionBuilder.Value op_composition = null;
1588
                    op_composition = builder.expression().not_is_null(builder.expression().column(
1589
                            field.getFeatureStore().getName(),
1590
                            descriptor.getName()
1591
                    ));
1592

    
1593
                    filter = buildExists(builder, field, op_composition);
1594
            }
1595
        }
1596

    
1597
        filter = builder.expression().group(filter);
1598
        return filter;
1599
    }
1600

    
1601
    private ExpressionBuilder.Value getFilterForOperatorIsNotValid(
1602
            FeatureAttributeDescriptor parentDescriptor,
1603
            FeatureAttributeDescriptor descriptor,
1604
            DALExpressionBuilder builder,
1605
            Field field) {
1606

    
1607
        ExpressionBuilder.Value filter = null;
1608
        if (parentDescriptor == null) {
1609
            filter = builder.expression().not(
1610
                    builder.expression().ST_IsValid(
1611
                            builder.expression().column(this.store.getName(), descriptor.getName())
1612
                    )
1613
            );
1614
        } else {
1615
            // Se busca en campos de una tabla relacionada.
1616
            switch (parentDescriptor.getRelationType()) {
1617
                case DynField.RELATION_TYPE_COLLABORATION:
1618
                case DynField.RELATION_TYPE_IDENTITY:
1619
                    filter = builder.expression().not(
1620
                        builder.expression().ST_IsValid(
1621
                            builder.foreing_value(
1622
                                parentDescriptor.getName(),
1623
                                descriptor.getName()
1624
                            )
1625
                        )
1626
                    );
1627
                    break;
1628
                case DynField.RELATION_TYPE_AGGREGATE:
1629
                case DynField.RELATION_TYPE_COMPOSITION:
1630
                    ExpressionBuilder.Value op_composition = null;
1631
                    op_composition = builder.expression().not(
1632
                        builder.expression().ST_IsValid(
1633
                            builder.expression().column(
1634
                                field.getFeatureStore().getName(),
1635
                                descriptor.getName()
1636
                            )
1637
                        )
1638
                    );
1639

    
1640
                    filter = buildExists(builder, field, op_composition);
1641
            }
1642
        }
1643

    
1644
        filter = builder.expression().group(filter);
1645
        return filter;
1646
    }
1647

    
1648
    private ExpressionBuilder.Value getFilterForOperatorIsValid(
1649
            FeatureAttributeDescriptor parentDescriptor,
1650
            FeatureAttributeDescriptor descriptor,
1651
            DALExpressionBuilder builder,
1652
            Field field) {
1653

    
1654
        ExpressionBuilder.Value filter = null;
1655
        if (parentDescriptor == null) {
1656
            filter =builder.expression().ST_IsValid(
1657
                builder.expression().column(this.store.getName(), descriptor.getName())
1658
            );
1659
        } else {
1660
            // Se busca en campos de una tabla relacionada.
1661
            switch (parentDescriptor.getRelationType()) {
1662
                case DynField.RELATION_TYPE_COLLABORATION:
1663
                case DynField.RELATION_TYPE_IDENTITY:
1664
                    filter = builder.expression().ST_IsValid(
1665
                            builder.foreing_value(
1666
                                parentDescriptor.getName(),
1667
                                descriptor.getName()
1668
                            )
1669
                    );
1670
                    break;
1671
                case DynField.RELATION_TYPE_AGGREGATE:
1672
                case DynField.RELATION_TYPE_COMPOSITION:
1673
                    ExpressionBuilder.Value op_composition = null;
1674
                    op_composition = 
1675
                        builder.expression().ST_IsValid(
1676
                            builder.expression().column(
1677
                                field.getFeatureStore().getName(),
1678
                                descriptor.getName()
1679
                            )
1680
                    );
1681

    
1682
                    filter = buildExists(builder, field, op_composition);
1683
            }
1684
        }
1685

    
1686
        filter = builder.expression().group(filter);
1687
        return filter;
1688
    }
1689

    
1690
    private ExpressionBuilder.Value createGeometryFilter(
1691
            DALExpressionBuilder builder, 
1692
            FeatureAttributeDescriptor parentDescriptor, 
1693
            FeatureAttributeDescriptor descriptor, 
1694
            Field field,
1695
            StringBuilder warnings
1696
        ) {
1697
        ExpressionBuilder.Value filter = null;
1698

    
1699
        if( parentDescriptor!=null ) {
1700
            return null; //FIXME
1701
        }
1702
        Geometry geometry = this.getGeometryOperand(descriptor.getSRS(), warnings);
1703
        String operator = this.getRelationalOperator();
1704
        switch (operator) {
1705
            case ExpressionBuilder.OPERATOR_IS_NULL:
1706
                filter = getFilterForOperatorNull(parentDescriptor, descriptor, builder, field);
1707
                break;
1708
            case ExpressionBuilder.OPERATOR_IS_NOT_NULL:
1709
                filter = getFilterForOperatorNotNull(parentDescriptor, descriptor, builder, field);
1710
                break;
1711
            case GeometryExpressionBuilder.FUNCTION_ST_ISVALID:
1712
                filter = getFilterForOperatorIsValid(parentDescriptor, descriptor, builder, field);
1713
                break;
1714
            case FUNCTION_ISNOTVALID:
1715
                filter = getFilterForOperatorIsNotValid(parentDescriptor, descriptor, builder, field);
1716
                break;
1717
                
1718
                
1719
            case FUNCTION_INTERSECTSWITHBBOX:
1720
                if( geometry==null ) {
1721
                    return null; // FIXME
1722
                }
1723
                filter = builder.expression().ST_Intersects(
1724
                        builder.expression().ST_Envelope(
1725
                            builder.expression().column(descriptor.getName())
1726
                        ),
1727
                        builder.expression().geometry(geometry)
1728
                );
1729
                break;
1730
            case GeometryExpressionBuilder.FUNCTION_ST_CONTAINS:
1731
            case GeometryExpressionBuilder.FUNCTION_ST_COVERS:
1732
            case GeometryExpressionBuilder.FUNCTION_ST_COVEREDBY:
1733
            case GeometryExpressionBuilder.FUNCTION_ST_CROSSES:
1734
            case GeometryExpressionBuilder.FUNCTION_ST_DISJOINT:
1735
            case GeometryExpressionBuilder.FUNCTION_ST_EQUALS:
1736
            case GeometryExpressionBuilder.FUNCTION_ST_INTERSECTS:
1737
            case GeometryExpressionBuilder.FUNCTION_ST_OVERLAPS: 
1738
            case GeometryExpressionBuilder.FUNCTION_ST_WITHIN: 
1739
            case GeometryExpressionBuilder.FUNCTION_ST_TOUCHES:
1740
                if( geometry==null ) {
1741
                    return null; // FIXME
1742
                }
1743
                filter = builder.expression().function(
1744
                        operator,
1745
                        builder.expression().column(descriptor.getName()),
1746
                        builder.expression().geometry(geometry)
1747
                );
1748
                break;
1749
            case GeometryExpressionBuilder.FUNCTION_ST_ISCLOSED:
1750
                filter = builder.expression().function(
1751
                        operator,
1752
                        builder.expression().column(descriptor.getName())
1753
                );
1754
                break;
1755
            default:
1756
                return null;
1757
        }
1758
        if( filter!=null ) {
1759
            String s = filter.toString();
1760
            if( s.length()>10000 ) {
1761
                warnings.append("There are many selected geometries or they are very large.");
1762
                warnings.append("\n");
1763
            }
1764
        }
1765
        return filter;
1766
    }
1767

    
1768
    private Geometry getGeometryOperand(IProjection proj, StringBuilder warnings) {
1769
        List<Geometry> geoms;
1770
        switch(this.geometryOperandMode) {
1771
            case GEOM_OPERAND_MODE_LAYER_SELECTION:
1772
                geoms = this.getGeometryOperandFromLayerSelection(this.geometryOperandStoreId, warnings);
1773
                break;
1774
            case GEOM_OPERAND_MODE_CONSTANT:
1775
                geoms = this.getGeometryOperandConstant(proj, warnings);
1776
                break;
1777
            case GEOM_OPERAND_MODE_CLIPBOARD:
1778
                geoms = this.getGeometryOperandFromClipboard(proj, warnings);
1779
                break;
1780
            case GEOM_OPERAND_MODE_CURRENT_BOUNDINGBOX:
1781
                geoms = this.getCurrentBoundingBoxGeometry(proj, warnings);
1782
                break;
1783
            case GEOM_OPERAND_MODE_EMPTY:
1784
            default:
1785
                return null;
1786
        }
1787
        if( geoms==null || geoms.isEmpty() ) {
1788
            return null;
1789
        }
1790
        if( geoms.size()==1 ) {
1791
            return geoms.get(0);
1792
        }
1793
        Geometry geom = GeometryUtils.toAggregate(geoms, warnings);
1794
        if( geom!=null && geom.getProjection()==null ) {
1795
            geom.setProjection(proj);
1796
        }
1797
        return geom;
1798
    }
1799
    
1800
    private List<Geometry> getGeometryOperandConstant(IProjection proj, StringBuilder warnings) {
1801
        if( this.geometryOperandConstant==null ) {
1802
            warnings.append("The geometry with which to operate has not been indicated");
1803
            warnings.append("\n");
1804
            return null;
1805
        }
1806
        if( this.geometryOperandConstant.getProjection()==null ) {
1807
            this.geometryOperandConstant.setProjection(proj);
1808
        }
1809
        return Collections.singletonList(this.geometryOperandConstant);
1810
    }
1811
    
1812
    private List<Geometry> getGeometryOperandFromClipboard(IProjection proj, StringBuilder warnings) {
1813
        try {
1814
            ToolsSwingManager toolsSwingManager = ToolsSwingLocator.getToolsSwingManager();
1815

    
1816
            String s = toolsSwingManager.getFromClipboard();
1817
            if( StringUtils.isBlank(s) ) {
1818
                warnings.append("The clipboard is empty");
1819
                warnings.append("\n");
1820
                return null;
1821
            }
1822
            List<Geometry> geom = GeometryUtils.extractFrom(s, proj);
1823
            if( geom == null ) {
1824
                warnings.append("Can't locate geometries in clipboard");
1825
                warnings.append("\n");
1826
                return null;
1827
            }
1828
            return geom;
1829
        } catch (Exception ex) {
1830
            LOGGER.warn("Can't get geometry value.", ex);
1831
            warnings.append("Can't extract a geometry from clipboard");
1832
            warnings.append("\n(");
1833
            warnings.append(ex.getLocalizedMessage());
1834
            warnings.append(")\n");
1835
            return null;
1836
        }
1837
    }
1838
    
1839
    private synchronized List<Geometry> getGeometryOperandFromLayerSelection(String storeId, StringBuilder warnings) {
1840
        if( StringUtils.isBlank(storeId) ) {
1841
            return null;
1842
        }        
1843
        StoresRepository repo = null;
1844
        FeatureStore theStore = null;
1845
        try {
1846
            repo = DALLocator.getDataManager().getStoresRepository();
1847
            theStore = (FeatureStore) repo.getStore(storeId);
1848
            if( theStore == null ) {
1849
                warnings.append("Table not found in project.");
1850
                warnings.append("\n");
1851
                return null;
1852
            }
1853
            String geomAttrName = theStore.getDefaultFeatureTypeQuietly().getDefaultGeometryAttributeName();
1854
            if( StringUtils.isEmpty(geomAttrName) ) {
1855
                warnings.append("The selected table can't have geometries");
1856
                warnings.append("\n");
1857
                return null;
1858
            }
1859
            if( theStore.isFeatureSelectionEmpty() ) {
1860
                warnings.append("The selection of the selected table is empty.");
1861
                warnings.append("\n");
1862
                return null;
1863
            }
1864
            Iterator<FeatureReference> it = theStore.getFeatureSelectionQuietly().referenceIterator();
1865
            List<Geometry> geoms = new ArrayList<>();
1866
            for (Feature feature : theStore.getFeaturesIterable(it)) {
1867
                if(  this.useBox2dInGeometryOperand ) {
1868
                    geoms.add(feature.getGeometry(geomAttrName).getEnvelope().getBox2D());
1869
                } else {
1870
                    geoms.add(feature.getGeometry(geomAttrName));
1871
                }
1872
            }
1873
            return geoms;
1874
        } finally {
1875
            DisposeUtils.dispose(theStore);
1876
        }
1877
    }
1878
    
1879
    private void doSelectGeometryOperand() {
1880
        I18nManager i18n = ToolsLocator.getI18nManager();
1881
        WindowManager_v2 windowManager = (WindowManager_v2) ToolsSwingLocator.getWindowManager();
1882
        SelectGeometryPanel panel = new SelectGeometryPanel();
1883
        Dialog dialog = windowManager.createDialog(
1884
                panel, 
1885
                i18n.getTranslation("_Indicate_where_to_obtain_the_geometries"), 
1886
                null, 
1887
                WindowManager_v2.BUTTONS_OK_CANCEL
1888
        );
1889
        dialog.addActionListener((ActionEvent e) -> {
1890
            if( dialog.getAction()==WindowManager_v2.BUTTON_OK ) {
1891
                this.geometryOperandMode = panel.getMode();
1892
                this.geometryOperandConstant = panel.getGeometry();
1893
                this.geometryOperandStoreId = panel.getStoreId();
1894
                this.useBox2dInGeometryOperand = panel.useBox2dInGeometryOperand();
1895
                doUpdateCurrentValue();
1896
            }
1897
        });
1898
        panel.setMode(this.geometryOperandMode);
1899
        panel.setGeometry(this.geometryOperandConstant);
1900
        panel.setStoreId(this.geometryOperandStoreId);
1901
        panel.setUseBox2dInGeometryOperand(this.useBox2dInGeometryOperand);
1902
        
1903
        dialog.show(WindowManager.MODE.DIALOG);
1904
    }
1905
    
1906
    public String getWarnings() {
1907
        StringBuilder warns = new StringBuilder();
1908
        ExpressionBuilder.Value filter = this.getFilter(warns);
1909
        String s = warns.toString();
1910
        if( StringUtils.isBlank(s) ) {
1911
            return null;
1912
        }
1913
        return s;
1914
    }
1915
    private List<Geometry> getCurrentBoundingBoxGeometry(IProjection proj, StringBuilder warnings) {
1916
        DataSwingManager dataSwingManager = DALSwingLocator.getDataSwingManager();
1917
        Supplier<Envelope> bbox = dataSwingManager.getCurrentBoundingBox();
1918
        if( bbox!=null ) {
1919
            Envelope env = bbox.get();
1920
            if( env != null && !env.isEmpty() && !env.isCollapsed() ) {
1921
                return Collections.singletonList(env.getGeometry());
1922
            }
1923
        }    
1924
        return null;
1925
    }
1926

    
1927
}