Revision 40666
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