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

History | View | Annotate | Download (58.8 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.DrawingStatus;
97
import org.gvsig.vectorediting.lib.api.EditingLocator;
98
import org.gvsig.vectorediting.lib.api.EditingManager;
99
import org.gvsig.vectorediting.lib.api.EditingService;
100
import org.gvsig.vectorediting.lib.api.EditingServiceInfo;
101
import org.gvsig.vectorediting.lib.api.EditingServiceParameter;
102
import org.gvsig.vectorediting.lib.api.EditingServiceParameter.TYPE;
103
import org.gvsig.vectorediting.lib.api.exceptions.CreateEditingBehaviorException;
104
import org.gvsig.vectorediting.lib.api.exceptions.EndEditingException;
105
import org.gvsig.vectorediting.lib.api.exceptions.FinishServiceException;
106
import org.gvsig.vectorediting.lib.api.exceptions.InvalidEntryException;
107
import org.gvsig.vectorediting.lib.api.exceptions.ParsePointException;
108
import org.gvsig.vectorediting.lib.api.exceptions.ParseValueException;
109
import org.gvsig.vectorediting.lib.api.exceptions.ServiceInformationException;
110
import org.gvsig.vectorediting.lib.api.exceptions.StartEditingException;
111
import org.gvsig.vectorediting.lib.api.exceptions.StartServiceException;
112
import org.gvsig.vectorediting.lib.api.exceptions.StopServiceException;
113
import org.gvsig.vectorediting.lib.api.exceptions.VectorEditingException;
114
import org.gvsig.vectorediting.swing.api.EditingContext;
115
import org.gvsig.vectorediting.swing.api.EditingSwingLocator;
116
import org.gvsig.vectorediting.swing.api.EditingSwingManager;
117
import org.gvsig.vectorediting.swing.api.console.EditingConsole;
118
import org.gvsig.vectorediting.swing.impl.console.DefaultEditingConsole;
119
import org.slf4j.Logger;
120
import org.slf4j.LoggerFactory;
121

    
122
public class DefaultEditingContext implements EditingContext {
123

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

    
127
    private WeakReference<MapControl> mapControlReference;
128

    
129
    private WeakReference<MapContext> mapContextReference;
130

    
131
    private EditingCompoundBehavior editingCompoundBehavior;
132

    
133
    private Behavior[] lastAdditionalBehaviors;
134

    
135
    private final ObservableHelper observableHelper;
136

    
137
    private EditingConsole console;
138

    
139
    private JDockPanel dockConsole = null;
140

    
141
    private boolean isShowConsole = false;
142

    
143
    private final Stack<EditingService> serviceStack;
144

    
145
    private FLyrVect currentLayer;
146

    
147
    private EditingServiceParameter currentParam;
148

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

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

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

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

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

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

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

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

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

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

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

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

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

    
262
        }
263

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

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

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

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

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

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

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

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

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

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

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

    
340
            EditingManager manager = EditingLocator.getManager();
341

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

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

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

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

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

    
377
                    } catch (InvalidEntryException e) {
378

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

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

    
394
                    setActiveService(service);
395

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

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

    
405
        DefaultEditingBehavior editingBehavior;
406
        EditingCompoundBehavior editingCompoundBehavior;
407

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

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

    
415
            if (additionalBehavior != null) {
416

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

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

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

    
425
                lastAdditionalBehaviors = additionalBehavior;
426

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

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

    
441
    }
442

    
443
    private void addLayerListeners() {
444

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

    
447
        layers.addLayerListener(layerListener);
448

    
449
        layers.addLayerCollectionListener(new LayerCollectionListener() {
450

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
551

    
552
        setCurrentLayer(layer);
553

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

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

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

    
583
        }
584

    
585
        featureStore.addObserver(getMapControl());
586

    
587
        enableSnapping();
588
    }
589

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

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

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

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

    
639
    public void notifyDrawingStatus(DrawingStatus status, EditingService service) {
640
        Notification notification = new BaseNotification(
641
            EditingContext.DRAWING_STATUS_NOTIFICATION,
642
            new Object[] {status, service}
643
        );
644
        this.observableHelper.notifyObservers(this, notification);
645
    }
646

    
647

    
648
    private void cleanEditingContext() {
649
        serviceStack.clear();
650
        currentParam = null;
651
        
652
        I18nManager i18n = ToolsLocator.getI18nManager();
653
        showConsoleMessage("\n" + i18n.getTranslation("select_new_tool") + "\n");
654

    
655
        changeSelectedTool(DEFAULT_TOOL);
656
        notifyChangeSelectedTool(DEFAULT_ACTION_NAME);
657
    }
658

    
659
    @Override
660
    public void deleteObserver(Observer o) {
661
        this.observableHelper.deleteObserver(o);
662
    }
663

    
664
    @Override
665
    public void deleteObservers() {
666
        this.observableHelper.deleteObservers();
667
    }
668

    
669
    private void discardChanges(FLyrVect layer) throws EndEditingException {
670
        FeatureStore featureStore = layer.getFeatureStore();
671
        try {
672
            featureStore.cancelEditing();
673
        } catch (Exception e) {
674
            throw new EndEditingException(e);
675
        }
676
    }
677

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

    
704
        case DISCARD_CHANGES:
705
            try {
706
                discardChanges(layer);
707
            } catch (VectorEditingException e) {
708
                String msg =
709
                    String.format("Changes can not be discared in %1$s",
710
                        layer.getName());
711
                LOGGER.info(msg, e);
712
                dialogs.messageDialog(                   
713
                    i18n.getTranslation("_There_are_problems_discarding_changes")+"\n"+
714
                    "\n" + i18n.getTranslation("_See_error_log_for_more_information"), 
715
                    null, 
716
                    i18n.getTranslation("_Warning"), 
717
                    JOptionPane.WARNING_MESSAGE, 
718
                    "Vectorediting_cant_discard_changes"
719
                );
720
                return;
721
            }
722
            break;
723

    
724
        case EXPORT_LAYER:
725
            try {
726
                exportLayer(layer);
727
            } catch (VectorEditingException e) {
728
                String msg =
729
                    String.format("Changes of %1$s can not be exported",
730
                        layer.getName());
731
                LOGGER.info(msg, e);
732
                dialogs.messageDialog(                   
733
                    i18n.getTranslation("_There_are_problems_exporting_changes")+"\n\n"+
734
                    i18n.getTranslation("_See_error_log_for_more_information"), 
735
                    null, 
736
                    i18n.getTranslation("_Warning"), 
737
                    JOptionPane.WARNING_MESSAGE, 
738
                    "Vectorediting_cant_export_changes"
739
                );
740
                return;
741
            }
742
            break;
743

    
744
        case CANCEL:
745
            return;
746
        }
747

    
748
        cleanEditingContext();
749
        hideConsole();
750
        disableSnapping();
751
        changeSelectedTool(DEFAULT_TOOL);
752

    
753
        FeatureStore featureStore = layer.getFeatureStore();
754
        featureStore.deleteObserver(getMapControl());
755

    
756
    }
