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

History | View | Annotate | Download (43.5 KB)

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

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

    
27
import java.awt.BorderLayout;
28
import java.awt.Component;
29
import java.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.logging.Level;
35
import java.util.prefs.PreferenceChangeEvent;
36
import java.util.prefs.PreferenceChangeListener;
37
import java.util.prefs.Preferences;
38

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

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

    
95
import org.apache.commons.lang3.StringUtils;
96
import org.gvsig.expressionevaluator.ExpressionUtils;
97
import org.gvsig.expressionevaluator.MutableSymbolTable;
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.DataTypesManager;
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 ObservableHelper observableHelper;
127

    
128
    private EditingConsole console;
129

    
130
    private JDockPanel dockConsole = null;
131

    
132
    private boolean isShowConsole = false;
133

    
134
    private Stack<EditingService> serviceStack;
135

    
136
    private FLyrVect currentLayer;
137

    
138
    private EditingServiceParameter currentParam;
139

    
140
    private Behavior[] defaultBehaviors;
141

    
142
    private 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

    
159
            FLayer[] activeLayers =
160
                layer.getMapContext().getLayers().getActives();
161

    
162
            if ((activeLayers.length == 1) && (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
            hideConsole();
172
            if ((getMapControl().getCurrentTool() != null)
173
                && getMapControl().getCurrentTool().equals("VectorEditing")) {
174
                getMapControl().setPrevTool();
175
            }
176
        }
177

    
178
        public void drawValueChanged(LayerEvent e) {
179
        }
180

    
181
        @Override
182
        public void editionChanged(final LayerEvent e) {
183
            if( !SwingUtilities.isEventDispatchThread() ) {
184
                SwingUtilities.invokeLater(new Runnable() {
185

    
186
                    @Override
187
                    public void run() {
188
                        editionChanged(e);
189
                    }
190
                });
191
                return;
192
            }
193
            FLayer layer = e.getSource();
194

    
195
            if (layer instanceof FLyrVect) {
196
                if (layer.isEditing()) {
197
                    synchronized (DefaultEditingContext.this) {
198
                        beginEdition((FLyrVect) layer);
199
                        showConsole();
200
                    }
201
                } else {
202
                    hideConsole();
203
                }
204
            }
205

    
206
        }
207

    
208
        public void nameChanged(LayerEvent e) {
209
        }
210

    
211
        public void visibilityChanged(LayerEvent e) {
212
        }
213
    };
214

    
215
    private PreferenceChangeListener preferenceChangeListener =
216
        new PreferenceChangeListener() {
217

    
218
            public void preferenceChange(PreferenceChangeEvent evt) {
219
                String key = evt.getKey();
220
                if (key.equalsIgnoreCase("apply-snappers")) {
221
                    boolean newValue = Boolean.parseBoolean(evt.getNewValue());
222
                    getMapControl().setRefentEnabled(newValue);
223
                }
224
            }
225
        };
226

    
227
    public DefaultEditingContext(MapControl mapControl) {
228

    
229
        this.mapControlReference = new WeakReference<MapControl>(mapControl);
230
        this.mapContextReference =
231
            new WeakReference<MapContext>(mapControl.getMapContext());
232
        this.observableHelper = new ObservableHelper();
233

    
234
        this.serviceStack = new Stack<EditingService>();
235

    
236
        addLayerListeners();
237
        addPreferenceListener();
238
    }
239

    
240
    private void addPreferenceListener() {
241
        Preferences prefs = Preferences.userRoot().node("snappers");
242
        prefs.addPreferenceChangeListener(preferenceChangeListener);
243
    }
244

    
245
    public void activateService(String name) {
246

    
247
        if ((getMapControl() != null)
248
            && getMapControl().hasTool("VectorEditing")) {
249

    
250
            CompoundBehavior editingCompoundBehavior =
251
                getEditingCompoundBehavior();
252
            getMapControl().setTool("VectorEditing");
253
            editingCompoundBehavior.setDrawnBehavior(
254
                EditingCompoundBehavior.EDITING_INDEX, true);
255

    
256
            EditingManager manager = EditingLocator.getManager();
257

    
258
            if (currentLayer != null) {
259

    
260
                EditingService service =
261
                    manager.getEditingService(name,
262
                        currentLayer.getFeatureStore(),
263
                        mapContextReference.get());
264

    
265
                if (service != null) {
266

    
267
                    this.enableSelection(false);
268

    
269
                    try {
270
                        service.start();
271
                    } catch (StartServiceException e) {
272

    
273
                        logger.info(String.format(
274
                            "Can't start the service %1$s", service.getName()),
275
                            e);
276
                        cleanEditingContext();
277
                        return;
278

    
279
                    } catch (InvalidEntryException e) {
280

    
281
                        I18nManager i18nManager = ToolsLocator.getI18nManager();
282
                        showConsoleMessage("\n"
283
                            + i18nManager.getTranslation("invalid_option"));
284
                    }
285

    
286
                    if (!serviceStack.isEmpty()
287
                        && !getActiveService().next().getTypes()
288
                            .contains(TYPE.GEOMETRY)) {
289
                        serviceStack.pop();
290
                    }
291

    
292
                    setActiveService(service);
293

    
294
                    getNextParameter();
295
                }
296
            }
297
        }
298
    }
