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

History | View | Annotate | Download (43.7 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.AbstractList;
32
import java.util.ArrayList;
33
import java.util.List;
34
import java.util.Set;
35
import java.util.Stack;
36
import java.util.prefs.PreferenceChangeEvent;
37
import java.util.prefs.PreferenceChangeListener;
38
import java.util.prefs.Preferences;
39

    
40
import javax.swing.JComponent;
41
import javax.swing.JOptionPane;
42
import javax.swing.SwingUtilities;
43

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

    
94
import org.apache.commons.lang3.StringUtils;
95
import org.gvsig.expressionevaluator.ExpressionUtils;
96
import org.gvsig.expressionevaluator.MutableSymbolTable;
97
import org.gvsig.expressionevaluator.SymbolTable;
98
import org.gvsig.fmap.dal.DataTypes;
99

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

    
110
import org.slf4j.Logger;
111
import org.slf4j.LoggerFactory;
112

    
113
public class DefaultEditingContext implements EditingContext {
114

    
115
    private static final Logger logger = LoggerFactory
116
        .getLogger(EditingManager.class);
117

    
118
    private WeakReference<MapControl> mapControlReference;
119

    
120
    private WeakReference<MapContext> mapContextReference;
121

    
122
    private EditingCompoundBehavior editingCompoundBehavior;
123

    
124
    private Behavior[] lastAdditionalBehaviors;
125

    
126
    private final ObservableHelper observableHelper;
127

    
128
    private EditingConsole console;
129

    
130
    private JDockPanel dockConsole = null;
131

    
132
    private boolean isShowConsole = false;
133

    
134
    private final Stack<EditingService> serviceStack;
135

    
136
    private FLyrVect currentLayer;
137

    
138
    private EditingServiceParameter currentParam;
139

    
140
    private Behavior[] defaultBehaviors;
141

    
142
    private final LayerListener layerListener = new LayerListener() {
143

    
144
        @Override
145
        public void activationChanged(final LayerEvent e) {
146
            if( !SwingUtilities.isEventDispatchThread() ) {
147
                SwingUtilities.invokeLater(new Runnable() {
148

    
149
                    @Override
150
                    public void run() {
151
                        activationChanged(e);
152
                    }
153
                });
154
                return;
155
            }
156

    
157
            FLayer layer = e.getSource();
158
            final MapContext mapContext = layer.getMapContext();
159

    
160
            if (countActiveAndEditingLayers(mapContext) > 1) {
161
                hideConsole();
162
                return;
163
            }
164

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

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

    
188
            hideConsole();
189
            if ((getMapControl().getCurrentTool() != null)
190
                && getMapControl().getCurrentTool().equals("VectorEditing")) {
191
                getMapControl().setPrevTool();
192
            }
193
        }
194

    
195
        @Override
196
        public void drawValueChanged(LayerEvent e) {
197
        }
198

    
199
        @Override
200
        public void editionChanged(final LayerEvent e) {
201
            if( !SwingUtilities.isEventDispatchThread() ) {
202
                SwingUtilities.invokeLater(new Runnable() {
203

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

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

    
224
        }
225

    
226
        @Override
227
        public void nameChanged(LayerEvent e) {
228
        }
229

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

    
252
    private final PreferenceChangeListener preferenceChangeListener =
253
        new PreferenceChangeListener() {
254

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

    
265
    public DefaultEditingContext(MapControl mapControl) {
266

    
267
        this.mapControlReference = new WeakReference<>(mapControl);
268
        this.mapContextReference =
269
            new WeakReference<>(mapControl.getMapContext());
270
        this.observableHelper = new ObservableHelper();
271

    
272
        this.serviceStack = new Stack<>();
273

    
274
        addLayerListeners();
275
        addPreferenceListener();
276
    }
277

    
278
    private void addPreferenceListener() {
279
        Preferences prefs = Preferences.userRoot().node("snappers");
280
        prefs.addPreferenceChangeListener(preferenceChangeListener);
281
    }
282

    
283
    @Override
284
    public void activateService(String name) {
285

    
286
        if ((getMapControl() != null)
287
            && getMapControl().hasTool("VectorEditing")) {
288

    
289
            CompoundBehavior editingCompoundBehavior =
290
                getEditingCompoundBehavior();
291
            getMapControl().setTool("VectorEditing");
292
            editingCompoundBehavior.setDrawnBehavior(
293
                EditingCompoundBehavior.EDITING_INDEX, true);
294

    
295
            EditingManager manager = EditingLocator.getManager();
296

    
297
            if (currentLayer != null) {
298

    
299
                EditingService service =
300
                    manager.getEditingService(name,
301
                        currentLayer.getFeatureStore(),
302
                        mapContextReference.get());
303

    
304
                if (service != null) {
305

    
306
                    this.enableSelection(false);
307

    
308
                    try {
309
                        service.start();
310
                    } catch (StartServiceException e) {
311

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

    
318
                    } catch (InvalidEntryException e) {
319

    
320
                        I18nManager i18nManager = ToolsLocator.getI18nManager();
321
                        showConsoleMessage("\n"
322
                            + i18nManager.getTranslation("invalid_option"));
323
                    }
324

    
325
                    if (!serviceStack.isEmpty()
326
                        && !getActiveService().next().getTypes()
327
                            .contains(TYPE.GEOMETRY)) {
328
                        serviceStack.pop();
329
                    }
330

    
331
                    setActiveService(service);
332

    
333
                    nextParameter();
334
                }
335
            }
336
        }
337
    }
338

    
339
    private void addBehaviors(Behavior[] additionalBehavior)
340
        throws CreateEditingBehaviorException {
341

    
342
        DefaultEditingBehavior editingBehavior;
343
        EditingCompoundBehavior editingCompoundBehavior;
344

    
345
        if (!getMapControl().hasTool("VectorEditing")) {
346

    
347
            editingBehavior = new DefaultEditingBehavior(this);
348
            editingCompoundBehavior =
349
                new EditingCompoundBehavior(editingBehavior);
350
            setCompoundBehavior(editingCompoundBehavior);
351

    
352
            if (additionalBehavior != null) {
353

    
354
                Behavior[] behaviors =
355
                    new Behavior[additionalBehavior.length + 1];
356
                behaviors[0] = editingCompoundBehavior;
357

    
358
                System.arraycopy(additionalBehavior, 0, behaviors, 1, additionalBehavior.length);
359

    
360
                getMapControl().addBehavior("VectorEditing", behaviors);
361

    
362
                lastAdditionalBehaviors = additionalBehavior;
363

    
364
            } else {
365
                getMapControl().addBehavior("VectorEditing",
366
                    editingCompoundBehavior);
367
            }
368

    
369
        } else {
370
            editingCompoundBehavior = getEditingCompoundBehavior();
371
            editingBehavior =
372
                (DefaultEditingBehavior) editingCompoundBehavior
373
                    .getBehavior(EditingCompoundBehavior.EDITING_INDEX);
374
            setCompoundBehavior(editingCompoundBehavior);
375
            cleanEditingContext();
376
        }
377

    
378
    }
379

    
380
    private void addLayerListeners() {
381

    
382
        FLayers layers = mapContextReference.get().getLayers();
383

    
384
        layers.addLayerListener(layerListener);
385

    
386
        layers.addLayerCollectionListener(new LayerCollectionListener() {
387

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

    
399
            @Override
400
            public void layerAdded(LayerCollectionEvent e) {
401
                addLayer(e.getLayers());
402
            }
403

    
404
            @Override
405
            public void layerAdding(LayerCollectionEvent e)
406
                throws CancelationException {
407
            }
408

    
409
            @Override
410
            public void layerMoved(LayerPositionEvent e) {
411
            }
412

    
413
            @Override
414
            public void layerMoving(LayerPositionEvent e)
415
                throws CancelationException {
416
            }
417

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

    
429
            @Override
430
            public void layerRemoved(LayerCollectionEvent e) {
431
                removeLayer(e.getLayers());
432
            }
433

    
434
            @Override
435
            public void layerRemoving(LayerCollectionEvent e)
436
                throws CancelationException {
437
            }
438

    
439
            @Override
440
            public void visibilityChanged(LayerCollectionEvent e)
441
                throws CancelationException {
442
            }
443
        });
444
    }
445

    
446
    @Override
447
    public void addObserver(Observer o) {
448
        this.observableHelper.addObserver(o);
449
    }
450

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

    
457
        Object defaultValue = param.getDefaultValue();
458
        String strDefaultValue;
459

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

    
487
    @Override
488
    public synchronized void beginEdition(FLyrVect layer,
489
        Behavior[] additionalBehaviors) {
490

    
491
        try{
492
            throw new Exception("Deprecated method");
493
        } catch (Exception e){
494
            logger.info("Deprecated method", e);
495
        }
496

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

    
506
    @Override
507
    public synchronized void beginEdition(FLyrVect layer) {
508

    
509
        EditingNotificationManager editingNotificationManager =
510
            DALSwingLocator.getEditingNotificationManager();
511

    
512
        EditingNotification notification =
513
            editingNotificationManager.notifyObservers(this,
514
                EditingNotification.BEFORE_ENTER_EDITING_STORE, null, layer,layer.getFeatureStore());
515

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

    
524
        setCurrentLayer(layer);
525

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

    
540
        featureStore.addObserver(getMapControl());
541

    
542
        editingNotificationManager.notifyObservers(this,
543
            EditingNotification.AFTER_ENTER_EDITING_STORE, null, layer, layer.getFeatureStore());
544

    
545
        enableSnapping();
546
    }
547

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

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

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

    
582
    private void cleanEditingContext() {
583
        serviceStack.clear();
584
        currentParam = null;
585
        this.enableSelection(false);
586
        refreshMenusAndToolBars();
587

    
588
        I18nManager i18nManager = ToolsLocator.getI18nManager();
589
        showConsoleMessage("\n" + i18nManager.getTranslation("select_new_tool")
590
            + "\n");
591
    }
592

    
593
    @Override
594
    public void deleteObserver(Observer o) {
595
        this.observableHelper.deleteObserver(o);
596
    }
597

    
598
    @Override
599
    public void deleteObservers() {
600
        this.observableHelper.deleteObservers();
601
    }
602

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

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

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

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

    
677
        case CANCEL:
678
            return;
679
        }
680

    
681
        cleanEditingContext();
682
        hideConsole();
683
        disableSnapping();
684
        changeSelectedTool(DEFAULT_TOOL);
685

    
686
        FeatureStore featureStore = layer.getFeatureStore();
687
        featureStore.deleteObserver(getMapControl());
688

    
689
    }
690

    
691
    private void enableSelection(boolean enableSelection) {
692
        this.editingCompoundBehavior.setDrawnBehavior(
693
            EditingCompoundBehavior.SELECTION_INDEX, enableSelection);
694
    }
695

    
696
    @Override
697
    public void endEdition(FLyrVect layer) {
698
        if (layer.isEditing()) {
699
            EditingNotificationManager editingNotificationManager =
700
                DALSwingLocator.getEditingNotificationManager();
701

    
702
            EditingNotification notification =
703
                editingNotificationManager.notifyObservers(this,
704
                    EditingNotification.BEFORE_EXIT_EDITING_STORE, null, layer, layer.getFeatureStore());
705

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

    
713
            }
714

    
715
            getMapControl().getCanceldraw().setCanceled(true);
716
            int option;
717
            EditingSwingManager swingManager =
718
                EditingSwingLocator.getSwingManager();
719

    
720

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

    
731
            doAction(layer, option);
732

    
733
            editingNotificationManager.notifyObservers(this,
734
                EditingNotification.AFTER_EXIT_EDITING_STORE, null, layer, layer.getFeatureStore());
735

    
736
        }
737

    
738
    }
739

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

    
746
    protected void finishService() {
747
        EditingService lastService = serviceStack.pop();
748
        try {
749

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

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

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

    
781
        nextParameter();
782
    }
783

    
784
    public EditingService getActiveService() {
785
        if (!serviceStack.isEmpty()) {
786
            return serviceStack.peek();
787
        }
788
        return null;
789
    }
790

    
791
    private EditingConsole getConsolePanel() {
792
        if (console == null) {
793
            console = new DefaultEditingConsole(new ResponseListener() {
794

    
795
                @Override
796
                public void acceptResponse(String response) {
797
                    textEntered(response);
798
                }
799
            });
800
        }
801
        return console;
802
    }
803

    
804
    protected FLyrVect getCurrentLayer() {
805
        return this.currentLayer;
806
    }
807

    
808
    protected EditingServiceParameter getCurrentParam() {
809
        return this.currentParam;
810
    }
811

    
812
    private Component getDockConsole() {
813
        if (dockConsole == null) {
814
            dockConsole = new JDockPanel((JComponent) getConsolePanel());
815
        }
816
        return dockConsole;
817
    }
818

    
819
    private DefaultEditingBehavior getEditingBehavior() {
820
        if (editingCompoundBehavior != null) {
821
            return (DefaultEditingBehavior) editingCompoundBehavior
822
                .getBehavior(EditingCompoundBehavior.EDITING_INDEX);
823
        }
824
        return null;
825
    }
826

    
827
    private EditingCompoundBehavior getEditingCompoundBehavior() {
828
        if (editingCompoundBehavior != null) {
829
            return editingCompoundBehavior;
830
        } else {
831
            EditingCompoundBehavior editingCompoundBehavior;
832

    
833
            CompoundBehavior compoundBehavior =
834
                (CompoundBehavior) getMapControl().getMapTool("VectorEditing");
835

    
836
            if (compoundBehavior instanceof EditingCompoundBehavior) {
837
                editingCompoundBehavior =
838
                    (EditingCompoundBehavior) compoundBehavior;
839
            } else {
840
                editingCompoundBehavior =
841
                    (EditingCompoundBehavior) compoundBehavior.getBehavior(0);
842
            }
843

    
844
            setCompoundBehavior(editingCompoundBehavior);
845
            return editingCompoundBehavior;
846
        }
847
    }
848

    
849
    @Override
850
    public MapControl getMapControl() {
851
        return mapControlReference.get();
852
    }
853

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

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

    
874
    protected Stack<EditingService> getServiceStack() {
875
        return this.serviceStack;
876
    }
877

    
878
    private void hideConsole() {
879
        isShowConsole = false;
880
        if( !SwingUtilities.isEventDispatchThread() ) {
881
            try {
882
                SwingUtilities.invokeAndWait(new Runnable() {
883

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

    
898
    @Override
899
    public boolean isServiceCompatible(String name) {
900
        DefaultEditingBehavior editingBehavior = getEditingBehavior();
901

    
902
        if (editingBehavior != null) {
903

    
904
            try {
905
                EditingManager manager = EditingLocator.getManager();
906
                EditingServiceInfo serviceInfo = manager.getServiceInfo(name);
907
                GeometryType geoType = null;
908

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

    
914
                        int geometryType = parameter.getGeometryType();
915
                        int subType = -1;
916

    
917
                        try {
918
                            subType =
919
                                getCurrentLayer().getFeatureStore()
920
                                    .getDefaultFeatureType()
921
                                    .getDefaultGeometryAttribute()
922
                                    .getGeomType().getSubType();
923

    
924
                            geoType =
925
                                GeometryLocator.getGeometryManager()
926
                                    .getGeometryType(geometryType, subType);
927
                        } catch (Exception e) {
928

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

    
937
                            throw new ServiceInformationException(msg, e);
938
                        }
939

    
940
                        return serviceInfo.isCompatibleWith(geoType)
941
                            && serviceInfo.createsNewGeometries();
942
                    }
943
                }
944

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

    
959
                    return serviceInfo.isCompatibleWith(geoType);
960
                }
961

    
962
                return false;
963
            } catch (ServiceInformationException e) {
964
                logger.warn(
965
                    "Problems getting if editing context is compatible with "
966
                        + name, e);
967
            }
968
        }
969
        return false;
970
    }
971
     
972
    private static EditingContextSymbolTable contextSymbolTable = new EditingContextSymbolTable();
973
    
974
    private Point parsePoint(String response) throws ParsePointException {
975
        try {
976
            Object x = ExpressionUtils.evaluate(contextSymbolTable, response);
977
            if( x instanceof Point ) {
978
                contextSymbolTable.addPoint((Point) x);
979
                return (Point) x;
980
            }
981
        } catch(Exception ex) {
982
            
983
        }
984
        String s = "ST_MakePoint("+response+")";
985
        try {
986
            Object x = ExpressionUtils.evaluate(contextSymbolTable, s);
987
            if( x instanceof Point ) {
988
                contextSymbolTable.addPoint((Point) x);
989
                return (Point) x;
990
            }
991
        } catch(Exception ex) {
992
            throw new ParsePointException(ex);
993
        }
994
        throw new ParsePointException(null);
995
    }
996
    
997
    private Double parseValue(String response) throws ParseValueException {
998
        try {
999
            Object x = ExpressionUtils.evaluate(contextSymbolTable, response);
1000
            if( x instanceof Double ) {
1001
                return (Double) x;
1002
            }  
1003
            if( x==null ) {
1004
                throw new ParseValueException(new NullPointerException());
1005
            }
1006
            Coercion toDouble = ToolsLocator.getDataTypesManager().get(DataTypes.DOUBLE).getCoercion();
1007
            return (Double) toDouble.coerce(x);
1008
        } catch(Exception ex) {
1009
            throw new ParseValueException(ex);
1010
        }
1011

    
1012
    }
1013

    
1014
    protected void refreshMenusAndToolBars() {
1015
        if (!SwingUtilities.isEventDispatchThread()) {
1016
            SwingUtilities.invokeLater(new Runnable() {
1017

    
1018
                @Override
1019
                public void run() {
1020
                    refreshMenusAndToolBars();
1021
                }
1022
            });
1023
            return;
1024
        }
1025
        Notification notification = new BaseNotification(
1026
                EditingContext.REFRESH_TOOLS_NOTIFICATION,
1027
                null
1028
        );
1029
        this.observableHelper.notifyObservers(this, notification);
1030
    }
1031

    
1032
    private void saveChanges(FLyrVect layer) throws EndEditingException {
1033
        FeatureStore featureStore = layer.getFeatureStore();
1034
        try {
1035
            featureStore.finishEditing();
1036
        } catch (Exception e) {
1037
            throw new EndEditingException(e);
1038
        }
1039
    }
1040

    
1041
    private void setActiveService(EditingService service) {
1042
        serviceStack.add(service);
1043
    }
1044

    
1045
    private void setCompoundBehavior(EditingCompoundBehavior compoundBehavior) {
1046
        this.editingCompoundBehavior = compoundBehavior;
1047
    }
1048

    
1049
    private void setCurrentLayer(FLyrVect layer) {
1050

    
1051
        if (this.currentLayer != layer) {
1052
            this.currentLayer = layer;
1053
            cleanEditingContext();
1054
        }
1055

    
1056
    }
1057

    
1058
    @Override
1059
    public void setMapControl(MapControl mapControl) {
1060

    
1061
        this.mapControlReference = new WeakReference<>(mapControl);
1062
        this.mapContextReference =
1063
            new WeakReference<>(mapControl.getMapContext());
1064

    
1065
        // When mapControl is updated we have to add older additional behaviors
1066
        // to new mapControl
1067
        if (lastAdditionalBehaviors != null) {
1068
            try {
1069
                addBehaviors(lastAdditionalBehaviors);
1070
            } catch (CreateEditingBehaviorException e1) {
1071
                logger.info("Problems adding behaviors to editing context", e1);
1072
                getMapControl().setTool("pan");
1073
            }
1074
        }
1075
    }
1076

    
1077
    private void showConsole() {
1078
        if (isShowConsole) {
1079
            return;
1080
        }
1081
        if( !SwingUtilities.isEventDispatchThread() ) {
1082
            try {
1083
                SwingUtilities.invokeAndWait(new Runnable() {
1084

    
1085
                    @Override
1086
                    public void run() {
1087
                        showConsole();
1088
                    }
1089
                });
1090
                return;
1091
            } catch (InterruptedException | InvocationTargetException ex) {
1092
                logger.warn("Can't show editing console.",ex);
1093
            }
1094
            return;
1095
        }
1096
        isShowConsole = true;
1097
        getMapControl().remove(getDockConsole());
1098
        getMapControl().setLayout(new BorderLayout());
1099
        getMapControl().add(getDockConsole(), BorderLayout.SOUTH);
1100
        getDockConsole().setVisible(true);
1101
    }
1102

    
1103
    protected void showConsoleMessage(final String text) {
1104
        if (!SwingUtilities.isEventDispatchThread()) {
1105
            SwingUtilities.invokeLater(new Runnable() {
1106

    
1107
                @Override
1108
                public void run() {
1109
                    showConsoleMessage(text);
1110
                }
1111
            });
1112
            return;
1113
        }
1114
        getConsolePanel().addText(text);
1115
    }
1116

    
1117
    protected void textEntered(String response) {
1118
        FeatureStore featureStore = getCurrentLayer().getFeatureStore();
1119
        EditingService activeService = getActiveService();
1120
        if (response == null) {
1121
            if (activeService != null) {
1122
                try {
1123
                    activeService.stop();
1124
                    serviceStack.pop();
1125
                    if (serviceStack.isEmpty()) {
1126
                        featureStore
1127
                            .getFeatureSelection().deselectAll();
1128
                        changeSelectedTool(DEFAULT_TOOL);
1129
                    } else {
1130
                        changeSelectedTool(activeService.getName());
1131
                    }
1132

    
1133
                    refreshMenusAndToolBars();
1134
                    activeService = getActiveService();
1135
                    if (activeService != null) {
1136
                        nextParameter();
1137
                    } else {
1138
                        cleanEditingContext();
1139
                    }
1140

    
1141
                } catch (StopServiceException e) {
1142
                    logger
1143
                        .info("Can't stop " + activeService.getName(), e);
1144
                } catch (DataException e) {
1145
                    logger.info("Can't get selection of "
1146
                        + featureStore.getFullName(), e);
1147
                }
1148
            }
1149
        } else {
1150

    
1151
            I18nManager i18nManager = ToolsLocator.getI18nManager();
1152
            if (getCurrentParam() != null) {
1153
                try {
1154
                    Object coercedValue = coerceInputParameter(getCurrentParam(), response);
1155
                    activeService.setValue(coercedValue);
1156
                } catch (InvalidEntryException ex) {
1157
                    showConsoleMessage("\n"
1158
                            + i18nManager.getTranslation("invalid_option"));
1159
                }
1160
            }
1161

    
1162
            nextParameter();
1163
        }
1164
    }
1165
    
1166
    private Object coerceInputParameter(EditingServiceParameter parameter, String input) throws InvalidEntryException {
1167
        if (parameter != null) {
1168
            FeatureStore featureStore = getCurrentLayer().getFeatureStore();
1169
            Set<TYPE> types = parameter.getTypes();
1170
            Point point = null;
1171
            Double value = null;
1172
            Point defaultPoint = null;
1173
            Object defaultValue = parameter.getDefaultValue();
1174

    
1175
            boolean insertedValue = false;
1176
            if ((!insertedValue && types.contains(TYPE.POSITION))
1177
                    || types.contains(TYPE.LIST_POSITIONS)) {
1178

    
1179
                defaultPoint = (Point) defaultValue;
1180
                try {
1181
                    if (StringUtils.isEmpty(input.replace("\n", ""))) {
1182
                        point = defaultPoint;
1183
                    } else {
1184
                        point = parsePoint(input);
1185
                    }
1186

    
1187
                    if (point != null) {
1188
                        return point;
1189
                    }
1190

    
1191
                } catch (ParsePointException e) {
1192
                    // Do nothing to try other types
1193
                }
1194
            }
1195
            if (types.contains(TYPE.VALUE)) {
1196

    
1197
                try {
1198
                    value = parseValue(input);
1199
                    if (value != null) {
1200
                        return value;
1201
                    }
1202

    
1203
                } catch (ParseValueException e) {
1204
                    // Do nothing to try other types
1205
                }
1206

    
1207
            }
1208
            if (types.contains(TYPE.OPTION)) {
1209
                input = input.replace("\n", "");
1210
                return input;
1211
            }
1212
            if (!insertedValue && types.contains(TYPE.SELECTION)) {
1213
                if (input.equalsIgnoreCase("\n")) {
1214
                    enableSelection(false);
1215
                    insertedValue = true;
1216

    
1217
                    FeatureSelection clonedSelection;
1218
                    try {
1219
                        clonedSelection = (FeatureSelection) featureStore
1220
                                .getFeatureSelection().clone();
1221
                        if (clonedSelection.isEmpty()) {
1222
                            throw new InvalidEntryException(null);
1223
                        }
1224
                    } catch (InvalidEntryException e) {
1225
                        throw e;
1226
                    } catch (Exception e) {
1227
                        logger.warn("Can't access to selection.", e);
1228
                        throw new InvalidEntryException(e);
1229
//                        cleanEditingContext();
1230
//                        return null;
1231
                    }
1232
                    
1233
                    return clonedSelection;
1234
                }
1235
            }
1236
        }
1237
        return null;
1238
    }
1239

    
1240
    @Override
1241
    public void setDefaultBehaviors(Behavior[] defaultBehaviors) {
1242
        this.defaultBehaviors = defaultBehaviors;
1243
        try {
1244
            addBehaviors(defaultBehaviors);
1245
        } catch (CreateEditingBehaviorException e1) {
1246
            logger.info("Problems adding behaviors to editing context", e1);
1247
            getMapControl().setTool("pan");
1248
        }
1249
    }
1250

    
1251
    @Override
1252
    public Behavior[] getDefaultBehaviors() {
1253
        return this.defaultBehaviors;
1254
    }
1255

    
1256
    @Override
1257
    public void setValue(EditingServiceParameter parameter, Object value) throws InvalidEntryException {
1258
        if( value instanceof CharSequence){
1259
            value = coerceInputParameter(parameter, value.toString());
1260
        } else if( value instanceof Point) {
1261
            contextSymbolTable.addPoint((Point) value);
1262
        }
1263
        getActiveService().setValue(parameter, value);
1264
        nextParameter();
1265
    }
1266
    
1267
    
1268
}