757

    
758
    private void enableSelection(boolean enableSelection) {
759
        this.getEditingCompoundBehavior().setDrawnBehavior(
760
                EditingCompoundBehavior.SELECTION_INDEX, enableSelection);
761
    }
762

    
763
    @Override
764
    public void endEdition(FLyrVect layer) {
765
        if( this.isProcessing() ) {
766
            return;
767
        }
768
        if (layer.isEditing()) {
769
            EditingNotificationManager editingNotificationManager =
770
                DALSwingLocator.getEditingNotificationManager();
771

    
772
            EditingNotification notification =
773
                editingNotificationManager.notifyObservers(this,
774
                    EditingNotification.BEFORE_EXIT_EDITING_STORE, null, layer, layer.getFeatureStore());
775

    
776
            if (notification.isCanceled()) {
777
                String msg =
778
                    String.format(
779
                        "Stop edit layer %1$s canceled by somme observer.",
780
                        layer.getName());
781
                LOGGER.info(msg, new EndEditingException(msg, null));
782

    
783
            }
784

    
785
            getMapControl().getCanceldraw().setCanceled(true);
786
            int option;
787
            EditingSwingManager swingManager =
788
                EditingSwingLocator.getSwingManager();
789

    
790

    
791
            if (layer.isWritable() && getMapControl().getProjection().equals(layer.getProjection()) ) {
792
                option =
793
                    swingManager.showPanelSaveOrDiscard(getMapControl(),
794
                        layer.getName());
795
            } else {
796
                option =
797
                    swingManager.showPanelExportOrDiscard(getMapControl(),
798
                        layer.getName());
799
            }
800

    
801
            doAction(layer, option);
802

    
803
            editingNotificationManager.notifyObservers(this,
804
                EditingNotification.AFTER_EXIT_EDITING_STORE, null, layer, layer.getFeatureStore());
805

    
806
        }
807

    
808
    }
