Revision 44655

View differences:

trunk/org.gvsig.desktop/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.dal/org.gvsig.fmap.dal.impl/src/main/java/org/gvsig/fmap/dal/feature/impl/featureset/AbstractFeatureSet.java
23 23
 */
24 24
package org.gvsig.fmap.dal.feature.impl.featureset;
25 25

  
26
import javax.json.Json;
27
import javax.json.JsonArray;
28
import javax.json.JsonArrayBuilder;
29
import javax.json.JsonObject;
26 30
import org.gvsig.fmap.dal.DataStore;
27 31
import org.gvsig.fmap.dal.exception.DataException;
28 32
import org.gvsig.fmap.dal.feature.Feature;
29 33
import org.gvsig.fmap.dal.feature.FeatureSet;
30 34
import org.gvsig.fmap.dal.feature.FeatureStore;
35
import org.gvsig.fmap.dal.feature.impl.DefaultFeature;
31 36
import org.gvsig.fmap.dal.feature.impl.dynobjectutils.DynObjectSetFeatureSetFacade;
32 37
import org.gvsig.tools.dispose.DisposableIterator;
33 38
import org.gvsig.tools.dispose.DisposeUtils;
......
155 160
        }
156 161
    }
157 162

  
163
    public JsonArray toJSON() {
164
        // TODO: estaria bien hacer una implementacion alternativa que devolviese
165
        // un JsonArray basado en el FeatureSet/FeaturePagingHelper, asi no 
166
        // tendria que construirse en memoria el JSON entero.
167
        try {
168
            JsonArrayBuilder builder = Json.createArrayBuilder();
169
            this.accept(new Visitor() {
170
                @Override
171
                public void visit(Object obj) throws VisitCanceledException, BaseException {
172
                    DefaultFeature f = (DefaultFeature) obj;
173
                    JsonObject fjson = f.toJSON();
174
                    builder.add(fjson);
175
                }
176
            });
177
            return builder.build();        
178
        } catch (Exception ex) {
179
            throw new RuntimeException("Can't create JSON array.",ex);
180
        }
181
    }
158 182
}
trunk/org.gvsig.desktop/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.dal/org.gvsig.fmap.dal.impl/src/main/java/org/gvsig/fmap/dal/feature/impl/DefaultFeatureStore.java
38 38
import java.util.Map;
39 39
import java.util.Map.Entry;
40 40
import java.util.Set;
41
import javax.json.JsonObject;
41 42

  
42 43
import org.apache.commons.io.FilenameUtils;
43 44
import org.apache.commons.io.IOUtils;
......
2466 2467
    }
2467 2468

  
2468 2469
    @Override
2470
    public EditableFeature createNewFeature(JsonObject defaultValues) throws DataException {
2471
        FeatureType ft = this.getDefaultFeatureType();
2472
        EditableFeature f = this.createNewFeature(ft, false);
2473
        f.copyFrom(defaultValues);
2474
        return f;
2475
    }
2476

  
2477
    @Override
