Revision 40666

View differences:

trunk/org.gvsig.desktop/org.gvsig.desktop.plugin/org.gvsig.editing.app/org.gvsig.editing.app.mainplugin/src/main/java/org/gvsig/editing/clipboard/CopyFeaturesToClipboardExtension.java
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;
25

  
26
import java.awt.Component;
27
import java.util.List;
28
import java.util.prefs.Preferences;
29

  
30
import javax.swing.JOptionPane;
31

  
32
import org.slf4j.Logger;
33
import org.slf4j.LoggerFactory;
34

  
35
import org.gvsig.andami.IconThemeHelper;
36
import org.gvsig.andami.PluginServices;
37
import org.gvsig.andami.messages.NotificationManager;
38
import org.gvsig.andami.plugins.Extension;
39
import org.gvsig.andami.ui.mdiManager.IWindow;
40
import org.gvsig.app.ApplicationLocator;
41
import org.gvsig.app.gui.preferencespage.GridPage;
42
import org.gvsig.app.project.documents.view.ViewDocument;
43
import org.gvsig.app.project.documents.view.gui.DefaultViewPanel;
44
import org.gvsig.app.project.documents.view.gui.IView;
45
import org.gvsig.editing.clipboard.util.FeatureTextUtils;
46
import org.gvsig.editing.gui.cad.CADTool;
47
import org.gvsig.editing.gui.tokenmarker.ConsoleToken;
48
import org.gvsig.fmap.dal.exception.DataException;
49
import org.gvsig.fmap.dal.exception.ReadException;
50
import org.gvsig.fmap.dal.feature.FeatureSelection;
51
import org.gvsig.fmap.dal.feature.FeatureStore;
52
import org.gvsig.fmap.mapcontext.layers.FLayer;
53
import org.gvsig.fmap.mapcontext.layers.vectorial.FLyrVect;
54
import org.gvsig.fmap.mapcontrol.MapControl;
55
import org.gvsig.i18n.Messages;
56
import org.gvsig.utils.console.jedit.KeywordMap;
57
import org.gvsig.utils.console.jedit.Token;
58

  
59

  
60
public class CopyFeaturesToClipboardExtension extends Extension {
61
    
62
    private static Logger logger = LoggerFactory.getLogger(
63
    		CopyFeaturesToClipboardExtension.class);
64

  
65
	public void initialize() {
66
		
67
		IconThemeHelper.registerIcon("action", "layer-modify-clipboard-copy", this);
68
	}
69

  
70
	public void execute(String actionCommand) {
71

  
72
		if (actionCommand.compareToIgnoreCase("layer-modify-clipboard-copy") != 0) {
73
			return;
74
		}
75
		
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
				FeatureSelection sele = null;
88
				FeatureStore fsto = null;
89
				try {
90
					fsto = vect.getFeatureStore();
91
					sele = (FeatureSelection) fsto.getSelection();
92
					StringBuilder strb = FeatureTextUtils.toString(
93
							sele, fsto.getDefaultFeatureType());
94
					/*
95
					 * Put selected features in clipboard.
96
					 */
97
					PluginServices.putInClipboard(strb.toString());
98

  
99
					JOptionPane.showMessageDialog(
100
							ApplicationLocator.getManager().getRootComponent(),
101
							Messages.getText("_Number_of_features_copied_to_clipboard")
102
							+ ":   " + sele.getSize() + "    ",
103
							Messages.getText("_Copy_selected_features_to_clipboard"),
104
							JOptionPane.INFORMATION_MESSAGE);
105
					
106
				} catch (DataException e) {
107
					logger.error("While getting store and selection. ", e);
108
				}
109
			}
110
		}		
111
		
112
	}
113

  
114
	public boolean isEnabled() {
115
		
116
		/*
117
		 * It's enabled if there is exactly one vector layer in the active view
118
		 * and it has a selection 
119
		 */
120
		
121
		IWindow actw = actWin();
122
		
123
		if (actw instanceof IView) {
124
			
125
			IView vw = (IView) actw;
126
			FLayer[] act_lyr = vw.getMapControl().getMapContext().getLayers().getActives();
127
			if (act_lyr == null || act_lyr.length != 1
128
					|| !(act_lyr[0] instanceof FLyrVect)) {
129
				return false;
130
				
131
			} else {
132
				FLyrVect vect = (FLyrVect) act_lyr[0];
133
				FeatureSelection sele = null;
134
				long sele_count = 0;
135
				try {
136
					sele = (FeatureSelection) vect.getFeatureStore().getSelection();
137
					sele_count = sele.getSize(); 
138
				} catch (DataException e) {
139
					logger.error("While getting store. ", e);
140
					return false;
141
				}
142
				return sele_count > 0;
143
			}
144
			
145
		} else {
146
			return false;
147
		}
148
	}
