Statistics
| Revision:

gvsig-vectorediting / org.gvsig.vectorediting / trunk / org.gvsig.vectorediting / org.gvsig.vectorediting.swing / org.gvsig.vectorediting.swing.impl / src / main / java / org / gvsig / vectorediting / swing / impl / DefaultEditingContext.java @ 4084

History | View | Annotate | Download (57.5 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright ? 2007-2014 gvSIG Association
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 2
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24

    
25
package org.gvsig.vectorediting.swing.impl;
26

    
27
import java.awt.BorderLayout;
28
import java.awt.Component;
29
import java.awt.Cursor;
30
import java.lang.ref.WeakReference;
31
import java.lang.reflect.InvocationTargetException;
32
import java.util.ArrayList;
33
import java.util.HashSet;
34
import java.util.List;
35
import java.util.Set;
36
import java.util.Stack;
37
import java.util.concurrent.BlockingQueue;
38
import java.util.concurrent.LinkedBlockingQueue;
39
import java.util.concurrent.TimeUnit;
40
import java.util.prefs.PreferenceChangeEvent;
41
import java.util.prefs.PreferenceChangeListener;
42
import java.util.prefs.Preferences;
43
import javax.swing.JComponent;
44
import javax.swing.JOptionPane;
45
import javax.swing.SwingUtilities;
46
import org.apache.commons.lang3.StringUtils;
47
import org.apache.commons.text.StringEscapeUtils;
48
import org.gvsig.expressionevaluator.ExpressionUtils;
49
import org.gvsig.expressionevaluator.Function;
50
import org.gvsig.expressionevaluator.SymbolTable;
51
import org.gvsig.fmap.dal.DataTypes;
52
import org.gvsig.fmap.dal.EditingNotification;
53
import org.gvsig.fmap.dal.EditingNotificationManager;
54
import org.gvsig.fmap.dal.exception.DataException;
55
import org.gvsig.fmap.dal.feature.Feature;
56
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
57
import org.gvsig.fmap.dal.feature.FeatureSelection;
58
import org.gvsig.fmap.dal.feature.FeatureStore;
59
import org.gvsig.fmap.dal.feature.FeatureType;
60
import org.gvsig.fmap.dal.swing.DALSwingLocator;
61
import org.gvsig.fmap.geom.Geometry;
62
import org.gvsig.fmap.geom.GeometryLocator;
63
import org.gvsig.fmap.geom.primitive.Point;
64
import org.gvsig.fmap.geom.type.GeometryType;
65
import org.gvsig.fmap.mapcontext.MapContext;
66
import org.gvsig.fmap.mapcontext.layers.CancelationException;
67
import org.gvsig.fmap.mapcontext.layers.FLayer;
68
import org.gvsig.fmap.mapcontext.layers.FLayers;
69
import org.gvsig.fmap.mapcontext.layers.LayerCollectionEvent;
70
import org.gvsig.fmap.mapcontext.layers.LayerCollectionListener;
71
import org.gvsig.fmap.mapcontext.layers.LayerEvent;
72
import org.gvsig.fmap.mapcontext.layers.LayerListener;
73
import org.gvsig.fmap.mapcontext.layers.LayerPositionEvent;
74
import org.gvsig.fmap.mapcontext.layers.SpatialCache;
75
import org.gvsig.fmap.mapcontext.layers.vectorial.FLyrVect;
76
import org.gvsig.fmap.mapcontext.rendering.legend.IVectorLegend;
77
import org.gvsig.fmap.mapcontrol.MapControl;
78
import org.gvsig.fmap.mapcontrol.tools.Behavior.Behavior;
79
import org.gvsig.fmap.mapcontrol.tools.CompoundBehavior;
80
import org.gvsig.tools.ToolsLocator;
81
import org.gvsig.tools.dataTypes.Coercion;
82
import org.gvsig.tools.dispose.DisposableIterator;
83
import org.gvsig.tools.exception.BaseException;
84
import org.gvsig.tools.i18n.I18nManager;
85
import org.gvsig.tools.locator.LocatorException;
86
import org.gvsig.tools.observer.BaseNotification;
87
import org.gvsig.tools.observer.Notification;
88
import org.gvsig.tools.observer.ObservableHelper;
89
import org.gvsig.tools.observer.Observer;
90
import org.gvsig.tools.swing.api.ToolsSwingLocator;
91
import org.gvsig.tools.swing.api.threadsafedialogs.ThreadSafeDialogsManager;
92
import org.gvsig.tools.task.SimpleTaskStatus;
93
import org.gvsig.utils.console.JDockPanel;
94
import org.gvsig.utils.console.ResponseListener;
95
import org.gvsig.vectorediting.lib.api.EditingLocator;
96
import org.gvsig.vectorediting.lib.api.EditingManager;
97
import org.gvsig.vectorediting.lib.api.EditingService;
98
import org.gvsig.vectorediting.lib.api.EditingServiceInfo;
99
import org.gvsig.vectorediting.lib.api.EditingServiceParameter;
100
import org.gvsig.vectorediting.lib.api.EditingServiceParameter.TYPE;
101
import org.gvsig.vectorediting.lib.api.exceptions.CreateEditingBehaviorException;
102
import org.gvsig.vectorediting.lib.api.exceptions.EndEditingException;
103
import org.gvsig.vectorediting.lib.api.exceptions.FinishServiceException;
104
import org.gvsig.vectorediting.lib.api.exceptions.InvalidEntryException;
105
import org.gvsig.vectorediting.lib.api.exceptions.ParsePointException;
106
import org.gvsig.vectorediting.lib.api.exceptions.ParseValueException;
107
import org.gvsig.vectorediting.lib.api.exceptions.ServiceInformationException;
108
import org.gvsig.vectorediting.lib.api.exceptions.StartEditingException;
109
import org.gvsig.vectorediting.lib.api.exceptions.StartServiceException;
110
import org.gvsig.vectorediting.lib.api.exceptions.StopServiceException;
111
import org.gvsig.vectorediting.lib.api.exceptions.VectorEditingException;
112
import org.gvsig.vectorediting.swing.api.EditingContext;
113
import org.gvsig.vectorediting.swing.api.EditingSwingLocator;
114
import org.gvsig.vectorediting.swing.api.EditingSwingManager;
115
import org.gvsig.vectorediting.swing.api.console.EditingConsole;
116
import org.gvsig.vectorediting.swing.impl.console.DefaultEditingConsole;
117
import org.slf4j.Logger;
118
import org.slf4j.LoggerFactory;
119

    
120
public class DefaultEditingContext implements EditingContext {
121

    
122
    private static final Logger LOGGER = LoggerFactory
123
        .getLogger(EditingManager.class);
124

    
125
    private WeakReference<MapControl> mapControlReference;
126

    
127
    private WeakReference<MapContext> mapContextReference;
128

    
129
    private EditingCompoundBehavior editingCompoundBehavior;
130

    
131
    private Behavior[] lastAdditionalBehaviors;
132

    
133
    private final ObservableHelper observableHelper;
134

    
135
    private EditingConsole console;
136

    
137
    private JDockPanel dockConsole = null;
138

    
139
    private boolean isShowConsole = false;
140

    
141
    private final Stack<EditingService> serviceStack;
142

    
143
    private FLyrVect currentLayer;
144

    
145
    private EditingServiceParameter currentParam;
146

    
147
    private Behavior[] defaultBehaviors;
148
    
149
    private Set<FLyrVect> layersSpatialCacheEnabled = new HashSet<>();
150
    
151
//    private boolean processing;
152
    
153
    private int drawMode;
154
    
155
    private Set<FLyrVect> removeFromSnapping;
156

    
157
    private final LayerListener layerListener = new LayerListener() {
158

    
159
        @Override
160
        public void activationChanged(final LayerEvent e) {
161
            if( !SwingUtilities.isEventDispatchThread() ) {
162
                SwingUtilities.invokeLater(new Runnable() {
163

    
164
                    @Override
165
                    public void run() {
166
                        activationChanged(e);
167
                    }
168
                });
169
                return;
170
            }
171

    
172
            FLayer layer = e.getSource();
173
            final MapContext mapContext = layer.getMapContext();
174

    
175
            if (countActiveAndEditingLayers(mapContext) > 1) {
176
                hideConsole();
177
                return;
178
            }
179

    
180
            if (layer instanceof FLyrVect) {
181
                if (layer.isActive()) {
182
                    if(layer.isEditing()) {
183
                        // Al activar una capa en edicion esto hace que el usuario
184
                        // pierda la herramienta que tuvise activa.
185
//                        getMapControl().setTool(VECTOREDITING_TOOL_NAME);
186
                        setCurrentLayer((FLyrVect) layer);
187
                        showConsole();
188
                        return;
189
                    } else {
190
                        final SpatialCache spatialCache = ((FLyrVect) layer).getSpatialCache();
191
                        if(!spatialCache.isEnabled("active")){
192
                            spatialCache.setEnabled("active",true);
193
                            //We keep the list of layers whose spatial cache is enabled here.
194
                            layersSpatialCacheEnabled.add((FLyrVect) layer);
195
                            ((FLyrVect) layer).refreshSpatialCache(mapContext.getViewPort().getEnvelope());
196
                        }
197
                    }
198
                } else {
199
                    if(!layer.isEditing()) {
200
                        //We disabled the spatial cache of the layers that we had enabled here.
201
                        final SpatialCache spatialCache = ((FLyrVect) layer).getSpatialCache();
202
                        if(spatialCache.isEnabled("active") && layersSpatialCacheEnabled.contains((FLyrVect) layer)){
203
                            spatialCache.setEnabled("active",false);
204
                            layersSpatialCacheEnabled.remove((FLyrVect) layer);
205
                        }
206
                    }
207
                }
208
            }
209

    
210
            FLayer[] activeLayers =
211
                layer.getMapContext().getLayers().getActives();
212
            
213
            for (FLayer activeLayer : activeLayers) {
214
                if (activeLayer instanceof FLyrVect) {
215
                    if (activeLayer.isEditing()) {
216
//                        getMapControl().setTool(VECTOREDITING_TOOL_NAME);
217
                        setCurrentLayer((FLyrVect) activeLayer);
218
                        showConsole();
219
                        return;
220
                    }
221
                }
222
            }
223

    
224
            hideConsole();
225
//            if ((getMapControl().getCurrentTool() != null)
226
//                && getMapControl().getCurrentTool().equals(VECTOREDITING_TOOL_NAME)) {
227
//                getMapControl().setPrevTool();
228
//            }
229
        }
230

    
231
        @Override
232
        public void drawValueChanged(LayerEvent e) {
233
        }
234

    
235
        @Override
236
        public void editionChanged(final LayerEvent e) {
237
            if( !SwingUtilities.isEventDispatchThread() ) {
238
                SwingUtilities.invokeLater(new Runnable() {
239

    
240
                    @Override
241
                    public void run() {
242
                        editionChanged(e);
243
                    }
244
                });
245
                return;
246
            }
247
            FLayer layer = e.getSource();
248

    
249
            if (layer instanceof FLyrVect) {
250
                if (layer.isEditing()) {
251
                    synchronized (DefaultEditingContext.this) {
252
                        beginEdition((FLyrVect) layer);
253
                        showConsole();
254
                    }
255
                } else {
256
                    hideConsole();
257
                }
258
            }
259

    
260
        }
261

    
262
        @Override
263
        public void nameChanged(LayerEvent e) {
264
        }
265

    
266
        @Override
267
        public void visibilityChanged(LayerEvent e) {
268
        }
269
    };
270
    
271
    private int countActiveAndEditingLayers(MapContext mapcontext){
272
        int count = 0;
273
        
274
        FLayer[] activeLayers =
275
                mapcontext.getLayers().getActives();
276
            
277
        for (FLayer activeLayer : activeLayers) {
278
            if (activeLayer instanceof FLyrVect) {
279
                if (activeLayer.isEditing()) {
280
                    count++;
281
                }
282
            }
283
        }
284
        
285
        return count;
286
    }
287

    
288
    private final PreferenceChangeListener preferenceChangeListener =
289
        new PreferenceChangeListener() {
290

    
291
            @Override
292
            public void preferenceChange(PreferenceChangeEvent evt) {
293
                String key = evt.getKey();
294
                if (key.equalsIgnoreCase("apply-snappers")) {
295
                    boolean newValue = Boolean.parseBoolean(evt.getNewValue());
296
                    getMapControl().setRefentEnabled(newValue);
297
                }
298
            }
299
        };
300

    
301
    public DefaultEditingContext(MapControl mapControl) {
302
//        this.processing = false;
303
        this.mapControlReference = new WeakReference<>(mapControl);
304
        this.mapContextReference =
305
            new WeakReference<>(mapControl.getMapContext());
306
        this.observableHelper = new ObservableHelper();
307

    
308
        this.serviceStack = new Stack<>();
309
        
310
        this.drawMode = DRAWMODE_NORMAL;
311
        
312
        this.removeFromSnapping = new HashSet<>();
313

    
314
        addLayerListeners();
315
        addPreferenceListener();
316
    }
317

    
318
    private void addPreferenceListener() {
319
        Preferences prefs = Preferences.userRoot().node("snappers");
320
        prefs.addPreferenceChangeListener(preferenceChangeListener);
321
    }
322

    
323
    @Override
324
    public void activateService(String name) {
325
        if( this.isProcessing() ) {
326
            return;
327
        }
328

    
329
        if ((getMapControl() != null)
330
            && getMapControl().hasTool(VECTOREDITING_TOOL_NAME)) {
331

    
332
            CompoundBehavior editingCompoundBehavior =
333
                getEditingCompoundBehavior();
334
            getMapControl().setTool(VECTOREDITING_TOOL_NAME);
335
            editingCompoundBehavior.setDrawnBehavior(
336
                EditingCompoundBehavior.EDITING_INDEX, true);
337

    
338
            EditingManager manager = EditingLocator.getManager();
339

    
340
            if (currentLayer != null) {
341
                IVectorLegend legend = null;
342
                try {
343
                    legend = (IVectorLegend) currentLayer.getLegend();
344
                } catch (Exception e) {
345
                    LOGGER.trace("Can't retrieve legend from layer.");
346
                    //DO NOTHING
347
                }
348

    
349
//                EditingService activeService = getActiveService();
350
//                if(activeService != null && !activeService.next().getTypes().contains(TYPE.GEOMETRY)) {
351
//                    activeService.setShowPreviewSymbol(true);
352
//                }
353
                EditingService service =
354
                    manager.getEditingService(name,
355
                        currentLayer.getFeatureStore(),
356
                        mapContextReference.get(), 
357
                        legend);
358

    
359
                if (service != null) {
360
//                     if(!serviceStack.isEmpty()) { service.setShowPreviewSymbol(false); }
361
                    this.enableSelection(false);
362

    
363
                    try {
364
                        service.activate();
365
                        service.start();
366
                        setDrawMode(DRAWMODE_NORMAL);
367
                    } catch (StartServiceException e) {
368

    
369
                        LOGGER.info(String.format(
370
                            "Can't start the service %1$s", service.getName()),
371
                            e);
372
                        cleanEditingContext();
373
                        return;
374

    
375
                    } catch (InvalidEntryException e) {
376

    
377
                        I18nManager i18nManager = ToolsLocator.getI18nManager();
378
                        showConsoleMessage("\n"
379
                            + i18nManager.getTranslation("invalid_option"));
380
                    }
381

    
382
                    if (!serviceStack.isEmpty()){
383
                        if(getActiveService().next().getTypes().contains(TYPE.GEOMETRY)) {
384
                            service.setShowPreviewSymbol(false);
385
                        } else {
386
//                            service.setShowPreviewSymbol(true);
387
//                            getActiveService().setShowPreviewSymbol(true);
388
                            serviceStack.pop();
389
                        }
390
                    }
391

    
392
                    setActiveService(service);
393

    
394
                    nextParameter();
395
                }
396
            }
397
        }
398
    }
399

    
400
    private void addBehaviors(Behavior[] additionalBehavior)
401
        throws CreateEditingBehaviorException {
402

    
403
        DefaultEditingBehavior editingBehavior;
404
        EditingCompoundBehavior editingCompoundBehavior;
405

    
406
        if (!getMapControl().hasTool(VECTOREDITING_TOOL_NAME)) {
407

    
408
            editingBehavior = new DefaultEditingBehavior(this);
409
            editingCompoundBehavior =
410
                new EditingCompoundBehavior(editingBehavior);
411
            setCompoundBehavior(editingCompoundBehavior);
412

    
413
            if (additionalBehavior != null) {
414

    
415
                Behavior[] behaviors =
416
                    new Behavior[additionalBehavior.length + 1];
417
                behaviors[0] = editingCompoundBehavior;
418

    
419
                System.arraycopy(additionalBehavior, 0, behaviors, 1, additionalBehavior.length);
420

    
421
                getMapControl().addBehavior(VECTOREDITING_TOOL_NAME, behaviors);
422

    
423
                lastAdditionalBehaviors = additionalBehavior;
424

    
425
            } else {
426
                getMapControl().addBehavior(VECTOREDITING_TOOL_NAME,
427
                    editingCompoundBehavior);
428
            }
429

    
430
        } else {
431
            editingCompoundBehavior = getEditingCompoundBehavior();
432
            editingBehavior =
433
                (DefaultEditingBehavior) editingCompoundBehavior
434
                    .getBehavior(EditingCompoundBehavior.EDITING_INDEX);
435
            setCompoundBehavior(editingCompoundBehavior);
436
            cleanEditingContext();
437
        }
438

    
439
    }
440

    
441
    private void addLayerListeners() {
442

    
443
        FLayers layers = mapContextReference.get().getLayers();
444

    
445
        layers.addLayerListener(layerListener);
446

    
447
        layers.addLayerCollectionListener(new LayerCollectionListener() {
448

    
449
            public void addLayer(FLayer layer) {
450
                if (layer instanceof FLayers) {
451
                    FLayers layers = (FLayers) layer;
452
                    for (int i = 0; i < layers.getLayersCount(); i++) {
453
                        addLayer(layers.getLayer(i));
454
                    }
455
                } else if (layer instanceof FLyrVect) {
456
                    ((FLyrVect) layer).addLayerListener(layerListener);
457
                }
458
            }
459

    
460
            @Override
461
            public void layerAdded(LayerCollectionEvent e) {
462
                addLayer(e.getLayers());
463
            }
464

    
465
            @Override
466
            public void layerAdding(LayerCollectionEvent e)
467
                throws CancelationException {
468
            }
469

    
470
            @Override
471
            public void layerMoved(LayerPositionEvent e) {
472
            }
473

    
474
            @Override
475
            public void layerMoving(LayerPositionEvent e)
476
                throws CancelationException {
477
            }
478

    
479
            public void removeLayer(FLayer layer) {
480
                if (layer instanceof FLayers) {
481
                    FLayers layers = (FLayers) layer;
482
                    for (int i = 0; i < layers.getLayersCount(); i++) {
483
                        addLayer(layers.getLayer(i));
484
                    }
485
                } else if (layer instanceof FLyrVect) {
486
                    ((FLyrVect) layer).removeLayerListener(layerListener);
487
                }
488
            }
489

    
490
            @Override
491
            public void layerRemoved(LayerCollectionEvent e) {
492
                removeLayer(e.getLayers());
493
            }
494

    
495
            @Override
496
            public void layerRemoving(LayerCollectionEvent e)
497
                throws CancelationException {
498
            }
499

    
500
            @Override
501
            public void visibilityChanged(LayerCollectionEvent e)
502
                throws CancelationException {
503
            }
504
        });
505
    }
506

    
507
    @Override
508
    public void addObserver(Observer o) {
509
        this.observableHelper.addObserver(o);
510
    }
511

    
512
    private void askQuestion(EditingServiceParameter param) {
513
        I18nManager i18nManager = ToolsLocator.getI18nManager();
514
        String translation = i18nManager.getTranslation(param.getDescription());
515
        String activeServiceName =
516
            i18nManager.getTranslation(getActiveService().getName());
517

    
518
        String strDefaultValue = param.getConsoleDefaultValue();
519
        
520
        if(StringUtils.isBlank(strDefaultValue)) {
521
            showConsoleMessage("\n" + activeServiceName + "# " + translation + " : ");
522
        } else {
523
            showConsoleMessage("\n" + activeServiceName + "# " + translation + "<" + strDefaultValue + "> : ");
524
        }
525
    }
526

    
527
    @Override
528
    public synchronized void beginEdition(FLyrVect layer,
529
        Behavior[] additionalBehaviors) {
530

    
531
        try{
532
            throw new Exception("Deprecated method");
533
        } catch (Exception e){
534
            LOGGER.info("Deprecated method", e);
535
        }
536

    
537
        beginEdition(layer);
538
        try {
539
            addBehaviors(additionalBehaviors);
540
        } catch (CreateEditingBehaviorException e1) {
541
            LOGGER.info("Problems adding behaviors to editing context", e1);
542
            getMapControl().setTool("pan");
543
        }
544
    }
545

    
546
    @Override
547
    public synchronized void beginEdition(FLyrVect layer) {
548

    
549

    
550
        setCurrentLayer(layer);
551

    
552
        FeatureStore featureStore = layer.getFeatureStore();
553
        if (!featureStore.isEditing()) {
554
            EditingNotificationManager editingNotificationManager =
555
                DALSwingLocator.getEditingNotificationManager();
556

    
557
            EditingNotification notification =
558
                editingNotificationManager.notifyObservers(this,
559
                    EditingNotification.BEFORE_ENTER_EDITING_STORE, null, layer,layer.getFeatureStore());
560

    
561
            if (notification.isCanceled() || notification.isAborted() ) {
562
                String msg =
563
                    String.format("Edit layer %1$s canceled by somme observer.",
564
                        layer.getName());
565
                LOGGER.info(msg, new StartEditingException(msg, null));
566
                return;
567
            }
568
            try {
569
                featureStore.edit();
570
            } catch (Exception e) {
571
                String msg =
572
                    String.format("Can't set %1$s in edit mode",
573
                        featureStore.getName());
574
                LOGGER.info(msg, new VectorEditingException(e));
575
                cleanEditingContext();
576
                return;
577
            }
578
            editingNotificationManager.notifyObservers(this,
579
                EditingNotification.AFTER_ENTER_EDITING_STORE, null, layer, layer.getFeatureStore());
580

    
581
        }
582

    
583
        featureStore.addObserver(getMapControl());
584

    
585
        enableSnapping();
586
    }
587

    
588
    @SuppressWarnings({ "rawtypes", "unchecked" })
589
    private void enableSnapping() {
590
        Preferences prefs = Preferences.userRoot().node("snappers");
591
         getMapControl().setRefentEnabled(prefs.getBoolean("apply-snappers", false));
592
         if (currentLayer != null) {
593
            Set<FLyrVect> layersToSnap = getMapControl().getMapContext().getLayersToSnap();
594
            if (!layersToSnap.contains(currentLayer)) {
595
                layersToSnap.add(currentLayer);
596
                this.removeFromSnapping.add(currentLayer);
597
            }
598
        }
599
    }
600

    
601
    @SuppressWarnings("rawtypes")
602
    private void disableSnapping() {
603
        Set<FLyrVect> layersToSnap =
604
            getMapControl().getMapContext().getLayersToSnap();
605
        if (layersToSnap.contains(currentLayer)) {
606
            if(this.removeFromSnapping.contains(currentLayer)){
607
                layersToSnap.remove(currentLayer);
608
                this.removeFromSnapping.remove(currentLayer);
609
            }
610
        }
611
    }
612

    
613
    private void changeSelectedTool(String name) {
614
        if (name.equalsIgnoreCase(DEFAULT_TOOL)) {
615
            name = DEFAULT_ACTION_NAME;
616
            this.getMapControl().setTool(DEFAULT_TOOL_NAME);
617
//            notifyChangeSelectedTool();
618
        }
619
    }
620
    
621
    private void notifyChangeSelectedTool() {
622
        Notification notification = new BaseNotification(
623
            EditingContext.CHANGE_SELECTED_TOOL_NOTIFICATION,
624
            null
625
        );
626
        this.observableHelper.notifyObservers(this, notification);
627
    }
628

    
629
    private void notifyChangeSelectedTool(String actionName) {
630
        Notification notification = new BaseNotification(
631
            EditingContext.CHANGE_SELECTED_TOOL_NOTIFICATION,
632
            new String[] { actionName }
633
        );
634
        this.observableHelper.notifyObservers(this, notification);
635
    }
636

    
637

    
638
    private void cleanEditingContext() {
639
        serviceStack.clear();
640
        currentParam = null;
641
        
642
        I18nManager i18n = ToolsLocator.getI18nManager();
643
        showConsoleMessage("\n" + i18n.getTranslation("select_new_tool") + "\n");
644

    
645
        changeSelectedTool(DEFAULT_TOOL);
646
        notifyChangeSelectedTool(DEFAULT_ACTION_NAME);
647
    }
648

    
649
    @Override
650
    public void deleteObserver(Observer o) {
651
        this.observableHelper.deleteObserver(o);
652
    }
653

    
654
    @Override
655
    public void deleteObservers() {
656
        this.observableHelper.deleteObservers();
657
    }
658

    
659
    private void discardChanges(FLyrVect layer) throws EndEditingException {
660
        FeatureStore featureStore = layer.getFeatureStore();
661
        try {
662
            featureStore.cancelEditing();
663
        } catch (Exception e) {
664
            throw new EndEditingException(e);
665
        }
666
    }
667

    
668
    private void doAction(FLyrVect layer, int option) {
669
        ThreadSafeDialogsManager dialogs = ToolsSwingLocator.getThreadSafeDialogsManager();
670
        I18nManager i18n = ToolsLocator.getI18nManager();
671
        
672
        switch (option) {
673
        case SAVE_CHANGES:
674
            try {
675
                saveChanges(layer);
676
            } catch (VectorEditingException e) {
677
                String msg =
678
                    String.format("Changes can not be saved in %1$s",
679
                        layer.getName());
680
                LOGGER.info(msg, e);
681
                dialogs.messageDialog(                   
682
                    i18n.getTranslation("_There_are_problems_saving_changes")+"\n\n"+
683
                            BaseException.getMessageStack(e, 2)+"\n\n"+
684
                    i18n.getTranslation("_See_error_log_for_more_information"), 
685
                    null, 
686
                    i18n.getTranslation("_Warning"), 
687
                    JOptionPane.WARNING_MESSAGE, 
688
                    "Vectorediting_cant_save_changes"
689
                );
690
                return;
691
            }
692
            break;
693

    
694
        case DISCARD_CHANGES:
695
            try {
696
                discardChanges(layer);
697
            } catch (VectorEditingException e) {
698
                String msg =
699
                    String.format("Changes can not be discared in %1$s",
700
                        layer.getName());
701
                LOGGER.info(msg, e);
702
                dialogs.messageDialog(                   
703
                    i18n.getTranslation("_There_are_problems_discarding_changes")+"\n"+
704
                    "\n" + i18n.getTranslation("_See_error_log_for_more_information"), 
705
                    null, 
706
                    i18n.getTranslation("_Warning"), 
707
                    JOptionPane.WARNING_MESSAGE, 
708
                    "Vectorediting_cant_discard_changes"
709
                );
710
                return;
711
            }
712
            break;
713

    
714
        case EXPORT_LAYER:
715
            try {
716
                exportLayer(layer);
717
            } catch (VectorEditingException e) {
718
                String msg =
719
                    String.format("Changes of %1$s can not be exported",
720
                        layer.getName());
721
                LOGGER.info(msg, e);
722
                dialogs.messageDialog(                   
723
                    i18n.getTranslation("_There_are_problems_exporting_changes")+"\n\n"+
724
                    i18n.getTranslation("_See_error_log_for_more_information"), 
725
                    null, 
726
                    i18n.getTranslation("_Warning"), 
727
                    JOptionPane.WARNING_MESSAGE, 
728
                    "Vectorediting_cant_export_changes"
729
                );
730
                return;
731
            }
732
            break;
733

    
734
        case CANCEL:
735
            return;
736
        }
737

    
738
        cleanEditingContext();
739
        hideConsole();
740
        disableSnapping();
741
        changeSelectedTool(DEFAULT_TOOL);
742

    
743
        FeatureStore featureStore = layer.getFeatureStore();
744
        featureStore.deleteObserver(getMapControl());
745

    
746
    }
747

    
748
    private void enableSelection(boolean enableSelection) {
749
        this.getEditingCompoundBehavior().setDrawnBehavior(
750
                EditingCompoundBehavior.SELECTION_INDEX, enableSelection);
751
    }
752

    
753
    @Override
754
    public void endEdition(FLyrVect layer) {
755
        if( this.isProcessing() ) {
756
            return;
757
        }
758
        if (layer.isEditing()) {
759
            EditingNotificationManager editingNotificationManager =
760
                DALSwingLocator.getEditingNotificationManager();
761

    
762
            EditingNotification notification =
763
                editingNotificationManager.notifyObservers(this,
764
                    EditingNotification.BEFORE_EXIT_EDITING_STORE, null, layer, layer.getFeatureStore());
765

    
766
            if (notification.isCanceled()) {
767
                String msg =
768
                    String.format(
769
                        "Stop edit layer %1$s canceled by somme observer.",
770
                        layer.getName());
771
                LOGGER.info(msg, new EndEditingException(msg, null));
772

    
773
            }
774

    
775
            getMapControl().getCanceldraw().setCanceled(true);
776
            int option;
777
            EditingSwingManager swingManager =
778
                EditingSwingLocator.getSwingManager();
779

    
780

    
781
            if (layer.isWritable() && getMapControl().getProjection().equals(layer.getProjection()) ) {
782
                option =
783
                    swingManager.showPanelSaveOrDiscard(getMapControl(),
784
                        layer.getName());
785
            } else {
786
                option =
787
                    swingManager.showPanelExportOrDiscard(getMapControl(),
788
                        layer.getName());
789
            }
790

    
791
            doAction(layer, option);
792

    
793
            editingNotificationManager.notifyObservers(this,
794
                EditingNotification.AFTER_EXIT_EDITING_STORE, null, layer, layer.getFeatureStore());
795

    
796
        }
797

    
798
    }
799

    
800
    private void exportLayer(FLyrVect layer) throws EndEditingException {
801
        Notification notification = new BaseNotification(EditingContext.EXPORT_LAYER_NOTIFICATION,1);
802
        notification.setValue(layer);
803
        this.observableHelper.notifyObservers(this, notification);
804
    }
805

    
806
    protected void finishService() {
807
        enqueueTask(() -> {
808
            doFinishService();
809
        });
810
        refreshMenusAndToolBars();
811
    }
812

    
813
    private void doFinishService() {
814
        try {
815
            EditingService lastService = serviceStack.pop();
816
            try {
817
                if (!serviceStack.isEmpty()
818
                        && getActiveService().next().getTypes().contains(TYPE.GEOMETRY)) {
819
                    Geometry geometry = lastService.finish();
820
                    lastService.setShowPreviewSymbol(true);
821
                    if (geometry != null) {
822
                        getActiveService().setValue(geometry);
823
                    }
824
                } else {
825
                    lastService.finishAndStore();
826
                    getMapControl().rePaintDirtyLayers();
827
                    refreshMenusAndToolBars();
828

    
829
                    I18nManager i18nManager = ToolsLocator.getI18nManager();
830
                    showConsoleMessage("\n"
831
                            + i18nManager.getTranslation(lastService.getName()) + "# "
832
                            + i18nManager.getTranslation("finished") + "\n");
833
//                lastService.stop();
834
                    setActiveService(lastService);
835
//                lastService.start();
836
                    lastService.restart();
837
                    setDrawMode(DRAWMODE_NORMAL);
838
                    changeSelectedTool(getActiveService().getName());
839
                }
840

    
841
            } catch (FinishServiceException ex) {
842
                showConsoleMessage("\n"+ex.getLocalizedMessage());
843
                cleanEditingContext();
844
                return;
845
            } catch (InvalidEntryException ex) {
846
                I18nManager i18nManager = ToolsLocator.getI18nManager();
847
                showConsoleMessage("\n"
848
                        + i18nManager.getTranslation("invalid_option"));
849
                changeSelectedTool(getActiveService().getName());
850
            } catch (Exception ex) {
851
                LOGGER.warn("Can't finish " + lastService.getName(), ex);
852
                I18nManager i18nManager = ToolsLocator.getI18nManager();
853
                showConsoleMessage("\n"+i18nManager.getTranslation("_An_error_has_occurred"));
854
                cleanEditingContext();
855
                return;
856
            }
857

    
858
            doNextParameter();
859
        } finally {
860
            refreshMenusAndToolBars();
861
        }
862
    }
863

    
864
    public EditingService getActiveService() {
865
        if (!serviceStack.isEmpty()) {
866
            return serviceStack.peek();
867
        }
868
        return null;
869
    }
870

    
871
    public EditingConsole getConsolePanel() {
872
        if (console == null) {
873
            console = new DefaultEditingConsole(new ResponseListener() {
874

    
875
                @Override
876
                public void acceptResponse(String response) {
877
                    textEntered(response);
878
                }
879
            });
880
        }
881
        return console;
882
    }
883

    
884
    protected FLyrVect getCurrentLayer() {
885
        return this.currentLayer;
886
    }
887

    
888
    protected EditingServiceParameter getCurrentParam() {
889
        return this.currentParam;
890
    }
891

    
892
    private Component getDockConsole() {
893
        if (dockConsole == null) {
894
            dockConsole = new JDockPanel((JComponent) getConsolePanel());
895
        }
896
        return dockConsole;
897
    }
898

    
899
    private DefaultEditingBehavior getEditingBehavior() {
900
        if (editingCompoundBehavior != null) {
901
            return (DefaultEditingBehavior) editingCompoundBehavior
902
                .getBehavior(EditingCompoundBehavior.EDITING_INDEX);
903
        }
904
        return null;
905
    }
906

    
907
    private EditingCompoundBehavior getEditingCompoundBehavior() {
908
        if (editingCompoundBehavior != null) {
909
            return editingCompoundBehavior;
910
        } else {
911
            EditingCompoundBehavior editingCompoundBehavior;
912

    
913
            CompoundBehavior compoundBehavior =
914
                (CompoundBehavior) getMapControl().getMapTool(VECTOREDITING_TOOL_NAME);
915

    
916
            if (compoundBehavior instanceof EditingCompoundBehavior) {
917
                editingCompoundBehavior =
918
                    (EditingCompoundBehavior) compoundBehavior;
919
            } else {
920
                editingCompoundBehavior =
921
                    (EditingCompoundBehavior) compoundBehavior.getBehavior(0);
922
            }
923

    
924
            setCompoundBehavior(editingCompoundBehavior);
925
            return editingCompoundBehavior;
926
        }
927
    }
928

    
929
    @Override
930
    public MapControl getMapControl() {
931
        return mapControlReference.get();
932
    }
933

    
934
    
935
    @Override
936
    public void nextParameter() {
937
        enqueueTask(() -> {
938
            doNextParameter();
939
        });
940
    }
941
    
942
    private void doNextParameter() {
943
        if ((getMapControl().getCurrentTool() != null)
944
            && !getMapControl().getCurrentTool().equals(VECTOREDITING_TOOL_NAME)) {
945
            getMapControl().setTool(VECTOREDITING_TOOL_NAME);
946
        }
947
        EditingService activeService = getActiveService();
948
        currentParam = activeService.next();
949

    
950
        if (currentParam == null) {
951
            doFinishService();
952
        } else {
953
            askQuestion(currentParam);
954
            if (currentParam.getTypes().contains(TYPE.SELECTION)) {
955
                enableSelection(true);
956
            } else if (currentParam.getTypes().contains(TYPE.MULTILAYER_SELECTION)) {
957
                enableSelection(true);
958
            } else if (currentParam.getTypes().contains(TYPE.GEOMETRY)) {
959
                refreshMenusAndToolBars();
960
            }
961
        }
962
    }
963

    
964
    protected Stack<EditingService> getServiceStack() {
965
        return this.serviceStack;
966
    }
967

    
968
    private void hideConsole() {
969
        isShowConsole = false;
970
        if( !SwingUtilities.isEventDispatchThread() ) {
971
            try {
972
                SwingUtilities.invokeAndWait(new Runnable() {
973

    
974
                    @Override
975
                    public void run() {
976
                        hideConsole();
977
                    }
978
                });
979
                return;
980
            } catch (InterruptedException | InvocationTargetException ex) {
981
                LOGGER.warn("Can't hide editing console.",ex);
982
            }
983
            return;
984
        }
985
        getDockConsole().setVisible(false);
986
    }
987

    
988
    @Override
989
    public boolean isServiceCompatible(String name) {
990
        DefaultEditingBehavior editingBehavior = getEditingBehavior();
991

    
992
        if (editingBehavior != null) {
993

    
994
            try {
995
                EditingManager manager = EditingLocator.getManager();
996
                EditingServiceInfo serviceInfo = manager.getServiceInfo(name);
997
                GeometryType geoType = null;
998

    
999
                for (EditingService editingService : getServiceStack()) {
1000
                    EditingServiceParameter parameter = editingService.next();
1001
                    if (parameter != null) {
1002
                        if (parameter.getTypes().contains(TYPE.GEOMETRY)) {
1003

    
1004
                            int geometryType = parameter.getGeometryType();
1005
                            int subType = -1;
1006

    
1007
                            try {
1008
                                subType
1009
                                        = getCurrentLayer().getFeatureStore()
1010
                                                .getDefaultFeatureType()
1011
                                                .getDefaultGeometryAttribute()
1012
                                                .getGeomType().getSubType();
1013

    
1014
                                geoType
1015
                                        = GeometryLocator.getGeometryManager()
1016
                                                .getGeometryType(geometryType, subType);
1017
                            } catch (Exception e) {
1018

    
1019
                                String msg
1020
                                        = String.format(
1021
                                                "Problems getting default feature"
1022
                                                + " type of %1$s or getting geometry"
1023
                                                + " type of %2$s %3$s",
1024
                                                getCurrentLayer().getName(), geometryType,
1025
                                                subType);
1026

    
1027
                                throw new ServiceInformationException(msg, e);
1028
                            }
1029

    
1030
                            return serviceInfo.isCompatibleWith(geoType)
1031
                                    && serviceInfo.createsNewGeometries();
1032
                        }
1033
                    }
1034
                }
1035

    
1036
                if (getCurrentLayer() != null) {
1037
                    try {
1038
                        geoType
1039
                                = getCurrentLayer().getFeatureStore()
1040
                                        .getDefaultFeatureType()
1041
                                        .getDefaultGeometryAttribute().getGeomType();
1042

    
1043
                        if (serviceInfo.isCompatibleWith(geoType)) {
1044
                            return true;
1045
                        }
1046
                    } catch (DataException e) {
1047
                        String msg
1048
                                = String.format("Problems getting default "
1049
                                        + "feature type of %1$s", getCurrentLayer()
1050
                                                .getName());
1051
                        throw new ServiceInformationException(msg, e);
1052
                    }
1053
                }
1054

    
1055
                return false;
1056
            } catch (ServiceInformationException e) {
1057
                LOGGER.warn(
1058
                    "Problems getting if editing context is compatible with "
1059
                        + name, e);
1060
            }
1061
        }
1062
        return false;
1063
    }
1064
     
1065
    private static final EditingContextSymbolTable contextSymbolTable = new EditingContextSymbolTable();
1066
    
1067
    @Override
1068
    public SymbolTable getContextSymbolTable() {
1069
        return contextSymbolTable;
1070
    }
1071
    
1072
    @Override
1073
    public Point parsePoint(String response) throws ParsePointException {
1074
        response = fixResponseUsingBookmarks(response);
1075
        
1076
        try {
1077
            Object x = ExpressionUtils.evaluate(contextSymbolTable, response);
1078
            if( x instanceof Point ) {
1079
                contextSymbolTable.addPoint((Point) x);
1080
                return (Point) x;
1081
            }
1082
        } catch(Exception ex) {
1083
            LOGGER.debug("Can't evaluate: "+StringEscapeUtils.escapeJava(response),ex);
1084
        }
1085
        String s = "ST_MakePoint("+response+")";
1086
        try {
1087
            Object x = ExpressionUtils.evaluate(contextSymbolTable, s);
1088
            if( x instanceof Point ) {
1089
                contextSymbolTable.addPoint((Point) x);
1090
                return (Point) x;
1091
            }
1092
        } catch(Exception ex) {
1093
            throw new ParsePointException(ex);
1094
        }
1095
        throw new ParsePointException(null);
1096
    }
1097
    
1098
    private Double parseValue(String response) throws ParseValueException {
1099
        response = fixResponseUsingBookmarks(response);
1100

    
1101
        try {
1102
            Object x = ExpressionUtils.evaluate(contextSymbolTable, response);
1103
            if( x instanceof Double ) {
1104
                return (Double) x;
1105
            }  
1106
            if( x==null ) {
1107
                throw new ParseValueException(new NullPointerException());
1108
            }
1109
            Coercion toDouble = ToolsLocator.getDataTypesManager().get(DataTypes.DOUBLE).getCoercion();
1110
            return (Double) toDouble.coerce(x);
1111
        } catch(Exception ex) {
1112
            throw new ParseValueException(ex);
1113
        }
1114

    
1115
    }
1116

    
1117
    protected String fixResponseUsingBookmarks(String response) throws LocatorException {
1118
        if( response != null ) {
1119
            response = response.trim();
1120
            int n = StringUtils.indexOf(response, " ");
1121
            if(n>0){
1122
                String name = StringUtils.left(response, n);
1123
                Function fn = contextSymbolTable.function(name);
1124
                if(fn != null){
1125
                    response = name+"("+response.substring(n)+")";
1126
                }
1127
            }
1128
        }
1129
        return response;
1130
    }
1131

    
1132
    protected void refreshMenusAndToolBars() {
1133
        if (!SwingUtilities.isEventDispatchThread()) {
1134
            SwingUtilities.invokeLater(() -> { refreshMenusAndToolBars(); });
1135
            return;
1136
        }
1137
        Notification notification = new BaseNotification(
1138
                EditingContext.REFRESH_TOOLS_NOTIFICATION,
1139
                null
1140
        );
1141
        this.observableHelper.notifyObservers(this, notification);
1142
    }
1143

    
1144
    private void saveChanges(FLyrVect layer) throws EndEditingException {
1145
        FeatureStore featureStore = layer.getFeatureStore();
1146
        try {
1147
            featureStore.finishEditing();
1148
        } catch (Exception e) {
1149
            throw new EndEditingException(e);
1150
        }
1151
    }
1152

    
1153
    private void setActiveService(EditingService service) {
1154
        //Si se hace este metodo publico hay que comprobar el isProcessing
1155
        serviceStack.add(service);
1156
        notifyChangeSelectedTool(service.getName());
1157
    }
1158

    
1159
    private void setCompoundBehavior(EditingCompoundBehavior compoundBehavior) {
1160
        if( this.isProcessing() ) {
1161
            return;
1162
        }
1163
        this.editingCompoundBehavior = compoundBehavior;
1164
    }
1165

    
1166
    private void setCurrentLayer(FLyrVect layer) {
1167
        if( this.isProcessing() ) {
1168
            return;
1169
        }
1170
        if (this.currentLayer != layer) {
1171
            this.currentLayer = layer;
1172
            if( !this.serviceStack.isEmpty() ) {
1173
                EditingService x = this.serviceStack.firstElement();
1174
                if( x != null && this.isServiceCompatible(x.getName())) {
1175
                    String name = x.getName();
1176
                    cleanEditingContext();
1177
                    this.serviceStack.clear();
1178
                    this.activateService(name);
1179
                } else {
1180
                    cleanEditingContext();
1181
                }
1182
            }
1183
        }
1184

    
1185
    }
1186

    
1187
    @Override
1188
    public void setMapControl(MapControl mapControl) {
1189
        if( this.isProcessing() ) {
1190
            return;
1191
        }
1192

    
1193
        this.mapControlReference = new WeakReference<>(mapControl);
1194
        this.mapContextReference =
1195
            new WeakReference<>(mapControl.getMapContext());
1196

    
1197
        // When mapControl is updated we have to add older additional behaviors
1198
        // to new mapControl
1199
        if (lastAdditionalBehaviors != null) {
1200
            try {
1201
                addBehaviors(lastAdditionalBehaviors);
1202
            } catch (CreateEditingBehaviorException e1) {
1203
                LOGGER.info("Problems adding behaviors to editing context", e1);
1204
                getMapControl().setTool("pan");
1205
            }
1206
        }
1207
    }
1208

    
1209
    private void showConsole() {
1210
        if (isShowConsole) {
1211
            return;
1212
        }
1213
        if( !SwingUtilities.isEventDispatchThread() ) {
1214
            try {
1215
                SwingUtilities.invokeAndWait(new Runnable() {
1216

    
1217
                    @Override
1218
                    public void run() {
1219
                        showConsole();
1220
                    }
1221
                });
1222
                return;
1223
            } catch (InterruptedException | InvocationTargetException ex) {
1224
                LOGGER.warn("Can't show editing console.",ex);
1225
            }
1226
            return;
1227
        }
1228
        isShowConsole = true;
1229
        getMapControl().remove(getDockConsole());
1230
        getMapControl().setLayout(new BorderLayout());
1231
        getMapControl().add(getDockConsole(), BorderLayout.SOUTH);
1232
        getDockConsole().setVisible(true);
1233
    }
1234

    
1235
    protected void showConsoleMessage(final String text) {
1236
        if (!SwingUtilities.isEventDispatchThread()) {
1237
            SwingUtilities.invokeLater(new Runnable() {
1238

    
1239
                @Override
1240
                public void run() {
1241
                    showConsoleMessage(text);
1242
                }
1243
            });
1244
            return;
1245
        }
1246
        getConsolePanel().addText(text);
1247
    }
1248

    
1249
    @Override
1250
    public void cancelActiveService() {
1251
        this.textEntered(null);
1252
    }
1253
    
1254
//    protected void selectedValue(Object value) {
1255
//        EditingService activeService = getActiveService();
1256
//        I18nManager i18nManager = ToolsLocator.getI18nManager();
1257
//        
1258
//        try {
1259
//            activeService.setValue(value);
1260
//        } catch (InvalidEntryException ex) {
1261
//            showConsoleMessage("\n"
1262
//                    + i18nManager.getTranslation("invalid_option"));
1263
//        }
1264
//
1265
//        activeService = getActiveService();
1266
//        if (activeService != null) {
1267
//            nextParameter();
1268
//        } else {
1269
//            cleanEditingContext();
1270
//        }
1271
//
1272
//    }
1273
    
1274
    protected void textEntered(String response) {
1275
        if( this.isProcessing() ) {
1276
            return;
1277
        }
1278
        FeatureStore featureStore = getCurrentLayer().getFeatureStore();        
1279
        if (response == null) {
1280
            EditingService activeService = getActiveService();
1281
            if (activeService != null) {
1282
                try {
1283
                    activeService.stop();
1284
                    serviceStack.pop();
1285
                    if (serviceStack.isEmpty()) {
1286
                        featureStore
1287
                            .getFeatureSelection().deselectAll();
1288
                        changeSelectedTool(DEFAULT_TOOL);
1289
                    } else {
1290
                        changeSelectedTool(activeService.getName());
1291
                    }
1292

    
1293
                    refreshMenusAndToolBars();
1294
                    activeService = getActiveService();
1295
                    if (activeService != null) {
1296
                        nextParameter();
1297
                    } else {
1298
                        cleanEditingContext();
1299
                    }
1300

    
1301
                } catch (StopServiceException e) {
1302
                    LOGGER
1303
                        .info("Can't stop " + activeService.getName(), e);
1304
                } catch (DataException e) {
1305
                    LOGGER.info("Can't get selection of "
1306
                        + featureStore.getFullName(), e);
1307
                }
1308
            }
1309
        } else {
1310
            enqueueTask(() -> {
1311
                try {
1312
                    I18nManager i18nManager = ToolsLocator.getI18nManager();
1313
                    EditingService activeService = getActiveService();
1314
                    if (getCurrentParam() != null) {
1315
                        try {
1316
                            Object coercedValue = coerceInputParameter(getCurrentParam(), response);
1317
                            activeService.setValue(coercedValue);
1318
                        } catch (InvalidEntryException ex) {
1319
                            showConsoleMessage("\n"
1320
                                    + i18nManager.getTranslation("invalid_option"));
1321
                        }
1322
                    }
1323

    
1324
                    activeService = getActiveService();
1325
                    if (activeService != null) {
1326
                        doNextParameter();
1327
                    } else {
1328
                        cleanEditingContext();
1329
                    }
1330
                } finally {
1331
                    refreshMenusAndToolBars();
1332
                }
1333
            });
1334
            refreshMenusAndToolBars();
1335
        }
1336
    }
1337
    
1338
    private Object coerceInputParameter(EditingServiceParameter parameter, String input) throws InvalidEntryException {
1339
        if (parameter != null) {
1340
            FeatureStore featureStore = getCurrentLayer().getFeatureStore();
1341
            Set<TYPE> types = parameter.getTypes();
1342
            Point point = null;
1343
            Double value = null;
1344
            Point defaultPoint = null;
1345
            Object defaultValue = parameter.getDefaultValue();
1346

    
1347
//            boolean insertedValue = false;
1348
            if ((types.contains(TYPE.POSITION))
1349
                    || types.contains(TYPE.LIST_POSITIONS)) {
1350

    
1351
                if(defaultValue instanceof Point){
1352
                    defaultPoint = (Point) defaultValue;
1353
                }
1354
                try {
1355
                    if (StringUtils.isEmpty(input.replace("\n", ""))) {
1356
                        point = defaultPoint;
1357
                    } else {
1358
                        point = parsePoint(input);
1359
                    }
1360

    
1361
                    if (point != null) {
1362
                        return point;
1363
                    }
1364

    
1365
                } catch (ParsePointException e) {
1366
                    // Do nothing to try other types
1367
                }
1368
            }
1369
            if (types.contains(TYPE.VALUE)) {
1370

    
1371
                try {
1372
                    value = parseValue(input);
1373
                    if (value != null) {
1374
                        return value;
1375
                    }
1376

    
1377
                } catch (ParseValueException e) {
1378
                    // Do nothing to try other types
1379
                }
1380

    
1381
            }
1382
            if (types.contains(TYPE.OPTION)) {
1383
                input = input.replace("\n", "");
1384
                return input;
1385
            }
1386

    
1387
            if (types.contains(TYPE.SELECTION)) {
1388
                if (input.equalsIgnoreCase("\n")) {
1389
                    enableSelection(false);
1390

    
1391
                    FeatureSelection clonedSelection;
1392
                    try {
1393
                        clonedSelection = (FeatureSelection) featureStore
1394
                                .getFeatureSelection().clone();
1395
                        if (!clonedSelection.isEmpty()) {
1396
                            return clonedSelection;
1397
                        }
1398
                    } catch (Exception e) {
1399
                        LOGGER.warn("Can't access to selection.", e);
1400
                        throw new InvalidEntryException(e);
1401
                    }
1402
                }
1403
            }
1404

    
1405
            if (types.contains(TYPE.MULTILAYER_SELECTION)) {
1406
                if (input.equalsIgnoreCase("\n")) {
1407
                    enableSelection(false);
1408
                    MapContext mapContext = this.getMapControl().getMapContext();
1409
                    List<Feature> features = new ArrayList<>();
1410
                    for (FLayer lyrActive : mapContext.getLayers().getActives()) {
1411
                        if(lyrActive instanceof FLyrVect){
1412
                            if(!((FLyrVect) lyrActive).getFeatureStore().isFeatureSelectionEmpty()) {
1413
                                this.getSelectedFeaturesCopy(features, ((FLyrVect) lyrActive).getFeatureStore().getFeatureSelectionQuietly());
1414
                            }
1415
                        }
1416
                    }
1417
                    if(!features.isEmpty()){
1418
                        return features;
1419
                    }
1420
                }
1421
            }
1422
        }
1423
        return null;
1424
    }
1425
    
1426
    private List<Feature> getSelectedFeaturesCopy(List<Feature> features, FeatureSelection selection)  {
1427
        SimpleTaskStatus status = ToolsLocator.getTaskStatusManager().createDefaultSimpleTaskStatus("Loading selection");
1428
        try {
1429
            status.add();
1430
            status.setAutoremove(true);
1431
            status.setRangeOfValues(0, selection.size());
1432
            if(features == null){
1433
                features = new ArrayList<>();
1434
            }
1435
            DisposableIterator it = selection.fastIterator();
1436
            while (it.hasNext()) {
1437
                if( status.isCancellationRequested() ) {
1438
                    status.cancel();
1439
                    return features;
1440
                }
1441
                Feature feature = (Feature) it.next();
1442
                if( feature.getDefaultGeometry()==null ) {
1443
                    continue;
1444
                }
1445
                features.add(feature.getCopy());
1446
                status.incrementCurrentValue();
1447
            }
1448
            status.terminate();
1449
            return features;
1450
        } catch (DataException ex) {
1451
            status.abort();
1452
            throw new RuntimeException("Can't calculate selected features", ex);
1453
        }
1454
    }
1455

    
1456
    @Override
1457
    public void setDefaultBehaviors(Behavior[] defaultBehaviors) {
1458
        if( this.isProcessing() ) {
1459
            return;
1460
        }
1461
        this.defaultBehaviors = defaultBehaviors;
1462
        try {
1463
            addBehaviors(defaultBehaviors);
1464
        } catch (CreateEditingBehaviorException e1) {
1465
            LOGGER.info("Problems adding behaviors to editing context", e1);
1466
            getMapControl().setTool("pan");
1467
        }
1468
    }
1469

    
1470
    @Override
1471
    public Behavior[] getDefaultBehaviors() {
1472
        return this.defaultBehaviors;
1473
    }
1474

    
1475
    @Override
1476
    public void setValue(EditingServiceParameter parameter, Object value) throws InvalidEntryException {
1477
        setValue(parameter, value, false);
1478
    }
1479
    
1480
    private static class TasksDispatcher extends Thread {
1481
        private BlockingQueue<Runnable> tasks = new LinkedBlockingQueue<>();
1482
        private boolean processing = false;
1483
        private final JComponent component;
1484
        private Cursor lastNoBusyCursor = null;
1485

    
1486
        public TasksDispatcher(JComponent component) {
1487
            this.component = component;
1488
        }
1489

    
1490
        public void setMouseBusy(boolean busy) {
1491
            if (busy) {
1492
                if (lastNoBusyCursor == null) {
1493
                    this.lastNoBusyCursor = component.getCursor();
1494
                }
1495
                component.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
1496
            } else {
1497
                component.setCursor(lastNoBusyCursor);
1498
                lastNoBusyCursor = null;
1499
            }
1500
        }
1501

    
1502
        public void run() {
1503
            while (true){
1504
                try {
1505
                    Runnable task = tasks.poll(1, TimeUnit.MINUTES);
1506
                    if(task == null){
1507
                        return;
1508
                    }
1509
                    this.processing = true;
1510
                    setMouseBusy(true);
1511
                    task.run();
1512
                    if(tasks.isEmpty()){
1513
                        this.processing = false;
1514
                        setMouseBusy(false);
1515
                    }
1516
                    
1517
                } catch (Throwable t) {
1518
                    LOGGER.warn("Can't proccess task", t);
1519
                }
1520
            }
1521
        }
1522
        public void add(Runnable task){
1523
            try {
1524
                this.tasks.put(task);
1525
            } catch (InterruptedException ex) {
1526
                throw new RuntimeException("Can't addd task", ex);
1527
            }
1528
        }
1529
        public boolean isProcessing() {
1530
            if(!this.isAlive()){
1531
                return false;
1532
            }
1533
            return this.processing;
1534
        }
1535
    }
1536

    
1537
    TasksDispatcher tasksDispatcher = null;
1538
    
1539
    @Override
1540
    public void setValue(EditingServiceParameter parameter, Object value, boolean next) throws InvalidEntryException {
1541
        
1542
        
1543
        if( value instanceof CharSequence){
1544
            value = coerceInputParameter(parameter, value.toString());
1545
        } else if( value instanceof Point) {
1546
            contextSymbolTable.addPoint((Point) value);
1547
        }
1548
        Object v = value;
1549
        Runnable task = () -> {
1550
            try {
1551
                getActiveService().setValue(parameter, v);
1552
                if(next){
1553
                    doNextParameter();
1554
                }
1555
            } catch (InvalidEntryException ex) {
1556
                I18nManager i18nManager = ToolsLocator.getI18nManager();
1557
                String stateMessage = ex.getStateMessage();
1558
                if(StringUtils.isBlank(stateMessage)){
1559
                    showConsoleMessage("\n"+ i18nManager.getTranslation("invalid_option"));
1560
                } else {
1561
                    showConsoleMessage("\n"+ i18nManager.getTranslation("invalid_option")+": "+StringUtils.defaultIfBlank(ex.getStateMessage(), ""));
1562
                }
1563
                doNextParameter();
1564
            } catch (Exception ex) {
1565
                LOGGER.warn("Can't set value", ex);
1566
                cleanEditingContext();
1567
                return;
1568
            } finally {
1569
                refreshMenusAndToolBars();
1570
            }
1571
        };
1572
        enqueueTask(task);
1573
        refreshMenusAndToolBars();
1574
        
1575
        
1576
    }
1577

    
1578
    private void enqueueTask(Runnable task) {
1579
        if(this.tasksDispatcher == null || !this.tasksDispatcher.isAlive()){
1580
            this.tasksDispatcher = new TasksDispatcher(this.getMapControl());
1581
            this.tasksDispatcher.start();
1582
        }
1583
        this.tasksDispatcher.add(task);
1584
    }
1585

    
1586
    public GeometryType getGeometryType() {
1587
        if( this.currentLayer==null ) {
1588
            return null;
1589
        }
1590
        FeatureStore store = this.currentLayer.getFeatureStore();
1591
        if( store == null ) {
1592
            return null;
1593
        }
1594
        FeatureType ftype = store.getDefaultFeatureTypeQuietly();
1595
        if( ftype == null ) {
1596
            return null;
1597
        }
1598
        FeatureAttributeDescriptor geomattr = ftype.getDefaultGeometryAttribute();
1599
        if( geomattr == null ) {
1600
            return null;
1601
        }
1602
        return geomattr.getGeomType();
1603
    }    
1604
    
1605
    public boolean isProcessing() {
1606
        if(this.tasksDispatcher == null){
1607
            return false;
1608
        }
1609
        return this.tasksDispatcher.isProcessing();
1610
    }
1611
    
1612
    @Override
1613
    public int getDrawMode() {
1614
        return this.drawMode;
1615
    }
1616

    
1617
    @Override
1618
    public void setDrawMode(int mode) {
1619
        this.drawMode = mode;
1620
        refreshMenusAndToolBars();
1621
    }
1622
}