2469 2478
    public EditableFeatureType createFeatureType() {
2470 2479
        EditableFeatureType ftype = new DefaultEditableFeatureType(this);
2471 2480
        return ftype;
trunk/org.gvsig.desktop/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.dal/org.gvsig.fmap.dal.impl/src/main/java/org/gvsig/fmap/dal/feature/impl/DefaultEditableFeature.java
23 23
 */
24 24
package org.gvsig.fmap.dal.feature.impl;
25 25

  
26
import java.time.LocalDate;
27
import java.time.LocalDateTime;
28
import java.time.ZoneId;
29
import java.time.ZoneOffset;
30
import java.time.format.DateTimeFormatter;
31
import java.time.temporal.TemporalAccessor;
26 32
import java.util.Date;
27
import java.util.Iterator;
33
import javax.json.JsonNumber;
34
import javax.json.JsonObject;
35
import org.gvsig.fmap.dal.DataTypes;
28 36

  
29 37
import org.gvsig.fmap.dal.feature.EditableFeature;
30 38
import org.gvsig.fmap.dal.feature.Feature;
31 39
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
32
import org.gvsig.fmap.dal.feature.FeatureType;
33 40
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
34 41
import org.gvsig.fmap.geom.Geometry;
42
import org.gvsig.fmap.geom.GeometryUtils;
35 43
import org.gvsig.timesupport.Instant;
36 44
import org.gvsig.timesupport.Interval;
45
import org.json.JSONObject;
37 46

  
38 47
public class DefaultEditableFeature extends DefaultFeature implements
39 48
        EditableFeature {
......
240 249
        this.set(attribute, value);
241 250
    }
242 251

  
252
    public void copyFrom(JsonObject values) {
253
        // iterate over the attributes and copy one by one
254
        for (FeatureAttributeDescriptor attr : this.getType()) {
255
            if (attr==null || attr.isAutomatic() || attr.isReadOnly() || attr.isComputed() ) {
256
                continue;
257
            }
258
            String attrname = attr.getName();
259
            if( !values.containsKey(attrname) ) {
260
                continue;
261
            }           
262
            Object value;
263
            try {
264
                switch( values.getValueType() ) {
265
                    case STRING:
266
                        switch(attr.getType()) {
267
                            case DataTypes.GEOMETRY:
268
                                value = GeometryUtils.createFrom(values.getString(attrname));
269
                                break;
270
                            case DataTypes.DATE:
271
                                try {
272
                                    TemporalAccessor x = DateTimeFormatter.ISO_DATE_TIME.parse(values.getString(attrname));
273
                                    LocalDateTime date = LocalDateTime.from(x);
274
//                                    value = Date.from(date.atZone(ZoneId.systemDefault()).toInstant());
275
                                    value = Date.from(date.toInstant(ZoneOffset.UTC));
276
                                } catch(Exception ex) {
277
                                    value = values.getString(attrname);
278
                                }
279
                                break;
280
                            case DataTypes.STRING:
281
                            default:
282
                                value = values.getString(attrname);
283
                                break;
284
                        }
285
                        break;
286
                    case NUMBER:
287
                        JsonNumber n = values.getJsonNumber(attrname);
288
                        switch(attr.getType()) {
289
                            case DataTypes.BIGDECIMAL:
290
                                value = n.bigDecimalValue();
291
                                break;
292
                            case DataTypes.BYTE:
293
                                value = n.bigDecimalValue();
294
                                break;
295
                            case DataTypes.FLOAT:
296
                            case DataTypes.DOUBLE:
297
                                value = n.doubleValue();
298
                                break;
299
                            case DataTypes.INT:
300
                                value = n.intValue();
301
                                break;
302
                            case DataTypes.LONG:
303
                                value = n.longValue();
304
                                break;
305
                            default:
306
                                value = n.toString();
307
                                break;
308
                        }
309
                        break;
310
                    case TRUE:
311
                        value = true;
312
                        break;
313
                    case FALSE:
314
                        value = false;
315
                        break;
316
                    case NULL:
317
                        value = null;
318
                        break;
319
                    default:
320
                        value = values.getString(attrname);
321
                        break;
322
                }
323
            } catch(Exception ex) {
324
                continue;
325
            }
326
            if (value == null && !attr.allowNull()) {
327
                continue;
328
            }
329
            try {
330
                set(attr.getIndex(), value);
331
            } catch(Throwable th) {
332
                // Ignore
333
            }
334
        }
335
    }
336
    
243 337
    public void copyFrom(Feature source) {
244 338
        // iterate over the attributes and copy one by one
245
        FeatureType sourceType = source.getType();
246 339
        for (FeatureAttributeDescriptor attr : this.getType()) {
247 340
            if (attr==null || attr.isAutomatic() || attr.isReadOnly() || attr.isComputed() ) {
248 341
                continue;
trunk/org.gvsig.desktop/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.dal/org.gvsig.fmap.dal.impl/src/main/java/org/gvsig/fmap/dal/feature/impl/DefaultFeature.java
24 24
package org.gvsig.fmap.dal.feature.impl;
25 25

  
26 26
import java.lang.ref.WeakReference;
27
import java.time.format.DateTimeFormatter;
27 28
import java.util.ArrayList;
28 29
import java.util.Date;
29 30
import java.util.Iterator;
30 31
import java.util.List;
31 32
import java.util.Map;
33
import java.util.Objects;
34
import javax.json.Json;
35
import javax.json.JsonObject;
36
import javax.json.JsonObjectBuilder;
32 37
import org.apache.commons.lang3.StringUtils;
33 38
import org.cresques.cts.IProjection;
34 39
import org.gvsig.fmap.dal.DALLocator;
......
1099 1104
        return this.data.getExtraValue(index);
1100 1105
    }
1101 1106

  
1107
    public JsonObject toJSON() {
1108
        JsonObjectBuilder builder = Json.createObjectBuilder();
1109
        
1110
        FeatureType ft = this.getType();
1111
        for (FeatureAttributeDescriptor desc : ft) {
1112
            if (desc.isComputed()) {
1113
                continue;
1114
            }
1115
            switch(desc.getType()) {
1116
                case DataTypes.GEOMETRY:
1117
                    {
1118
                        try {
1119
                            builder.add(desc.getName(), this.getGeometry(desc.getIndex()).convertToWKT());
1120
                        } catch (Exception ex) {
1121
                            throw new RuntimeException("Can't convert geometry to WKT.", ex);
1122
                        }
1123
                    }
1124
                    break;
1125
                case DataTypes.BOOLEAN:
1126
                    builder.add(desc.getName(), this.getBoolean(desc.getIndex()));
1127
                    break;
1128
                case DataTypes.BYTE:
1129
                    builder.add(desc.getName(), this.getByte(desc.getIndex()));
1130
                    break;
1131
                case DataTypes.INT:
1132
                    builder.add(desc.getName(), this.getInt(desc.getIndex()));
1133
                    break;
1134
                case DataTypes.LONG:
1135
                    builder.add(desc.getName(), this.getLong(desc.getIndex()));
1136
                    break;
1137
                case DataTypes.DOUBLE:
1138
                    builder.add(desc.getName(), this.getDouble(desc.getIndex()));
1139
                    break;
1140
                case DataTypes.FLOAT:
1141
                    builder.add(desc.getName(), this.getFloat(desc.getIndex()));
1142
                    break;
1143
                case DataTypes.DATE:
1144
                    // Format date as ISO 8601
1145
                    Date date = this.getDate(desc.getIndex());
1146
                    String value = DateTimeFormatter.ISO_DATE_TIME.format(date.toInstant());
1147
                    builder.add(desc.getName(), value);
1148
                    break;
1149
                default:
1150
                    builder.add(desc.getName(), Objects.toString(this.get(desc.getIndex()),""));
1151
            }
1152
        }        
1153
        return builder.build();
1154
    }
1102 1155

  
1103 1156
}
trunk/org.gvsig.desktop/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.dal/org.gvsig.fmap.dal.impl/pom.xml
92 92
            <artifactId>json</artifactId>
93 93
            <scope>compile</scope>
94 94
        </dependency>
95
        
95 96
        <dependency>
97
            <groupId>org.glassfish</groupId>
98
            <artifactId>javax.json</artifactId>
99
            <scope>compile</scope>
100
        </dependency>
101
        
102
        <dependency>
96 103
            <groupId>org.gvsig</groupId>
97 104
            <artifactId>org.gvsig.expressionevaluator.lib.api</artifactId>
98 105
            <scope>compile</scope>
trunk/org.gvsig.desktop/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.dal/org.gvsig.fmap.dal.api/src/test/java/org/gvsig/fmap/dal/feature/DummyFetureStore.java
5 5
import java.util.Iterator;
6 6
import java.util.List;
7 7
import java.util.Set;
8
import javax.json.JsonObject;
8 9

  
9 10
import org.cresques.cts.IProjection;
10 11
import org.gvsig.expressionevaluator.Expression;
......
219 220
    }
220 221

  
221 222
    @Override
223
    public EditableFeature createNewFeature(JsonObject defaultValues) throws DataException {
224
        return null;
225
    }
226
    
227
    @Override
222 228
    public void validateFeatures(int mode) throws DataException {
223 229

  
224 230
    }
......
792 798
        return false;
793 799
    }
794 800
    
795
    