299

    
300
    private void addBehaviors(Behavior[] additionalBehavior)
301
        throws CreateEditingBehaviorException {
302

    
303
        DefaultEditingBehavior editingBehavior;
304
        EditingCompoundBehavior editingCompoundBehavior;
305

    
306
        if (!getMapControl().hasTool("VectorEditing")) {
307

    
308
            editingBehavior = new DefaultEditingBehavior(this);
309
            editingCompoundBehavior =
310
                new EditingCompoundBehavior(editingBehavior);
311
            setCompoundBehavior(editingCompoundBehavior);
312

    
313
            if (additionalBehavior != null) {
314

    
315
                Behavior[] behaviors =
316
                    new Behavior[additionalBehavior.length + 1];
317
                behaviors[0] = editingCompoundBehavior;
318

    
319
                for (int i = 0; i < additionalBehavior.length; i++) {
320
                    behaviors[i + 1] = additionalBehavior[i];
321
                }
322

    
323
                getMapControl().addBehavior("VectorEditing", behaviors);
324

    
325
                lastAdditionalBehaviors = additionalBehavior;
326

    
327
            } else {
328
                getMapControl().addBehavior("VectorEditing",
329
                    editingCompoundBehavior);
330
            }
331

    
332
        } else {
333
            editingCompoundBehavior = getEditingCompoundBehavior();
334
            editingBehavior =
335
                (DefaultEditingBehavior) editingCompoundBehavior
336
                    .getBehavior(EditingCompoundBehavior.EDITING_INDEX);
337
            setCompoundBehavior(editingCompoundBehavior);
338
            cleanEditingContext();
339
        }
340

    
341
    }
342

    
343
    private void addLayerListeners() {
344

    
345
        FLayers layers = mapContextReference.get().getLayers();
346

    
347
        layers.addLayerListener(layerListener);
348

    
349
        layers.addLayerCollectionListener(new LayerCollectionListener() {
350

    
351
            public void addLayer(FLayer layer) {
352
                if (layer instanceof FLayers) {
353
                    FLayers layers = (FLayers) layer;
354
                    for (int i = 0; i < layers.getLayersCount(); i++) {
355
                        addLayer(layers.getLayer(i));
356
                    }
357
                } else if (layer instanceof FLyrVect) {
358
                    ((FLyrVect) layer).addLayerListener(layerListener);
359
                }
360
            }
361

    
362
            public void layerAdded(LayerCollectionEvent e) {
363
                addLayer(e.getLayers());
364
            }
365

    
366
            public void layerAdding(LayerCollectionEvent e)
367
                throws CancelationException {
368
            }
369

    
370
            public void layerMoved(LayerPositionEvent e) {
371
            }
372

    
373
            public void layerMoving(LayerPositionEvent e)
374
                throws CancelationException {
375
            }
376

    
377
            public void removeLayer(FLayer layer) {
378
                if (layer instanceof FLayers) {
379
                    FLayers layers = (FLayers) layer;
380
                    for (int i = 0; i < layers.getLayersCount(); i++) {
381
                        addLayer(layers.getLayer(i));
382
                    }
383
                } else if (layer instanceof FLyrVect) {
384
                    ((FLyrVect) layer).removeLayerListener(layerListener);
385
                }
386
            }
387

    
388
            public void layerRemoved(LayerCollectionEvent e) {
389
                removeLayer(e.getLayers());
390
            }
391

    
392
            public void layerRemoving(LayerCollectionEvent e)
393
                throws CancelationException {
394
            }
395

    
396
            public void visibilityChanged(LayerCollectionEvent e)
397
                throws CancelationException {
398
            }
399
        });
400
    }
401

    
402
    public void addObserver(Observer o) {
403
        this.observableHelper.addObserver(o);
404
    }
