001: package com.vividsolutions.jump.workbench.ui.cursortool;
002:
003: import java.awt.AlphaComposite;
004: import java.awt.Color;
005: import java.awt.Composite;
006: import java.awt.Cursor;
007: import java.awt.Graphics2D;
008: import java.awt.Shape;
009: import java.awt.event.FocusAdapter;
010: import java.awt.event.FocusEvent;
011: import java.awt.geom.NoninvertibleTransformException;
012: import java.awt.geom.Point2D;
013: import java.util.Arrays;
014: import java.util.Collection;
015: import java.util.Collections;
016: import java.util.Date;
017:
018: import javax.swing.BorderFactory;
019: import javax.swing.Icon;
020: import javax.swing.ImageIcon;
021: import javax.swing.JLabel;
022: import javax.swing.JTextArea;
023: import javax.swing.SwingUtilities;
024: import javax.swing.event.CaretEvent;
025: import javax.swing.event.CaretListener;
026:
027: import com.vividsolutions.jts.geom.Coordinate;
028: import com.vividsolutions.jts.geom.Envelope;
029: import com.vividsolutions.jts.geom.GeometryFactory;
030: import com.vividsolutions.jts.util.Assert;
031: import com.vividsolutions.jump.I18N;
032: import com.vividsolutions.jump.feature.AttributeType;
033: import com.vividsolutions.jump.feature.BasicFeature;
034: import com.vividsolutions.jump.feature.Feature;
035: import com.vividsolutions.jump.feature.FeatureDataset;
036: import com.vividsolutions.jump.feature.FeatureSchema;
037: import com.vividsolutions.jump.workbench.model.FeatureEventType;
038: import com.vividsolutions.jump.workbench.model.Layer;
039: import com.vividsolutions.jump.workbench.model.LayerManager;
040: import com.vividsolutions.jump.workbench.model.StandardCategoryNames;
041: import com.vividsolutions.jump.workbench.model.UndoableCommand;
042: import com.vividsolutions.jump.workbench.ui.EditTransaction;
043: import com.vividsolutions.jump.workbench.ui.GUIUtil;
044: import com.vividsolutions.jump.workbench.ui.LayerViewPanel;
045: import com.vividsolutions.jump.workbench.ui.Viewport;
046: import com.vividsolutions.jump.workbench.ui.images.IconLoader;
047: import com.vividsolutions.jump.workbench.ui.renderer.style.Style;
048: import com.vividsolutions.jump.workbench.ui.snap.SnapToFeaturesPolicy;
049:
050: //Notes layer can now be saved with a task [LDB 12-15-2005]
051:
052: public class NoteTool extends NClickTool {
053:
054: private LayerViewPanel panel;
055:
056: private abstract class Mode {
057:
058: private Feature noteFeature;
059:
060: public Mode(Feature noteFeature) {
061: this .noteFeature = noteFeature;
062: }
063:
064: public Coordinate location() {
065: return noteFeature.getGeometry().getCoordinate();
066: }
067:
068: public abstract void commit(String text);
069:
070: protected Feature getNoteFeature() {
071: return noteFeature;
072: }
073:
074: public abstract String initialText();
075: }
076:
077: private class CreateMode extends Mode {
078:
079: public CreateMode(final Coordinate location) {
080: super (new BasicFeature(layer()
081: .getFeatureCollectionWrapper().getFeatureSchema()) {
082:
083: {
084: setAttribute(NoteStyle.CREATED, new Date());
085: setAttribute(NoteStyle.GEOMETRY,
086: new GeometryFactory().createPoint(location));
087: }
088: });
089: }
090:
091: public void commit(String text) {
092: if (text.length() > 0) {
093: disableAutomaticInitialZooming();
094: getNoteFeature().setAttribute(NoteStyle.MODIFIED,
095: new Date());
096: getNoteFeature().setAttribute(NoteStyle.TEXT, text);
097: EditTransaction transaction = new EditTransaction(
098: Collections.EMPTY_LIST, getName(), layer(),
099: isRollingBackInvalidEdits(), true, getPanel());
100: transaction.createFeature(getNoteFeature());
101: transaction.commit();
102: }
103: }
104:
105: public String initialText() {
106: return "";
107: }
108: }
109:
110: private class EditMode extends Mode {
111:
112: public EditMode(Feature noteFeature) {
113: super (noteFeature);
114: }
115:
116: public void commit(final String text) {
117: final Date modifiedDate = new Date();
118: final Date oldModifiedDate = (Date) getNoteFeature()
119: .getAttribute(NoteStyle.MODIFIED);
120: final String oldText = getNoteFeature().getString(
121: NoteStyle.TEXT);
122: execute(new UndoableCommand(getName()) {
123:
124: public void execute() {
125: update(getNoteFeature(), text, modifiedDate,
126: layer());
127: }
128:
129: public void unexecute() {
130: update(getNoteFeature(), oldText, oldModifiedDate,
131: layer());
132: }
133: });
134: }
135:
136: private void update(Feature noteFeature, String text,
137: Date modifiedDate, Layer layer) {
138: noteFeature.setAttribute(NoteStyle.MODIFIED, modifiedDate);
139: noteFeature.setAttribute(NoteStyle.TEXT, text);
140: layer.getLayerManager().fireFeaturesChanged(
141: Collections.singleton(noteFeature),
142: FeatureEventType.ATTRIBUTES_MODIFIED, layer);
143: }
144:
145: public String initialText() {
146: return getNoteFeature().getString(NoteStyle.TEXT);
147: }
148: }
149:
150: public NoteTool() {
151: super (1);
152: panel = getPanel();
153: getSnapManager().addPolicies(
154: Collections.singleton(new SnapToFeaturesPolicy()));
155: textArea = NoteStyle.createTextArea();
156: textArea.addFocusListener(new FocusAdapter() {
157:
158: public void focusLost(FocusEvent e) {
159: if (panelContainsTextArea()) {
160: boolean doit = (textArea.getText().trim().length() > 0);
161: if (doit)
162: getPanel().getLayerManager()
163: .getUndoableEditReceiver()
164: .startReceiving();
165: removeTextAreaFromPanel();
166: if (doit)
167: getPanel().getLayerManager()
168: .getUndoableEditReceiver()
169: .stopReceiving();
170: }
171: }
172: });
173: }
174:
175: private JTextArea textArea;
176:
177: private Mode mode;
178:
179: public void deactivate() {
180: if (panelContainsTextArea()) {
181: boolean doit = (textArea.getText().trim().length() > 0);
182: if (doit)
183: getPanel().getLayerManager().getUndoableEditReceiver()
184: .startReceiving();
185: removeTextAreaFromPanel();
186: if (doit)
187: getPanel().getLayerManager().getUndoableEditReceiver()
188: .stopReceiving();
189: }
190: super .deactivate();
191: }
192:
193: public Cursor getCursor() {
194: return cursor;
195: }
196:
197: protected void gestureFinished() throws Exception {
198: reportNothingToUndoYet();
199: Feature noteFeatureAtClick = noteFeature(getModelDestination());
200: removeTextAreaFromPanel();
201: mode = mode(noteFeatureAtClick, getModelDestination());
202:
203: //Since focusLost will be called after gestureFinished() is called
204: //any testArea added here would be removed.
205: //However the invokeLater will be called after any other calls to removeTextAreaFromPanel()
206: SwingUtilities.invokeLater(new Runnable() {
207: public void run() {
208: try {
209: addTextAreaToPanel(mode.location());
210: } catch (NoninvertibleTransformException e) {
211: getPanel().getContext().handleThrowable(e);
212: }
213: }
214: });
215: }
216:
217: private Mode mode(Feature noteFeatureAtClick, Coordinate click) {
218: return noteFeatureAtClick == null ? (Mode) new CreateMode(click)
219: : new EditMode(noteFeatureAtClick);
220: }
221:
222: private Feature noteFeature(Coordinate click) {
223: return noteFeature(new Envelope(click, new Coordinate(click.x
224: - NoteStyle.WIDTH / scale(), click.y + NoteStyle.HEIGHT
225: / scale())));
226: }
227:
228: private Feature noteFeature(Envelope envelope) {
229: return (Feature) firstOrNull(layer()
230: .getFeatureCollectionWrapper().query(envelope));
231: }
232:
233: private Object firstOrNull(Collection items) {
234: return !items.isEmpty() ? items.iterator().next() : null;
235: }
236:
237: private double scale() {
238: return getPanel().getViewport().getScale();
239: }
240:
241: private void addTextAreaToPanel(Coordinate location)
242: throws NoninvertibleTransformException {
243: layer().setVisible(true);
244: if (getPanel().getLayout() != null) {
245: getPanel().setLayout(null);
246: }
247: textArea.setText(mode.initialText());
248: textArea.setBackground(layer().getBasicStyle().getFillColor());
249: getPanel().add(textArea);
250:
251: textArea.addCaretListener(new CaretListener() {
252: public void caretUpdate(CaretEvent e) {
253: JTextArea textArea = (JTextArea) e.getSource();
254: int ht = textArea.getPreferredSize().height;
255: int wt = textArea.getPreferredSize().width;
256: if (ht < NoteStyle.HEIGHT)
257: ht = NoteStyle.HEIGHT;
258: if (wt < NoteStyle.WIDTH)
259: wt = NoteStyle.WIDTH;
260: int x = textArea.getBounds().x;
261: int y = textArea.getBounds().y;
262: textArea.setBounds(x, y, wt, ht);
263: }
264: });
265:
266: int ht = textArea.getPreferredSize().height;
267: int wt = textArea.getPreferredSize().width;
268: if (ht < NoteStyle.HEIGHT)
269: ht = NoteStyle.HEIGHT;
270: if (wt < NoteStyle.WIDTH)
271: wt = NoteStyle.WIDTH;
272: textArea.setBounds((int) getPanel().getViewport().toViewPoint(
273: location).getX(), (int) getPanel().getViewport()
274: .toViewPoint(location).getY(), wt, ht);
275:
276: //textArea.setBounds((int) getPanel().getViewport().toViewPoint(location)
277: // .getX(), (int) getPanel().getViewport().toViewPoint(location)
278: // .getY(), NoteStyle.WIDTH, NoteStyle.HEIGHT);
279: textArea.requestFocus();
280: }
281:
282: private boolean panelContainsTextArea() {
283: return Arrays.asList(getPanel().getComponents()).contains(
284: textArea);
285: }
286:
287: private void removeTextAreaFromPanel() {
288: if (!panelContainsTextArea()) {
289: return;
290: }
291: mode.commit(textArea.getText().trim());
292: getPanel().remove(textArea);
293: getPanel().super Repaint();
294: }
295:
296: private void disableAutomaticInitialZooming() {
297: getPanel().setViewportInitialized(true);
298: }
299:
300: public Layer layer() {
301: LayerManager layerManager = getPanel().getLayerManager();
302: if (layerManager.getLayer(NoteStyle.NAME) != null) {
303: return layerManager.getLayer(NoteStyle.NAME);
304: }
305: Layer noteLayer = new Layer(NoteStyle.NAME, Color.yellow
306: .brighter().brighter(), new FeatureDataset(NoteStyle
307: .createFeatureSchema()), layerManager);
308:
309: boolean firingEvents = layerManager.isFiringEvents();
310: layerManager.setFiringEvents(false);
311: try {
312: noteLayer.addStyle(new NoteStyle());
313: } finally {
314: layerManager.setFiringEvents(firingEvents);
315: }
316: layerManager.addLayer(StandardCategoryNames.SYSTEM, noteLayer);
317: return noteLayer;
318: }
319:
320: public Icon getIcon() {
321: return icon;
322: }
323:
324: protected Shape getShape() throws NoninvertibleTransformException {
325: return null;
326: }
327:
328: private ImageIcon icon = IconLoader.icon("sticky.png");
329:
330: private Cursor cursor = GUIUtil.createCursorFromIcon(icon
331: .getImage());
332:
333: }
|