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

History | View | Annotate | Download (44 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.lang.ref.WeakReference;
30
import java.lang.reflect.InvocationTargetException;
31
import java.util.ArrayList;
32
import java.util.Set;
33
import java.util.Stack;
34
import java.util.prefs.PreferenceChangeEvent;
35
import java.util.prefs.PreferenceChangeListener;
36
import java.util.prefs.Preferences;
37

    
38
import javax.swing.JComponent;
39
import javax.swing.JOptionPane;
40
import javax.swing.SwingUtilities;
41

    
42
import org.gvsig.fmap.dal.exception.DataException;
43
import org.gvsig.fmap.dal.feature.FeatureSelection;
44
import org.gvsig.fmap.dal.feature.FeatureStore;
45
import org.gvsig.fmap.geom.Geometry;
46
import org.gvsig.fmap.geom.GeometryLocator;
47
import org.gvsig.fmap.geom.type.GeometryType;
48
import org.gvsig.fmap.mapcontext.MapContext;
49
import org.gvsig.fmap.mapcontext.layers.CancelationException;
50
import org.gvsig.fmap.mapcontext.layers.FLayer;
51
import org.gvsig.fmap.mapcontext.layers.FLayers;
52
import org.gvsig.fmap.mapcontext.layers.LayerCollectionEvent;
53
import org.gvsig.fmap.mapcontext.layers.LayerCollectionListener;
54
import org.gvsig.fmap.mapcontext.layers.LayerEvent;
55
import org.gvsig.fmap.mapcontext.layers.LayerListener;
56
import org.gvsig.fmap.mapcontext.layers.LayerPositionEvent;
57
import org.gvsig.fmap.mapcontext.layers.vectorial.FLyrVect;
58
import org.gvsig.fmap.mapcontrol.MapControl;
59
import org.gvsig.fmap.mapcontrol.tools.CompoundBehavior;
60
import org.gvsig.fmap.mapcontrol.tools.Behavior.Behavior;
61
import org.gvsig.tools.ToolsLocator;
62
import org.gvsig.tools.i18n.I18nManager;
63
import org.gvsig.tools.observer.BaseNotification;
64
import org.gvsig.tools.observer.Notification;
65
import org.gvsig.tools.observer.ObservableHelper;
66
import org.gvsig.tools.observer.Observer;
67
import org.gvsig.utils.console.JDockPanel;
68
import org.gvsig.utils.console.ResponseListener;
69
import org.gvsig.vectorediting.lib.api.EditingLocator;
70
import org.gvsig.vectorediting.lib.api.EditingManager;
71
import org.gvsig.vectorediting.lib.api.EditingService;
72
import org.gvsig.vectorediting.lib.api.EditingServiceInfo;
73
import org.gvsig.vectorediting.lib.api.EditingServiceParameter;
74
import org.gvsig.vectorediting.lib.api.EditingServiceParameter.TYPE;
75
import org.gvsig.vectorediting.lib.api.exceptions.CreateEditingBehaviorException;
76
import org.gvsig.vectorediting.lib.api.exceptions.EndEditingException;
77
import org.gvsig.vectorediting.lib.api.exceptions.InvalidEntryException;
78
import org.gvsig.vectorediting.lib.api.exceptions.ParsePointException;
79
import org.gvsig.vectorediting.lib.api.exceptions.ParseValueException;
80
import org.gvsig.vectorediting.lib.api.exceptions.ServiceInformationException;
81
import org.gvsig.vectorediting.lib.api.exceptions.StartEditingException;
82
import org.gvsig.vectorediting.lib.api.exceptions.StartServiceException;
83
import org.gvsig.vectorediting.lib.api.exceptions.StopServiceException;
84
import org.gvsig.vectorediting.lib.api.exceptions.VectorEditingException;
85
import org.gvsig.vectorediting.swing.api.EditingContext;
86
import org.gvsig.vectorediting.swing.api.EditingSwingLocator;
87
import org.gvsig.vectorediting.swing.api.EditingSwingManager;
88
import org.gvsig.vectorediting.swing.api.console.EditingConsole;
89
import org.gvsig.vectorediting.swing.impl.console.DefaultEditingConsole;
90
import org.gvsig.fmap.geom.primitive.Point;
91

    
92
import org.apache.commons.lang3.StringUtils;
93
import org.gvsig.expressionevaluator.ExpressionUtils;
94
import org.gvsig.expressionevaluator.MutableSymbolTable;
95
import org.gvsig.fmap.dal.DataTypes;
96

    
97
import org.gvsig.fmap.dal.EditingNotification;
98
import org.gvsig.fmap.dal.EditingNotificationManager;
99
import org.gvsig.fmap.dal.swing.DALSwingLocator;
100
import org.gvsig.temporarystorage.TemporaryStorageGroup;
101
import org.gvsig.temporarystorage.TemporaryStorageLocator;
102
import org.gvsig.temporarystorage.TemporaryStorageManager;
103
import org.gvsig.tools.dataTypes.Coercion;
104
import org.gvsig.tools.swing.api.ToolsSwingLocator;
105
import org.gvsig.tools.swing.api.threadsafedialogs.ThreadSafeDialogsManager;
106

    
107
import org.slf4j.Logger;
108
import org.slf4j.LoggerFactory;
109

    
110
public class DefaultEditingContext implements EditingContext {
111

    
112
    private static final Logger logger = LoggerFactory
113
        .getLogger(EditingManager.class);
114

    
115
    private WeakReference<MapControl> mapControlReference;
116

    
117
    private WeakReference<MapContext> mapContextReference;
118

    
119
    private EditingCompoundBehavior editingCompoundBehavior;
120

    
121
    private Behavior[] lastAdditionalBehaviors;
122

    
123
    private final ObservableHelper observableHelper;
124

    
125
    private EditingConsole console;
126

    
127
    private JDockPanel dockConsole = null;
128

    
129
    private boolean isShowConsole = false;
130

    
131
    private final Stack<EditingService> serviceStack;
132

    
133
    private FLyrVect currentLayer;
134

    
135
    private EditingServiceParameter currentParam;
136

    
137
    private Behavior[] defaultBehaviors;
138

    
139
    private final LayerListener layerListener = new LayerListener() {
140

    
141
        @Override
142
        public void activationChanged(final LayerEvent e) {
143
            if( !SwingUtilities.isEventDispatchThread() ) {
144
                SwingUtilities.invokeLater(new Runnable() {
145

    
146
                    @Override
147
                    public void run() {
148
                        activationChanged(e);
149
                    }
150
                });
151
                return;
152
            }
153

    
154
            FLayer layer = e.getSource();
155
            final MapContext mapContext = layer.getMapContext();
156

    
157
            if (countActiveAndEditingLayers(mapContext) > 1) {
158
                hideConsole();
159
                return;
160
            }
161

    
162
            if (layer instanceof FLyrVect) {
163
                if (layer.isActive() && layer.isEditing()) {
164
                    getMapControl().setTool("VectorEditing");
165
                    setCurrentLayer((FLyrVect) layer);
166
                    showConsole();
167
                    return;
168
                }
169
            }
170

    
171
            FLayer[] activeLayers =
172
                layer.getMapContext().getLayers().getActives();
173
            
174
            for (FLayer activeLayer : activeLayers) {
175
                if (activeLayer instanceof FLyrVect) {
176
                    if (activeLayer.isEditing()) {
177
                        getMapControl().setTool("VectorEditing");
178
                        setCurrentLayer((FLyrVect) activeLayer);
179
                        showConsole();
180
                        return;
181
                    }
182
                }
183
            }
184

    
185
            hideConsole();
186
            if ((getMapControl().getCurrentTool() != null)
187
                && getMapControl().getCurrentTool().equals("VectorEditing")) {
188
                getMapControl().setPrevTool();
189
            }
190
        }
191

    
192
        @Override
193
        public void drawValueChanged(LayerEvent e) {
194
        }
195

    
196
        @Override
197
        public void editionChanged(final LayerEvent e) {
198
            if( !SwingUtilities.isEventDispatchThread() ) {
199
                SwingUtilities.invokeLater(new Runnable() {
200

    
201
                    @Override
202
                    public void run() {
203
                        editionChanged(e);
204
                    }
205
                });
206
                return;
207
            }
208
            FLayer layer = e.getSource();
209

    
210
            if (layer instanceof FLyrVect) {
211
                if (layer.isEditing()) {
212
                    synchronized (DefaultEditingContext.this) {
213
                        beginEdition((FLyrVect) layer);
214
                        showConsole();
215
                    }
216
                } else {
217
                    hideConsole();
218
                }
219
            }
220

    
221
        }
222

    
223
        @Override
224
        public void nameChanged(LayerEvent e) {
225
        }
226

    
227
        @Override
228
        public void visibilityChanged(LayerEvent e) {
229
        }
230
    };
231
    
232
    private int countActiveAndEditingLayers(MapContext mapcontext){
233
        int count = 0;
234
        
235
        FLayer[] activeLayers =
236
                mapcontext.getLayers().getActives();
237
            
238
        for (FLayer activeLayer : activeLayers) {
239
            if (activeLayer instanceof FLyrVect) {
240
                if (activeLayer.isEditing()) {
241
                    count++;
242
                }
243
            }
244
        }
245
        
246
        return count;
247
    }
248

    
249
    private final PreferenceChangeListener preferenceChangeListener =
250
        new PreferenceChangeListener() {
251

    
252
            @Override
253
            public void preferenceChange(PreferenceChangeEvent evt) {
254
                String key = evt.getKey();
255
                if (key.equalsIgnoreCase("apply-snappers")) {
256
                    boolean newValue = Boolean.parseBoolean(evt.getNewValue());
257
                    getMapControl().setRefentEnabled(newValue);
258
                }
259
            }
260
        };
261

    
262
    public DefaultEditingContext(MapControl mapControl) {
263

    
264
        this.mapControlReference = new WeakReference<>(mapControl);
265
        this.mapContextReference =
266
            new WeakReference<>(mapControl.getMapContext());
267
        this.observableHelper = new ObservableHelper();
268

    
269
        this.serviceStack = new Stack<>();
270

    
271
        addLayerListeners();
272
        addPreferenceListener();
273
    }
274

    
275
    private void addPreferenceListener() {
276
        Preferences prefs = Preferences.userRoot().node("snappers");
277
        prefs.addPreferenceChangeListener(preferenceChangeListener);
278
    }
279

    
280
    @Override
281
    public void activateService(String name) {
282

    
283
        if ((getMapControl() != null)
284
            && getMapControl().hasTool("VectorEditing")) {
285

    
286
            CompoundBehavior editingCompoundBehavior =
287
                getEditingCompoundBehavior();
288
            getMapControl().setTool("VectorEditing");
289
            editingCompoundBehavior.setDrawnBehavior(
290
                EditingCompoundBehavior.EDITING_INDEX, true);
291

    
292
            EditingManager manager = EditingLocator.getManager();
293

    
294
            if (currentLayer != null) {
295

    
296
                EditingService service =
297
                    manager.getEditingService(name,
298
                        currentLayer.getFeatureStore(),
299
                        mapContextReference.get());
300

    
301
                if (service != null) {
302

    
303
                    this.enableSelection(false);
304

    
305
                    try {
306
                        service.start();
307
                    } catch (StartServiceException e) {
308

    
309
                        logger.info(String.format(
310
                            "Can't start the service %1$s", service.getName()),
311
                            e);
312
                        cleanEditingContext();
313
                        return;
314

    
315
                    } catch (InvalidEntryException e) {
316

    
317
                        I18nManager i18nManager = ToolsLocator.getI18nManager();
318
                        showConsoleMessage("\n"
319
                            + i18nManager.getTranslation("invalid_option"));
320
                    }
321

    
322
                    if (!serviceStack.isEmpty()
323
                        && !getActiveService().next().getTypes()
324
                            .contains(TYPE.GEOMETRY)) {
325
                        serviceStack.pop();
326
                    }
327

    
328
                    setActiveService(service);
329

    
330
                    nextParameter();
331
                }
332
            }
333
        }
334
    }
335

    
336
    private void addBehaviors(Behavior[] additionalBehavior)
337
        throws CreateEditingBehaviorException {
338

    
339
        DefaultEditingBehavior editingBehavior;
340
        EditingCompoundBehavior editingCompoundBehavior;
341

    
342
        if (!getMapControl().hasTool("VectorEditing")) {
343

    
344
            editingBehavior = new DefaultEditingBehavior(this);
345
            editingCompoundBehavior =
346
                new EditingCompoundBehavior(editingBehavior);
347
            setCompoundBehavior(editingCompoundBehavior);
348

    
349
            if (additionalBehavior != null) {
350

    
351
                Behavior[] behaviors =
352
                    new Behavior[additionalBehavior.length + 1];
353
                behaviors[0] = editingCompoundBehavior;
354

    
355
                System.arraycopy(additionalBehavior, 0, behaviors, 1, additionalBehavior.length);
356

    
357
                getMapControl().addBehavior("VectorEditing", behaviors);
358

    
359
                lastAdditionalBehaviors = additionalBehavior;
360

    
361
            } else {
362
                getMapControl().addBehavior("VectorEditing",
363
                    editingCompoundBehavior);
364
            }
365

    
366
        } else {
367
            editingCompoundBehavior = getEditingCompoundBehavior();
368
            editingBehavior =
369
                (DefaultEditingBehavior) editingCompoundBehavior
370
                    .getBehavior(EditingCompoundBehavior.EDITING_INDEX);
371
            setCompoundBehavior(editingCompoundBehavior);
372
            cleanEditingContext();
373
        }
374

    
375
    }
376

    
377
    private void addLayerListeners() {
378

    
379
        FLayers layers = mapContextReference.get().getLayers();
380

    
381
        layers.addLayerListener(layerListener);
382

    
383
        layers.addLayerCollectionListener(new LayerCollectionListener() {
384

    
385
            public void addLayer(FLayer layer) {
386
                if (layer instanceof FLayers) {
387
                    FLayers layers = (FLayers) layer;
388
                    for (int i = 0; i < layers.getLayersCount(); i++) {
389
                        addLayer(layers.getLayer(i));
390
                    }
391
                } else if (layer instanceof FLyrVect) {
392
                    ((FLyrVect) layer).addLayerListener(layerListener);
393
                }
394
            }
395

    
396
            @Override
397
            public void layerAdded(LayerCollectionEvent e) {
398
                addLayer(e.getLayers());
399
            }
400

    
401
            @Override
402
            public void layerAdding(LayerCollectionEvent e)
403
                throws CancelationException {
404
            }
405

    
406
            @Override
407
            public void layerMoved(LayerPositionEvent e) {
408
            }
409

    
410
            @Override
411
            public void layerMoving(LayerPositionEvent e)
412
                throws CancelationException {
413
            }
414

    
415
            public void removeLayer(FLayer layer) {
416
                if (layer instanceof FLayers) {
417
                    FLayers layers = (FLayers) layer;
418
                    for (int i = 0; i < layers.getLayersCount(); i++) {
419
                        addLayer(layers.getLayer(i));
420
                    }
421
                } else if (layer instanceof FLyrVect) {
422
                    ((FLyrVect) layer).removeLayerListener(layerListener);
423
                }
424
            }
425

    
426
            @Override
427
            public void layerRemoved(LayerCollectionEvent e) {
428
                removeLayer(e.getLayers());
429
            }
430

    
431
            @Override
432
            public void layerRemoving(LayerCollectionEvent e)
433
                throws CancelationException {
434
            }
435

    
436
            @Override
437
            public void visibilityChanged(LayerCollectionEvent e)
438
                throws CancelationException {
439
            }
440
        });
441
    }
442

    
443
    @Override
444
    public void addObserver(Observer o) {
445
        this.observableHelper.addObserver(o);
446
    }
447

    
448
    private void askQuestion(EditingServiceParameter param) {
449
        I18nManager i18nManager = ToolsLocator.getI18nManager();
450
        String translation = i18nManager.getTranslation(param.getDescription());
451
        String activeServiceName =
452
            i18nManager.getTranslation(getActiveService().getName());
453

    
454
        Object defaultValue = param.getDefaultValue();
455
        String strDefaultValue;
456

    
457
        if (defaultValue != null) {
458
            if (defaultValue instanceof String) {
459
                strDefaultValue =
460
                    i18nManager.getTranslation((String) defaultValue);
461
            } else {
462
                if(defaultValue instanceof Point){
463
                    Point point = (Point)defaultValue;
464
                    StringBuilder builder = new StringBuilder();
465
                    for(int i=0; i<point.getDimension(); i++){
466
                        builder.append(point.getCoordinateAt(i));
467
                        if(i < point.getDimension()-1){
468
                            builder.append(" , ");
469
                        }
470
                    }
471
                    strDefaultValue = builder.toString();
472
                } else {
473
                    strDefaultValue = defaultValue.toString();
474
                }
475
            }
476
            showConsoleMessage("\n" + activeServiceName + "# " + translation
477
                + "<" + strDefaultValue + "> : ");
478
        } else {
479
            showConsoleMessage("\n" + activeServiceName + "# " + translation
480
                + " : ");
481
        }
482
    }
483

    
484
    @Override
485
    public synchronized void beginEdition(FLyrVect layer,
486
        Behavior[] additionalBehaviors) {
487

    
488
        try{
489
            throw new Exception("Deprecated method");
490
        } catch (Exception e){
491
            logger.info("Deprecated method", e);
492
        }
493

    
494
        beginEdition(layer);
495
        try {
496
            addBehaviors(additionalBehaviors);
497
        } catch (CreateEditingBehaviorException e1) {
498
            logger.info("Problems adding behaviors to editing context", e1);
499
            getMapControl().setTool("pan");
500
        }
501
    }
502

    
503
    @Override
504
    public synchronized void beginEdition(FLyrVect layer) {
505

    
506
        EditingNotificationManager editingNotificationManager =
507
            DALSwingLocator.getEditingNotificationManager();
508

    
509
        EditingNotification notification =
510
            editingNotificationManager.notifyObservers(this,
511
                EditingNotification.BEFORE_ENTER_EDITING_STORE, null, layer,layer.getFeatureStore());
512

    
513
        if (notification.isCanceled()) {
514
            String msg =
515
                String.format("Edit layer %1$s canceled by somme observer.",
516
                    layer.getName());
517
            logger.info(msg, new StartEditingException(msg, null));
518
            return;
519
        }
520

    
521
        setCurrentLayer(layer);
522

    
523
        FeatureStore featureStore = layer.getFeatureStore();
524
        if (!featureStore.isEditing()) {
525
            try {
526
                featureStore.edit();
527
            } catch (Exception e) {
528
                String msg =
529
                    String.format("Can't set %1$s in edit mode",
530
                        featureStore.getName());
531
                logger.info(msg, new VectorEditingException(e));
532
                cleanEditingContext();
533
                return;
534
            }
535
        }
536

    
537
        featureStore.addObserver(getMapControl());
538

    
539
        editingNotificationManager.notifyObservers(this,
540
            EditingNotification.AFTER_ENTER_EDITING_STORE, null, layer, layer.getFeatureStore());
541

    
542
        enableSnapping();
543
    }
544

    
545
    @SuppressWarnings({ "rawtypes", "unchecked" })
546
    private void enableSnapping() {
547
        Preferences prefs = Preferences.userRoot().node("snappers");
548
         getMapControl().setRefentEnabled(prefs.getBoolean("apply-snappers", false));
549
         if (currentLayer != null) {
550
            ArrayList layersToSnap =
551
                getMapControl().getMapContext().getLayersToSnap();
552
            if (!layersToSnap.contains(currentLayer)) {
553
                layersToSnap.add(currentLayer);
554
            }
555
        }
556
    }
557

    
558
    @SuppressWarnings("rawtypes")
559
    private void disableSnapping() {
560
        ArrayList layersToSnap =
561
            getMapControl().getMapContext().getLayersToSnap();
562
        if (layersToSnap.contains(currentLayer)) {
563
            layersToSnap.remove(currentLayer);
564
        }
565
    }
566

    
567
    private void changeSelectedTool(String name) {
568
        if (name.equalsIgnoreCase(DEFAULT_TOOL)) {
569
            name = "selection-simple-select-view";
570
            this.getMapControl().setTool("pointSelection");
571
        }
572
        Notification notification =
573
            new BaseNotification(
574
                EditingContext.CHANGE_SELECTED_TOOL_NOTIFICATION,
575
                new Object[] { name });
576
        this.observableHelper.notifyObservers(this, notification);
577
    }
578

    
579
    private void cleanEditingContext() {
580
        serviceStack.clear();
581
        currentParam = null;
582
        this.enableSelection(false);
583
        refreshMenusAndToolBars();
584

    
585
        I18nManager i18nManager = ToolsLocator.getI18nManager();
586
        showConsoleMessage("\n" + i18nManager.getTranslation("select_new_tool")
587
            + "\n");
588
    }
589

    
590
    @Override
591
    public void deleteObserver(Observer o) {
592
        this.observableHelper.deleteObserver(o);
593
    }
594

    
595
    @Override
596
    public void deleteObservers() {
597
        this.observableHelper.deleteObservers();
598
    }
599

    
600
    private void discardChanges(FLyrVect layer) throws EndEditingException {
601
        FeatureStore featureStore = layer.getFeatureStore();
602
        try {
603
            featureStore.cancelEditing();
604
        } catch (Exception e) {
605
            throw new EndEditingException(e);
606
        }
607
    }
608

    
609
    private void doAction(FLyrVect layer, int option) {
610
        ThreadSafeDialogsManager dialogs = ToolsSwingLocator.getThreadSafeDialogsManager();
611
        I18nManager i18n = ToolsLocator.getI18nManager();
612
        
613
        switch (option) {
614
        case SAVE_CHANGES:
615
            try {
616
                saveChanges(layer);
617
            } catch (VectorEditingException e) {
618
                String msg =
619
                    String.format("Changes can not be saved in %1$s",
620
                        layer.getName());
621
                logger.info(msg, e);
622
                dialogs.messageDialog(                   
623
                    i18n.getTranslation("_There_are_problems_saving_changes")+"\n\n"+
624
                    i18n.getTranslation("_See_error_log_for_more_information"), 
625
                    null, 
626
                    i18n.getTranslation("_Warning"), 
627
                    JOptionPane.WARNING_MESSAGE, 
628
                    "Vectorediting_cant_save_changes"
629
                );
630
                return;
631
            }
632
            break;
633

    
634
        case DISCARD_CHANGES:
635
            try {
636
                discardChanges(layer);
637
            } catch (VectorEditingException e) {
638
                String msg =
639
                    String.format("Changes can not be discared in %1$s",
640
                        layer.getName());
641
                logger.info(msg, e);
642
                dialogs.messageDialog(                   
643
                    i18n.getTranslation("_There_are_problems_discarding_changes")+"\n"+
644
                    "\n" + i18n.getTranslation("_See_error_log_for_more_information"), 
645
                    null, 
646
                    i18n.getTranslation("_Warning"), 
647
                    JOptionPane.WARNING_MESSAGE, 
648
                    "Vectorediting_cant_discard_changes"
649
                );
650
                return;
651
            }
652
            break;
653

    
654
        case EXPORT_LAYER:
655
            try {
656
                exportLayer(layer);
657
            } catch (VectorEditingException e) {
658
                String msg =
659
                    String.format("Changes of %1$s can not be exported",
660
                        layer.getName());
661
                logger.info(msg, e);
662
                dialogs.messageDialog(                   
663
                    i18n.getTranslation("_There_are_problems_exporting_changes")+"\n\n"+
664
                    i18n.getTranslation("_See_error_log_for_more_information"), 
665
                    null, 
666
                    i18n.getTranslation("_Warning"), 
667
                    JOptionPane.WARNING_MESSAGE, 
668
                    "Vectorediting_cant_export_changes"
669
                );
670
                return;
671
            }
672
            break;
673

    
674
        case CANCEL:
675
            return;
676
        }
677

    
678
        cleanEditingContext();
679
        hideConsole();
680
        disableSnapping();
681
        changeSelectedTool(DEFAULT_TOOL);
682

    
683
        FeatureStore featureStore = layer.getFeatureStore();
684
        featureStore.deleteObserver(getMapControl());
685

    
686
    }
687

    
688
    private void enableSelection(boolean enableSelection) {
689
        this.editingCompoundBehavior.setDrawnBehavior(
690
            EditingCompoundBehavior.SELECTION_INDEX, enableSelection);
691
    }
692

    
693
    @Override
694
    public void endEdition(FLyrVect layer) {
695
        if (layer.isEditing()) {
696
            EditingNotificationManager editingNotificationManager =
697
                DALSwingLocator.getEditingNotificationManager();
698

    
699
            EditingNotification notification =
700
                editingNotificationManager.notifyObservers(this,
701
                    EditingNotification.BEFORE_EXIT_EDITING_STORE, null, layer, layer.getFeatureStore());
702

    
703
            if (notification.isCanceled()) {
704
                String msg =
705
                    String.format(
706
                        "Stop edit layer %1$s canceled by somme observer.",
707
                        layer.getName());
708
                logger.info(msg, new EndEditingException(msg, null));
709

    
710
            }
711

    
712
            getMapControl().getCanceldraw().setCanceled(true);
713
            int option;
714
            EditingSwingManager swingManager =
715
                EditingSwingLocator.getSwingManager();
716

    
717

    
718
            if (layer.isWritable() && getMapControl().getProjection().equals(layer.getProjection()) ) {
719
                option =
720
                    swingManager.showPanelSaveOrDiscard(getMapControl(),
721
                        layer.getName());
722
            } else {
723
                option =
724
                    swingManager.showPanelExportOrDiscard(getMapControl(),
725
                        layer.getName());
726
            }
727

    
728
            doAction(layer, option);
729

    
730
            editingNotificationManager.notifyObservers(this,
731
                EditingNotification.AFTER_EXIT_EDITING_STORE, null, layer, layer.getFeatureStore());
732

    
733
        }
734

    
735
    }
736

    
737
    private void exportLayer(FLyrVect layer) throws EndEditingException {
738
        Notification notification = new BaseNotification(EditingContext.EXPORT_LAYER_NOTIFICATION,1);
739
        notification.setValue(layer);
740
        this.observableHelper.notifyObservers(this, notification);
741
    }
742

    
743
    protected void finishService() {
744
        EditingService lastService = serviceStack.pop();
745
        try {
746

    
747
            if (!serviceStack.isEmpty()
748
                && getActiveService().next().getTypes().contains(TYPE.GEOMETRY)) {
749
                Geometry geometry = lastService.finish();
750
                if (geometry != null) {
751
                    getActiveService().setValue(geometry);
752
                }
753
            } else {
754
                lastService.finishAndStore();
755
                getMapControl().rePaintDirtyLayers();
756

    
757
                I18nManager i18nManager = ToolsLocator.getI18nManager();
758
                showConsoleMessage("\n"
759
                    + i18nManager.getTranslation(lastService.getName()) + "# "
760
                    + i18nManager.getTranslation("finished") + "\n");
761
                lastService.stop();
762
                setActiveService(lastService);
763
                lastService.start();
764
                changeSelectedTool(getActiveService().getName());
765
            }
766

    
767
        } catch (InvalidEntryException ex) {
768
            I18nManager i18nManager = ToolsLocator.getI18nManager();
769
            showConsoleMessage("\n"
770
                + i18nManager.getTranslation("invalid_option"));
771
            changeSelectedTool(getActiveService().getName());
772
        } catch (VectorEditingException ex) {
773
            logger.info("Can't finish " + lastService.getName(), ex);
774
            cleanEditingContext();
775
            return;
776
        }
777

    
778
        nextParameter();
779
    }
780

    
781
    public EditingService getActiveService() {
782
        if (!serviceStack.isEmpty()) {
783
            return serviceStack.peek();
784
        }
785
        return null;
786
    }
787

    
788
    private EditingConsole getConsolePanel() {
789
        if (console == null) {
790
            console = new DefaultEditingConsole(new ResponseListener() {
791

    
792
                @Override
793
                public void acceptResponse(String response) {
794
                    textEntered(response);
795
                }
796
            });
797
        }
798
        return console;
799
    }
800

    
801
    protected FLyrVect getCurrentLayer() {
802
        return this.currentLayer;
803
    }
804

    
805
    protected EditingServiceParameter getCurrentParam() {
806
        return this.currentParam;
807
    }
808

    
809
    private Component getDockConsole() {
810
        if (dockConsole == null) {
811
            dockConsole = new JDockPanel((JComponent) getConsolePanel());
812
        }
813
        return dockConsole;
814
    }
815

    
816
    private DefaultEditingBehavior getEditingBehavior() {
817
        if (editingCompoundBehavior != null) {
818
            return (DefaultEditingBehavior) editingCompoundBehavior
819
                .getBehavior(EditingCompoundBehavior.EDITING_INDEX);
820
        }
821
        return null;
822
    }
823

    
824
    private EditingCompoundBehavior getEditingCompoundBehavior() {
825
        if (editingCompoundBehavior != null) {
826
            return editingCompoundBehavior;
827
        } else {
828
            EditingCompoundBehavior editingCompoundBehavior;
829

    
830
            CompoundBehavior compoundBehavior =
831
                (CompoundBehavior) getMapControl().getMapTool("VectorEditing");
832

    
833
            if (compoundBehavior instanceof EditingCompoundBehavior) {
834
                editingCompoundBehavior =
835
                    (EditingCompoundBehavior) compoundBehavior;
836
            } else {
837
                editingCompoundBehavior =
838
                    (EditingCompoundBehavior) compoundBehavior.getBehavior(0);
839
            }
840

    
841
            setCompoundBehavior(editingCompoundBehavior);
842
            return editingCompoundBehavior;
843
        }
844
    }
845

    
846
    @Override
847
    public MapControl getMapControl() {
848
        return mapControlReference.get();
849
    }
850

    
851
    
852
    /*friend*/ void nextParameter() {
853
        if ((getMapControl().getCurrentTool() != null)
854
            && !getMapControl().getCurrentTool().equals("VectorEditing")) {
855
            getMapControl().setTool("VectorEditing");
856
        }
857
        currentParam = getActiveService().next();
858

    
859
        if (currentParam == null) {
860
            finishService();
861
        } else {
862
            askQuestion(currentParam);
863
            if (currentParam.getTypes().contains(TYPE.SELECTION)) {
864
                enableSelection(true);
865
            } else if (currentParam.getTypes().contains(TYPE.GEOMETRY)) {
866
                refreshMenusAndToolBars();
867
            }
868
        }
869
    }
870

    
871
    protected Stack<EditingService> getServiceStack() {
872
        return this.serviceStack;
873
    }
874

    
875
    private void hideConsole() {
876
        isShowConsole = false;
877
        if( !SwingUtilities.isEventDispatchThread() ) {
878
            try {
879
                SwingUtilities.invokeAndWait(new Runnable() {
880

    
881
                    @Override
882
                    public void run() {
883
                        hideConsole();
884
                    }
885
                });
886
                return;
887
            } catch (InterruptedException | InvocationTargetException ex) {
888
                logger.warn("Can't hide editing console.",ex);
889
            }
890
            return;
891
        }
892
        getDockConsole().setVisible(false);
893
    }
894

    
895
    @Override
896
    public boolean isServiceCompatible(String name) {
897
        DefaultEditingBehavior editingBehavior = getEditingBehavior();
898

    
899
        if (editingBehavior != null) {
900

    
901
            try {
902
                EditingManager manager = EditingLocator.getManager();
903
                EditingServiceInfo serviceInfo = manager.getServiceInfo(name);
904
                GeometryType geoType = null;
905

    
906
                for (EditingService editingService : getServiceStack()) {
907
                    EditingServiceParameter parameter = editingService.next();
908
                    if (parameter != null
909
                        && parameter.getTypes().contains(TYPE.GEOMETRY)) {
910

    
911
                        int geometryType = parameter.getGeometryType();
912
                        int subType = -1;
913

    
914
                        try {
915
                            subType =
916
                                getCurrentLayer().getFeatureStore()
917
                                    .getDefaultFeatureType()
918
                                    .getDefaultGeometryAttribute()
919
                                    .getGeomType().getSubType();
920

    
921
                            geoType =
922
                                GeometryLocator.getGeometryManager()
923
                                    .getGeometryType(geometryType, subType);
924
                        } catch (Exception e) {
925

    
926
                            String msg =
927
                                String.format(
928
                                    "Problems getting default feature"
929
                                        + " type of %1$s or getting geometry"
930
                                        + " type of %2$s %3$s",
931
                                    getCurrentLayer().getName(), geometryType,
932
                                    subType);
933

    
934
                            throw new ServiceInformationException(msg, e);
935
                        }
936

    
937
                        return serviceInfo.isCompatibleWith(geoType)
938
                            && serviceInfo.createsNewGeometries();
939
                    }
940
                }
941

    
942
                if (getCurrentLayer() != null) {
943
                    try {
944
                        geoType =
945
                            getCurrentLayer().getFeatureStore()
946
                                .getDefaultFeatureType()
947
                                .getDefaultGeometryAttribute().getGeomType();
948
                    } catch (DataException e) {
949
                        String msg =
950
                            String.format("Problems getting default "
951
                                + "feature type of %1$s", getCurrentLayer()
952
                                .getName());
953
                        throw new ServiceInformationException(msg, e);
954
                    }
955

    
956
                    return serviceInfo.isCompatibleWith(geoType);
957
                }
958

    
959
                return false;
960
            } catch (ServiceInformationException e) {
961
                logger.warn(
962
                    "Problems getting if editing context is compatible with "
963
                        + name, e);
964
            }
965
        }
966
        return false;
967
    }
968
    
969
    private Point parsePoint(String response) throws ParsePointException {
970
        TemporaryStorageManager manager = TemporaryStorageLocator.getTemporaryStorageManager();
971
        TemporaryStorageGroup storage = manager.create("Points",Point.class);
972

    
973
        MutableSymbolTable symbolTable = ExpressionUtils.createSymbolTable();
974
        symbolTable.setVar("LAST_POINT_ADDED", storage.get("LAST_POINT_ADDED_IN_EDTING"));
975
        
976
        try {
977
            Object x = ExpressionUtils.evaluate(symbolTable, response);
978
            if( x instanceof Point ) {
979
                storage.put("LAST_POINT_ADDED_IN_EDTING", x);
980
                return (Point) x;
981
            }
982
        } catch(Exception ex) {
983
            
984
        }
985
        String s = "ST_MakePoint("+response+")";
986
        try {
987
            Object x = ExpressionUtils.evaluate(symbolTable, s);
988
            if( x instanceof Point ) {
989
                storage.put("LAST_POINT_ADDED_IN_EDTING", x);
990
                return (Point) x;
991
            }
992
        } catch(Exception ex) {
993
            throw new ParsePointException(ex);
994
        }
995
        throw new ParsePointException(null);
996
    }
997
    
998
    private Double parseValue(String response) throws ParseValueException {
999
        TemporaryStorageManager manager = TemporaryStorageLocator.getTemporaryStorageManager();
1000
        TemporaryStorageGroup storage = manager.create("Points",Point.class);
1001

    
1002
        MutableSymbolTable symbolTable = ExpressionUtils.createSymbolTable();
1003
        symbolTable.setVar("LAST_POINT_ADDED", storage.get("LAST_POINT_ADDED_IN_EDTING"));
1004
        
1005
        try {
1006
            Object x = ExpressionUtils.evaluate(symbolTable, response);
1007
            if( x instanceof Double ) {
1008
                return (Double) x;
1009
            }  
1010
            if( x==null ) {
1011
                throw new ParseValueException(new NullPointerException());
1012
            }
1013
            Coercion toDouble = ToolsLocator.getDataTypesManager().get(DataTypes.DOUBLE).getCoercion();
1014
            return (Double) toDouble.coerce(x);
1015
        } catch(Exception ex) {
1016
            throw new ParseValueException(ex);
1017
        }
1018

    
1019
    }
1020

    
1021
    protected void refreshMenusAndToolBars() {
1022
        if (!SwingUtilities.isEventDispatchThread()) {
1023
            SwingUtilities.invokeLater(new Runnable() {
1024

    
1025
                @Override
1026
                public void run() {
1027
                    refreshMenusAndToolBars();
1028
                }
1029
            });
1030
            return;
1031
        }
1032
        Notification notification = new BaseNotification(
1033
                EditingContext.REFRESH_TOOLS_NOTIFICATION,
1034
                null
1035
        );
1036
        this.observableHelper.notifyObservers(this, notification);
1037
    }
1038

    
1039
    private void saveChanges(FLyrVect layer) throws EndEditingException {
1040
        FeatureStore featureStore = layer.getFeatureStore();
1041
        try {
1042
            featureStore.finishEditing();
1043
        } catch (Exception e) {
1044
            throw new EndEditingException(e);
1045
        }
1046
    }
1047

    
1048
    private void setActiveService(EditingService service) {
1049
        serviceStack.add(service);
1050
    }
1051

    
1052
    private void setCompoundBehavior(EditingCompoundBehavior compoundBehavior) {
1053
        this.editingCompoundBehavior = compoundBehavior;
1054
    }
1055

    
1056
    private void setCurrentLayer(FLyrVect layer) {
1057

    
1058
        if (this.currentLayer != layer) {
1059
            this.currentLayer = layer;
1060
            cleanEditingContext();
1061
        }
1062

    
1063
    }
1064

    
1065
    @Override
1066
    public void setMapControl(MapControl mapControl) {
1067

    
1068
        this.mapControlReference = new WeakReference<>(mapControl);
1069
        this.mapContextReference =
1070
            new WeakReference<>(mapControl.getMapContext());
1071

    
1072
        // When mapControl is updated we have to add older additional behaviors
1073
        // to new mapControl
1074
        if (lastAdditionalBehaviors != null) {
1075
            try {
1076
                addBehaviors(lastAdditionalBehaviors);
1077
            } catch (CreateEditingBehaviorException e1) {
1078
                logger.info("Problems adding behaviors to editing context", e1);
1079
                getMapControl().setTool("pan");
1080
            }
1081
        }
1082
    }
1083

    
1084
    private void showConsole() {
1085
        if (isShowConsole) {
1086
            return;
1087
        }
1088
        if( !SwingUtilities.isEventDispatchThread() ) {
1089
            try {
1090
                SwingUtilities.invokeAndWait(new Runnable() {
1091

    
1092
                    @Override
1093
                    public void run() {
1094
                        showConsole();
1095
                    }
1096
                });
1097
                return;
1098
            } catch (InterruptedException | InvocationTargetException ex) {
1099
                logger.warn("Can't show editing console.",ex);
1100
            }
1101
            return;
1102
        }
1103
        isShowConsole = true;
1104
        getMapControl().remove(getDockConsole());
1105
        getMapControl().setLayout(new BorderLayout());
1106
        getMapControl().add(getDockConsole(), BorderLayout.SOUTH);
1107
        getDockConsole().setVisible(true);
1108
    }
1109

    
1110
    protected void showConsoleMessage(final String text) {
1111
        if (!SwingUtilities.isEventDispatchThread()) {
1112
            SwingUtilities.invokeLater(new Runnable() {
1113

    
1114
                @Override
1115
                public void run() {
1116
                    showConsoleMessage(text);
1117
                }
1118
            });
1119
            return;
1120
        }
1121
        getConsolePanel().addText(text);
1122
    }
1123

    
1124
    protected void textEntered(String response) {
1125
        FeatureStore featureStore = getCurrentLayer().getFeatureStore();
1126
        EditingService activeService = getActiveService();
1127
        if (response == null) {
1128
            if (activeService != null) {
1129
                try {
1130
                    activeService.stop();
1131
                    serviceStack.pop();
1132
                    if (serviceStack.isEmpty()) {
1133
                        featureStore
1134
                            .getFeatureSelection().deselectAll();
1135
                        changeSelectedTool(DEFAULT_TOOL);
1136
                    } else {
1137
                        changeSelectedTool(activeService.getName());
1138
                    }
1139

    
1140
                    refreshMenusAndToolBars();
1141
                    activeService = getActiveService();
1142
                    if (activeService != null) {
1143
                        nextParameter();
1144
                    } else {
1145
                        cleanEditingContext();
1146
                    }
1147

    
1148
                } catch (StopServiceException e) {
1149
                    logger
1150
                        .info("Can't stop " + activeService.getName(), e);
1151
                } catch (DataException e) {
1152
                    logger.info("Can't get selection of "
1153
                        + featureStore.getFullName(), e);
1154
                }
1155
            }
1156
        } else {
1157

    
1158
            I18nManager i18nManager = ToolsLocator.getI18nManager();
1159
            if (getCurrentParam() != null) {
1160
                try {
1161
                    Object coercedValue = coerceInputParameter(getCurrentParam(), response);
1162
                    activeService.setValue(coercedValue);
1163
                } catch (InvalidEntryException ex) {
1164
                    showConsoleMessage("\n"
1165
                            + i18nManager.getTranslation("invalid_option"));
1166
                }
1167
            }
1168

    
1169
            nextParameter();
1170
        }
1171
    }
1172
    
1173
    private Object coerceInputParameter(EditingServiceParameter parameter, String input) throws InvalidEntryException {
1174
        if (parameter != null) {
1175
            FeatureStore featureStore = getCurrentLayer().getFeatureStore();
1176
            Set<TYPE> types = parameter.getTypes();
1177
            Point point = null;
1178
            Double value = null;
1179
            Point defaultPoint = null;
1180
            Object defaultValue = parameter.getDefaultValue();
1181

    
1182
            boolean insertedValue = false;
1183
            if ((!insertedValue && types.contains(TYPE.POSITION))
1184
                    || types.contains(TYPE.LIST_POSITIONS)) {
1185

    
1186
                defaultPoint = (Point) defaultValue;
1187
                try {
1188
                    if (StringUtils.isEmpty(input.replace("\n", ""))) {
1189
                        point = defaultPoint;
1190
                    } else {
1191
                        point = parsePoint(input);
1192
                    }
1193

    
1194
                    if (point != null) {
1195
                        return point;
1196
                    }
1197

    
1198
                } catch (ParsePointException e) {
1199
                    // Do nothing to try other types
1200
                }
1201
            }
1202
            if (types.contains(TYPE.VALUE)) {
1203

    
1204
                try {
1205
                    value = parseValue(input);
1206
                    if (value != null) {
1207
                        return value;
1208
                    }
1209

    
1210
                } catch (ParseValueException e) {
1211
                    // Do nothing to try other types
1212
                }
1213

    
1214
            }
1215
            if (types.contains(TYPE.OPTION)) {
1216
                input = input.replace("\n", "");
1217
                return input;
1218
            }
1219
            if (!insertedValue && types.contains(TYPE.SELECTION)) {
1220
                if (input.equalsIgnoreCase("\n")) {
1221
                    enableSelection(false);
1222
                    insertedValue = true;
1223

    
1224
                    FeatureSelection clonedSelection;
1225
                    try {
1226
                        clonedSelection = (FeatureSelection) featureStore
1227
                                .getFeatureSelection().clone();
1228
                        if (clonedSelection.isEmpty()) {
1229
                            throw new InvalidEntryException(null);
1230
                        }
1231
                    } catch (InvalidEntryException e) {
1232
                        throw e;
1233
                    } catch (Exception e) {
1234
                        logger.warn("Can't access to selection.", e);
1235
                        throw new InvalidEntryException(e);
1236
//                        cleanEditingContext();
1237
//                        return null;
1238
                    }
1239
                    
1240
                    return clonedSelection;
1241
                }
1242
            }
1243
        }
1244
        return null;
1245
    }
1246

    
1247
    @Override
1248
    public void setDefaultBehaviors(Behavior[] defaultBehaviors) {
1249
        this.defaultBehaviors = defaultBehaviors;
1250
        try {
1251
            addBehaviors(defaultBehaviors);
1252
        } catch (CreateEditingBehaviorException e1) {
1253
            logger.info("Problems adding behaviors to editing context", e1);
1254
            getMapControl().setTool("pan");
1255
        }
1256
    }
1257

    
1258
    @Override
1259
    public Behavior[] getDefaultBehaviors() {
1260
        return this.defaultBehaviors;
1261
    }
1262

    
1263
    @Override
1264
    public void setValue(EditingServiceParameter parameter, String value) throws InvalidEntryException {
1265
        Object obj = coerceInputParameter(parameter, value);
1266
        getActiveService().setValue(parameter, obj);
1267
        nextParameter();
1268
    }
1269
    
1270
    
1271
}