405

    
406
    private void askQuestion(EditingServiceParameter param) {
407
        I18nManager i18nManager = ToolsLocator.getI18nManager();
408
        String translation = i18nManager.getTranslation(param.getDescription());
409
        String activeServiceName =
410
            i18nManager.getTranslation(getActiveService().getName());
411

    
412
        Object defaultValue = param.getDefaultValue();
413
        String strDefaultValue;
414

    
415
        if (defaultValue != null) {
416
            if (defaultValue instanceof String) {
417
                strDefaultValue = (String) defaultValue;
418
                strDefaultValue =
419
                    i18nManager.getTranslation((String) defaultValue);
420
            } else {
421
                if(defaultValue instanceof Point){
422
                    Point point = (Point)defaultValue;
423
                    StringBuilder builder = new StringBuilder();
424
                    for(int i=0; i<point.getDimension(); i++){
425
                        builder.append(point.getCoordinateAt(i));
426
                        if(i < point.getDimension()-1){
427
                            builder.append(" , ");
428
                        }
429
                    }
430
                    strDefaultValue = builder.toString();
431
                } else {
432
                    strDefaultValue = defaultValue.toString();
433
                }
434
            }
435
            showConsoleMessage("\n" + activeServiceName + "# " + translation
436
                + "<" + strDefaultValue + "> : ");
437
        } else {
438
            showConsoleMessage("\n" + activeServiceName + "# " + translation
439
                + " : ");
440
        }
441
    }
442

    
443
    public synchronized void beginEdition(FLyrVect layer,
444
        Behavior[] additionalBehaviors) {
445

    
446
        try{
447
            throw new Exception("Deprecated method");
448
        } catch (Exception e){
449
            logger.info("Deprecated method", e);
450
        }
451

    
452
        beginEdition(layer);
453
        try {
454
            addBehaviors(additionalBehaviors);
455
        } catch (CreateEditingBehaviorException e1) {
456
            logger.info("Problems adding behaviors to editing context", e1);
457
            getMapControl().setTool("pan");
458
            return;
459
        }
460
    }
461

    
462
    public synchronized void beginEdition(FLyrVect layer) {
463

    
464
        EditingNotificationManager editingNotificationManager =
465
            DALSwingLocator.getEditingNotificationManager();
466

    
467
        EditingNotification notification =
468
            editingNotificationManager.notifyObservers(this,
469
                EditingNotification.BEFORE_ENTER_EDITING_STORE, null, layer,layer.getFeatureStore());
470

    
471
        if (notification.isCanceled()) {
472
            String msg =
473
                String.format("Edit layer %1$s canceled by somme observer.",
474
                    layer.getName());
475
            logger.info(msg, new StartEditingException(msg, null));
476
            return;
477
        }
478

    
479
        setCurrentLayer(layer);
480

    
481
        FeatureStore featureStore = layer.getFeatureStore();
482
        if (!featureStore.isEditing()) {
483
            try {
484
                featureStore.edit();
485
            } catch (Exception e) {
486
                String msg =
487
                    String.format("Can't set %1$s in edit mode",
488
                        featureStore.getName());
489
                logger.info(msg, new VectorEditingException(e));
490
                cleanEditingContext();
491
                return;
492
            }
493
        }
494

    
495
        featureStore.addObserver(getMapControl());
496

    
497
        editingNotificationManager.notifyObservers(this,
498
            EditingNotification.AFTER_ENTER_EDITING_STORE, null, layer, layer.getFeatureStore());
499

    
500
        enableSnapping();
501
    }
502

    
503
    @SuppressWarnings({ "rawtypes", "unchecked" })
504
    private void enableSnapping() {
505
        Preferences prefs = Preferences.userRoot().node("snappers");
506
         getMapControl().setRefentEnabled(prefs.getBoolean("apply-snappers", false));
507
         if (currentLayer != null) {
508
            ArrayList layersToSnap =
509
                getMapControl().getMapContext().getLayersToSnap();
510
            if (!layersToSnap.contains(currentLayer)) {
511
                layersToSnap.add(currentLayer);
512
            }
513
        }
514
    }
515

    
516
    @SuppressWarnings("rawtypes")
517
    private void disableSnapping() {
518
        ArrayList layersToSnap =
519
            getMapControl().getMapContext().getLayersToSnap();
520
        if (layersToSnap.contains(currentLayer)) {
521
            layersToSnap.remove(currentLayer);
522
        }
523
    }
524

    
525
    private void changeSelectedTool(String name) {
526
        if (name.equalsIgnoreCase(DEFAULT_TOOL)) {
527
            name = "selection-simple-select-view";
528
            this.getMapControl().setTool("pointSelection");
529
        }
530
        Notification notification =
531
            new BaseNotification(
532
                EditingContext.CHANGE_SELECTED_TOOL_NOTIFICATION,
533
                new Object[] { name });
534
        this.observableHelper.notifyObservers(this, notification);
535
    }
536

    
537
    private void cleanEditingContext() {
538
        serviceStack.clear();
539
        currentParam = null;
540
        this.enableSelection(false);
541
        refreshMenusAndToolBars();
542

    
543
        I18nManager i18nManager = ToolsLocator.getI18nManager();
544
        showConsoleMessage("\n" + i18nManager.getTranslation("select_new_tool")
545
            + "\n");
546
    }
547

    
548
    public void deleteObserver(Observer o) {
549
        this.observableHelper.deleteObserver(o);
550
    }
551

    
552
    public void deleteObservers() {
553
        this.observableHelper.deleteObservers();
554
    }