149

  
150
	public boolean isVisible() {
151

  
152
		return actWin() instanceof IView;
153
	}
154
	
155
	/**
156
	 * Gets active window
157
	 * @return
158
	 */
159
	private IWindow actWin() {
160
		return ApplicationLocator.getManager().getActiveWindow();
161
	}
162

  
163

  
164
}
trunk/org.gvsig.desktop/org.gvsig.desktop.plugin/org.gvsig.editing.app/org.gvsig.editing.app.mainplugin/src/main/java/org/gvsig/editing/clipboard/PasteFeaturesFromClipboardExtension.java
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;
25

  
26
import java.awt.Component;
27
import java.util.ArrayList;
28
import java.util.Iterator;
29
import java.util.List;
30
import java.util.prefs.Preferences;
31

  
32
import javax.swing.JOptionPane;
33

  
34
import org.slf4j.Logger;
35
import org.slf4j.LoggerFactory;
36

  
37
import org.gvsig.andami.IconThemeHelper;
38
import org.gvsig.andami.PluginServices;
39
import org.gvsig.andami.messages.NotificationManager;
40
import org.gvsig.andami.plugins.Extension;
41
import org.gvsig.andami.ui.mdiManager.IWindow;
42
import org.gvsig.app.ApplicationLocator;
43
import org.gvsig.app.gui.preferencespage.GridPage;
44
import org.gvsig.app.project.documents.view.ViewDocument;
45
import org.gvsig.app.project.documents.view.gui.DefaultViewPanel;
46
import org.gvsig.app.project.documents.view.gui.IView;
47
import org.gvsig.editing.EditionUtilities;
48
import org.gvsig.editing.clipboard.util.FeatureTextUtils;
49
import org.gvsig.editing.gui.cad.CADTool;
50
import org.gvsig.editing.gui.tokenmarker.ConsoleToken;
51
import org.gvsig.fmap.dal.exception.DataException;
52
import org.gvsig.fmap.dal.exception.ReadException;
53
import org.gvsig.fmap.dal.feature.EditableFeature;
54
import org.gvsig.fmap.dal.feature.Feature;
55
import org.gvsig.fmap.dal.feature.FeatureSelection;
56
import org.gvsig.fmap.dal.feature.FeatureStore;
57
import org.gvsig.fmap.geom.Geometry;
58
import org.gvsig.fmap.geom.GeometryException;
59
import org.gvsig.fmap.geom.primitive.Envelope;
60
import org.gvsig.fmap.geom.type.GeometryType;
61
import org.gvsig.fmap.mapcontext.MapContext;
62
import org.gvsig.fmap.mapcontext.layers.FLayer;
63
import org.gvsig.fmap.mapcontext.layers.vectorial.FLyrVect;
64
import org.gvsig.fmap.mapcontrol.MapControl;
65
import org.gvsig.i18n.Messages;
66
import org.gvsig.utils.console.jedit.KeywordMap;
67
import org.gvsig.utils.console.jedit.Token;
68

  
69

  
70
public class PasteFeaturesFromClipboardExtension extends Extension {
71
    
72
    private static Logger logger = LoggerFactory.getLogger(
73
    		PasteFeaturesFromClipboardExtension.class);
74

  
75
	public void initialize() {
76
		
77
		IconThemeHelper.registerIcon("action", "layer-modify-clipboard-paste", this);
78
	}
79

  
80
	public void execute(String actionCommand) {
81
		
82
		if (actionCommand.compareToIgnoreCase("layer-modify-clipboard-paste") != 0) {
83
			return;
84
		}
85

  
86
		IWindow actw = actWin();
87
		
88
		if (actw instanceof IView) {
89
			
90
			IView vw = (IView) actw;
91
			FLayer[] act_lyr = vw.getMapControl().getMapContext().getLayers().getActives();
92
			if (act_lyr == null || act_lyr.length != 1
93
					|| !(act_lyr[0] instanceof FLyrVect)) {
94
				
95
			} else {
96
				FLyrVect vect = (FLyrVect) act_lyr[0];
97
				if (vect.isEditing()) {
98
					
99
					// Discard if no text data or empty:
100
					if (!FeatureTextUtils.textInClipboard()) {
101
						JOptionPane.showMessageDialog(
102
								ApplicationLocator.getManager().getRootComponent(),
103
								Messages.getText("_Clipboard_has_no_valid_info_or_is_empty"),
104
								Messages.getText("_Pasting_features_from_clipboard"),
105
								JOptionPane.INFORMATION_MESSAGE);
106
						return;
107
					}
108
					String clipb = PluginServices.getFromClipboard();
109
					if (clipb == null || clipb.length() == 0) {
110
						JOptionPane.showMessageDialog(
111
								ApplicationLocator.getManager().getRootComponent(),
112
								Messages.getText("_Clipboard_has_no_valid_info_or_is_empty"),
113
								Messages.getText("_Pasting_features_from_clipboard"),
114
								JOptionPane.INFORMATION_MESSAGE);
115
						return;
116
					}
117
					
118
					// ============================================
119
					// ============================================
120

  
121
					FeatureStore fsto = vect.getFeatureStore();
122
					List<EditableFeature> try_feats = FeatureTextUtils.fromString(clipb, fsto);
123
					/*
124
					 * This method will check geometry type
125
					 */
126
					List<EditableFeature> added_feats = addFeatures(fsto, try_feats);
127
					
128
					int n_orig = try_feats.size();
129
					int n_added = added_feats.size();
130
					int n_disc = n_orig - n_added;  
131
					
132
					String msg = "";
133
					
134
					if (n_orig == 0) {
135
						msg = Messages.getText("_No_features_found_in_clipboard");
136
					} else {
137
						msg = Messages.getText("_Number_of_features_pasted_from_clipboard");
138
						msg = msg + ":   " + n_added + "    \n";
139
						msg = msg + Messages.getText("_Number_of_features_from_clipboard_discarded_due_to_bad_format");
140
						msg = msg + ":   " + n_disc + "    ";
141
					}
142
					
143
					
144
					if (n_added > 0) {
145
						
146
						msg = msg + "\n\n" +
147
								Messages.getText("_Zoom_to_added_features_question");
148
						int user_opt = JOptionPane.showConfirmDialog(
149
								ApplicationLocator.getManager().getRootComponent(),
150
								msg,
151
								Messages.getText("_Pasting_features_from_clipboard"),
152
								JOptionPane.YES_NO_OPTION);
153
						if (user_opt == JOptionPane.YES_OPTION) {
154
							try {
155
								zoomToExtent(added_feats,
156
										vw.getMapControl().getMapContext());
157
							} catch (Exception ex) {
158
								JOptionPane.showMessageDialog(
159
										ApplicationLocator.getManager().getRootComponent(),
160
										Messages.getText("_Unable_to_zoom_to_features")
161
										+ ": " + ex.getMessage(),
162
										Messages.getText("_Pasting_features_from_clipboard"),
163
										JOptionPane.ERROR_MESSAGE);
164
							}
165
							
166
						} else {
167
							// Repaint view
168
							vw.getMapControl().getMapContext().invalidate();
169
						}
170
						
171
					} else {
172
						JOptionPane.showMessageDialog(
173
								ApplicationLocator.getManager().getRootComponent(),
174
								msg,
175
								Messages.getText("_Pasting_features_from_clipboard"),
176
								JOptionPane.INFORMATION_MESSAGE);
177
					}
178
				}
179
			}
180
			
181
		}		
182
		
183
		
184
	}
185
	
186
	private void zoomToExtent(
187
			List<EditableFeature> added_feats,
188
			MapContext mco) throws Exception {
189

  
190
		Envelope env = null;
191
		Envelope itemenv = null;
192
		Iterator<EditableFeature> iter = added_feats.iterator();
193
		Feature feat = null;
194
		while (iter.hasNext()) {
195
			feat = (Feature) iter.next();
196
			itemenv = feat.getDefaultGeometry().getEnvelope();
197
			if (itemenv != null) {
198
				if (env == null) {
199
					itemenv = (Envelope) itemenv.clone();
200
					env = itemenv;
201
				} else {
202
					env.add(itemenv);
203
				}
204
			}
205
		}
206
		if (env == null) {
207
			throw new GeometryException(new Exception("All envelopes are null."));
208
		}
209
		mco.getViewPort().setEnvelope(env);
210
	}
211

  
212
	/**
213
	 * Add features if geometry is of right type.
214
	 * Returns number of features added.
215
	 * If returned number is negative, it means there were errors.
216
	 * Example: -5 means 5 were added and there were errors with other geometries.
217
	 * 
218
	 * @param fsto
219
	 * @param add_feats
220
	 * @throws DataException 
221
	 */
222
	private List<EditableFeature> addFeatures(
223
			FeatureStore fsto,
224
			List<EditableFeature> add_feats) {
225
		
226
		List<EditableFeature> really_added = new ArrayList<EditableFeature>();
227
		
228
		Iterator<EditableFeature> iter = add_feats.iterator();
229
		EditableFeature item = null;
230
		Geometry geom = null;
231
		GeometryType good_gt = null;
232
		int good_dimensions = 0;
233
		
234
		try {
235
			good_gt = fsto.getDefaultFeatureType().getDefaultGeometryAttribute().getGeomType();
236
			good_dimensions = FeatureTextUtils.geoman().create(good_gt).getDimension();
237
		} catch (Exception e) {
238
			logger.error("While getting geom type.", e);
239
			return really_added;
240
		}
241
		
242
		while (iter.hasNext()) {
243
			item = iter.next();
244
			geom = item.getDefaultGeometry();
245
			/*
246
			 * Same number of dimensions and compatible types
247
			 */
248
			if ((geom.getDimension() == good_dimensions)
249
					&&
250
					(geom.getGeometryType().isTypeOf(good_gt)
251
					|| simpleTypeOf(geom.getGeometryType(), good_gt))
252
					) {
253
				try {
254
					fsto.insert(item);
255
					really_added.add(item);
256
				} catch (DataException e) {
257
					/*
258
					 * This error will cause that "really_added"
259
					 * will be shorter than "add_feats" and the user
260
					 * must be notified of that when the process ends.
261
					 */
262
					logger.info("Error while inserting feature from clipboard: " + e.getMessage());
263
				}
264
			}
265
		}
266
		
267
		return really_added;
268
	}
269

  
270
	private boolean simpleTypeOf(GeometryType simplet, GeometryType multit) {
271
		
272
		return (multit.getType() == Geometry.TYPES.MULTISURFACE
273
				&& simplet.isTypeOf(Geometry.TYPES.SURFACE))
274
				||
275
				(multit.getType() == Geometry.TYPES.MULTICURVE
276
				&& simplet.isTypeOf(Geometry.TYPES.CURVE))
277
				||
278
				(multit.getType() == Geometry.TYPES.MULTIPOINT
279
				&& simplet.getType() == Geometry.TYPES.POINT);
280
	}
281

  
282
	public boolean isEnabled() {
283

  
284
		/*
285
		 * I think it's better to make it enabled always when the active layer
286
		 * is in editing mode, so it's not necessary to refresh the state of the button
287
		 * (with a zoom or changing window, etc). The content of the clipboard can change
288
		 * and gvSIG does not know. Of course, if the user clicks the button,
289
		 * a dialog will tell if the clipboard is empty or has invalid data.
290
		 */
291
		return isVisible();
292

  
293
		/*
294
		 * Discarded by now:
295
		 * 
296
		 * It's enabled if the active layer is a vector layer
297
		 * in editing mode and the clipboard seems to have valid features
298
		 * 
299
		IWindow actw = actWin();
300
		if (actw instanceof IView) {
301
			
302
			IView vw = (IView) actw;
303
			FLayer[] act_lyr = vw.getMapControl().getMapContext().getLayers().getActives();
304
			if (act_lyr == null || act_lyr.length != 1
305
					|| !(act_lyr[0] instanceof FLyrVect)) {
306
				return false;
307
				
308
			} else {
309
				FLyrVect vect = (FLyrVect) act_lyr[0];
310
				if (vect.isEditing()) {
311
					return FeatureTextUtils.clipboardSeemsToHaveValidFeatures();
312
				} else {
313
					return false;
314
				}
315
			}
316
			
317
		} else {
318
			return false;
319
		}
320
		*/
321
	}
322

  
323

  
324
	public boolean isVisible() {
325
		if (EditionUtilities.getEditionStatus() ==
326
				EditionUtilities.EDITION_STATUS_ONE_VECTORIAL_LAYER_ACTIVE_AND_EDITABLE) {
327
			return true;
328
		}
329
		return false;
330
	}
331
	
332
	/**
333
	 * Gets active window
334
	 * @return
335
	 */
336
	private IWindow actWin() {
337
		return ApplicationLocator.getManager().getActiveWindow();
338
	}
339

  
340
}
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
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
}
trunk/org.gvsig.desktop/org.gvsig.desktop.plugin/org.gvsig.editing.app/org.gvsig.editing.app.mainplugin/src/main/resources-plugin/config.xml
832 832
                    />