809

    
810
    private void exportLayer(FLyrVect layer) throws EndEditingException {
811
        Notification notification = new BaseNotification(EditingContext.EXPORT_LAYER_NOTIFICATION,1);
812
        notification.setValue(layer);
813
        this.observableHelper.notifyObservers(this, notification);
814
    }
815

    
816
    protected void finishService() {
817
        enqueueTask(() -> {
818
            doFinishService();
819
        });
820
        refreshMenusAndToolBars();
821
    }
822

    
823
    private void doFinishService() {
824
        try {
825
            if(serviceStack.isEmpty()){
826
                return;
827
            }
828
            EditingService lastService = serviceStack.pop();
829
            try {
830
                if (!serviceStack.isEmpty()
831
                        && getActiveService().next().getTypes().contains(TYPE.GEOMETRY)) {
832
                    Geometry geometry = lastService.finish();
833
                    lastService.setShowPreviewSymbol(true);
834
                    if (geometry != null) {
835
                        getActiveService().setValue(geometry);
836
                    }
837
                } else {
838
                    lastService.finishAndStore();
839
                    getMapControl().rePaintDirtyLayers();
840
                    refreshMenusAndToolBars();
841

    
842
                    I18nManager i18nManager = ToolsLocator.getI18nManager();
843
                    showConsoleMessage("\n"
844
                            + i18nManager.getTranslation(lastService.getName()) + "# "
845
                            + i18nManager.getTranslation("finished") + "\n");
846
                    if(lastService.mustRestartAtFinish()){
847
    //                lastService.stop();
848
                        setActiveService(lastService);
849
    //                lastService.start();
850
                        lastService.restart();
851
                        setDrawMode(DRAWMODE_NORMAL);
852
                        changeSelectedTool(getActiveService().getName());
853
                    } else {
854
                        setDrawMode(DRAWMODE_NORMAL);
855
                        enqueueTask(()->{
856
                            try {
857
                                lastService.stop();
858
                                if(serviceStack.isEmpty()){
859
                                    cleanEditingContext();
860
                                }
861
                                refreshMenusAndToolBars();
862
                            } catch (StopServiceException ex) {
863
                                
864
                            }
865
                        });
866
                    }
867
                }
868

    
869
            } catch (FinishServiceException ex) {
870
                showConsoleMessage("\n"+ex.getLocalizedMessage());
871
                cleanEditingContext();
872
                return;
873
            } catch (InvalidEntryException ex) {
874
                I18nManager i18nManager = ToolsLocator.getI18nManager();
875
                showConsoleMessage("\n"
876
                        + i18nManager.getTranslation("invalid_option"));
877
                changeSelectedTool(getActiveService().getName());
878
            } catch (Exception ex) {
879
                LOGGER.warn("Can't finish " + lastService.getName(), ex);
880
                I18nManager i18nManager = ToolsLocator.getI18nManager();
881
                showConsoleMessage("\n"+i18nManager.getTranslation("_An_error_has_occurred"));
882
                cleanEditingContext();
883
                return;
884
            }
885

    
886
            doNextParameter();
887
        } finally {
888
            refreshMenusAndToolBars();
889
        }
890
    }