555

    
556
    private void discardChanges(FLyrVect layer) throws EndEditingException {
557
        FeatureStore featureStore = layer.getFeatureStore();
558
        try {
559
            featureStore.cancelEditing();
560
        } catch (Exception e) {
561
            throw new EndEditingException(e);
562
        }
563
    }
564

    
565
    private void doAction(FLyrVect layer, int option) {
566
        ThreadSafeDialogsManager dialogs = ToolsSwingLocator.getThreadSafeDialogsManager();
567
        I18nManager i18n = ToolsLocator.getI18nManager();
568
        
569
        switch (option) {
570
        case SAVE_CHANGES:
571
            try {
572
                saveChanges(layer);
573
            } catch (VectorEditingException e) {
574
                String msg =
575
                    String.format("Changes can not be saved in %1$s",
576
                        layer.getName());
577
                logger.info(msg, e);
578
                dialogs.messageDialog(                   
579
                    i18n.getTranslation("_There_are_problems_saving_changes")+"\n\n"+
580
                    i18n.getTranslation("_See_error_log_for_more_information"), 
581
                    null, 
582
                    i18n.getTranslation("_Warning"), 
583
                    JOptionPane.WARNING_MESSAGE, 
584
                    "Vectorediting_cant_save_changes"
585
                );
586
                return;
587
            }
588
            break;
589

    
590
        case DISCARD_CHANGES:
591
            try {
592
                discardChanges(layer);
593
            } catch (VectorEditingException e) {
594
                String msg =
595
                    String.format("Changes can not be discared in %1$s",
596
                        layer.getName());
597
                logger.info(msg, e);
598
                dialogs.messageDialog(                   
599
                    i18n.getTranslation("_There_are_problems_discarding_changes")+"\n"+
600
//                    i18n.getTranslation("_The_layer_is_marked_as_temporary_to_avoid_possible_problems_when_trying_to_save_the_project")+"\n"+
601
                    "\n" + i18n.getTranslation("_See_error_log_for_more_information"), 
602
                    null, 
603
                    i18n.getTranslation("_Warning"), 
604
                    JOptionPane.WARNING_MESSAGE, 
605
                    "Vectorediting_cant_discard_changes"
606
                );
607
                return;
608
            }
609
            break;
610

    
611
        case EXPORT_LAYER:
612
            try {
613
                exportLayer(layer);
614
            } catch (VectorEditingException e) {
615
                String msg =
616
                    String.format("Changes of %1$s can not be exported",
617
                        layer.getName());
618
                logger.info(msg, e);
619
                dialogs.messageDialog(                   
620
                    i18n.getTranslation("_There_are_problems_exporting_changes")+"\n\n"+
621
                    i18n.getTranslation("_See_error_log_for_more_information"), 
622
                    null, 
623
                    i18n.getTranslation("_Warning"), 
624
                    JOptionPane.WARNING_MESSAGE, 
625
                    "Vectorediting_cant_export_changes"
626
                );
627
                return;
628
            }
629
            break;
630

    
631
        case CANCEL:
632
            return;
633
        }
634

    
635
        cleanEditingContext();
636
        hideConsole();
637
        disableSnapping();
638
        changeSelectedTool(DEFAULT_TOOL);
639

    
640
        FeatureStore featureStore = layer.getFeatureStore();
641
        featureStore.deleteObserver(getMapControl());
642

    
643
    }
644

    
645
    private void enableSelection(boolean enableSelection) {
646
        this.editingCompoundBehavior.setDrawnBehavior(
647
            EditingCompoundBehavior.SELECTION_INDEX, enableSelection);
648
    }
649

    
650
    public void endEdition(FLyrVect layer) {
651
        if (layer.isEditing()) {
652
            EditingNotificationManager editingNotificationManager =
653
                DALSwingLocator.getEditingNotificationManager();
654

    
655
            EditingNotification notification =
656
                editingNotificationManager.notifyObservers(this,
657
                    EditingNotification.BEFORE_EXIT_EDITING_STORE, null, layer, layer.getFeatureStore());
658

    
659
            if (notification.isCanceled()) {
660
                String msg =
661
                    String.format(
662
                        "Stop edit layer %1$s canceled by somme observer.",
663
                        layer.getName());
664
                logger.info(msg, new EndEditingException(msg, null));
665

    
666
            }
667

    
668
            getMapControl().getCanceldraw().setCanceled(true);
669
            int option;
670
            EditingSwingManager swingManager =
671
                EditingSwingLocator.getSwingManager();
672

    
673

    
674
            if (layer.isWritable() && getMapControl().getProjection().equals(layer.getProjection()) ) {
675
                option =
676
                    swingManager.showPanelSaveOrDiscard(getMapControl(),
677
                        layer.getName());
678
            } else {
679
                option =
680
                    swingManager.showPanelExportOrDiscard(getMapControl(),
681
                        layer.getName());
682
            }
683

    
684
            doAction(layer, option);
685

    
686
            editingNotificationManager.notifyObservers(this,
687
                EditingNotification.AFTER_EXIT_EDITING_STORE, null, layer, layer.getFeatureStore());
688

    
689
        }
690

    
691
    }
