svn-gvsig-desktop / 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 @ 43510
History | View | Annotate | Download (10.8 KB)
1 |
/**
|
---|---|
2 |
* gvSIG. Desktop Geographic Information System.
|
3 |
*
|
4 |
* Copyright (C) 2007-2013 gvSIG Association.
|
5 |
*
|
6 |
* This program is free software; you can redistribute it and/or
|
7 |
* modify it under the terms of the GNU General Public License
|
8 |
* as published by the Free Software Foundation; either version 3
|
9 |
* of the License, or (at your option) any later version.
|
10 |
*
|
11 |
* This program is distributed in the hope that it will be useful,
|
12 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
* GNU General Public License for more details.
|
15 |
*
|
16 |
* You should have received a copy of the GNU General Public License
|
17 |
* along with this program; if not, write to the Free Software
|
18 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
19 |
* MA 02110-1301, USA.
|
20 |
*
|
21 |
* For any additional information, do not hesitate to contact us
|
22 |
* at info AT gvsig.com, or visit our website www.gvsig.com.
|
23 |
*/
|
24 |
package org.gvsig.app.extension.clipboard; |
25 |
|
26 |
import java.util.ArrayList; |
27 |
import java.util.Iterator; |
28 |
import java.util.List; |
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.plugins.Extension; |
38 |
import org.gvsig.andami.ui.mdiManager.IWindow; |
39 |
import org.gvsig.app.ApplicationLocator; |
40 |
import org.gvsig.app.extension.clipboard.util.FeatureTextUtils; |
41 |
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; |
45 |
import org.gvsig.fmap.dal.feature.EditableFeature; |
46 |
import org.gvsig.fmap.dal.feature.Feature; |
47 |
import org.gvsig.fmap.dal.feature.FeatureStore; |
48 |
import org.gvsig.fmap.geom.Geometry; |
49 |
import org.gvsig.fmap.geom.GeometryException; |
50 |
import org.gvsig.fmap.geom.primitive.Envelope; |
51 |
import org.gvsig.fmap.geom.type.GeometryType; |
52 |
import org.gvsig.fmap.mapcontext.MapContext; |
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 |
import org.gvsig.fmap.mapcontext.layers.vectorial.FLyrVect; |
57 |
import org.gvsig.i18n.Messages; |
58 |
|
59 |
|
60 |
public class PasteFeaturesFromClipboardExtension extends Extension { |
61 |
|
62 |
private static Logger logger = LoggerFactory.getLogger( |
63 |
PasteFeaturesFromClipboardExtension.class); |
64 |
|
65 |
public void initialize() { |
66 |
|
67 |
IconThemeHelper.registerIcon("action", "layer-modify-clipboard-paste", this); |
68 |
} |
69 |
|
70 |
public void execute(String actionCommand) { |
71 |
|
72 |
if (actionCommand.compareToIgnoreCase("layer-modify-clipboard-paste") != 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 |
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 |
|
272 |
@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) |
320 |
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++; |
342 |
} |
343 |
|
344 |
} |
345 |
|
346 |
if (numActiveVectorialEditable == 1 && numActiveVectorial == 1) |
347 |
return true; |
348 |
} |
349 |
return false; |
350 |
} |
351 |
|
352 |
/**
|
353 |
* Gets active window
|
354 |
* @return
|
355 |
*/
|
356 |
private IWindow actWin() {
|
357 |
return ApplicationLocator.getManager().getActiveWindow();
|
358 |
} |
359 |
|
360 |
} |