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 @ 4284

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

    
121
public class DefaultEditingContext implements EditingContext {
122

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

    
126
    private WeakReference<MapControl> mapControlReference;
127

    
128
    private WeakReference<MapContext> mapContextReference;
129

    
130
    private EditingCompoundBehavior editingCompoundBehavior;
131

    
132
    private Behavior[] lastAdditionalBehaviors;
133

    
134
    private final ObservableHelper observableHelper;
135

    
136
    private EditingConsole console;
137

    
138
    private JDockPanel dockConsole = null;
139

    
140
    private boolean isShowConsole = false;
141

    
142
    private final Stack<EditingService> serviceStack;
143

    
144
    private FLyrVect currentLayer;
145

    
146
    private EditingServiceParameter currentParam;
147

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

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

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

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

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

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

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

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

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

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

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

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

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

    
261
        }
262

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

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

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

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

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

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

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

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

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

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

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

    
339
            EditingManager manager = EditingLocator.getManager();
340

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

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

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

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

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

    
376
                    } catch (InvalidEntryException e) {
377

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

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

    
393
                    setActiveService(service);
394

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

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

    
404
        DefaultEditingBehavior editingBehavior;
405
        EditingCompoundBehavior editingCompoundBehavior;
406

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

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

    
414
            if (additionalBehavior != null) {
415

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

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

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

    
424
                lastAdditionalBehaviors = additionalBehavior;
425

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

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

    
440
    }
441

    
442
    private void addLayerListeners() {
443

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

    
446
        layers.addLayerListener(layerListener);
447

    
448
        layers.addLayerCollectionListener(new LayerCollectionListener() {
449

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
550

    
551
        setCurrentLayer(layer);
552

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

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

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

    
582
        }
583

    
584
        featureStore.addObserver(getMapControl());
585

    
586
        enableSnapping();
587
    }
588

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

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

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

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

    
638

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

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

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

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

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

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

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

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

    
735
        case CANCEL:
736
            return;
737
        }
738

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

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

    
747
    }
748

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

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

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

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

    
774
            }
775

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

    
781

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

    
792
            doAction(layer, option);
793

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

    
797
        }
798

    
799
    }
800

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

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

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

    
833
                    I18nManager i18nManager = ToolsLocator.getI18nManager();
834
                    showConsoleMessage("\n"
835
                            + i18nManager.getTranslation(lastService.getName()) + "# "
836
                            + i18nManager.getTranslation("finished") + "\n");
837
                    if(lastService.mustRestartAtFinish()){
838
    //                lastService.stop();
839
                        setActiveService(lastService);
840
    //                lastService.start();
841
                        lastService.restart();
842
                        setDrawMode(DRAWMODE_NORMAL);
843
                        changeSelectedTool(getActiveService().getName());
844
                    } else {
845
                        setDrawMode(DRAWMODE_NORMAL);
846
                        enqueueTask(()->{
847
                            try {
848
                                lastService.stop();
849
                                if(serviceStack.isEmpty()){
850
                                    cleanEditingContext();
851
                                }
852
                                refreshMenusAndToolBars();
853
                            } catch (StopServiceException ex) {
854
                                
855
                            }
856
                        });
857
                    }
858
                }
859

    
860
            } catch (FinishServiceException ex) {
861
                showConsoleMessage("\n"+ex.getLocalizedMessage());
862
                cleanEditingContext();
863
                return;
864
            } catch (InvalidEntryException ex) {
865
                I18nManager i18nManager = ToolsLocator.getI18nManager();
866
                showConsoleMessage("\n"
867
                        + i18nManager.getTranslation("invalid_option"));
868
                changeSelectedTool(getActiveService().getName());
869
            } catch (Exception ex) {
870
                LOGGER.warn("Can't finish " + lastService.getName(), ex);
871
                I18nManager i18nManager = ToolsLocator.getI18nManager();
872
                showConsoleMessage("\n"+i18nManager.getTranslation("_An_error_has_occurred"));
873
                cleanEditingContext();
874
                return;
875
            }