692

    
693
    private void exportLayer(FLyrVect layer) throws EndEditingException {
694
        Notification notification = new BaseNotification(EditingContext.EXPORT_LAYER_NOTIFICATION,1);
695
        notification.setValue(layer);
696
        this.observableHelper.notifyObservers(this, notification);
697
    }
698

    
699
    protected void finishService() {
700
        EditingService lastService = serviceStack.pop();
701
        try {
702

    
703
            if (!serviceStack.isEmpty()
704
                && getActiveService().next().getTypes().contains(TYPE.GEOMETRY)) {
705
                Geometry geometry = lastService.finish();
706
                if (geometry != null) {
707
                    getActiveService().setValue(geometry);
708
                }
709
            } else {
710
                lastService.finishAndStore();
711
                getMapControl().rePaintDirtyLayers();
712

    
713
                I18nManager i18nManager = ToolsLocator.getI18nManager();
714
                showConsoleMessage("\n"
715
                    + i18nManager.getTranslation(lastService.getName()) + "# "
716
                    + i18nManager.getTranslation("finished") + "\n");
717
                lastService.stop();
718
                setActiveService(lastService);
719
                lastService.start();
720
                changeSelectedTool(getActiveService().getName());
721
            }
722

    
723
        } catch (InvalidEntryException ex) {
724
            I18nManager i18nManager = ToolsLocator.getI18nManager();
725
            showConsoleMessage("\n"
726
                + i18nManager.getTranslation("invalid_option"));
727
            changeSelectedTool(getActiveService().getName());
728
        } catch (VectorEditingException ex) {
729
            logger.info("Can't finish " + lastService.getName(), ex);
730
            cleanEditingContext();
731
            return;
732
        }
733

    
734
        getNextParameter();
735
    }
736

    
737
    protected EditingService getActiveService() {
738
        if (!serviceStack.isEmpty()) {
739
            return serviceStack.peek();
740
        }
741
        return null;
742
    }
743

    
744
    private EditingConsole getConsolePanel() {
745
        if (console == null) {
746
            console = new DefaultEditingConsole(new ResponseListener() {
747

    
748
                public void acceptResponse(String response) {
749
                    textEntered(response);
750
                }
751
            });
752
        }
753
        return console;
754
    }
755

    
756
    protected FLyrVect getCurrentLayer() {
757
        return this.currentLayer;
758
    }
759

    
760
    protected EditingServiceParameter getCurrentParam() {
761
        return this.currentParam;
762
    }
763

    
764
    private Component getDockConsole() {
765
        if (dockConsole == null) {
766
            dockConsole = new JDockPanel((JComponent) getConsolePanel());
767
        }
768
        return dockConsole;
769
    }
770

    
771
    private DefaultEditingBehavior getEditingBehavior() {
772
        if (editingCompoundBehavior != null) {
773
            return (DefaultEditingBehavior) editingCompoundBehavior
774
                .getBehavior(EditingCompoundBehavior.EDITING_INDEX);
775
        }
776
        return null;
777
    }
778

    
779
    private EditingCompoundBehavior getEditingCompoundBehavior() {
780
        if (editingCompoundBehavior != null) {
781
            return editingCompoundBehavior;
782
        } else {
783
            EditingCompoundBehavior editingCompoundBehavior;
784

    
785
            CompoundBehavior compoundBehavior =
786
                (CompoundBehavior) getMapControl().getMapTool("VectorEditing");
787

    
788
            if (compoundBehavior instanceof EditingCompoundBehavior) {
789
                editingCompoundBehavior =
790
                    (EditingCompoundBehavior) compoundBehavior;
791
            } else {
792
                editingCompoundBehavior =
793
                    (EditingCompoundBehavior) compoundBehavior.getBehavior(0);
794
            }
795

    
796
            setCompoundBehavior(editingCompoundBehavior);
797
            return editingCompoundBehavior;
798
        }
799
    }
800

    
801
    public MapControl getMapControl() {
802
        return mapControlReference.get();
803
    }
804

    
805
    protected void getNextParameter() {
806
        if ((getMapControl().getCurrentTool() != null)
807
            && !getMapControl().getCurrentTool().equals("VectorEditing")) {
808
            getMapControl().setTool("VectorEditing");
809
        }
810
        currentParam = getActiveService().next();
811

    
812
        if (currentParam == null) {
813
            finishService();
814
        } else {
815
            askQuestion(currentParam);
816
            if (currentParam.getTypes().contains(TYPE.SELECTION)) {
817
                enableSelection(true);
818
            } else if (currentParam.getTypes().contains(TYPE.GEOMETRY)) {
819
                refreshMenusAndToolBars();
820
            }
821
        }
822
    }