796 801
}
trunk/org.gvsig.desktop/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.dal/org.gvsig.fmap.dal.api/src/main/java/org/gvsig/fmap/dal/feature/FeatureStore.java
25 25

  
26 26
import java.util.Iterator;
27 27
import java.util.List;
28
import javax.json.JsonObject;
28 29

  
29 30
import org.cresques.cts.IProjection;
30 31
import org.gvsig.expressionevaluator.Expression;
......
33 34
import org.gvsig.fmap.dal.DataServerExplorer;
34 35
import org.gvsig.fmap.dal.DataStore;
35 36
import org.gvsig.fmap.dal.DataStoreParameters;
36
import org.gvsig.fmap.dal.StoresRepository;
37 37
import org.gvsig.fmap.dal.exception.DataException;
38 38
import org.gvsig.fmap.dal.exception.ReadException;
39 39
import org.gvsig.fmap.dal.feature.exception.FeatureIndexException;
......
46 46
import org.gvsig.tools.lang.Cloneable;
47 47
import org.gvsig.tools.observer.Observer;
48 48
import org.gvsig.tools.undo.UndoRedoStack;
49
import org.gvsig.tools.resourcesstorage.ResourcesStorage;
50 49
import org.gvsig.tools.util.UnmodifiableBasicList64;
51 50

  
52 51
/**
......
827 826
    public EditableFeature createNewFeature(Feature defaultValues)
828 827
        throws DataException;
829 828

  
829
    public EditableFeature createNewFeature(JsonObject defaultValues)
830
        throws DataException;
831

  
830 832
    /**
831 833
     * Applies the validation rules associated to the given mode to the active
832 834
     * {@link FeatureSet}.
trunk/org.gvsig.desktop/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.dal/org.gvsig.fmap.dal.api/src/main/java/org/gvsig/fmap/dal/feature/EditableFeature.java
24 24
package org.gvsig.fmap.dal.feature;
25 25

  
26 26
import java.util.Date;
27
import javax.json.JsonObject;
27 28

  
28 29
import org.gvsig.fmap.geom.Geometry;
29 30
import org.gvsig.timesupport.Instant;
......
281 282
	 * 			source feature from which the values will be copied.
282 283
	 */
283 284
	public void copyFrom(Feature source);	
285
        
286
	public void copyFrom(JsonObject source);	
284 287
	
285 288
	/**
286 289
     * Sets the value of an attribute of type instant, given its name
trunk/org.gvsig.desktop/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.dal/org.gvsig.fmap.dal.api/src/main/java/org/gvsig/fmap/dal/feature/FeatureSet.java
24 24
package org.gvsig.fmap.dal.feature;
25 25

  
26 26
import java.util.List;
27
import javax.json.JsonArray;
27 28

  
28 29
import org.gvsig.fmap.dal.DataSet;
29 30
import org.gvsig.fmap.dal.exception.DataException;
......
333 334
    void accept(Visitor visitor, long firstValueIndex, long elements) throws BaseException;
334 335
    
335 336
    public FeatureStore getFeatureStore();
337
    
338
    public JsonArray toJSON();
336 339
}
trunk/org.gvsig.desktop/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.dal/org.gvsig.fmap.dal.api/pom.xml
54 54
        <artifactId>slf4j-api</artifactId>
55 55
        <scope>compile</scope>
56 56
    </dependency>
57
        
58
        <dependency>
59
            <groupId>org.glassfish</groupId>
60
            <artifactId>javax.json</artifactId>
61
            <scope>compile</scope>
62
        </dependency>
63
    
57 64
    <!-- Implementation dependencies for TESTS -->
58 65
    <dependency>
59 66
      <groupId>org.gvsig</groupId>
trunk/org.gvsig.desktop/org.gvsig.desktop.framework/org.gvsig.andami/pom.xml
360 360
            <groupId>xml-apis</groupId>
361 361
            <artifactId>xml-apis-ext</artifactId>
362 362
            <scope>runtime</scope>
363
        </dependency>        
364
        <dependency>
365
            <groupId>org.glassfish</groupId>
366
            <artifactId>javax.json</artifactId>
367
            <version>1.0.4</version>
368
            <scope>compile</scope>
363 369
        </dependency>
364 370
        <dependency>
365 371
            <groupId>com.github.lespaul361</groupId>
trunk/org.gvsig.desktop/org.gvsig.desktop.plugin/org.gvsig.app/org.gvsig.app.mainplugin/src/main/java/org/gvsig/app/extension/clipboard/CopyFeaturesToClipboardExtension.java
23 23
 */