876

    
877
            doNextParameter();
878
        } finally {
879
            refreshMenusAndToolBars();
880
        }
881
    }
882

    
883
    public EditingService getActiveService() {
884
        if (!serviceStack.isEmpty()) {
885
            return serviceStack.peek();
886
        }
887
        return null;
888
    }
889

    
890
    public EditingConsole getConsolePanel() {
891
        if (console == null) {
892
            console = new DefaultEditingConsole(new ResponseListener() {
893

    
894
                @Override
895
                public void acceptResponse(String response) {
896
                    textEntered(response);
897
                }
898
            });
899
        }
900
        return console;
901
    }
902

    
903
    protected FLyrVect getCurrentLayer() {
904
        return this.currentLayer;
905
    }
906

    
907
    protected EditingServiceParameter getCurrentParam() {
908
        return this.currentParam;
909
    }
910

    
911
    private Component getDockConsole() {
912
        if (dockConsole == null) {
913
            dockConsole = new JDockPanel((JComponent) getConsolePanel());
914
        }
915
        return dockConsole;
916
    }
917

    
918
    private DefaultEditingBehavior getEditingBehavior() {
919
        if (editingCompoundBehavior != null) {
920
            return (DefaultEditingBehavior) editingCompoundBehavior
921
                .getBehavior(EditingCompoundBehavior.EDITING_INDEX);
922
        }
923
        return null;
924
    }
925

    
926
    private EditingCompoundBehavior getEditingCompoundBehavior() {
927
        if (editingCompoundBehavior != null) {
928
            return editingCompoundBehavior;
929
        } else {
930
            EditingCompoundBehavior editingCompoundBehavior;
931

    
932
            CompoundBehavior compoundBehavior =
933
                (CompoundBehavior) getMapControl().getMapTool(VECTOREDITING_TOOL_NAME);
934

    
935
            if (compoundBehavior instanceof EditingCompoundBehavior) {
936
                editingCompoundBehavior =
937
                    (EditingCompoundBehavior) compoundBehavior;
938
            } else {
939
                editingCompoundBehavior =
940
                    (EditingCompoundBehavior) compoundBehavior.getBehavior(0);
941
            }
942

    
943
            setCompoundBehavior(editingCompoundBehavior);
944
            return editingCompoundBehavior;
945
        }
946
    }
947

    
948
    @Override
949
    public MapControl getMapControl() {
950
        return mapControlReference.get();
951
    }
952

    
953
    
954
    @Override
955
    public void nextParameter() {
956
        enqueueTask(() -> {
957
            doNextParameter();
958
        });
959
    }
960
    
961
    private void doNextParameter() {
962
        if ((getMapControl().getCurrentTool() != null)
963
            && !getMapControl().getCurrentTool().equals(VECTOREDITING_TOOL_NAME)) {
964
            getMapControl().setTool(VECTOREDITING_TOOL_NAME);
965
        }
966
        EditingService activeService = getActiveService();
967
        if(activeService == null){
968
            currentParam = null;
969
        } else {
970
            currentParam = activeService.next();
971
        }
972

    
973
        if (currentParam == null) {
974
            doFinishService();
975
        } else {
976
            askQuestion(currentParam);
977
            if (currentParam.getTypes().contains(TYPE.SELECTION)) {
978
                enableSelection(true);
979
            } else if (currentParam.getTypes().contains(TYPE.MULTILAYER_SELECTION)) {
980
                enableSelection(true);
981
            } else if (currentParam.getTypes().contains(TYPE.GEOMETRY)) {
982
                refreshMenusAndToolBars();
983
            }
984
        }
985
    }
986

    
987
    protected Stack<EditingService> getServiceStack() {
988
        return this.serviceStack;
989
    }
