Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.plugin / org.gvsig.editing.app / org.gvsig.editing.app.mainplugin / src / main / java / org / gvsig / editing / clipboard / util / FeatureTextUtils.java @ 40666

History | View | Annotate | Download (8.77 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.editing.clipboard.util;
25

    
26
import java.awt.Toolkit;
27
import java.awt.datatransfer.DataFlavor;
28
import java.util.ArrayList;
29
import java.util.Date;
30
import java.util.List;
31

    
32
import org.gvsig.andami.PluginServices;
33
import org.gvsig.fmap.dal.exception.DataException;
34
import org.gvsig.fmap.dal.feature.EditableFeature;
35
import org.gvsig.fmap.dal.feature.Feature;
36
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
37
import org.gvsig.fmap.dal.feature.FeatureSet;
38
import org.gvsig.fmap.dal.feature.FeatureStore;
39
import org.gvsig.fmap.dal.feature.FeatureType;
40
import org.gvsig.fmap.geom.DataTypes;
41
import org.gvsig.fmap.geom.Geometry;
42
import org.gvsig.fmap.geom.GeometryLocator;
43
import org.gvsig.fmap.geom.GeometryManager;
44
import org.gvsig.fmap.geom.exception.CreateGeometryException;
45
import org.gvsig.fmap.geom.operation.GeometryOperationContext;
46
import org.gvsig.fmap.geom.operation.GeometryOperationException;
47
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
48
import org.gvsig.fmap.geom.operation.fromwkt.FromWKT;
49
import org.gvsig.fmap.geom.operation.fromwkt.FromWKTGeometryOperationContext;
50
import org.gvsig.fmap.geom.type.GeometryType;
51
import org.gvsig.tools.dataTypes.DataType;
52
import org.gvsig.tools.dispose.DisposableIterator;
53
import org.slf4j.Logger;
54
import org.slf4j.LoggerFactory;
55

    
56
public class FeatureTextUtils {
57
        
58
        private static final Logger logger = LoggerFactory.getLogger(FeatureTextUtils.class);
59
        
60
        /**
61
         * The format of the clipboard content will be:
62
         * 
63
         * <FEATURE><CLIPBOARD_SEPARATOR_1><FEATURE><CLIPBOARD_SEPARATOR_1><FEATURE>...
64
         * 
65
         * <FEATURE> = <WKT><CLIPBOARD_SEPARATOR_2><FIELD><CLIPBOARD_SEPARATOR_2><FIELD>...
66
         * 
67
         * <FIELD> = <NAME><CLIPBOARD_SEPARATOR_3><TYPE><CLIPBOARD_SEPARATOR_3><VALUE>
68
         * 
69
         *  Fields are optional, so a WKT string alone will also be valid.
70
         */
71
        public static final String CLIPBOARD_SEPARATOR_1 = "_GVSIGCOPYPASTESEPARATOR1_";
72
        public static final String CLIPBOARD_SEPARATOR_2 = "_GVSIGCOPYPASTESEPARATOR2_";
73
        public static final String CLIPBOARD_SEPARATOR_3 = "_GVSIGCOPYPASTESEPARATOR3_";
74
        
75
        private static GeometryManager gm = null;
76
        private static Geometry nullgeo = null;
77
        private static GeometryOperationContext wktctxt = new GeometryOperationContext(); 
78
        
79
        
80
        public static GeometryManager geoman() {
81
                if (gm == null) {
82
                        gm = GeometryLocator.getGeometryManager();
83
                }
84
                return gm;
85
        }
86
        
87
        private static Geometry nullgeo() {
88
                if (nullgeo == null) {
89
                        try {
90
                                nullgeo = geoman().createNullGeometry(Geometry.SUBTYPES.GEOM2D);
91
                        } catch (CreateGeometryException e) {
92
                                logger.error("While creating null geometry", e);
93
                        }
94
                }
95
                return nullgeo;
96
                
97
        }
98
        
99
        private static GeometryOperationContext wktctxt(String val) {
100
                wktctxt.setAttribute(FromWKTGeometryOperationContext.TEXT, val);
101
                return wktctxt;
102
        }
103
        
104
        
105
        public static boolean clipboardSeemsToHaveValidFeatures() {
106
                
107
                if (!textInClipboard()) {
108
                        return false;
109
                }
110
                
111
                String clipb = PluginServices.getFromClipboard();
112
                
113
                if (clipb == null || clipb.length() < 5) {
114
                        return false;
115
                }
116
                
117
                String[] feats = clipb.split(CLIPBOARD_SEPARATOR_1);
118
                String[] feat_parts = feats[0].split(CLIPBOARD_SEPARATOR_2);
119
                
120
                if (feat_parts[0].length() > 10000) {
121
                        logger.info("Clipboard: First part (wkt) of feature description is long ("
122
                                        + feat_parts[0].length() +
123
                                        "). Not parsed. Returned 'true' meaning 'perhaps'.");
124
                        /*
125
                         * 10000 characters is about 400 vertices or more.
126
                         * This seems to be a large geometry and we are not
127
                         * going to parse it here because this method must be fast.
128
                         * We will say "true" so the user will try to paste it, and perhaps it will
129
                         * not work (a dialog message will show, for example)
130
                         */
131
                        return true;
132
                }
133
                
134
                Object geom_obj = null;
135
                
136
                try {
137
                        geom_obj = geoman().invokeOperation(
138
                                        FromWKT.NAME,
139
                                        nullgeo(),
140
                                        wktctxt(feat_parts[0]));
141
                } catch (Exception e) {
142
                        logger.info("Unable to parse short WKT: " + e.getMessage());
143
                        /*
144
                         * We discard the content of the clipboard after trying to parse only the
145
                         * first geometry (perhaps there were other geometries, but this method
146
                         * has to be very fast)
147
                         */
148
                        return false;
149
                }
150
                
151
                return geom_obj instanceof Geometry;
152
        }
153
        
154
        public static boolean textInClipboard() {
155
                
156
                return Toolkit.getDefaultToolkit().getSystemClipboard(
157
                                ).isDataFlavorAvailable(DataFlavor.stringFlavor);
158
        }
159

    
160
        public static StringBuilder toString(FeatureSet fset, FeatureType fty) throws DataException {
161
                
162
                StringBuilder strb = new StringBuilder();
163
                Feature feat = null;
164
                DisposableIterator diter = fset.fastIterator();
165
                while (diter.hasNext()) {
166
                        feat = (Feature) diter.next();
167
                        if (strb.length() > 0) {
168
                                strb.append(CLIPBOARD_SEPARATOR_1);
169
                        }
170
                        try {
171
                                appendFeatureText(strb, feat, fty);
172
                        } catch (Exception e) {
173
                                logger.info("One of the features in clipboard was not valid.", e);
174
                        }
175
                }
176
                diter.dispose();
177
                return strb;
178
        }
179
        
180
        private static void appendFeatureText(
181
                        StringBuilder strb,
182
                        Feature feat,
183
                        FeatureType fty) throws Exception {
184

    
185
                String aux = feat.getDefaultGeometry().convertToWKT();
186
                strb.append(aux);
187
                FeatureAttributeDescriptor[] atts = fty.getAttributeDescriptors();
188
                for (int i=0; i<atts.length; i++) {
189
                        if (atts[i].getType() != DataTypes.GEOMETRY) {
190
                                strb.append(CLIPBOARD_SEPARATOR_2);
191
                                appendAttribute(strb, feat, atts[i].getName(), atts[i].getType());
192
                        }
193
                }
194
                
195
        }
196

    
197
        private static void appendAttribute(
198
                        StringBuilder strb,
199
                        Feature feat,
200
                        String name,
201
                        int type) {
202
                
203
                strb.append(name);
204
                strb.append(CLIPBOARD_SEPARATOR_3);
205
                strb.append(type);
206
                strb.append(CLIPBOARD_SEPARATOR_3);
207
                strb.append(feat.get(name).toString());
208
        }
209

    
210
        public static List<EditableFeature> fromString(String str, FeatureStore fsto) {
211
                
212
                List<EditableFeature> resp = new ArrayList<EditableFeature>();
213
                
214
                if (!textInClipboard()) {
215
                        return resp;
216
                }
217

    
218
                if (str == null || str.length() < 5) {
219
                        return resp;
220
                }
221
                
222
                String[] feats = str.split(CLIPBOARD_SEPARATOR_1);
223
                EditableFeature item = null;
224
                
225
                for (int i=0; i<feats.length; i++) {
226
                        item = stringToFeature(feats[i], fsto);
227
                        if (item != null) {
228
                                resp.add(item);
229
                        }
230
                }
231
                return resp;
232
        }
233

    
234
        /**
235
         * Returns null if feature was not created
236
         * 
237
         * @param str
238
         * @param fsto
239
         * @return
240
         */
241
        private static EditableFeature stringToFeature(String str, FeatureStore fsto) {
242
                
243
                String[] feat_parts = str.split(CLIPBOARD_SEPARATOR_2);
244
                Object geom_obj = null;
245
                try {
246
                        geom_obj = geoman().invokeOperation(FromWKT.NAME,
247
                                        nullgeo(),
248
                                        wktctxt(feat_parts[0]));
249
                } catch (Exception e) {
250
                        logger.info("Unable to parse WKT: " + e.getMessage());
251
                        return null;
252
                }
253
                
254
                if (!(geom_obj instanceof Geometry)) {
255
                        // Parse issue, no feature
256
                        return null;
257
                }
258
                
259
                EditableFeature resp = null;
260
                try {
261
                        resp = fsto.createNewFeature(true);
262
                } catch (DataException e) {
263
                        logger.error("Unable to create feature in clipboard operation.", e);
264
                        return null;
265
                }
266
                
267
                // set geometry
268
                resp.setDefaultGeometry((Geometry) geom_obj);
269
                for (int i=1; i<feat_parts.length; i++) {
270
                        setAttribute(resp, feat_parts[i]);
271
                }
272
                return resp;
273
        }
274

    
275
        private static void setAttribute(EditableFeature resp, String att_desc) {
276
                
277
                String[] att_parts = att_desc.split(CLIPBOARD_SEPARATOR_3);
278
                if (att_parts.length != 3) {
279
                        // must be: name - type - value
280
                        return;
281
                }
282
                
283
                FeatureType fty = null;
284
                fty = resp.getType();
285
                
286
                if (fty.get(att_parts[0]) == null) {
287
                        // name not in feature type
288
                        return;
289
                }
290
                
291
                try {
292
                        resp.set(att_parts[0], att_parts[2]);
293
                } catch (Exception ex) {
294
                        /*
295
                        logger.info("Did not set value for field '" + att_parts[0]
296
                                        + "': " + ex.getMessage());
297
                        */
298
                }
299
        }
300
        
301
        
302
        
303
        
304

    
305
}