891

    
892
    public EditingService getActiveService() {
893
        if (!serviceStack.isEmpty()) {
894
            return serviceStack.peek();
895
        }
896
        return null;
897
    }
898

    
899
    public EditingConsole getConsolePanel() {
900
        if (console == null) {
901
            console = new DefaultEditingConsole(new ResponseListener() {
902

    
903
                @Override
904
                public void acceptResponse(String response) {
905
                    textEntered(response);
906
                }
907
            });
908
        }
909
        return console;
910
    }
911

    
912
    protected FLyrVect getCurrentLayer() {
913
        return this.currentLayer;
914
    }
915

    
916
    protected EditingServiceParameter getCurrentParam() {
917
        return this.currentParam;
918
    }
919

    
920
    private Component getDockConsole() {
921
        if (dockConsole == null) {
922
            dockConsole = new JDockPanel((JComponent) getConsolePanel());
923
        }
924
        return dockConsole;
925
    }
926

    
927
    private DefaultEditingBehavior getEditingBehavior() {
928
        if (editingCompoundBehavior != null) {
929
            return (DefaultEditingBehavior) editingCompoundBehavior
930
                .getBehavior(EditingCompoundBehavior.EDITING_INDEX);
931
        }
932
        return null;
933
    }
934

    
935
    private EditingCompoundBehavior getEditingCompoundBehavior() {
936
        if (editingCompoundBehavior != null) {
937
            return editingCompoundBehavior;
938
        } else {
939
            EditingCompoundBehavior editingCompoundBehavior;
940

    
941
            CompoundBehavior compoundBehavior =
942
                (CompoundBehavior) getMapControl().getMapTool(VECTOREDITING_TOOL_NAME);
943

    
944
            if (compoundBehavior instanceof EditingCompoundBehavior) {
945
                editingCompoundBehavior =
946
                    (EditingCompoundBehavior) compoundBehavior;
947
            } else {
948
                editingCompoundBehavior =
949
                    (EditingCompoundBehavior) compoundBehavior.getBehavior(0);
950
            }
951

    
952
            setCompoundBehavior(editingCompoundBehavior);
953
            return editingCompoundBehavior;
954
        }
955
    }
956

    
957
    @Override
958
    public MapControl getMapControl() {
959
        return mapControlReference.get();
960
    }
961

    
962
    
963
    @Override
964
    public void nextParameter() {
965
        enqueueTask(() -> {
966
            doNextParameter();
967
        });
968
    }
969
    
970
    private void doNextParameter() {
971
        if ((getMapControl().getCurrentTool() != null)
972
            && !getMapControl().getCurrentTool().equals(VECTOREDITING_TOOL_NAME)) {
973
            getMapControl().setTool(VECTOREDITING_TOOL_NAME);
974
        }
975
        EditingService activeService = getActiveService();
976
        if(activeService == null){
977
            currentParam = null;
978
        } else {
979
            currentParam = activeService.next();
980
        }
981

    
982
        if (currentParam == null) {
983
            doFinishService();
984
        } else {
985
            askQuestion(currentParam);
986
            if (currentParam.getTypes().contains(TYPE.SELECTION)) {
987
                enableSelection(true);
988
            } else if (currentParam.getTypes().contains(TYPE.MULTILAYER_SELECTION)) {
989
                enableSelection(true);
990
            } else if (currentParam.getTypes().contains(TYPE.GEOMETRY)) {
991
                refreshMenusAndToolBars();
992
            }
993
        }
994
    }
995

    
996
    protected Stack<EditingService> getServiceStack() {
997
        return this.serviceStack;
998
    }