990

    
991
    private void hideConsole() {
992
        isShowConsole = false;
993
        if( !SwingUtilities.isEventDispatchThread() ) {
994
            try {
995
                SwingUtilities.invokeAndWait(new Runnable() {
996

    
997
                    @Override
998
                    public void run() {
999
                        hideConsole();
1000
                    }
1001
                });
1002
                return;
1003
            } catch (InterruptedException | InvocationTargetException ex) {
1004
                LOGGER.warn("Can't hide editing console.",ex);
1005
            }
1006
            return;
1007
        }
1008
        getDockConsole().setVisible(false);
1009
    }
1010

    
1011
    @Override
1012
    public boolean isServiceCompatible(String name) {
1013
        DefaultEditingBehavior editingBehavior = getEditingBehavior();
1014

    
1015
        if (editingBehavior != null) {
1016

    
1017
            try {
1018
                EditingManager manager = EditingLocator.getManager();
1019
                EditingServiceInfo serviceInfo = manager.getServiceInfo(name);
1020
                GeometryType geoType = null;
1021

    
1022
                for (EditingService editingService : getServiceStack()) {
1023
                    EditingServiceParameter parameter = editingService.next();
1024
                    if (parameter != null) {
1025
                        if (parameter.getTypes().contains(TYPE.GEOMETRY)) {
1026

    
1027
                            int geometryType = parameter.getGeometryType();
1028
                            int subType = -1;
1029

    
1030
                            try {
1031
                                subType
1032
                                        = getCurrentLayer().getFeatureStore()
1033
                                                .getDefaultFeatureType()
1034
                                                .getDefaultGeometryAttribute()
1035
                                                .getGeomType().getSubType();
1036

    
1037
                                geoType
1038
                                        = GeometryLocator.getGeometryManager()
1039
                                                .getGeometryType(geometryType, subType);
1040
                            } catch (Exception e) {
1041

    
1042
                                String msg
1043
                                        = String.format(
1044
                                                "Problems getting default feature"
1045
                                                + " type of %1$s or getting geometry"
1046
                                                + " type of %2$s %3$s",
1047
                                                getCurrentLayer().getName(), geometryType,
1048
                                                subType);
1049

    
1050
                                throw new ServiceInformationException(msg, e);
1051
                            }
1052

    
1053
                            return serviceInfo.isCompatibleWith(geoType)
1054
                                    && serviceInfo.createsNewGeometries();
1055
                        }
1056
                    }
1057
                }
1058

    
1059
                if (getCurrentLayer() != null) {
1060
                    try {
1061
                        geoType
1062
                                = getCurrentLayer().getFeatureStore()
1063
                                        .getDefaultFeatureType()
1064
                                        .getDefaultGeometryAttribute().getGeomType();
1065

    
1066
                        if (serviceInfo.isCompatibleWith(geoType)) {
1067
                            return true;
1068
                        }
1069
                    } catch (DataException e) {
1070
                        String msg
1071
                                = String.format("Problems getting default "
1072
                                        + "feature type of %1$s", getCurrentLayer()
1073
                                                .getName());
1074
                        throw new ServiceInformationException(msg, e);
1075
                    }
1076
                }
1077

    
1078
                return false;
1079
            } catch (ServiceInformationException e) {
1080
                LOGGER.warn(
1081
                    "Problems getting if editing context is compatible with "
1082
                        + name, e);
1083
            }
1084
        }
1085
        return false;
1086
    }
1087
     
1088
    private static final EditingContextSymbolTable contextSymbolTable = new EditingContextSymbolTable();
1089
    
1090
    @Override
1091
    public SymbolTable getContextSymbolTable() {
1092
        return contextSymbolTable;
1093
    }
1094
    
1095
    @Override
