001: /* uDig - User Friendly Desktop Internet GIS client
002: * http://udig.refractions.net
003: * (C) 2004, Refractions Research Inc.
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation;
008: * version 2.1 of the License.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: */
015: package net.refractions.udig.style.sld.simple;
016:
017: import java.awt.Color;
018: import java.text.MessageFormat;
019:
020: import net.refractions.udig.style.sld.AbstractSimpleConfigurator;
021: import net.refractions.udig.style.sld.internal.Messages;
022: import net.refractions.udig.style.sld.internal.StolenColorEditor;
023: import net.refractions.udig.ui.graphics.SLDs;
024:
025: import org.eclipse.swt.SWT;
026: import org.eclipse.swt.events.KeyListener;
027: import org.eclipse.swt.events.ModifyEvent;
028: import org.eclipse.swt.events.ModifyListener;
029: import org.eclipse.swt.events.SelectionEvent;
030: import org.eclipse.swt.events.SelectionListener;
031: import org.eclipse.swt.widgets.Button;
032: import org.eclipse.swt.widgets.Combo;
033: import org.eclipse.swt.widgets.Composite;
034: import org.geotools.styling.Stroke;
035: import org.geotools.styling.StyleBuilder;
036:
037: /**
038: * Allows editing/viewing of a Style Layer Descriptor "Stroke".
039: * <p>
040: * Here is the pretty picture: <pre><code>
041: * +-+ +-------+ +------+ +------+
042: * Line: |x| | color | |size\/| |100%\/|
043: * +-+ +-------+ +------+ +------+
044: * </code></pre>
045: * </p>
046: * <p>
047: * Workflow:
048: * <ol>
049: * <li>createControl( parent ) - set up controls
050: * <li>setStroke( stroke, mode ) - provide content from SimpleStyleConfigurator
051: * <ol>
052: * <li> Symbolizer values copied into fields based on mode
053: * <li> fields copied into controls
054: * <li> controls enabled based on mode & fields
055: * </ol>
056: * <li>Listener.widgetSelected/modifyText - User performs an "edit"
057: * <li>Listener.sync( SelectionEvent ) - update fields with values of controls
058: * <li>fire( SelectionSevent ) - notify SimpleStyleConfigurator of change
059: * <li>getStroke( StyleBuilder ) - construct a Stroke based on fields
060: * </ul>
061: * </p>
062: * @author Jody Garnett
063: * @since 1.0.0
064: */
065: public class StrokeViewer {
066: boolean enabled = false;
067: Color color = null;
068: double width = Double.NaN;
069: double opacity = Double.NaN;
070:
071: Button on;
072: StolenColorEditor chooser;
073: Combo size;
074: Combo percent;
075:
076: private class Listener implements SelectionListener, ModifyListener {
077: public void widgetSelected(SelectionEvent e) {
078: sync(e);
079: };
080:
081: public void widgetDefaultSelected(SelectionEvent e) {
082: sync(e);
083: };
084:
085: public void modifyText(final ModifyEvent e) {
086: sync(AbstractSimpleConfigurator.selectionEvent(e));
087: };
088:
089: private void sync(SelectionEvent cause) {
090: try {
091: StrokeViewer.this .enabled = StrokeViewer.this .on
092: .getSelection();
093: StrokeViewer.this .color = StrokeViewer.this .chooser
094: .getColor();
095: try {
096: StrokeViewer.this .width = Integer
097: .parseInt(StrokeViewer.this .size.getText());
098: } catch (NumberFormatException nan) {
099: // well lets just leave width alone
100: }
101: try {
102: String ptext = StrokeViewer.this .percent.getText();
103: if (ptext.endsWith("%")) { //$NON-NLS-1$
104: ptext = ptext.substring(0, ptext.length() - 1);
105: StrokeViewer.this .opacity = Double
106: .parseDouble(ptext);
107: StrokeViewer.this .opacity /= 100.0;
108: } else {
109: StrokeViewer.this .opacity = Double
110: .parseDouble(ptext);
111: if (StrokeViewer.this .opacity > 1) {
112: StrokeViewer.this .opacity /= 100.0;
113: }
114: }
115: } catch (NumberFormatException nan) {
116: // well lets just leave opacity alone
117: }
118: fire(cause); // everything worked
119: } catch (Throwable t) {
120: // meh - should we of rolled back?
121: } finally {
122: StrokeViewer.this .chooser
123: .setEnabled(StrokeViewer.this .enabled);
124: StrokeViewer.this .size
125: .setEnabled(StrokeViewer.this .enabled);
126: StrokeViewer.this .percent
127: .setEnabled(StrokeViewer.this .enabled);
128: }
129: }
130:
131: };
132:
133: Listener sync = new Listener();
134:
135: /** TODO: replace w/ support for more then one listener - when needed */
136: SelectionListener listener = null;
137:
138: /**
139: * TODO summary sentence for createControl ...
140: *
141: * @param parent
142: * @param klisten
143: * @return Generated composite
144: */
145: public Composite createControl(Composite parent, KeyListener klisten) {
146: Composite part = AbstractSimpleConfigurator.subpart(parent,
147: Messages.SimpleStyleConfigurator_line_label);
148:
149: this .on = new Button(part, SWT.CHECK);
150:
151: this .chooser = new StolenColorEditor(part, this .sync);
152:
153: this .size = new Combo(part, SWT.DROP_DOWN);
154: this .size.setItems(new String[] { "1", "2", "3", "5", "10" }); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
155: this .size.setTextLimit(2);
156: this .size.addKeyListener(klisten);
157: this .size.setToolTipText(Messages.StrokeViewer_size_tooltip);
158:
159: this .percent = new Combo(part, SWT.DROP_DOWN);
160: this .percent.setItems(new String[] {
161: "0%", "25%", "50%", "75%", "100%" }); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$//$NON-NLS-4$//$NON-NLS-5$
162: this .percent.setTextLimit(3);
163: this .percent.addKeyListener(klisten);
164: this .percent
165: .setToolTipText(Messages.StrokeViewer_percent_tooltip);
166: return part;
167: }
168:
169: /**
170: * Accepts a listener that will be notified when content changes.
171: * @param listener1
172: */
173: public void addListener(SelectionListener listener1) {
174: this .listener = listener1;
175: }
176:
177: /**
178: * Remove listener.
179: * @param listener1
180: */
181: public void removeListener(SelectionListener listener1) {
182: if (this .listener == listener1)
183: this .listener = null;
184: }
185:
186: /**
187: * TODO summary sentence for fire ...
188: *
189: * @param event
190: */
191: protected void fire(SelectionEvent event) {
192: if (this .listener == null)
193: return;
194: this .listener.widgetSelected(event);
195: }
196:
197: void listen(boolean listen) {
198: if (listen) {
199: this .on.addSelectionListener(this .sync);
200: this .chooser.setListener(this .sync);
201: this .size.addSelectionListener(this .sync);
202: this .size.addModifyListener(this .sync);
203: this .percent.addSelectionListener(this .sync);
204: this .percent.addModifyListener(this .sync);
205: } else {
206: this .on.removeSelectionListener(this .sync);
207: this .chooser.setListener(null);
208: this .size.removeSelectionListener(this .sync);
209: this .size.removeModifyListener(this .sync);
210: this .percent.removeSelectionListener(this .sync);
211: this .percent.removeModifyListener(this .sync);
212: }
213: }
214:
215: /**
216: * TODO summary sentence for setStroke ...
217: *
218: * @param line
219: * @param mode
220: * @param defaultColor
221: */
222: public void setStroke(Stroke aLine, Mode mode, Color defaultColor) {
223: listen(false);
224: try {
225: boolean enabled = true;
226: Stroke line = aLine;
227:
228: if (line == null) {
229: StyleBuilder builder = new StyleBuilder();
230: line = builder.createStroke(defaultColor);
231: enabled = false;
232: }
233: this .enabled = enabled
234: && (mode != Mode.NONE && line != null);
235: this .color = SLDs.strokeColor(line);
236: this .width = SLDs.width(line);
237: this .opacity = SLDs.opacity(line);
238:
239: // Stroke is used in line, point and polygon
240: this .on.setEnabled(mode != Mode.NONE);
241: this .chooser.setColor(this .color);
242:
243: String text = MessageFormat.format(
244: "{0,number,#0}", this .width); //$NON-NLS-1$
245: this .size.setText(text);
246: this .size.select(this .size.indexOf(text));
247:
248: text = MessageFormat.format("{0,number,#0%}", this .opacity); //$NON-NLS-1$
249: this .percent.setText(text);
250: this .percent.select(this .percent.indexOf(text));
251:
252: this .on.setSelection(this .enabled);
253: this .chooser.setEnabled(this .enabled);
254: this .size.setEnabled(this .enabled);
255: this .percent.setEnabled(this .enabled);
256: } finally {
257: listen(true); // listen to user now
258: }
259: }
260:
261: /**
262: * Called to set up this "viewer" based on the provided symbolizer
263: *
264: * @param sym public void set( LineSymbolizer sym, Mode mode ){ listen( false ); // don't sync
265: * when setting up try { this.enabled = mode != Mode.NONE || sym == null; this.color =
266: * SLDs.color( sym ); this.width = SLDs.width( sym ); this.opacity = SLDs.lineOpacity(
267: * sym ); this.on.setEnabled( mode == Mode.LINE ); // forced on for line
268: * this.chooser.setColor( this.color ); String text = MessageFormat.format(
269: * "{0,number,#0}", this.width ); //$NON-NLS-1$ this.size.setText( text );
270: * this.size.select( this.size.indexOf( text )); text = MessageFormat.format(
271: * "{0,number,#0%}", this.opacity );//(int)( opacity * 100.0 ) + "%"; //$NON-NLS-1$
272: * this.percent.setText( text ); this.percent.select( this.percent.indexOf( text ) );
273: * this.on.setSelection( this.enabled ); this.chooser.setEnabled( this.enabled );
274: * this.size.setEnabled( this.enabled ); this.percent.setEnabled( this.enabled ); }
275: * finally { listen( true ); // listen to user now } }
276: */
277:
278: /**
279: * TODO summary sentence for getStroke ...
280: * @param build
281: *
282: * @return Stroke defined by this model
283: */
284: public Stroke getStroke(StyleBuilder build) {
285: if (!this.enabled)
286: return null;
287: if (this.opacity != Double.NaN) {
288: return build.createStroke(this.color, this.width,
289: this.opacity);
290: }
291: if (this.width != Double.NaN) {
292: return build.createStroke(this.color, this.width);
293: }
294: return build.createStroke(this.color);
295: }
296: }
|