833 833
            </tool-bar>             
834 834
        </extension>
835
        
836
        <!--
837
        ***********************************
838
        Copy/paste features between layers
839
        using system clipboard
840
        ***********************************
841
        -->
842
        
843
        <extension class-name="org.gvsig.editing.clipboard.CopyFeaturesToClipboardExtension"
844
            description="Copy selected features to system clipboard"
845
            active="true">
846

  
847
            <action 
848
                name="layer-modify-clipboard-copy"
849
                label="_Copy_selected_features_to_clipboard" 
850
                tooltip="_Copy_selected_features_to_clipboard" 
851
                position="601105000"
852
                action-command="layer-modify-clipboard-copy"
853
                icon="layer-modify-clipboard-copy"
854
                accelerator=""
855
                />
856
            
857
            <menu
858
                name="layer-modify-clipboard-copy"
859
                text="Layer/Modify/_Copy_selected_features_to_clipboard"
860
                />
861
            
862
            <tool-bar name="layer_modify">
863
                <action-tool 
864
                    name="layer-modify-clipboard-copy"
865
                    />
866
            </tool-bar>             
867
        </extension>
868
        
869
        <extension class-name="org.gvsig.editing.clipboard.PasteFeaturesFromClipboardExtension"
870
            description="Paste features from system clipboard into editing layer"