1096
    public Point parsePoint(String response) throws ParsePointException {
1097
        response = fixResponseUsingBookmarks(response);
1098
        
1099
        try {
1100
            Object x = ExpressionUtils.evaluate(contextSymbolTable, response);
1101
            if( x instanceof Point ) {
1102
                contextSymbolTable.addPoint((Point) x);
1103
                return (Point) x;
1104
            }
1105
        } catch(Exception ex) {
1106
            LOGGER.debug("Can't evaluate: "+StringEscapeUtils.escapeJava(response),ex);
1107
        }
1108
        String s = "ST_MakePoint("+response+")";
1109
        try {
1110
            Object x = ExpressionUtils.evaluate(contextSymbolTable, s);
1111
            if( x instanceof Point ) {
1112
                contextSymbolTable.addPoint((Point) x);
1113
                return (Point) x;
1114
            }
1115
        } catch(Exception ex) {
1116
            throw new ParsePointException(ex);
1117
        }
1118
        throw new ParsePointException(null);
1119
    }
1120
    
1121
    private Double parseValue(String response) throws ParseValueException {
1122
        response = fixResponseUsingBookmarks(response);
1123

    
1124
        try {
1125
            Object x = ExpressionUtils.evaluate(contextSymbolTable, response);
1126
            if( x instanceof Double ) {
1127
                return (Double) x;
1128
            }  
1129
            if( x==null ) {
1130
                throw new ParseValueException(new NullPointerException());
1131
            }
1132
            Coercion toDouble = ToolsLocator.getDataTypesManager().get(DataTypes.DOUBLE).getCoercion();
1133
            return (Double) toDouble.coerce(x);
1134
        } catch(Exception ex) {
1135
            throw new ParseValueException(ex);
1136
        }
1137

    
1138
    }
1139

    
1140
    protected String fixResponseUsingBookmarks(String response) throws LocatorException {
1141
        if( response != null ) {
1142
            response = response.trim();
1143
            int n = StringUtils.indexOf(response, " ");
1144
            if(n>0){
1145
                String name = StringUtils.left(response, n);
1146
                Function fn = contextSymbolTable.function(name);
1147
                if(fn != null){
1148
                    response = name+"("+response.substring(n)+")";
1149
                }
1150
            }
1151
        }
1152
        return response;
1153
    }
1154

    
1155
    protected void refreshMenusAndToolBars() {
1156
        if (!SwingUtilities.isEventDispatchThread()) {
1157
            SwingUtilities.invokeLater(() -> { refreshMenusAndToolBars(); });
1158
            return;
1159
        }
1160
        Notification notification = new BaseNotification(
1161
                EditingContext.REFRESH_TOOLS_NOTIFICATION,
1162
                null
1163
        );
1164
        this.observableHelper.notifyObservers(this, notification);
1165
    }
1166

    
1167
    private void saveChanges(FLyrVect layer) throws EndEditingException {
1168
        FeatureStore featureStore = layer.getFeatureStore();
1169
        try {
1170
            featureStore.finishEditing();
1171
        } catch (Exception e) {
1172
            throw new EndEditingException(e);
1173
        }
1174
    }
1175

    
1176
    private void setActiveService(EditingService service) {
1177
        //Si se hace este metodo publico hay que comprobar el isProcessing
1178
        serviceStack.add(service);
1179
        notifyChangeSelectedTool(service.getName());
1180
    }
1181

    
1182
    private void setCompoundBehavior(EditingCompoundBehavior compoundBehavior) {
1183
        if( this.isProcessing() ) {
1184
            return;
1185
        }
1186
        this.editingCompoundBehavior = compoundBehavior;
1187
    }
1188

    
1189
    private void setCurrentLayer(FLyrVect layer) {
1190
        if( this.isProcessing() ) {
1191
            return;
1192
        }
1193
        if (this.currentLayer != layer) {
1194
            this.currentLayer = layer;
1195
            if( !this.serviceStack.isEmpty() ) {
1196
                EditingService x = this.serviceStack.firstElement();
1197
                if( x != null && this.isServiceCompatible(x.getName())) {
1198
                    String name = x.getName();
1199
                    cleanEditingContext();
1200
                    this.serviceStack.clear();
1201
                    this.activateService(name);
1202
                } else {
1203
                    cleanEditingContext();
1204
                }
1205
            }
1206
        }
1207

    
1208
    }