823

    
824
    protected Stack<EditingService> getServiceStack() {
825
        return this.serviceStack;
826
    }
827

    
828
    private void hideConsole() {
829
        isShowConsole = false;
830
        if( !SwingUtilities.isEventDispatchThread() ) {
831
            try {
832
                SwingUtilities.invokeAndWait(new Runnable() {
833

    
834
                    @Override
835
                    public void run() {
836
                        hideConsole();
837
                    }
838
                });
839
                return;
840
            } catch (InterruptedException | InvocationTargetException ex) {
841
                logger.warn("Can't hide editing console.",ex);
842
            }
843
            return;
844
        }
845
        getDockConsole().setVisible(false);
846
    }
847

    
848
    public boolean isServiceCompatible(String name) {
849
        DefaultEditingBehavior editingBehavior = getEditingBehavior();
850

    
851
        if (editingBehavior != null) {
852

    
853
            try {
854
                EditingManager manager = EditingLocator.getManager();
855
                EditingServiceInfo serviceInfo = manager.getServiceInfo(name);
856
                GeometryType geoType = null;
857

    
858
                for (EditingService editingService : getServiceStack()) {
859
                    EditingServiceParameter parameter = editingService.next();
860
                    if (parameter != null
861
                        && parameter.getTypes().contains(TYPE.GEOMETRY)) {
862

    
863
                        int geometryType = parameter.getGeometryType();
864
                        int subType = -1;
865

    
866
                        try {
867
                            subType =
868
                                getCurrentLayer().getFeatureStore()
869
                                    .getDefaultFeatureType()
870
                                    .getDefaultGeometryAttribute()
871
                                    .getGeomType().getSubType();
872

    
873
                            geoType =
874
                                GeometryLocator.getGeometryManager()
875
                                    .getGeometryType(geometryType, subType);
876
                        } catch (Exception e) {
877

    
878
                            String msg =
879
                                String.format(
880
                                    "Problems getting default feature"
881
                                        + " type of %1$s or getting geometry"
882
                                        + " type of %2$s %3$s",
883
                                    getCurrentLayer().getName(), geometryType,
884
                                    subType);
885

    
886
                            throw new ServiceInformationException(msg, e);
887
                        }
888

    
889
                        return serviceInfo.isCompatibleWith(geoType)
890
                            && serviceInfo.createsNewGeometries();
891
                    }
892
                }
893

    
894
                if (getCurrentLayer() != null) {
895
                    try {
896
                        geoType =
897
                            getCurrentLayer().getFeatureStore()
898
                                .getDefaultFeatureType()
899
                                .getDefaultGeometryAttribute().getGeomType();
900
                    } catch (DataException e) {
901
                        String msg =
902
                            String.format("Problems getting default "
903
                                + "feature type of %1$s", getCurrentLayer()
904
                                .getName());
905
                        throw new ServiceInformationException(msg, e);
906
                    }
907

    
908
                    return serviceInfo.isCompatibleWith(geoType);
909
                }
910

    
911
                return false;
912
            } catch (ServiceInformationException e) {
913
                logger.warn(
914
                    "Problems getting if editing context is compatible with "
915
                        + name, e);
916
            }
917
        }
918
        return false;
919
    }
920
    
921
    private Point parsePoint(String response) throws ParsePointException {
922
        TemporaryStorageManager manager = TemporaryStorageLocator.getTemporaryStorageManager();
923
        TemporaryStorageGroup storage = manager.create("Points",Point.class);
924

    
925
        MutableSymbolTable symbolTable = ExpressionUtils.createSymbolTable();
926
        symbolTable.setVar("LAST_POINT_ADDED", storage.get("LAST_POINT_ADDED_IN_EDTING"));
927
        
928
        try {
929
            Object x = ExpressionUtils.evaluate(symbolTable, response);
930
            if( x instanceof Point ) {
931
                storage.put("LAST_POINT_ADDED_IN_EDTING", x);
932
                return (Point) x;
933
            }
934
        } catch(Exception ex) {
935
            
936
        }
937
        String s = "ST_MakePoint("+response+")";
938
        try {
939
            Object x = ExpressionUtils.evaluate(symbolTable, s);
940
            if( x instanceof Point ) {
941
                storage.put("LAST_POINT_ADDED_IN_EDTING", x);
942
                return (Point) x;
943
            }
944
        } catch(Exception ex) {
945
            throw new ParsePointException(ex);
946
        }
947
        throw new ParsePointException(null);
948
    }
949
    
