Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.plugin / org.gvsig.app.document.table.app / org.gvsig.app.document.table.app.mainplugin / src / main / java / org / gvsig / app / project / documents / table / TableOperations.java @ 47037

History | View | Annotate | Download (24.4 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 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 3
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
package org.gvsig.app.project.documents.table;
25

    
26
import java.awt.Component;
27
import java.awt.event.ActionEvent;
28
import java.awt.event.ActionListener;
29
import java.text.ParseException;
30
import java.util.ArrayList;
31
import java.util.Iterator;
32
import java.util.List;
33
import javax.json.JsonArray;
34
import javax.json.JsonObject;
35
import javax.json.JsonValue;
36
import javax.swing.JOptionPane;
37
import javax.swing.event.TableModelListener;
38
import org.apache.bcel.generic.DALOAD;
39
import org.apache.commons.collections.CollectionUtils;
40
import org.apache.commons.collections.ListUtils;
41
import org.apache.commons.lang3.StringUtils;
42
import org.gvsig.andami.PluginServices;
43
import org.gvsig.andami.messages.NotificationManager;
44
import org.gvsig.app.ApplicationLocator;
45
import org.gvsig.app.project.documents.table.gui.CreateNewAttributePanel;
46
import org.gvsig.app.project.documents.table.gui.FeatureTableDocumentPanel;
47
import org.gvsig.fmap.dal.DALLocator;
48
import org.gvsig.fmap.dal.DataManager;
49
import org.gvsig.fmap.dal.DataStoreProviderFactory;
50
import org.gvsig.fmap.dal.DataTypes;
51
import org.gvsig.fmap.dal.EditingNotification;
52
import org.gvsig.fmap.dal.EditingNotificationManager;
53
import org.gvsig.fmap.dal.exception.DataException;
54
import org.gvsig.fmap.dal.feature.EditableFeature;
55
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
56
import org.gvsig.fmap.dal.feature.EditableFeatureType;
57
import org.gvsig.fmap.dal.feature.Feature;
58
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
59
import org.gvsig.fmap.dal.feature.FeatureQuery;
60
import org.gvsig.fmap.dal.feature.FeatureQueryOrder;
61
import org.gvsig.fmap.dal.feature.FeatureSelection;
62
import org.gvsig.fmap.dal.feature.FeatureSet;
63
import org.gvsig.fmap.dal.feature.FeatureStore;
64
import org.gvsig.fmap.dal.feature.FeatureStoreProviderFactory;
65
import org.gvsig.fmap.dal.feature.FeatureType;
66
import org.gvsig.fmap.dal.feature.exception.StoreUpdateFeatureTypeException;
67
import org.gvsig.fmap.dal.swing.DALSwingLocator;
68
import org.gvsig.fmap.mapcontrol.dal.feature.swing.FeatureTable;
69
import org.gvsig.fmap.mapcontrol.dal.feature.swing.table.FeatureTableModel;
70
import org.gvsig.i18n.Messages;
71
import org.gvsig.json.Json;
72
import org.gvsig.tools.ToolsLocator;
73
import org.gvsig.tools.dispose.DisposableIterator;
74
import org.gvsig.tools.i18n.I18nManager;
75
import org.gvsig.tools.swing.api.ToolsSwingLocator;
76
import org.gvsig.tools.swing.api.threadsafedialogs.ThreadSafeDialogsManager;
77
import org.slf4j.Logger;
78
import org.slf4j.LoggerFactory;
79

    
80
/**
81
 * Feature Table Operations.
82
 *
83
 * @author Vicente Caballero Navarro
84
 *
85
 */
86
public class TableOperations {
87

    
88
    private static final Logger logger = LoggerFactory.getLogger(TableOperations.class);
89

    
90
    public static final int MAX_FIELD_LENGTH = 254;
91
    private static TableOperations fto = null;
92

    
93
    private FeatureTableDocumentPanel tablePanel = null;
94
    private FeatureStore featureStore;
95

    
96
    public static TableOperations getInstance() {
97
        if (fto == null) {
98
            fto = new TableOperations();
99
        }
100
        return fto;
101
    }
102

    
103
    public void setTablePanel(FeatureTableDocumentPanel tp) {
104
        tablePanel = tp;
105
        featureStore = tp.getModel().getStore();
106
    }
107

    
108
    public void copyFeatures() throws DataException {
109
        copy();
110
    }
111

    
112
    public boolean hasSelection() {
113
        return !ToolsSwingLocator.getToolsSwingManager().isClipboardEmpty();
114
    }
115

    
116
    public void pasteFeatures() throws DataException {
117
        try {
118
            if( featureStore==null ) {
119
                return;
120
            }
121
            List<EditableFeature> features = DALLocator.getDataManager().getFeaturesFromClipboard(
122
                    featureStore,
123
                    null
124
            );
125
            if( CollectionUtils.isEmpty(features) ) {
126
                return;
127
            }
128
            for (EditableFeature feature : features) {
129
                if (!insertFeature(feature) ) {
130
                    break;
131
                }
132
            }
133
        } catch (Exception e) {
134
            logger.warn("Can't paste from clipboard.", e);
135
        }
136

    
137
    }
138

    
139
    private void copy() throws DataException {
140
        DALLocator.getDataManager().putFeaturesInClipboard(featureStore.getFeatureSelection());
141
    }
142

    
143
    public void deleteFeatures() throws DataException {
144

    
145
        FeatureTableModel _ftm = this.tablePanel.getTablePanel().getTableModel();
146
        List<TableModelListener> tmll = removeTableModelListeners(_ftm);
147
        DisposableIterator feat_iter = null;
148
        Feature feat = null;
149
        try {
150
            FeatureSelection selection = featureStore.createFeatureSelection();
151
            selection.select((FeatureSet) featureStore.getSelection());
152
            feat_iter = selection.fastIterator();
153
            while (feat_iter.hasNext()) {
154
                feat = (Feature) feat_iter.next();
155
                if (!deleteFeature(feat)) {
156
                    return;
157
                }
158
            }
159
        } finally {
160
            if (feat_iter != null) {
161
                feat_iter.dispose();
162
            }
163

    
164
            addTableModelListeners(_ftm, tmll);
165
        }
166
    }
167

    
168
    /**
169
     * @param _ftm
170
     * @param tmll
171
     */
172
    private void addTableModelListeners(
173
            FeatureTableModel _model,
174
            List<TableModelListener> _list) {
175

    
176
        Iterator<TableModelListener> iter = _list.iterator();
177
        while (iter.hasNext()) {
178
            _model.addTableModelListener(iter.next());
179
        }
180
        _model.fireTableDataChanged();
181
    }
182

    
183
    /**
184
     * @param ftm
185
     * @param class1
186
     * @return
187
     */
188
    private List<TableModelListener> removeTableModelListeners(FeatureTableModel ftm) {
189

    
190
        TableModelListener[] ll = ftm.getListeners(TableModelListener.class);
191
        List<TableModelListener> resp = new ArrayList<>();
192

    
193
        int n = ll.length;
194
        for (int i = 0; i < n; i++) {
195
            resp.add(ll[i]);
196
            ftm.removeTableModelListener(ll[i]);
197
        }
198

    
199
        return resp;
200
    }
201

    
202
    public void insertNewFeature() throws DataException {
203
        EditableFeature feature = featureStore.createNewFeature();
204
        insertFeature(feature);
205
    }
206

    
207
    /*
208
     * Return false if the operation is canceled.
209
     */
210
    private boolean insertFeature(EditableFeature feature) throws DataException {
211
        EditingNotificationManager editingNotificationManager = DALSwingLocator.getEditingNotificationManager();
212
        EditingNotification notification = editingNotificationManager.notifyObservers(
213
                this,
214
                EditingNotification.BEFORE_INSERT_FEATURE,
215
                tablePanel.getDocument(),
216
                featureStore,
217
                feature);
218
        if (notification.isCanceled()) {
219
            return false;
220
        }
221
        if (notification.shouldValidateTheFeature()) {
222
            if (!editingNotificationManager.validateFeature(feature)) {
223
                return false;
224
            }
225
        }
226
        featureStore.insert(feature);
227
        editingNotificationManager.notifyObservers(
228
                this,
229
                EditingNotification.AFTER_INSERT_FEATURE,
230
                tablePanel.getDocument(),
231
                featureStore,
232
                feature);
233
        return true;
234
    }
235

    
236
    private boolean deleteFeature(Feature feature) throws DataException {
237
        EditingNotificationManager editingNotification = DALSwingLocator.getEditingNotificationManager();
238
        EditingNotification notification = editingNotification.notifyObservers(
239
                this,
240
                EditingNotification.BEFORE_REMOVE_FEATURE,
241
                tablePanel.getDocument(),
242
                featureStore,
243
                feature);
244
        if (notification.isCanceled()) {
245
            return false;
246
        }
247
        featureStore.delete(feature);
248
        editingNotification.notifyObservers(
249
                this,
250
                EditingNotification.AFTER_REMOVE_FEATURE,
251
                tablePanel.getDocument(),
252
                featureStore,
253
                feature);
254
        return true;
255
    }
256

    
257
    private boolean updateFeatureType(EditableFeatureType featureType) throws DataException {
258

    
259
        EditingNotificationManager editingNotification = DALSwingLocator.getEditingNotificationManager();
260
        EditingNotification notification = editingNotification.notifyObservers(
261
                this,
262
                EditingNotification.BEFORE_UPDATE_FEATURE_TYPE,
263
                tablePanel.getDocument(),
264
                featureStore,
265
                featureType);
266
        if (notification.isCanceled()) {
267
            return false;
268
        }
269
        featureStore.update(featureType);
270
        editingNotification.notifyObservers(
271
                this,
272
                EditingNotification.AFTER_UPDATE_FEATURE_TYPE,
273
                tablePanel.getDocument(),
274
                featureStore,
275
                featureType);
276
        return true;
277
    }
278

    
279
    public void deleteAttributes(FeatureTable table) throws DataException {
280
        FeatureAttributeDescriptor[] selecteds = table.getSelectedColumnsAttributeDescriptor();
281
        FeatureQuery query = this.tablePanel.getTablePanel().getFeatureQuery();
282
        if(query != null){
283
            FeatureQueryOrder order = query.getOrder();
284
            if(order != null) {
285
                I18nManager i18n = ToolsLocator.getI18nManager();
286
                for (FeatureAttributeDescriptor selected : selecteds) {
287
                    if(order.contains(selected.getName())){
288
                        int n = ToolsSwingLocator.getThreadSafeDialogsManager().confirmDialog(
289
                                i18n.getTranslation(
290
                                        "_You_are_trying_to_remove_the_column_XcolumnNameX_that_is_being_sorted_by_Do_you_wish_to_continue",
291
                                        new String[]{selected.getName()}
292
                                ),
293
                                i18n.getTranslation("_Delete_column"),
294
                                JOptionPane.OK_CANCEL_OPTION,
295
                                JOptionPane.QUESTION_MESSAGE, 
296
                                "_You_are_trying_to_remove_the_column_XcolumnNameX_that_is_being_sorted_by_Do_you_wish_to_continue"
297
                        );
298
                        if (n != JOptionPane.OK_OPTION){
299
                            return;
300
                        }
301
                        try {
302
                            order.remove(order.getIndex(selected.getName()));
303
                        } catch (Throwable t) {
304
                            logger.warn("Can't remove order", t);
305
                        }
306
                    }
307
                }
308
            }
309
        }
310
        EditableFeatureType eft = featureStore.getDefaultFeatureType().getEditable();
311
        for (FeatureAttributeDescriptor selected : selecteds) {
312
            eft.remove(selected.getName());
313
        }
314
        featureStore.update(eft);
315
    }
316

    
317
    public void insertAttributes(FeatureTable table) throws DataException {
318

    
319
        EditableFeatureType eft = featureStore.getDefaultFeatureType().getEditable();
320

    
321
        List<String> tmpfnames = new ArrayList<>();
322
        int size = eft.size();
323
        for (int i = 0; i < size; i++) {
324
            FeatureAttributeDescriptor ad = (FeatureAttributeDescriptor) eft.get(i);
325
            tmpfnames.add(ad.getName());
326
        }
327

    
328
        CreateNewAttributePanel panelNewField = new CreateNewAttributePanel(featureStore);
329
        panelNewField.setCurrentFieldNames(tmpfnames.toArray(new String[0]));
330
        DataManager dataManager = DALLocator.getDataManager();
331
        FeatureStoreProviderFactory factory
332
                = (FeatureStoreProviderFactory) dataManager.
333
                        getStoreProviderFactory(featureStore.getProviderName());
334
        panelNewField.setMaxAttributeNameSize(factory.getMaxAttributeNameSize());
335
        panelNewField.setOkAction(new NewFieldActionListener(panelNewField, eft));
336
        ApplicationLocator.getManager().getUIManager().addWindow(panelNewField);
337
        featureStore.update(eft);
338
    }
339

    
340
    public void renameAttributes(FeatureTable table) throws DataException {
341

    
342
        FeatureAttributeDescriptor[] selecteds = table.getSelectedColumnsAttributeDescriptor();
343
        I18nManager i18n = ToolsLocator.getI18nManager();
344
        FeatureQuery query = this.tablePanel.getTablePanel().getFeatureQuery();
345
        if(query != null){
346
            FeatureQueryOrder order = query.getOrder();
347
            if(order != null) {
348
                for (FeatureAttributeDescriptor selected : selecteds) {
349
                    if(order.contains(selected.getName())){
350
                        int n = ToolsSwingLocator.getThreadSafeDialogsManager().confirmDialog(
351
                                i18n.getTranslation(
352
                                        "_You_are_trying_to_rename_the_column_XcolumnNameX_that_is_being_sorted_by_Do_you_wish_to_continue",
353
                                        new String[]{selected.getName()}
354
                                ),
355
                                i18n.getTranslation("_Rename_column"),
356
                                JOptionPane.OK_CANCEL_OPTION,
357
                                JOptionPane.QUESTION_MESSAGE, 
358
                                "_You_are_trying_to_rename_the_column_XcolumnNameX_that_is_being_sorted_by_Do_you_wish_to_continue"
359
                        );
360
                        if (n != JOptionPane.OK_OPTION){
361
                            return;
362
                        }
363
                        try {
364
                            order.remove(order.getIndex(selected.getName()));
365
                        } catch (Throwable t) {
366
                            logger.warn("Can't remove order", t);
367
                        }
368
                    }
369
                }
370
            }
371
        }
372
        
373
        FeatureType _ft = featureStore.getDefaultFeatureType();
374

    
375

    
376
        int maxAttributeNameSize = getMaxAttributeSize();
377
        for (int i = selecteds.length - 1; i >= 0; i--) {
378
            String newName = "";
379
            while (newName != null 
380
                    && (newName.isEmpty() || checkFieldAlreadyExists(_ft, newName))
381
                    || (maxAttributeNameSize > -1 && StringUtils.length(newName) > maxAttributeNameSize)) {
382
                newName = JOptionPane.showInputDialog((Component) PluginServices
383
                        .getMDIManager().getActiveWindow(),
384
                        PluginServices.getText(
385
                                this, "_Please_insert_new_field_name"),
386
                        selecteds[i].getName());
387

    
388
                if (newName == null) {
389
                    continue;
390
                }
391
                if (newName.length() == 0) {
392
                    ThreadSafeDialogsManager dialogs = ToolsSwingLocator.getThreadSafeDialogsManager();
393
                    dialogs.messageDialog(
394
                            i18n.getTranslation("_Attribute_name_must_not_by_empty"),
395
                            null,
396
                            i18n.getTranslation("_Warning"),
397
                            JOptionPane.WARNING_MESSAGE
398
                    );
399
                }
400
                if (maxAttributeNameSize > -1 && StringUtils.length(newName) > maxAttributeNameSize) {
401
                    ThreadSafeDialogsManager dialogs = ToolsSwingLocator.getThreadSafeDialogsManager();
402
                    dialogs.messageDialog(
403
                            i18n.getTranslation("_Attribute_name_is_too_long") + "\n"
404
                            + i18n.getTranslation("_max_size_allowed_for_this_table_is_{0}", new String[]{String.valueOf(maxAttributeNameSize)}),
405
                            null,
406
                            i18n.getTranslation("_Warning"),
407
                            JOptionPane.WARNING_MESSAGE
408
                    );
409
                }
410
                // To be able to change the name of the attribute when it is changed
411
                // from uppercase to lowercase or vice versa
412
                if (checkFieldAlreadyExists(_ft, newName)) {
413
                    ThreadSafeDialogsManager dialogs = ToolsSwingLocator.getThreadSafeDialogsManager();
414
                    dialogs.messageDialog(
415
                            i18n.getTranslation("field_already_exists"),
416
                            null,
417
                            i18n.getTranslation("_Warning"),
418
                            JOptionPane.WARNING_MESSAGE
419
                    );
420
                }
421
            }
422
            if (newName == null) {
423
                continue;
424
            }
425
            renameAttribute(featureStore, selecteds[i].getName(), newName);
426
        }
427
    }
428
    
429
    private boolean checkFieldAlreadyExists(FeatureType ft, String name) {
430
        FeatureAttributeDescriptor attr = ft.getAttributeDescriptor(name);
431
        return (attr != null && attr.getName().equals(name));
432

    
433
    }
434
    
435
    private int getMaxAttributeSize() {
436
        if(featureStore == null){
437
            return -1;
438
        }
439
        DataStoreProviderFactory providerFactory = featureStore.getProviderFactory();
440
        if(providerFactory == null){
441
            return -1;
442
        }
443
        return ((FeatureStoreProviderFactory)providerFactory).getMaxAttributeNameSize();
444
    }
445

    
446

    
447
    /**
448
     * This method renames a field in three steps:
449
     *
450
     * (1) add new field using type and size of old field. (2) copy value from
451
     * old field to new field. (3) remove old field.
452
     *
453
     * @param fs
454
     * @param name
455
     * @param newName
456
     * @return true if the change took place
457
     */
458
    private static boolean renameAttribute(FeatureStore fs, String name, String newName) {
459

    
460
        EditableFeatureType eft = null;
461
        FeatureType dft = null;
462
        try {
463
            dft = fs.getDefaultFeatureType();
464

    
465
            if (dft instanceof EditableFeatureType) {
466
                eft = (EditableFeatureType) dft;
467
            } else {
468
                eft = dft.getEditable();
469
            }
470

    
471
            EditableFeatureAttributeDescriptor efad
472
                    = (EditableFeatureAttributeDescriptor) eft.getAttributeDescriptor(name);
473
            efad.setName(newName);
474
            fs.update(eft);
475

    
476
        } catch (DataException de) {
477

    
478
            Component root_comp
479
                    = ApplicationLocator.getManager().getRootComponent();
480

    
481
            JOptionPane.showMessageDialog(
482
                    root_comp,
483
                    Messages.getText("_Unable_to_rename_attribute")
484
                    + ": " + de.getMessage(),
485
                    Messages.getText("_Unable_to_rename_attribute"),
486
                    JOptionPane.ERROR_MESSAGE);
487
            return false;
488
        }
489
        return true;
490

    
491
        /*
492
        try {
493
            // ========== add new field
494
            eft = fs.getDefaultFeatureType().getEditable();
495
            FeatureAttributeDescriptor fad = eft.getAttributeDescriptor(name);
496
            eft.add(newName, fad.getType(), fad.getSize());
497
            fs.update(eft);
498
        } catch (DataException ex) {
499
            logger.info("Unable to rename attribute (" + name + " --> " + newName + ")", ex);
500
            ApplicationLocator.getManager().message(
501
                Messages.getText("_Unable_to_rename_attribute"),
502
                JOptionPane.ERROR_MESSAGE);
503
            // did not even add new field
504
            return false;
505
        }
506

507
        boolean error_when_inserting = false;
508
        try {
509
            // ========== copy value old field -> new field
510
            FeatureSet fset = fs.getFeatureSet();
511
            DisposableIterator diter = fset.fastIterator();
512
            Feature feat = null;
513
            Object val = null;
514
            EditableFeature efeat = null;
515
            while (diter.hasNext()) {
516
                feat = (Feature) diter.next();
517
                val = feat.get(name);
518
                efeat = feat.getEditable();
519
                efeat.set(newName, val);
520
                fset.update(efeat);
521
            }
522
            diter.dispose();
523

524
            // Closing editing to check that store admits new field
525
            fs.finishEditing();
526
        } catch (DataException ex) {
527

528
            logger.info("Error while renaming att to: " + newName, ex);
529
            String final_msg = getLastMessage(ex);
530
            JOptionPane.showMessageDialog(
531
                root_comp,
532
                Messages.getText("_Unable_to_rename_attribute")
533
                + ": " + final_msg,
534
                Messages.getText("_Rename_column"),
535
                JOptionPane.ERROR_MESSAGE);
536
            error_when_inserting = true;
537
        }
538

539
        if (error_when_inserting) {
540
            try {
541
                // Trying to remove new field and leave table as it was
542
                eft.remove(newName);
543
                fs.update(eft);
544
            } catch (DataException ex) {
545
                // Unable to remove added field but user was
546
                // already notified that something went wrong
547
            }
548
            // Not changed
549
            return false;
550
        }
551

552

553
        try {
554
            // Finally reopen editing and delete old field
555
            fs.edit(FeatureStore.MODE_FULLEDIT);
556
            eft = fs.getDefaultFeatureType().getEditable();
557
            eft.remove(name);
558
            fs.update(eft);
559

560
        } catch (DataException ex) {
561
            logger.info("Unable to rename attribute (" + name + " --> " + newName + ")", ex);
562
            ApplicationLocator.getManager().message(
563
                Messages.getText("_Unable_to_rename_attribute"),
564
                JOptionPane.ERROR_MESSAGE);
565
            return false;
566
        }
567
        return true;
568
         */
569
    }
570

    
571
    /**
572
     * Renames field in feature store
573
     *
574
     * @param fs
575
     * @param oldname
576
     * @param newname
577
     * @throws DataException
578
     */
579
    public static void renameColumn(FeatureStore fs,
580
            String oldname, String newname) throws DataException {
581

    
582
        FeatureType _ft = fs.getDefaultFeatureType();
583
        if (_ft.getIndex(newname) != -1) {
584
            throw new StoreUpdateFeatureTypeException(
585
                    new Exception("Attribute name already existed."),
586
                    fs.getName());
587
        }
588
        renameAttribute(fs, oldname, newname);
589
        // fs.finishEditing();
590
    }
591

    
592
    public class NewFieldActionListener implements ActionListener {
593

    
594
        private CreateNewAttributePanel panel = null;
595
        private EditableFeatureType eft = null;
596

    
597
        public NewFieldActionListener(CreateNewAttributePanel p, EditableFeatureType t) {
598
            eft = t;
599
            panel = p;
600
        }
601

    
602
        @Override
603
        public void actionPerformed(ActionEvent e) {
604
            try {
605
                EditableFeatureAttributeDescriptor ead = panel.loadFieldDescription(eft);
606
                if (ead == null) {
607
                    return;
608
                }
609
                if (ead.getType() == DataTypes.STRING
610
                        && ead.getSize() > TableOperations.MAX_FIELD_LENGTH) {
611
                    NotificationManager.showMessageInfo(
612
                            PluginServices.getText(this,
613
                                    "max_length_is")
614
                            + ":"
615
                            + TableOperations.MAX_FIELD_LENGTH,
616
                            null);
617
                    ead.setSize(TableOperations.MAX_FIELD_LENGTH);
618
                }
619
                PluginServices.getMDIManager().closeWindow(panel);
620
            } catch (ParseException e2) {
621
                NotificationManager.addError(e2);
622
            }
623

    
624
        }
625

    
626
    }
627

    
628
}