1209

    
1210
    @Override
1211
    public void setMapControl(MapControl mapControl) {
1212
        if( this.isProcessing() ) {
1213
            return;
1214
        }
1215

    
1216
        this.mapControlReference = new WeakReference<>(mapControl);
1217
        this.mapContextReference =
1218
            new WeakReference<>(mapControl.getMapContext());
1219

    
1220
        // When mapControl is updated we have to add older additional behaviors
1221
        // to new mapControl
1222
        if (lastAdditionalBehaviors != null) {
1223
            try {
1224
                addBehaviors(lastAdditionalBehaviors);
1225
            } catch (CreateEditingBehaviorException e1) {
1226
                LOGGER.info("Problems adding behaviors to editing context", e1);
1227
                getMapControl().setTool("pan");
1228
            }
1229
        }
1230
    }
1231

    
1232
    private void showConsole() {
1233
        if (isShowConsole) {
1234
            return;
1235
        }
1236
        if( !SwingUtilities.isEventDispatchThread() ) {
1237
            try {
1238
                SwingUtilities.invokeAndWait(new Runnable() {
1239

    
1240
                    @Override
1241
                    public void run() {
1242
                        showConsole();
1243
                    }
1244
                });
1245
                return;
1246
            } catch (InterruptedException | InvocationTargetException ex) {
1247
                LOGGER.warn("Can't show editing console.",ex);
1248
            }
1249
            return;
1250
        }
1251
        isShowConsole = true;
1252
        getMapControl().remove(getDockConsole());
1253
        getMapControl().setLayout(new BorderLayout());
1254
        getMapControl().add(getDockConsole(), BorderLayout.SOUTH);
1255
        getDockConsole().setVisible(true);
1256
    }
1257

    
1258
    protected void showConsoleMessage(final String text) {
1259
        if (!SwingUtilities.isEventDispatchThread()) {
1260
            SwingUtilities.invokeLater(new Runnable() {
1261

    
1262
                @Override
1263
                public void run() {
1264
                    showConsoleMessage(text);
1265
                }
1266
            });
1267
            return;
1268
        }
1269
        getConsolePanel().addText(text);
1270
    }
1271

    
1272
    @Override
1273
    public void cancelActiveService() {
1274
        this.textEntered(null);
1275
    }
1276
    
1277
//    protected void selectedValue(Object value) {
1278
//        EditingService activeService = getActiveService();
1279
//        I18nManager i18nManager = ToolsLocator.getI18nManager();
1280
//        
1281
//        try {
1282
//            activeService.setValue(value);
1283
//        } catch (InvalidEntryException ex) {
1284
//            showConsoleMessage("\n"
1285
//                    + i18nManager.getTranslation("invalid_option"));
1286
//        }
1287
//
1288
//        activeService = getActiveService();
1289
//        if (activeService != null) {
1290
//            nextParameter();
1291
//        } else {
1292
//            cleanEditingContext();
1293
//        }
1294
//
1295
//    }
1296
    