950
    private Double parseValue(String response) throws ParseValueException {
951
        TemporaryStorageManager manager = TemporaryStorageLocator.getTemporaryStorageManager();
952
        TemporaryStorageGroup storage = manager.create("Points",Point.class);
953

    
954
        MutableSymbolTable symbolTable = ExpressionUtils.createSymbolTable();
955
        symbolTable.setVar("LAST_POINT_ADDED", storage.get("LAST_POINT_ADDED_IN_EDTING"));
956
        
957
        try {
958
            Object x = ExpressionUtils.evaluate(symbolTable, response);
959
            if( x instanceof Double ) {
960
                return (Double) x;
961
            }  
962
            if( x==null ) {
963
                throw new ParseValueException(new NullPointerException());
964
            }
965
            DataTypesManager.Coercion toDouble = ToolsLocator.getDataTypesManager().get(DataTypes.DOUBLE).getCoercion();
966
            return (Double) toDouble.coerce(x);
967
        } catch(Exception ex) {
968
            throw new ParseValueException(ex);
969
        }
970

    
971
    }
972

    
973
    protected void refreshMenusAndToolBars() {
974
        if (!SwingUtilities.isEventDispatchThread()) {
975
            SwingUtilities.invokeLater(new Runnable() {
976

    
977
                @Override
978
                public void run() {
979
                    refreshMenusAndToolBars();
980
                }
981
            });
982
            return;
983
        }
984
        Notification notification = new BaseNotification(
985
                EditingContext.REFRESH_TOOLS_NOTIFICATION,
986
                null
987
        );
988
        this.observableHelper.notifyObservers(this, notification);
989
    }
990

    
991
    private void saveChanges(FLyrVect layer) throws EndEditingException {
992
        FeatureStore featureStore = layer.getFeatureStore();
993
        try {
994
            featureStore.finishEditing();
995
        } catch (Exception e) {
996
            throw new EndEditingException(e);
997
        }
998
    }
999

    
1000
    private void setActiveService(EditingService service) {
1001
        serviceStack.add(service);
1002
    }
1003

    
1004
    private void setCompoundBehavior(EditingCompoundBehavior compoundBehavior) {
1005
        this.editingCompoundBehavior = compoundBehavior;
1006
    }
1007

    
1008
    private void setCurrentLayer(FLyrVect layer) {
1009

    
1010
        if (this.currentLayer != layer) {
1011
            this.currentLayer = layer;
1012
            cleanEditingContext();
1013
        }
1014

    
1015
    }
1016

    
1017
    public void setMapControl(MapControl mapControl) {
1018

    
1019
        this.mapControlReference = new WeakReference<MapControl>(mapControl);
1020
        this.mapContextReference =
1021
            new WeakReference<MapContext>(mapControl.getMapContext());
1022

    
1023
        // When mapControl is updated we have to add older additional behaviors
1024
        // to new mapControl
1025
        if (lastAdditionalBehaviors != null) {
1026
            try {
1027
                addBehaviors(lastAdditionalBehaviors);
1028
            } catch (CreateEditingBehaviorException e1) {
1029
                logger.info("Problems adding behaviors to editing context", e1);
1030
                getMapControl().setTool("pan");
1031
                return;
1032
            }
1033
        }
1034
    }
1035

    
1036
    private void showConsole() {
1037
        if (isShowConsole) {
1038
            return;
1039
        }
1040
        if( !SwingUtilities.isEventDispatchThread() ) {
1041
            try {
1042
                SwingUtilities.invokeAndWait(new Runnable() {
1043

    
1044
                    @Override
1045
                    public void run() {
1046
                        showConsole();
1047
                    }
1048
                });
1049
                return;
1050
            } catch (InterruptedException | InvocationTargetException ex) {
1051
                logger.warn("Can't show editing console.",ex);
1052
            }
1053
            return;
1054
        }
1055
        isShowConsole = true;
1056
        getMapControl().remove(getDockConsole());
1057
        getMapControl().setLayout(new BorderLayout());
1058
        getMapControl().add(getDockConsole(), BorderLayout.SOUTH);
1059
        getDockConsole().setVisible(true);
1060
    }
1061

    
1062
    protected void showConsoleMessage(final String text) {
1063
        if (!SwingUtilities.isEventDispatchThread()) {
1064
            SwingUtilities.invokeLater(new Runnable() {
1065

    
1066
                @Override
1067
                public void run() {
1068
                    showConsoleMessage(text);
1069
                }
1070
            });
1071
            return;
1072
        }
1073
        getConsolePanel().addText(text);
1074
    }
