/* uDig - User Friendly Desktop Internet GIS client
* http://udig.refractions.net
* (C) 2004, Refractions Research Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.swt.styling.simple;
import java.awt.Color;
import java.text.MessageFormat;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.geotools.styling.SLD;
import org.geotools.styling.Stroke;
import org.geotools.styling.StyleBuilder;
import org.geotools.swt.utils.Messages;
/**
* Allows editing/viewing of a Style Layer Descriptor "Stroke".
* <p>
* Here is the pretty picture: <pre><code>
* +-+ +-------+ +------+ +------+
* Line: |x| | color | |size\/| |100%\/|
* +-+ +-------+ +------+ +------+
* </code></pre>
* </p>
* <p>
* Workflow:
* <ol>
* <li>createControl( parent ) - set up controls
* <li>setStroke( stroke, mode ) - provide content from SimpleStyleConfigurator
* <ol>
* <li> Symbolizer values copied into fields based on mode
* <li> fields copied into controls
* <li> controls enabled based on mode & fields
* </ol>
* <li>Listener.widgetSelected/modifyText - User performs an "edit"
* <li>Listener.sync( SelectionEvent ) - update fields with values of controls
* <li>fire( SelectionSevent ) - notify SimpleStyleConfigurator of change
* <li>getStroke( StyleBuilder ) - construct a Stroke based on fields
* </ul>
* </p>
* @author Jody Garnett
* @since 1.0.0
*
*
* @source $URL: http://svn.osgeo.org/geotools/trunk/modules/unsupported/swt/src/main/java/org/geotools/swt/styling/simple/StrokeViewer.java $
*/
public class StrokeViewer {
boolean enabled = false;
Color color = null;
double width = Double.NaN;
double opacity = Double.NaN;
Button on;
StolenColorEditor chooser;
Combo size;
Combo percent;
private class Listener implements SelectionListener, ModifyListener {
public void widgetSelected( SelectionEvent e ) {
sync(e);
};
public void widgetDefaultSelected( SelectionEvent e ) {
sync(e);
};
public void modifyText( final ModifyEvent e ) {
sync(AbstractSimpleConfigurator.selectionEvent(e));
};
private void sync( SelectionEvent cause ) {
try {
StrokeViewer.this.enabled = StrokeViewer.this.on.getSelection();
StrokeViewer.this.color = StrokeViewer.this.chooser.getColor();
try {
StrokeViewer.this.width = Integer.parseInt(StrokeViewer.this.size.getText());
} catch (NumberFormatException nan) {
// well lets just leave width alone
}
try {
String ptext = StrokeViewer.this.percent.getText();
if (ptext.endsWith("%")) { //$NON-NLS-1$
ptext = ptext.substring(0, ptext.length() - 1);
StrokeViewer.this.opacity = Double.parseDouble(ptext);
StrokeViewer.this.opacity /= 100.0;
} else {
StrokeViewer.this.opacity = Double.parseDouble(ptext);
if (StrokeViewer.this.opacity > 1) {
StrokeViewer.this.opacity /= 100.0;
}
}
} catch (NumberFormatException nan) {
// well lets just leave opacity alone
}
fire(cause); // everything worked
} catch (Throwable t) {
// meh - should we of rolled back?
} finally {
StrokeViewer.this.chooser.setEnabled(StrokeViewer.this.enabled);
StrokeViewer.this.size.setEnabled(StrokeViewer.this.enabled);
StrokeViewer.this.percent.setEnabled(StrokeViewer.this.enabled);
}
}
};
Listener sync = new Listener();
/** TODO: replace w/ support for more then one listener - when needed */
SelectionListener listener = null;
/**
* TODO summary sentence for createControl ...
*
* @param parent
* @param klisten
* @return Generated composite
*/
public Composite createControl( Composite parent, KeyListener klisten ) {
Composite part = AbstractSimpleConfigurator.subpart(parent, Messages.getString("SimpleStyleConfigurator_line_label"));
this.on = new Button(part, SWT.CHECK);
this.chooser = new StolenColorEditor(part, this.sync);
this.size = new Combo(part, SWT.DROP_DOWN);
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$
this.size.setTextLimit(2);
this.size.addKeyListener(klisten);
this.size.setToolTipText(Messages.getString("StrokeViewer_size_tooltip"));
this.percent = new Combo(part, SWT.DROP_DOWN);
this.percent.setItems(new String[]{"0%", "25%", "50%", "75%", "100%"}); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$//$NON-NLS-4$//$NON-NLS-5$
this.percent.setTextLimit(3);
this.percent.addKeyListener(klisten);
this.percent.setToolTipText(Messages.getString("StrokeViewer_percent_tooltip"));
return part;
}
/**
* Accepts a listener that will be notified when content changes.
* @param listener1
*/
public void addListener( SelectionListener listener1 ) {
this.listener = listener1;
}
/**
* Remove listener.
* @param listener1
*/
public void removeListener( SelectionListener listener1 ) {
if (this.listener == listener1)
this.listener = null;
}
/**
* TODO summary sentence for fire ...
*
* @param event
*/
protected void fire( SelectionEvent event ) {
if (this.listener == null)
return;
this.listener.widgetSelected(event);
}
void listen( boolean listen ) {
if (listen) {
this.on.addSelectionListener(this.sync);
this.chooser.setListener(this.sync);
this.size.addSelectionListener(this.sync);
this.size.addModifyListener(this.sync);
this.percent.addSelectionListener(this.sync);
this.percent.addModifyListener(this.sync);
} else {
this.on.removeSelectionListener(this.sync);
this.chooser.setListener(null);
this.size.removeSelectionListener(this.sync);
this.size.removeModifyListener(this.sync);
this.percent.removeSelectionListener(this.sync);
this.percent.removeModifyListener(this.sync);
}
}
/**
* TODO summary sentence for setStroke ...
*
* @param line
* @param mode
* @param defaultColor
*/
public void setStroke( Stroke aLine, Mode mode, Color defaultColor ) {
listen(false);
try {
boolean enabled = true;
Stroke line = aLine;
if (line == null) {
StyleBuilder builder = new StyleBuilder();
line = builder.createStroke(defaultColor);
enabled = false;
}
this.enabled = enabled && (mode != Mode.NONE && line != null);
this.color = SLD.color(line);
this.width = SLD.width(line);
this.opacity = SLD.opacity(line);
// Stroke is used in line, point and polygon
this.on.setEnabled(mode != Mode.NONE);
this.chooser.setColor(this.color);
String text = MessageFormat.format("{0,number,#0}", this.width); //$NON-NLS-1$
this.size.setText(text);
this.size.select(this.size.indexOf(text));
text = MessageFormat.format("{0,number,#0%}", this.opacity); //$NON-NLS-1$
this.percent.setText(text);
this.percent.select(this.percent.indexOf(text));
this.on.setSelection(this.enabled);
this.chooser.setEnabled(this.enabled);
this.size.setEnabled(this.enabled);
this.percent.setEnabled(this.enabled);
} finally {
listen(true); // listen to user now
}
}
/**
* TODO summary sentence for getStroke ...
* @param build
*
* @return Stroke defined by this model
*/
public Stroke getStroke( StyleBuilder build ) {
if (!this.enabled)
return null;
if (!Double.isNaN(this.opacity)) {
return build.createStroke(this.color, this.width, this.opacity);
}
if (!Double.isNaN(this.width)) {
return build.createStroke(this.color, this.width);
}
return build.createStroke(this.color);
}
}