1297
    protected void textEntered(String response) {
1298
        if( this.isProcessing() ) {
1299
            return;
1300
        }
1301
        FeatureStore featureStore = getCurrentLayer().getFeatureStore();        
1302
        if (response == null) {
1303
            EditingService activeService = getActiveService();
1304
            if (activeService != null) {
1305
                try {
1306
                    activeService.stop();
1307
                    serviceStack.pop();
1308
                    if (serviceStack.isEmpty()) {
1309
                        featureStore
1310
                            .getFeatureSelection().deselectAll();
1311
                        changeSelectedTool(DEFAULT_TOOL);
1312
                    } else {
1313
                        changeSelectedTool(activeService.getName());
1314
                    }
1315

    
1316
                    refreshMenusAndToolBars();
1317
                    activeService = getActiveService();
1318
                    if (activeService != null) {
1319
                        nextParameter();
1320
                    } else {
1321
                        cleanEditingContext();
1322
                    }
1323

    
1324
                } catch (StopServiceException e) {
1325
                    LOGGER
1326
                        .info("Can't stop " + activeService.getName(), e);
1327
                } catch (DataException e) {
1328
                    LOGGER.info("Can't get selection of "
1329
                        + featureStore.getFullName(), e);
1330
                }
1331
            }
1332
        } else {
1333
            enqueueTask(() -> {
1334
                try {
1335
                    I18nManager i18nManager = ToolsLocator.getI18nManager();
1336
                    EditingService activeService = getActiveService();
1337
                    if (getCurrentParam() != null) {
1338
                        try {
1339
                            Object coercedValue = coerceInputParameter(getCurrentParam(), response);
1340
                            activeService.setValue(coercedValue);
1341
                        } catch (InvalidEntryException ex) {
1342
                            showConsoleMessage("\n"
1343
                                    + i18nManager.getTranslation("invalid_option"));
1344
                        }
1345
                    }
1346

    
1347
                    activeService = getActiveService();
1348
                    if (activeService != null) {
1349
                        doNextParameter();
1350
                    } else {
1351
                        cleanEditingContext();
1352
                    }
1353
                } finally {
1354
                    refreshMenusAndToolBars();
1355
                }
1356
            });
1357
            refreshMenusAndToolBars();
1358
        }
1359
    }
1360
    
1361
    private Object coerceInputParameter(EditingServiceParameter parameter, String input) throws InvalidEntryException {
1362
        if (parameter != null) {
1363
            FeatureStore featureStore = getCurrentLayer().getFeatureStore();
1364
            Set<TYPE> types = parameter.getTypes();
1365
            Point point = null;
1366
            Double value = null;
1367
            Point defaultPoint = null;
1368
            Object defaultValue = parameter.getDefaultValue();
1369

    
1370
//            boolean insertedValue = false;
1371
            if ((types.contains(TYPE.POSITION))
1372
                    || types.contains(TYPE.LIST_POSITIONS)) {
1373

    
1374
                if(defaultValue instanceof Point){
1375
                    defaultPoint = (Point) defaultValue;
1376
                }
1377
                try {
1378
                    if (StringUtils.isEmpty(input.replace("\n", ""))) {
1379
                        point = defaultPoint;
1380
                    } else {
1381
                        point = parsePoint(input);
1382
                    }
1383

    
1384
                    if (point != null) {
1385
                        return point;
1386
                    }
1387

    
1388
                } catch (ParsePointException e) {
1389
                    // Do nothing to try other types
1390
                }
1391
            }
1392
            if (types.contains(TYPE.VALUE)) {
1393

    
1394
                try {
1395
                    value = parseValue(input);
1396
                    if (value != null) {
1397
                        return value;
1398
                    }
1399

    
1400
                } catch (ParseValueException e) {
1401
                    // Do nothing to try other types
1402
                }
1403

    
1404
            }
1405
            if (types.contains(TYPE.OPTION)) {
1406
                input = input.replace("\n", "");
1407
                return input;
1408
            }
1409

    
1410
            if (types.contains(TYPE.SELECTION)) {
1411
                if (input.equalsIgnoreCase("\n")) {
1412
                    enableSelection(false);
1413

    
1414
                    FeatureSelection clonedSelection;
1415
                    try {
1416
                        clonedSelection = (FeatureSelection) featureStore
1417
                                .getFeatureSelection().clone();
1418
                        if (!clonedSelection.isEmpty()) {
1419
                            return clonedSelection;
1420
                        }
1421
                    } catch (Exception e) {
1422
                        LOGGER.warn("Can't access to selection.", e);
1423
                        throw new InvalidEntryException(e);
1424
                    }
1425
                }
1426
            }
1427

    
1428
            if (types.contains(TYPE.MULTILAYER_SELECTION)) {
1429
                if (input.equalsIgnoreCase("\n")) {
1430
                    enableSelection(false);
1431
                    MapContext mapContext = this.getMapControl().getMapContext();
1432
                    List<Feature> features = new ArrayList<>();
1433
                    for (FLayer lyrActive : mapContext.getLayers().getActives()) {
1434
                        if(lyrActive instanceof FLyrVect){
1435
                            if(!((FLyrVect) lyrActive).getFeatureStore().isFeatureSelectionEmpty()) {
1436
                                this.getSelectedFeaturesCopy(features, ((FLyrVect) lyrActive).getFeatureStore().getFeatureSelectionQuietly());
1437
                            }
1438
                        }
1439
                    }
1440
                    if(!features.isEmpty()){
1441
                        return features;
1442
                    }
1443
                }
1444
            }
1445
        }
1446
        return null;
1447
    }