24 24
package org.gvsig.app.extension.clipboard;
25 25

  
26
import javax.json.JsonArray;
26 27
import javax.swing.JOptionPane;
27 28

  
28 29
import org.slf4j.Logger;
29 30
import org.slf4j.LoggerFactory;
30 31

  
31 32
import org.gvsig.andami.IconThemeHelper;
32
import org.gvsig.andami.PluginServices;
33 33
import org.gvsig.andami.plugins.Extension;
34
import org.gvsig.andami.ui.mdiManager.IWindow;
35 34
import org.gvsig.app.ApplicationLocator;
36
import org.gvsig.app.extension.clipboard.util.FeatureTextUtils;
37
import org.gvsig.app.project.documents.view.gui.IView;
38
import org.gvsig.fmap.dal.exception.DataException;
35
import org.gvsig.app.ApplicationManager;
36
import org.gvsig.app.project.documents.view.ViewDocument;
37
import org.gvsig.app.project.documents.view.ViewManager;
39 38
import org.gvsig.fmap.dal.feature.FeatureSelection;
40
import org.gvsig.fmap.dal.feature.FeatureStore;
41
import org.gvsig.fmap.mapcontext.layers.FLayer;
39
import org.gvsig.fmap.mapcontext.MapContext;
42 40
import org.gvsig.fmap.mapcontext.layers.vectorial.FLyrVect;
43
import org.gvsig.i18n.Messages;
41
import org.gvsig.tools.ToolsLocator;
42
import org.gvsig.tools.i18n.I18nManager;
44 43

  
45

  
46 44
public class CopyFeaturesToClipboardExtension extends Extension {
47 45

  
48
    private static Logger logger = LoggerFactory.getLogger(
49
    		CopyFeaturesToClipboardExtension.class);
46
    private static final Logger LOGGER = LoggerFactory.getLogger(CopyFeaturesToClipboardExtension.class);
50 47

  
51
	public void initialize() {
48
    public void initialize() {
52 49

  
53
		IconThemeHelper.registerIcon("action", "layer-modify-clipboard-copy", this);
54
	}
50
        IconThemeHelper.registerIcon("action", "layer-modify-clipboard-copy", this);
51
    }
55 52

  
56
	public void execute(String actionCommand) {
53
    public void execute(String actionCommand) {
57 54

  
58
		if (actionCommand.compareToIgnoreCase("layer-modify-clipboard-copy") != 0) {
59
			return;
60
		}
55
        if (actionCommand.compareToIgnoreCase("layer-modify-clipboard-copy") != 0) {
56
            return;
57
        }
58
        ApplicationManager application = ApplicationLocator.getManager();
59
        ViewDocument viewdoc = (ViewDocument) application.getActiveDocument(ViewManager.TYPENAME);
60
        if( viewdoc == null ) {
61
            return;
62
        }
63
        MapContext mapContext = viewdoc.getMapContext();
64
        FLyrVect layer = mapContext.getLayers().getFirstActiveVectorLayer();
65
        if( layer==null ) {
66
            return;
67
        }
68
        try {
69
            FeatureSelection selection = layer.getFeatureStore().getFeatureSelection();
61 70

  
62
		IWindow actw = actWin();
71
            JsonArray json = selection.toJSON();
72
            application.putInClipboard(json.toString());
63 73

  
64
		if (actw instanceof IView) {
74
            I18nManager i18n = ToolsLocator.getI18nManager();
75
            application.messageDialog(
76
                    i18n.getTranslation("_Number_of_features_copied_to_clipboard")
77
                        + ":   " + selection.getSize(),
78
                    null, 
79
                    i18n.getTranslation("_Copy_selected_features_to_clipboard"),
80
                    JOptionPane.INFORMATION_MESSAGE, 
81
                    "CopyFeaturesToClipboard"
82
            );
65 83

  
66
			IView vw = (IView) actw;
67
			FLayer[] act_lyr = vw.getMapControl().getMapContext().getLayers().getActives();
68
			if (act_lyr == null || act_lyr.length != 1
69
					|| !(act_lyr[0] instanceof FLyrVect)) {
84
        } catch (Exception e) {
85
            LOGGER.warn("Can't get the selection as JSON.", e);
86
        }
87
    }
70 88

  
71
			} else {
89
    public boolean isEnabled() {
90
        // it's enabled if there is exactly one vector layer in the active view
91
        // and it has a selection
72 92

  
73
				int usr_opt = JOptionPane.showConfirmDialog(
74
						ApplicationLocator.getManager().getRootComponent(),
75
						Messages.getText("_Include_alphanumeric_attributes_Question"),
76
						Messages.getText("_Copy_selected_features_to_clipboard"),
77
						JOptionPane.YES_NO_CANCEL_OPTION,
78
						JOptionPane.QUESTION_MESSAGE);
93
        ApplicationManager application = ApplicationLocator.getManager();
94
        ViewDocument viewdoc = (ViewDocument) application.getActiveDocument(ViewManager.TYPENAME);
95
        if( viewdoc == null ) {
96
            return false;
97
        }
98
        MapContext mapContext = viewdoc.getMapContext();
99
        FLyrVect layer = mapContext.getLayers().getFirstActiveVectorLayer();
100
        if( layer==null ) {
101
            return false;
102
        }
103
        if (!layer.isAvailable()) {
104
            // This can happen when opening a persisted project
105
            // and there is a "slow" layer (GeoDB)
106
            return false;
107
        }
108
        try {
109
            FeatureSelection selection = layer.getFeatureStore().getFeatureSelection();
110
            return !selection.isEmpty();
111
        } catch (Exception ex) {
112
            LOGGER.warn("Can't get selection from layer '"+layer.getName()+"'.", ex);
113
            return false;
114
        }
115
    }
79 116

  
117
    public boolean isVisible() {
118
        ApplicationManager application = ApplicationLocator.getManager();
119
        return application.getActiveDocument(ViewManager.TYPENAME)!=null;
120
    }
80 121

  
81
				if (usr_opt == JOptionPane.CANCEL_OPTION) {
82
					return;
83
				}
84

  
85
				FLyrVect vect = (FLyrVect) act_lyr[0];
86
				FeatureSelection sele = null;
87
				FeatureStore fsto = null;
88
				try {
89
					fsto = vect.getFeatureStore();
90
					sele = (FeatureSelection) fsto.getSelection();
91

  
92
					StringBuilder strb = FeatureTextUtils.toString(
93
							sele, fsto.getDefaultFeatureType(),
94
							usr_opt == JOptionPane.YES_OPTION);
95
					/*
96
					 * Put selected features in clipboard.
97
					 */
98
					PluginServices.putInClipboard(strb.toString());
99

  
100
					JOptionPane.showMessageDialog(
101
							ApplicationLocator.getManager().getRootComponent(),
102
							Messages.getText("_Number_of_features_copied_to_clipboard")
103
							+ ":   " + sele.getSize() + "    ",
104
							Messages.getText("_Copy_selected_features_to_clipboard"),
105
							JOptionPane.INFORMATION_MESSAGE);
106

  
107
				} catch (DataException e) {
108
					logger.error("While getting store and selection. ", e);
109
				}
110
			}
111
		}
112

  
113
	}
114

  
115
	public boolean isEnabled() {
116

  
117
		/*
118
		 * It's enabled if there is exactly one vector layer in the active view
119
		 * and it has a selection
120
		 */
121

  
122
		IWindow actw = actWin();
123

  
124
		if (actw instanceof IView) {
125

  
126
			IView vw = (IView) actw;
127
			FLayer[] act_lyr = vw.getMapControl().getMapContext().getLayers().getActives();
128
			if (act_lyr == null || act_lyr.length != 1
129
					|| !(act_lyr[0] instanceof FLyrVect)) {
130
				return false;
131

  
132
			} else {
133
				FLyrVect vect = (FLyrVect) act_lyr[0];
134
				if (!vect.isAvailable()) {
135
				    /*
136
				     * This can happen when opening a persisted project
137
				     * and there is a "slow" layer (GeoDB)
138
				     */
139
				    return false;
140
				}
141
				FeatureSelection sele = null;
142
				long sele_count = 0;
143
				try {
144
					sele = (FeatureSelection) vect.getFeatureStore().getSelection();
145
					sele_count = sele.getSize();
146
				} catch (DataException e) {
147
					logger.error("While getting store. ", e);
148
					return false;
149
				}
150
				return sele_count > 0;
151
			}
152

  
153
		} else {
154
			return false;
155
		}
156
	}
157

  
158
	public boolean isVisible() {
159

  
160
		return actWin() instanceof IView;
161
	}
162

  
163
	/**
164
	 * Gets active window
165
	 * @return
166
	 */
167
	private IWindow actWin() {
168
		return ApplicationLocator.getManager().getActiveWindow();
169
	}
170

  
171

  
172 122
}
trunk/org.gvsig.desktop/org.gvsig.desktop.plugin/org.gvsig.app/org.gvsig.app.mainplugin/src/main/java/org/gvsig/app/extension/clipboard/PasteFeaturesFromClipboardExtension.java
23 23
 */