999

    
1000
    private void hideConsole() {
1001
        isShowConsole = false;
1002
        if( !SwingUtilities.isEventDispatchThread() ) {
1003
            try {
1004
                SwingUtilities.invokeAndWait(new Runnable() {
1005

    
1006
                    @Override
1007
                    public void run() {
1008
                        hideConsole();
1009
                    }
1010
                });
1011
                return;
1012
            } catch (InterruptedException | InvocationTargetException ex) {
1013
                LOGGER.warn("Can't hide editing console.",ex);
1014
            }
1015
            return;
1016
        }
1017
        getDockConsole().setVisible(false);
1018
    }
1019

    
1020
    @Override
1021
    public boolean isServiceCompatible(String name) {
1022
        DefaultEditingBehavior editingBehavior = getEditingBehavior();
1023

    
1024
        if (editingBehavior != null) {
1025

    
1026
            try {
1027
                EditingManager manager = EditingLocator.getManager();
1028
                EditingServiceInfo serviceInfo = manager.getServiceInfo(name);
1029
                GeometryType geoType = null;
1030

    
1031
                for (EditingService editingService : getServiceStack()) {
1032
                    EditingServiceParameter parameter = editingService.next();
1033
                    if (parameter != null) {
1034
                        if (parameter.getTypes().contains(TYPE.GEOMETRY)) {
1035

    
1036
                            int geometryType = parameter.getGeometryType();
1037
                            int subType = -1;
1038

    
1039
                            try {
1040
                                subType
1041
                                        = getCurrentLayer().getFeatureStore()
1042
                                                .getDefaultFeatureType()
1043
                                                .getDefaultGeometryAttribute()
1044
                                                .getGeomType().getSubType();
1045

    
1046
                                geoType
1047
                                        = GeometryLocator.getGeometryManager()
1048
                                                .getGeometryType(geometryType, subType);
1049
                            } catch (Exception e) {
1050

    
1051
                                String msg
1052
                                        = String.format(
1053
                                                "Problems getting default feature"
1054
                                                + " type of %1$s or getting geometry"
1055
                                                + " type of %2$s %3$s",
1056
                                                getCurrentLayer().getName(), geometryType,
1057
                                                subType);
1058

    
1059
                                throw new ServiceInformationException(msg, e);
1060
                            }
1061

    
1062
                            return serviceInfo.isCompatibleWith(geoType)
1063
                                    && serviceInfo.createsNewGeometries();
1064
                        }
1065
                    }
1066
                }
1067

    
1068
                if (getCurrentLayer() != null) {
1069
                    try {
1070
                        geoType
1071
                                = getCurrentLayer().getFeatureStore()
1072
                                        .getDefaultFeatureType()
1073
                                        .getDefaultGeometryAttribute().getGeomType();
1074

    
1075
                        if (serviceInfo.isCompatibleWith(geoType)) {
1076
                            return true;
1077
                        }
1078
                    } catch (DataException e) {
1079
                        String msg
1080
                                = String.format("Problems getting default "
1081
                                        + "feature type of %1$s", getCurrentLayer()
1082
                                                .getName());
1083
                        throw new ServiceInformationException(msg, e);
1084
                    }
1085
                }
1086

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

    
1133
        try {
1134
            Object x = ExpressionUtils.evaluate(contextSymbolTable, response);
1135
            if( x instanceof Double ) {
1136
                return (Double) x;
1137
            }  
1138
            if( x==null ) {
1139
                throw new ParseValueException(new NullPointerException());
1140
            }
1141
            Coercion toDouble = ToolsLocator.getDataTypesManager().get(DataTypes.DOUBLE).getCoercion();
1142
            return (Double) toDouble.coerce(x);
1143
        } catch(Exception ex) {
1144
            throw new ParseValueException(ex);
1145
        }
1146

    
1147
    }
1148

    
1149
    protected String fixResponseUsingBookmarks(String response) throws LocatorException {
1150
        if( response != null ) {
1151
            response = response.trim();
1152
            int n = StringUtils.indexOf(response, " ");
1153
            if(n>0){
1154
                String name = StringUtils.left(response, n);
1155
                Function fn = contextSymbolTable.function(name);
1156
                if(fn != null){
1157
                    response = name+"("+response.substring(n)+")";
1158
                }
1159
            }
1160
        }
1161
        return response;
1162
    }
1163

    
1164
    protected void refreshMenusAndToolBars() {
1165
        if (!SwingUtilities.isEventDispatchThread()) {
1166
            SwingUtilities.invokeLater(() -> { refreshMenusAndToolBars(); });
1167
            return;
1168
        }
1169
        Notification notification = new BaseNotification(
1170
                EditingContext.REFRESH_TOOLS_NOTIFICATION,
1171
                null
1172
        );
1173
        this.observableHelper.notifyObservers(this, notification);
1174
    }
1175

    
1176
    private void saveChanges(FLyrVect layer) throws EndEditingException {
1177
        FeatureStore featureStore = layer.getFeatureStore();
1178
        try {
1179
            featureStore.finishEditing();
1180
        } catch (Exception e) {
1181
            throw new EndEditingException(e);
1182
        }
1183
    }
1184

    
1185
    private void setActiveService(EditingService service) {
1186
        //Si se hace este metodo publico hay que comprobar el isProcessing
1187
        serviceStack.add(service);
1188
        notifyChangeSelectedTool(service.getName());
1189
    }
1190

    
1191
    private void setCompoundBehavior(EditingCompoundBehavior compoundBehavior) {
1192
        if( this.isProcessing() ) {
1193
            return;
1194
        }
1195
        this.editingCompoundBehavior = compoundBehavior;
1196
    }
1197

    
1198
    private void setCurrentLayer(FLyrVect layer) {
1199
        if( this.isProcessing() ) {
1200
            return;
1201
        }
1202
        if (this.currentLayer != layer) {
1203
            this.currentLayer = layer;
1204
            if( !this.serviceStack.isEmpty() ) {
1205
                EditingService x = this.serviceStack.firstElement();
1206
                if( x != null && this.isServiceCompatible(x.getName())) {
1207
                    String name = x.getName();
1208
                    cleanEditingContext();
1209
                    this.serviceStack.clear();
1210
                    this.activateService(name);
1211
                } else {
1212
                    cleanEditingContext();
1213
                }
1214
            }
1215
        }
1216

    
1217
    }
1218

    
1219
    @Override
1220
    public void setMapControl(MapControl mapControl) {
1221
        if( this.isProcessing() ) {
1222
            return;
1223
        }
1224

    
1225
        this.mapControlReference = new WeakReference<>(mapControl);
1226
        this.mapContextReference =
1227
            new WeakReference<>(mapControl.getMapContext());
1228

    
1229
        // When mapControl is updated we have to add older additional behaviors
1230
        // to new mapControl
1231
        if (lastAdditionalBehaviors != null) {
1232
            try {
1233
                addBehaviors(lastAdditionalBehaviors);
1234
            } catch (CreateEditingBehaviorException e1) {
1235
                LOGGER.info("Problems adding behaviors to editing context", e1);
1236
                getMapControl().setTool("pan");
1237
            }
1238
        }
1239
    }
1240

    
1241
    private void showConsole() {
1242
        if (isShowConsole) {
1243
            return;
1244
        }
1245
        if( !SwingUtilities.isEventDispatchThread() ) {
1246
            try {
1247
                SwingUtilities.invokeAndWait(new Runnable() {
1248

    
1249
                    @Override
1250
                    public void run() {
1251
                        showConsole();
1252
                    }
1253
                });
1254
                return;
1255
            } catch (InterruptedException | InvocationTargetException ex) {
1256
                LOGGER.warn("Can't show editing console.",ex);
1257
            }
1258
            return;
1259
        }
1260
        isShowConsole = true;
1261
        getMapControl().remove(getDockConsole());
1262
        getMapControl().setLayout(new BorderLayout());
1263
        getMapControl().add(getDockConsole(), BorderLayout.SOUTH);
1264
        getDockConsole().setVisible(true);
1265
    }
1266

    
1267
    protected void showConsoleMessage(final String text) {
1268
        if (!SwingUtilities.isEventDispatchThread()) {
1269
            SwingUtilities.invokeLater(new Runnable() {
1270

    
1271
                @Override
1272
                public void run() {
1273
                    showConsoleMessage(text);
1274
                }
1275
            });
1276
            return;
1277
        }
1278
        getConsolePanel().addText(text);
1279
    }
1280

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

    
1325
                    refreshMenusAndToolBars();
1326
                    activeService = getActiveService();
1327
                    if (activeService != null) {
1328
                        nextParameter();
1329
                    } else {
1330
                        cleanEditingContext();
1331
                    }
1332

    
1333
                } catch (StopServiceException e) {
1334
                    LOGGER
1335
                        .info("Can't stop " + activeService.getName(), e);
1336
                } catch (DataException e) {
1337
                    LOGGER.info("Can't get selection of "
1338
                        + featureStore.getFullName(), e);
1339
                }
1340
            }