1448
    
1449
    private List<Feature> getSelectedFeaturesCopy(List<Feature> features, FeatureSelection selection)  {
1450
        SimpleTaskStatus status = ToolsLocator.getTaskStatusManager().createDefaultSimpleTaskStatus("Loading selection");
1451
        try {
1452
            status.add();
1453
            status.setAutoremove(true);
1454
            status.setRangeOfValues(0, selection.size());
1455
            if(features == null){
1456
                features = new ArrayList<>();
1457
            }
1458
            DisposableIterator it = selection.fastIterator();
1459
            while (it.hasNext()) {
1460
                if( status.isCancellationRequested() ) {
1461
                    status.cancel();
1462
                    return features;
1463
                }
1464
                Feature feature = (Feature) it.next();
1465
                if( feature.getDefaultGeometry()==null ) {
1466
                    continue;
1467
                }
1468
                features.add(feature.getCopy());
1469
                status.incrementCurrentValue();
1470
            }
1471
            status.terminate();
1472
            return features;
1473
        } catch (DataException ex) {
1474
            status.abort();
1475
            throw new RuntimeException("Can't calculate selected features", ex);
1476
        }
1477
    }
1478

    
1479
    @Override
1480
    public void setDefaultBehaviors(Behavior[] defaultBehaviors) {
1481
        if( this.isProcessing() ) {
1482
            return;
1483
        }
1484
        this.defaultBehaviors = defaultBehaviors;
1485
        try {
1486
            addBehaviors(defaultBehaviors);
1487
        } catch (CreateEditingBehaviorException e1) {
1488
            LOGGER.info("Problems adding behaviors to editing context", e1);
1489
            getMapControl().setTool("pan");
1490
        }
1491
    }
1492

    
1493
    @Override
1494
    public Behavior[] getDefaultBehaviors() {
1495
        return this.defaultBehaviors;
1496
    }
1497

    
1498
    @Override
1499
    public void setValue(EditingServiceParameter parameter, Object value) throws InvalidEntryException {
1500
        setValue(parameter, value, false);
1501
    }
1502
    
1503
    private static class TasksDispatcher extends Thread {
1504
        private BlockingQueue<Runnable> tasks = new LinkedBlockingQueue<>();
1505
        private boolean processing = false;
1506
        private final JComponent component;
1507
        private Cursor lastNoBusyCursor = null;
1508

    
1509
        public TasksDispatcher(JComponent component) {
1510
            this.component = component;
1511
        }
1512

    
1513
        public void setMouseBusy(boolean busy) {
1514
            if (busy) {
1515
                if (lastNoBusyCursor == null) {
1516
                    this.lastNoBusyCursor = component.getCursor();
1517
                }
1518
                component.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
1519
            } else {
1520
                component.setCursor(lastNoBusyCursor);
1521
                lastNoBusyCursor = null;
1522
            }
1523
        }
1524

    
1525
        public void run() {
1526
            while (true){
1527
                try {
1528
                    Runnable task = tasks.poll(1, TimeUnit.MINUTES);
1529
                    if(task == null){
1530
                        return;
1531
                    }
1532
                    this.processing = true;
1533
                    setMouseBusy(true);
1534
                    task.run();
1535
                } catch (Throwable t) {
1536
                    LOGGER.warn("Can't proccess task", t);
1537
                } finally {
1538
                    if(tasks.isEmpty()){
1539
                        this.processing = false;
1540
                        setMouseBusy(false);
1541
                    }
1542
                }
1543
            }
1544
        }
1545
        public void add(Runnable task){
1546
            try {
1547
                this.tasks.put(task);
1548
            } catch (InterruptedException ex) {
1549
                throw new RuntimeException("Can't addd task", ex);
1550
            }
1551
        }
1552
        public boolean isProcessing() {
1553
            if(!this.isAlive()){
1554
                return false;
1555
            }
1556
            return this.processing;
1557
        }
1558
    }