1075

    
1076
    protected void textEntered(String response) {
1077
        FeatureStore featureStore = getCurrentLayer().getFeatureStore();
1078
        EditingService activeService = getActiveService();
1079
        if (response == null) {
1080
            if (activeService != null) {
1081
                try {
1082
                    activeService.stop();
1083
                    serviceStack.pop();
1084
                    if (serviceStack.isEmpty()) {
1085
                        featureStore
1086
                            .getFeatureSelection().deselectAll();
1087
                        changeSelectedTool(DEFAULT_TOOL);
1088
                    } else {
1089
                        changeSelectedTool(activeService.getName());
1090
                    }
1091

    
1092
                    refreshMenusAndToolBars();
1093
                    activeService = getActiveService();
1094
                    if (activeService != null) {
1095
                        getNextParameter();
1096
                    } else {
1097
                        cleanEditingContext();
1098
                    }
1099

    
1100
                } catch (StopServiceException e) {
1101
                    logger
1102
                        .info("Can't stop " + activeService.getName(), e);
1103
                    return;
1104
                } catch (DataException e) {
1105
                    logger.info("Can't get selection of "
1106
                        + featureStore.getFullName(), e);
1107
                    return;
1108
                }
1109
            }
1110
        } else {
1111

    
1112
            if (getCurrentParam() != null) {
1113
                Set<TYPE> types = getCurrentParam().getTypes();
1114
                Point point = null;
1115
                Double value = null;
1116
                Point defaultPoint = null;
1117
                Object defaultValue = getCurrentParam().getDefaultValue();
1118
//                int dimension = 2;
1119
//                if(defaultValue != null && defaultValue instanceof Point){
1120
                    defaultPoint = (Point)defaultValue;
1121
//                    dimension = defaultPoint.getDimension();
1122
//                }
1123

    
1124
                boolean insertedValue = false;
1125
                if ((!insertedValue && types.contains(TYPE.POSITION))
1126
                    || types.contains(TYPE.LIST_POSITIONS)) {
1127

    
1128
                    try {
1129
                        if(StringUtils.isEmpty(response.replace("\n", ""))){
1130
                            point = defaultPoint;
1131
                        } else {
1132
                            point = parsePoint(response);
1133
                        }
1134

    
1135
                        if (point != null) {
1136
                            activeService.setValue(point);
1137
                            insertedValue = true;
1138
                        }
1139

    
1140
                    } catch (VectorEditingException e) {
1141
                        // Do nothing to try other types
1142
                    }
1143
                }
1144
                if (!insertedValue && types.contains(TYPE.VALUE)) {
1145

    
1146
                    try {
1147

    
1148
                        value = parseValue(response);
1149
                        if (value != null) {
1150
                            activeService.setValue(value);
1151
                            insertedValue = true;
1152
                        }
1153

    
1154
                    } catch (VectorEditingException e) {
1155
                        // Do nothing to try other types
1156
                    }
1157

    
1158
                }
1159
                if (!insertedValue && types.contains(TYPE.OPTION)) {
1160

    
1161
                    try {
1162

    
1163
                        response = response.replace("\n", "");
1164
                        if (response != null) {
1165
                            activeService.setValue(response);
1166
                            insertedValue = true;
1167
                        }
1168

    
1169
                    } catch (VectorEditingException e) {
1170
                        // Do nothing to try other types
1171
                    }
1172
                }
1173
                if (!insertedValue && types.contains(TYPE.SELECTION)) {
1174
                    if (response.equalsIgnoreCase("\n")) {
1175
                        enableSelection(false);
1176
                        insertedValue = true;
1177

    
1178
                        try {
1179

    
1180
                            FeatureSelection clonedSelection = (FeatureSelection)featureStore
1181
                                .getFeatureSelection().clone();
1182
                            if(clonedSelection.isEmpty()){
1183
                               throw new InvalidEntryException(null);
1184
                            }
1185
                            activeService.setValue(
1186
                                clonedSelection);
1187

    
1188
                        } catch (InvalidEntryException e) {
1189
                            I18nManager i18nManager =
1190
                                ToolsLocator.getI18nManager();
1191
                            showConsoleMessage("\n"
1192
                                + i18nManager.getTranslation("invalid_option"));
1193
                        } catch (Exception e) {
1194
                            logger.info("Can't access to selection.", e);
1195
                            cleanEditingContext();
1196
                            return;
1197
                        }
1198
                    }
1199
                }
1200
                if (!insertedValue) {
1201
                    I18nManager i18nManager = ToolsLocator.getI18nManager();
1202
                    showConsoleMessage("\n"
1203
                        + i18nManager.getTranslation("invalid_option"));
1204
                }
1205
                getNextParameter();
1206
            }
1207
        }
1208
    }
1209

    
1210
    public void setDefaultBehaviors(Behavior[] defaultBehaviors) {
1211
        this.defaultBehaviors = defaultBehaviors;
1212
        try {
1213
            addBehaviors(defaultBehaviors);
1214
        } catch (CreateEditingBehaviorException e1) {
1215
            logger.info("Problems adding behaviors to editing context", e1);
1216
            getMapControl().setTool("pan");
1217
            return;
1218
        }
1219
    }
1220

    
1221
    public Behavior[] getDefaultBehaviors() {
1222
        return this.defaultBehaviors;
1223
    }
1224
}