1341
        } else {
1342
            enqueueTask(() -> {
1343
                try {
1344
                    I18nManager i18nManager = ToolsLocator.getI18nManager();
1345
                    EditingService activeService = getActiveService();
1346
                    if (getCurrentParam() != null) {
1347
                        try {
1348
                            Object coercedValue = coerceInputParameter(getCurrentParam(), response);
1349
                            activeService.setValue(coercedValue);
1350
                        } catch (InvalidEntryException ex) {
1351
                            showConsoleMessage("\n"
1352
                                    + i18nManager.getTranslation("invalid_option"));
1353
                        }
1354
                    }
1355

    
1356
                    activeService = getActiveService();
1357
                    if (activeService != null) {
1358
                        doNextParameter();
1359
                    } else {
1360
                        cleanEditingContext();
1361
                    }
1362
                } finally {
1363
                    refreshMenusAndToolBars();
1364
                }
1365
            });
1366
            refreshMenusAndToolBars();
1367
        }
1368
    }
1369
    
1370
    private Object coerceInputParameter(EditingServiceParameter parameter, String input) throws InvalidEntryException {
1371
        if (parameter != null) {
1372
            FeatureStore featureStore = getCurrentLayer().getFeatureStore();
1373
            Set<TYPE> types = parameter.getTypes();
1374
            Point point = null;
1375
            Double value = null;
1376
            Point defaultPoint = null;
1377
            Object defaultValue = parameter.getDefaultValue();
1378

    
1379
//            boolean insertedValue = false;
1380
            if ((types.contains(TYPE.POSITION))
1381
                    || types.contains(TYPE.LIST_POSITIONS)) {
1382

    
1383
                if(defaultValue instanceof Point){
1384
                    defaultPoint = (Point) defaultValue;
1385
                }
1386
                try {
1387
                    if (StringUtils.isEmpty(input.replace("\n", ""))) {
1388
                        point = defaultPoint;
1389
                    } else {
1390
                        point = parsePoint(input);
1391
                    }
1392

    
1393
                    if (point != null) {
1394
                        return point;
1395
                    }
1396

    
1397
                } catch (ParsePointException e) {
1398
                    // Do nothing to try other types
1399
                }
1400
            }
1401
            if (types.contains(TYPE.VALUE)) {
1402

    
1403
                try {
1404
                    value = parseValue(input);
1405
                    if (value != null) {
1406
                        return value;
1407
                    }
1408

    
1409
                } catch (ParseValueException e) {
1410
                    // Do nothing to try other types
1411
                }
1412

    
1413
            }
1414
            if (types.contains(TYPE.OPTION)) {
1415
                input = input.replace("\n", "");
1416
                return input;
1417
            }
1418

    
1419
            if (types.contains(TYPE.SELECTION)) {
1420
                if (input.equalsIgnoreCase("\n")) {
1421
                    enableSelection(false);
1422

    
1423
                    FeatureSelection clonedSelection;
1424
                    try {
1425
                        clonedSelection = (FeatureSelection) featureStore
1426
                                .getFeatureSelection().clone();
1427
                        if (!clonedSelection.isEmpty()) {
1428
                            return clonedSelection;
1429
                        }
1430
                    } catch (Exception e) {
1431
                        LOGGER.warn("Can't access to selection.", e);
1432
                        throw new InvalidEntryException(e);
1433
                    }
1434
                }
1435
            }
1436

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

    
1488
    @Override
1489
    public void setDefaultBehaviors(Behavior[] defaultBehaviors) {
1490
        if( this.isProcessing() ) {
1491
            return;
1492
        }
1493
        this.defaultBehaviors = defaultBehaviors;
1494
        try {
1495
            addBehaviors(defaultBehaviors);
1496
        } catch (CreateEditingBehaviorException e1) {
1497
            LOGGER.info("Problems adding behaviors to editing context", e1);
1498
            getMapControl().setTool("pan");
1499
        }
1500
    }
1501

    
1502
    @Override
1503
    public Behavior[] getDefaultBehaviors() {
1504
        return this.defaultBehaviors;
1505
    }
1506

    
1507
    @Override
1508
    public void setValue(EditingServiceParameter parameter, Object value) throws InvalidEntryException {
1509
        setValue(parameter, value, false);
1510
    }
1511
    
1512
    private static class TasksDispatcher extends Thread {
1513
        private BlockingQueue<Runnable> tasks = new LinkedBlockingQueue<>();
1514
        private boolean processing = false;
1515
        private final JComponent component;
1516
        private Cursor lastNoBusyCursor = null;
1517

    
1518
        public TasksDispatcher(JComponent component) {
1519
            this.component = component;
1520
        }
1521

    
1522
        public void setMouseBusy(boolean busy) {
1523
            if (busy) {
1524
                if (lastNoBusyCursor == null) {
1525
                    this.lastNoBusyCursor = component.getCursor();
1526
                }
1527
                component.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
1528
            } else {
1529
                component.setCursor(lastNoBusyCursor);
1530
                lastNoBusyCursor = null;
1531
            }
1532
        }
1533

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

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

    
1610
    private void enqueueTask(Runnable task) {
1611
        if(this.tasksDispatcher == null || !this.tasksDispatcher.isAlive()){
1612
            this.tasksDispatcher = new TasksDispatcher(this.getMapControl());
1613
            this.tasksDispatcher.start();
1614
        }
1615
        this.tasksDispatcher.add(task);
1616
    }
1617

    
1618
    public GeometryType getGeometryType() {
1619
        if( this.currentLayer==null ) {
1620
            return null;
1621
        }
1622
        FeatureStore store = this.currentLayer.getFeatureStore();
1623
        if( store == null ) {
1624
            return null;
1625
        }
1626
        FeatureType ftype = store.getDefaultFeatureTypeQuietly();
1627
        if( ftype == null ) {
1628
            return null;
1629
        }
1630
        FeatureAttributeDescriptor geomattr = ftype.getDefaultGeometryAttribute();
1631
        if( geomattr == null ) {
1632
            return null;
1633
        }
1634
        return geomattr.getGeomType();
1635
    }    
1636
    
1637
    public boolean isProcessing() {
1638
        if(this.tasksDispatcher == null){
1639
            return false;
1640
        }
1641
        return this.tasksDispatcher.isProcessing();
1642
    }
1643
    
1644
    @Override
1645
    public int getDrawMode() {
1646
        return this.drawMode;
1647
    }
1648

    
1649
    @Override
1650
    public void setDrawMode(int mode) {
1651
        this.drawMode = mode;
1652
        refreshMenusAndToolBars();
1653
    }
1654
}