1559

    
1560
    TasksDispatcher tasksDispatcher = null;
1561
    
1562
    @Override
1563
    public void setValue(EditingServiceParameter parameter, Object value, boolean next) throws InvalidEntryException {
1564
        
1565
        
1566
        if( value instanceof CharSequence){
1567
            value = coerceInputParameter(parameter, value.toString());
1568
        } else if( value instanceof Point) {
1569
            contextSymbolTable.addPoint((Point) value);
1570
        }
1571
        Object v = value;
1572
        Runnable task = () -> {
1573
            try {
1574
                getActiveService().setValue(parameter, v);
1575
                if(next){
1576
                    doNextParameter();
1577
                }
1578
            } catch (InvalidEntryException ex) {
1579
                I18nManager i18nManager = ToolsLocator.getI18nManager();
1580
                String stateMessage = ex.getStateMessage();
1581
                if(StringUtils.isBlank(stateMessage)){
1582
                    showConsoleMessage("\n"+ i18nManager.getTranslation("invalid_option"));
1583
                } else {
1584
                    showConsoleMessage("\n"+ i18nManager.getTranslation("invalid_option")+": "+StringUtils.defaultIfBlank(ex.getStateMessage(), ""));
1585
                }
1586
                doNextParameter();
1587
            } catch (Exception ex) {
1588
                LOGGER.warn("Can't set value", ex);
1589
                cleanEditingContext();
1590
                return;
1591
            } finally {
1592
                refreshMenusAndToolBars();
1593
            }
1594
        };
1595
        enqueueTask(task);
1596
        refreshMenusAndToolBars();
1597
        
1598
        
1599
    }
1600

    
1601
    private void enqueueTask(Runnable task) {
1602
        if(this.tasksDispatcher == null || !this.tasksDispatcher.isAlive()){
1603
            this.tasksDispatcher = new TasksDispatcher(this.getMapControl());
1604
            this.tasksDispatcher.start();
1605
        }
1606
        this.tasksDispatcher.add(task);
1607
    }
1608

    
1609
    public GeometryType getGeometryType() {
1610
        if( this.currentLayer==null ) {
1611
            return null;
1612
        }
1613
        FeatureStore store = this.currentLayer.getFeatureStore();
1614
        if( store == null ) {
1615
            return null;
1616
        }
1617
        FeatureType ftype = store.getDefaultFeatureTypeQuietly();
1618
        if( ftype == null ) {
1619
            return null;
1620
        }
1621
        FeatureAttributeDescriptor geomattr = ftype.getDefaultGeometryAttribute();
1622
        if( geomattr == null ) {
1623
            return null;
1624
        }
1625
        return geomattr.getGeomType();
1626
    }    
1627
    
1628
    public boolean isProcessing() {
1629
        if(this.tasksDispatcher == null){
1630
            return false;
1631
        }
1632
        return this.tasksDispatcher.isProcessing();
1633
    }
1634
    
1635
    @Override
1636
    public int getDrawMode() {
1637
        return this.drawMode;
1638
    }
1639

    
1640
    @Override
1641
    public void setDrawMode(int mode) {
1642
        this.drawMode = mode;
1643
        refreshMenusAndToolBars();
1644
    }
1645
}