24 24
package org.gvsig.app.extension.clipboard;
25 25

  
26
import com.vividsolutions.jts.io.ByteArrayInStream;
27
import java.io.ByteArrayInputStream;
28
import java.io.InputStream;
29
import java.io.StringReader;
26 30
import java.util.ArrayList;
27
import java.util.Iterator;
28 31
import java.util.List;
32
import java.util.function.Predicate;
29 33

  
30 34
import javax.swing.JOptionPane;
35
import org.apache.commons.lang.mutable.MutableInt;
36
import org.apache.commons.lang3.StringUtils;
31 37

  
32 38
import org.slf4j.Logger;
33 39
import org.slf4j.LoggerFactory;
34 40

  
35 41
import org.gvsig.andami.IconThemeHelper;
36
import org.gvsig.andami.PluginServices;
37 42
import org.gvsig.andami.plugins.Extension;
38
import org.gvsig.andami.ui.mdiManager.IWindow;
39 43
import org.gvsig.app.ApplicationLocator;
40
import org.gvsig.app.extension.clipboard.util.FeatureTextUtils;
44
import org.gvsig.app.ApplicationManager;
41 45
import org.gvsig.app.project.documents.view.ViewDocument;
42
import org.gvsig.app.project.documents.view.gui.DefaultViewPanel;
43
import org.gvsig.app.project.documents.view.gui.IView;
44
import org.gvsig.fmap.dal.exception.DataException;
46
import org.gvsig.app.project.documents.view.ViewManager;
45 47
import org.gvsig.fmap.dal.feature.EditableFeature;
46
import org.gvsig.fmap.dal.feature.Feature;
47 48
import org.gvsig.fmap.dal.feature.FeatureStore;
48 49
import org.gvsig.fmap.geom.Geometry;
49
import org.gvsig.fmap.geom.GeometryException;
50
import org.gvsig.fmap.geom.GeometryUtils;
50 51
import org.gvsig.fmap.geom.primitive.Envelope;
51
import org.gvsig.fmap.geom.type.GeometryType;
52 52
import org.gvsig.fmap.mapcontext.MapContext;
53 53
import org.gvsig.fmap.mapcontext.layers.FLayer;
54
import org.gvsig.fmap.mapcontext.layers.FLayers;
55
import org.gvsig.fmap.mapcontext.layers.LayersIterator;
56 54
import org.gvsig.fmap.mapcontext.layers.vectorial.FLyrVect;
57
import org.gvsig.i18n.Messages;
55
import org.gvsig.tools.ToolsLocator;
56
import org.gvsig.tools.i18n.I18nManager;
57
import org.gvsig.tools.logger.FilteredLogger;
58
import org.json.JSONArray;
59
import org.json.JSONObject;
58 60

  
61
import javax.json.JsonObject;
62
import javax.json.Json;
63
import javax.json.JsonArray;
64
import javax.json.JsonReader;
65
import org.apache.commons.io.Charsets;
59 66

  
67

  
60 68
public class PasteFeaturesFromClipboardExtension extends Extension {
61 69

  
62
    private static Logger logger = LoggerFactory.getLogger(
63
    		PasteFeaturesFromClipboardExtension.class);
70
    private static final Logger LOGGER = LoggerFactory.getLogger(PasteFeaturesFromClipboardExtension.class);
64 71

  
65
	public void initialize() {
72
    public void initialize() {
66 73

  
67
		IconThemeHelper.registerIcon("action", "layer-modify-clipboard-paste", this);
68
	}
74
        IconThemeHelper.registerIcon("action", "layer-modify-clipboard-paste", this);
75
    }
69 76

  
70
	public void execute(String actionCommand) {
77
    public void execute(String actionCommand) {
71 78

  
72
		if (actionCommand.compareToIgnoreCase("layer-modify-clipboard-paste") != 0) {
73
			return;
74
		}
79
        if (actionCommand.compareToIgnoreCase("layer-modify-clipboard-paste") != 0) {
80
            return;
81
        }
82
        ApplicationManager application = ApplicationLocator.getManager();
83
        ViewDocument viewdoc = (ViewDocument) application.getActiveDocument(ViewManager.TYPENAME);
84
        if( viewdoc == null ) {
85
            return;
86
        }
87
        I18nManager i18n = ToolsLocator.getI18nManager();
88
        String clipboardValue = application.getFromClipboard();
89
        if( StringUtils.isBlank(clipboardValue) ) {
90
            application.messageDialog(
91
                i18n.getTranslation("_Clipboard_has_no_valid_info_or_is_empty"),
92
                null, 
93
                i18n.getTranslation("_Pasting_features_from_clipboard"),
94
                JOptionPane.INFORMATION_MESSAGE, 
95
                "ClipboardEmptyWhenPasteFeatures"
96
            );
97
            return;
98
        }
99
        
100
        JsonArray jsonArray;
101
        try {
102
            JsonReader jsonReader = Json.createReader(new StringReader(clipboardValue));
103
            jsonArray = jsonReader.readArray();
104
            jsonReader.close();
105
        } catch(Exception ex) {
106
            LOGGER.warn("Can't get JSON from the clipboard.", ex);
107
            application.messageDialog(
108
                i18n.getTranslation("_Clipboard_has_no_valid_info_or_is_empty"),
109
                null, 
110
                i18n.getTranslation("_Pasting_features_from_clipboard"),
111
                JOptionPane.WARNING_MESSAGE, 
112
                "ClipboardNotValidWhenPasteFeatures"
113
            );
114
            return;
115
        }
116
        if( jsonArray.size()<1 ) {
117
            application.messageDialog(
118
                i18n.getTranslation("_No_features_found_in_clipboard"),
119
                null, 
120
                i18n.getTranslation("_Pasting_features_from_clipboard"),
121
                JOptionPane.WARNING_MESSAGE, 
122
                "ClipboardNotHasElementsWhenPasteFeatures"
123
            );
124
            return;
125
        }
126
        
127
        
128
        MapContext mapContext = viewdoc.getMapContext();
129
        List<FLayer> layers = mapContext.getLayers().getLayers(new Predicate<FLayer>() {
130
            @Override
131
            public boolean test(FLayer layer) {
132
                return layer instanceof FLyrVect && 
133
                        layer.isActive() &&
134
                        layer.isAvailable() &&
135
                        layer.isEditing(); 
136
            }
137
        });
138
        if( layers.isEmpty() ) {
139
            return;
140
        }
141
        FLyrVect layer = (FLyrVect) layers.get(0);
142
        FeatureStore store = layer.getFeatureStore();
143
        List<EditableFeature> features = new ArrayList<>();
144
        FilteredLogger theLogger = new FilteredLogger(LOGGER, "PasteFeatures", 10);
145
        for (Object obj : jsonArray) {
146
            if( !(obj instanceof JsonObject ) ) {
147
                continue;
148
            }
149
            JsonObject fjson = (JsonObject) obj;
150
            try {
151
                EditableFeature f = store.createNewFeature(fjson);
152
                features.add(f);
153
            } catch (Exception ex) {
154
                theLogger.warn("Can't create feature from JSON.", ex);
155
            }
156
        }
157
        if( features.isEmpty() ) {
158
            application.messageDialog(
159
                i18n.getTranslation("_No_features_found_in_clipboard"),
160
                null, 
161
                i18n.getTranslation("_Pasting_features_from_clipboard"),
162
                JOptionPane.WARNING_MESSAGE, 
163
                "ClipboardNotHasFeaturesWhenPasteFeatures"
164
            );
165
            return;
166
        }
75 167

  
76
		IWindow actw = actWin();
77

  
78
		if (actw instanceof IView) {
79

  
80
			IView vw = (IView) actw;
81
			FLayer[] act_lyr = vw.getMapControl().getMapContext().getLayers().getActives();
82
			if (act_lyr == null || act_lyr.length != 1
83
					|| !(act_lyr[0] instanceof FLyrVect)) {
84

  
85
			} else {
86
				FLyrVect vect = (FLyrVect) act_lyr[0];
87
				if (vect.isEditing()) {
88

  
89
					// Discard if no text data or empty:
90
					if (!FeatureTextUtils.textInClipboard()) {
91
						JOptionPane.showMessageDialog(
92
								ApplicationLocator.getManager().getRootComponent(),
93
								Messages.getText("_Clipboard_has_no_valid_info_or_is_empty"),
94
								Messages.getText("_Pasting_features_from_clipboard"),
95
								JOptionPane.INFORMATION_MESSAGE);
96
						return;
97
					}
98
					String clipb = PluginServices.getFromClipboard();
99
					if (clipb == null || clipb.length() == 0) {
100
						JOptionPane.showMessageDialog(
101
								ApplicationLocator.getManager().getRootComponent(),
102
								Messages.getText("_Clipboard_has_no_valid_info_or_is_empty"),
103
								Messages.getText("_Pasting_features_from_clipboard"),
104
								JOptionPane.INFORMATION_MESSAGE);
105
						return;
106
					}
107

  
108
					// ============================================
109
					// ============================================
110

  
111
					FeatureStore fsto = vect.getFeatureStore();
112
					List<EditableFeature> try_feats = FeatureTextUtils.fromString(clipb, fsto);
113
					/*
114
					 * This method will check geometry type
115
					 */
116
					List<EditableFeature> added_feats = addFeatures(fsto, try_feats);
117

  
118
					int n_orig = try_feats.size();
119
					int n_added = added_feats.size();
120
					int n_disc = n_orig - n_added;
121

  
122
					String msg = "";
123

  
124
					if (n_orig == 0) {
125
						msg = Messages.getText("_No_features_found_in_clipboard");
126
					} else {
127
						msg = Messages.getText("_Number_of_features_pasted_from_clipboard");
128
						msg = msg + ":   " + n_added + "    \n";
129
						msg = msg + Messages.getText("_Number_of_features_from_clipboard_discarded_due_to_bad_format");
130
						msg = msg + ":   " + n_disc + "    ";
131
					}
132

  
133

  
134
					if (n_added > 0) {
135

  
136
						msg = msg + "\n\n" +
137
								Messages.getText("_Zoom_to_added_features_question");
138
						int user_opt = JOptionPane.showConfirmDialog(
139
								ApplicationLocator.getManager().getRootComponent(),
140
								msg,
141
								Messages.getText("_Pasting_features_from_clipboard"),
142
								JOptionPane.YES_NO_OPTION);
143
						if (user_opt == JOptionPane.YES_OPTION) {
144
							try {
145
								zoomToExtent(added_feats,
146
										vw.getMapControl().getMapContext());
147
							} catch (Exception ex) {
148
								JOptionPane.showMessageDialog(
149
										ApplicationLocator.getManager().getRootComponent(),
150
										Messages.getText("_Unable_to_zoom_to_features")
151
										+ ": " + ex.getMessage(),
152
										Messages.getText("_Pasting_features_from_clipboard"),
153
										JOptionPane.ERROR_MESSAGE);
154
							}
155

  
156
						} else {
157
							// Repaint view
158
							vw.getMapControl().getMapContext().invalidate();
159
						}
160

  
161
					} else {
162
						JOptionPane.showMessageDialog(
163
								ApplicationLocator.getManager().getRootComponent(),
164
								msg,
165
								Messages.getText("_Pasting_features_from_clipboard"),
166
								JOptionPane.INFORMATION_MESSAGE);
167
					}
168
				}
169
			}
170

  
171
		}
172

  
173

  
174
	}
175

  
176
	private void zoomToExtent(
177
			List<EditableFeature> added_feats,
178
			MapContext mco) throws Exception {
179

  
180
		Envelope env = null;
181
		Envelope itemenv = null;
182
		Iterator<EditableFeature> iter = added_feats.iterator();
183
		Feature feat = null;
184
		while (iter.hasNext()) {
185
			feat = (Feature) iter.next();
186
			itemenv = feat.getDefaultGeometry().getEnvelope();
187
			if (itemenv != null) {
188
				if (env == null) {
189
					itemenv = (Envelope) itemenv.clone();
190
					env = itemenv;
191
				} else {
192
					env.add(itemenv);
193
				}
194
			}
195
		}
196
		if (env == null) {
197
			throw new GeometryException(new Exception("All envelopes are null."));
198
		}
199
		mco.getViewPort().setEnvelope(env);
200
	}
201

  
202
	/**
203
	 * Add features if geometry is of right type.
204
	 * Returns number of features added.
205
	 * If returned number is negative, it means there were errors.
206
	 * Example: -5 means 5 were added and there were errors with other geometries.
207
	 *
208
	 * @param fsto
209
	 * @param add_feats
210
	 * @throws DataException
211
	 */
212
	private List<EditableFeature> addFeatures(
213
			FeatureStore fsto,
214
			List<EditableFeature> add_feats) {
215

  
216
		List<EditableFeature> really_added = new ArrayList<EditableFeature>();
217

  
218
		Iterator<EditableFeature> iter = add_feats.iterator();
219
		EditableFeature item = null;
220
		Geometry geom = null;
221
		GeometryType good_gt = null;
222
		int good_dimensions = 0;
223

  
224
		try {
225
			good_gt = fsto.getDefaultFeatureType().getDefaultGeometryAttribute().getGeomType();
226
			good_dimensions = FeatureTextUtils.geoman().create(good_gt).getDimension();
227
		} catch (Exception e) {
228
			logger.error("While getting geom type.", e);
229
			return really_added;
230
		}
231

  
232
		while (iter.hasNext()) {
233
			item = iter.next();
234
			geom = item.getDefaultGeometry();
235
			/*
236
			 * Same number of dimensions and compatible types
237
			 */
238
			if ((geom.getDimension() == good_dimensions)
239
					&&
240
					(geom.getGeometryType().isTypeOf(good_gt)
241
					|| simpleTypeOf(geom.getGeometryType(), good_gt))
242
					) {
243
				try {
244
					fsto.insert(item);
245
					really_added.add(item);
246
				} catch (DataException e) {
247
					/*
248
					 * This error will cause that "really_added"
249
					 * will be shorter than "add_feats" and the user
250
					 * must be notified of that when the process ends.
251
					 */
252
					logger.info("Error while inserting feature from clipboard: " + e.getMessage());
253
				}
254
			}
255
		}
256

  
257
		return really_added;
258
	}
259

  
260
	private boolean simpleTypeOf(GeometryType simplet, GeometryType multit) {
261

  
262
        return (multit.isTypeOf(Geometry.TYPES.MULTISURFACE) && 
263
                simplet.isTypeOf(Geometry.TYPES.SURFACE))
264
               ||
265
               (multit.isTypeOf(Geometry.TYPES.MULTICURVE) && 
266
                simplet.isTypeOf(Geometry.TYPES.CURVE))
267
               ||
268
               (multit.isTypeOf(Geometry.TYPES.MULTIPOINT) && 
269
                simplet.isTypeOf(Geometry.TYPES.POINT));
270
	}
271

  
168
        int inserteds = 0;
169
        theLogger = new FilteredLogger(LOGGER, "PasteFeatures", 10);
170
        Envelope envelope = GeometryUtils.createEnvelope(Geometry.SUBTYPES.GEOM2D);
171
        for (EditableFeature feature : features) {
172
            try {
173
                store.insert(feature);
174
                inserteds++;
175
                try {
176
                    envelope.add(feature.getDefaultGeometry());
177
                } catch(Exception ex) {
178
                    theLogger.warn("Can't calculate envelope.", ex);
179
                }
180
            } catch(Exception ex) {
181
                theLogger.warn("Can't insert feature.", ex);
182
            }
183
        }
184
        StringBuilder msg = new StringBuilder();
185
        msg.append(i18n.getTranslation("_Number_of_features_pasted_from_clipboard"));
186
        msg.append(":   ");
187
        msg.append(inserteds);
188
        msg.append("\n");
189
        msg.append(i18n.getTranslation("_Number_of_features_from_clipboard_discarded_due_to_bad_format"));
190
        msg.append(":   ");
191
        msg.append(jsonArray.size() - inserteds);
192
        if( inserteds<1 || envelope.isEmpty() ) {
193
            application.messageDialog(
194
                msg.toString(),
195
                null, 
196
                i18n.getTranslation("_Pasting_features_from_clipboard"),
197
                JOptionPane.WARNING_MESSAGE, 
198
                "ClipboardNotInsertFeaturesWhenPasteFeatures"
199
            );
200
            return;
201
        }
202
        msg.append("\n\n");
203
        msg.append(i18n.getTranslation("_Zoom_to_added_features_question"));
204
        int r = application.confirmDialog(
205
                msg.toString(), 
206
                i18n.getTranslation("_Pasting_features_from_clipboard"),
207
                JOptionPane.YES_NO_OPTION, 
208
                JOptionPane.QUESTION_MESSAGE, 
209
                "ZoomToInsertedFeaturesWhenPasteFeatures"
210
        );
211
        if( r == JOptionPane.NO_OPTION ) {
212
            return;
213
        }
214
        try {
215
            viewdoc.getMapContext().getViewPort().setEnvelope(envelope);
216
        } catch(Exception ex) {
217
            LOGGER.warn("Can't zoom to envelope.", ex);
218
        }
219
    }
220
    
272 221
    @Override
273
	public boolean isEnabled() {
274

  
275
		/*
276
		 * I think it's better to make it enabled always when the active layer
277
		 * is in editing mode, so it's not necessary to refresh the state of the button
278
		 * (with a zoom or changing window, etc). The content of the clipboard can change
279
		 * and gvSIG does not know. Of course, if the user clicks the button,
280
		 * a dialog will tell if the clipboard is empty or has invalid data.
281
		 */
282
		return isVisible();
283

  
284
		/*
285
		 * Discarded by now:
286
		 *
287
		 * It's enabled if the active layer is a vector layer
288
		 * in editing mode and the clipboard seems to have valid features
289
		 *
290
		IWindow actw = actWin();
291
		if (actw instanceof IView) {
292

  
293
			IView vw = (IView) actw;
294
			FLayer[] act_lyr = vw.getMapControl().getMapContext().getLayers().getActives();
295
			if (act_lyr == null || act_lyr.length != 1
296
					|| !(act_lyr[0] instanceof FLyrVect)) {
297
				return false;
298

  
299
			} else {
300
				FLyrVect vect = (FLyrVect) act_lyr[0];
301
				if (vect.isEditing()) {
302
					return FeatureTextUtils.clipboardSeemsToHaveValidFeatures();
303
				} else {
304
					return false;
305
				}
306
			}
307

  
308
		} else {
309
			return false;
310
		}
311
		*/
312
	}
313

  
314

  
315
	public boolean isVisible() {
316

  
317
        org.gvsig.andami.ui.mdiManager.IWindow f = PluginServices.getMDIManager()
318
        .getActiveWindow();
319
        if (f == null)
222
    public boolean isEnabled() {
223
        ApplicationManager application = ApplicationLocator.getManager();
224
        ViewDocument viewdoc = (ViewDocument) application.getActiveDocument(ViewManager.TYPENAME);
225
        if( viewdoc == null ) {
320 226
            return false;
321

  
322
        if (f instanceof DefaultViewPanel) {
323
            DefaultViewPanel vista = (DefaultViewPanel) f;
324
            ViewDocument model = vista.getViewDocument();
325
            MapContext mapa = model.getMapContext();
326

  
327
            FLayers capas = mapa.getLayers();
328

  
329
            int numActiveVectorial = 0;
330
            int numActiveVectorialEditable = 0;
331

  
332
            LayersIterator iter = new LayersIterator(capas);
333

  
334
            FLayer capa;
335
            while (iter.hasNext()) {
336
                capa = iter.nextLayer();
337
                if (capa instanceof FLyrVect &&
338
                        capa.isActive() && capa.isAvailable()) {
339
                    numActiveVectorial++;
340
                    if (capa.isEditing())
341
                        numActiveVectorialEditable++;
227
        }
228
        String clipboardValue = application.getFromClipboard();
229
        if( StringUtils.isBlank(clipboardValue) ) {
230
            return false;
231
        }
232
        MapContext mapContext = viewdoc.getMapContext();
233
        MutableInt numActiveVectorial = new MutableInt(0);
234
        MutableInt numActiveVectorialEditable = new MutableInt(0);
235
        List<FLayer> layers = mapContext.getLayers().getLayers(new Predicate<FLayer>() {
236
            @Override
237
            public boolean test(FLayer layer) {
238
                if (layer instanceof FLyrVect && 
239
                        layer.isActive() && 
240
                        layer.isAvailable() ) {
241
                        numActiveVectorial.increment();
242
                    if (layer.isEditing()) {
243
                        numActiveVectorialEditable.increment();
244
                    }
342 245
                }
343

  
246
                // No recuperamos ninguna capa, solo contamos las activa en edicion
247
                return false; 
344 248
            }
249
        });
250
        if (numActiveVectorialEditable.intValue() == 1 && 
251
                numActiveVectorial.intValue() == 1) {
252
            return true;
253
        }
254
        return false;
255
    }
345 256

  
346
            if (numActiveVectorialEditable == 1 && numActiveVectorial == 1)
347
			return true;
348
		}
349
		return false;
350
	}
257
    public boolean isVisible() {
258
        ApplicationManager application = ApplicationLocator.getManager();
259
        return application.getActiveDocument(ViewManager.TYPENAME)!=null;
260
    }
351 261

  
352
	/**
353
	 * Gets active window
354
	 * @return
355
	 */
356
	private IWindow actWin() {
357
		return ApplicationLocator.getManager().getActiveWindow();
358
	}
359

  
360 262
}
trunk/org.gvsig.desktop/org.gvsig.desktop.plugin/org.gvsig.app/org.gvsig.app.mainplugin/pom.xml
222 222
        <dependency>
223 223
            <groupId>org.gvsig</groupId>
224 224
            <artifactId>org.gvsig.expressionevaluator.geometry.lib.api</artifactId>
225
            <version>2.0.260-SNAPSHOT</version>
226
            <type>jar</type>
225
            <scope>compile</scope>
227 226
        </dependency>
227
        <dependency>
228
            <groupId>org.glassfish</groupId>
229
            <artifactId>javax.json</artifactId>
230
            <scope>compile</scope>
231
        </dependency>
228 232

  
229 233
        <!-- Dependencias de runtime -->
230 234
        <!-- Ordered by artifactId -->
......
254 258
            <artifactId>org.gvsig.fmap.dal.swing.impl</artifactId>
255 259
            <scope>runtime</scope>
256 260
        </dependency>
257
        <!--
258 261
        <dependency>
259 262
            <groupId>org.gvsig</groupId>
260
            <artifactId>org.gvsig.fmap.geometry.jts</artifactId>
261
            <scope>runtime</scope>
262
        </dependency>
263
        <dependency>
264
            <groupId>org.gvsig</groupId>
265
            <artifactId>org.gvsig.fmap.geometry.operation.jts</artifactId>
266
            <scope>runtime</scope>
267
        </dependency>
268
        -->
269
        <dependency>
270
            <groupId>org.gvsig</groupId>
271 263
            <artifactId>org.gvsig.fmap.mapcontext.impl</artifactId>
272 264
            <scope>runtime</scope>
273 265
        </dependency>
274
        <!--      <dependency>
275
            <groupId>org.gvsig</groupId>
276
            <artifactId>org.gvsig.fmap.mapcontext.operation</artifactId>
277
            <scope>runtime</scope>
278
        </dependency>-->
279 266
        <dependency>
280 267
            <groupId>org.gvsig</groupId>
281 268
            <artifactId>org.gvsig.metadata.lib.basic.impl</artifactId>
......
379 366
            <artifactId>org.gvsig.tools.lib</artifactId>
380 367
            <type>test-jar</type>
381 368
            <scope>test</scope>
382
        </dependency>
369
        </dependency>        
370

  
383 371
    </dependencies>
384 372

  
385 373
    <build>
trunk/org.gvsig.desktop/pom.xml
478 478
                <version>2.0.05</version>
479 479
            </dependency>
480 480
            <dependency>
481
                <groupId>org.glassfish</groupId>
482
                <artifactId>javax.json</artifactId>
483
                <version>1.0.4</version>
484
            </dependency>
485
            <dependency>
481 486
                <groupId>com.toedter</groupId>
482 487
                <artifactId>jcalendar</artifactId>
483 488
                <version>1.3.2</version>

Also available in: Unified diff