871
            active="true">
872

  
873
            <action 
874
                name="layer-modify-clipboard-paste"
875
                label="_Paste_features_from_clipboard" 
876
                tooltip="_Paste_features_from_clipboard" 
877
                position="601105100"
878
                action-command="layer-modify-clipboard-paste"
879
                icon="layer-modify-clipboard-paste"
880
                accelerator=""
881
                />
882
            
883
            <menu
884
                name="layer-modify-clipboard-paste"
885
                text="Layer/Modify/_Paste_features_from_clipboard"
886
                />
887
            
888
            <tool-bar name="layer_modify">
889
                <action-tool 
890
                    name="layer-modify-clipboard-paste"
891
                    />
892
            </tool-bar>             
893
        </extension>
835 894
		
836 895
	</extensions>
837 896
</plugin-config>
trunk/org.gvsig.desktop/org.gvsig.desktop.plugin/org.gvsig.editing.app/org.gvsig.editing.app.mainplugin/src/main/resources-plugin/i18n/text.properties
389 389
Insert=Insertar
390 390
Modify=Modificar
391 391
_Unable_to_create_geometry=No se pudo crear la geometr?a
392
_Number_of_features_copied_to_clipboard=N?mero de elementos copiados al portapapeles
393
_Number_of_features_pasted_from_clipboard=N?mero de elementos a?adidos desde portapapeles
394
_Number_of_features_from_clipboard_discarded_due_to_bad_format=N?mero de elementos del portapapeles descartados por error en formato
395
_Pasting_features_from_clipboard=A?adiendo elementos desde portapapeles
396
_Zoom_to_added_features_question=?Desea desplazar la vista hasta los elementos a?adidos?
397
_Unable_to_zoom_to_features=No ha sido posible desplazar la vista hasta los elementos
398
_Copy_selected_features_to_clipboard=Copiar elementos seleccionados al portapapeles
399
_Paste_features_from_clipboard=A?adir elementos desde el portapapeles
400
_Clipboard_has_no_valid_info_or_is_empty=El portapapeles no tiene datos v?lidos o est? vac?o
401
_No_features_found_in_clipboard=No se han encontrado elementos en el portapapeles
402
_Unable_to_save_edits_The_cause_is=No es posible guardar los cambios. La causa es
392 403

  
404

  
trunk/org.gvsig.desktop/org.gvsig.desktop.plugin/org.gvsig.editing.app/org.gvsig.editing.app.mainplugin/src/main/resources-plugin/i18n/text_en.properties
386 386
Insert=Insert
387 387
Modify=Modify
388 388
_Unable_to_create_geometry=Unable to create geometry
389
_Number_of_features_copied_to_clipboard=Number of features copied to clipboard
390
_Number_of_features_pasted_from_clipboard=Number of features pasted from clipboard
391
_Number_of_features_from_clipboard_discarded_due_to_bad_format=Number of features from clipboard discarded due to bad format
392
_Pasting_features_from_clipboard=Pasting features from clipboard
393
_Zoom_to_added_features_question=Zoom view to added features?
394
_Unable_to_zoom_to_features=Unable to zoom to features
395
_Copy_selected_features_to_clipboard=Copy selected features to clipboard
396
_Paste_features_from_clipboard=Paste features from clipboard
397
_Clipboard_has_no_valid_info_or_is_empty=Clipboard has no valid data or is empty
398
_No_features_found_in_clipboard=No features found in clipboard
399
_Unable_to_save_edits_The_cause_is=Unable to save edits. The cause is
389 400

  
401

  
402

  
403

  
404

  

Also available in: Unified diff