Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/port80/eclipse/util/HexColorFieldEditor.java


1   package com.port80.eclipse.util;
2   
3   import org.eclipse.jface.preference.FieldEditor;
4   import org.eclipse.jface.resource.StringConverter;
5   import org.eclipse.swt.SWT;
6   import org.eclipse.swt.events.DisposeEvent;
7   import org.eclipse.swt.events.DisposeListener;
8   import org.eclipse.swt.events.FocusAdapter;
9   import org.eclipse.swt.events.FocusEvent;
10  import org.eclipse.swt.events.KeyAdapter;
11  import org.eclipse.swt.events.KeyEvent;
12  import org.eclipse.swt.graphics.GC;
13  import org.eclipse.swt.graphics.Point;
14  import org.eclipse.swt.graphics.RGB;
15  import org.eclipse.swt.layout.GridData;
16  import org.eclipse.swt.widgets.Composite;
17  import org.eclipse.swt.widgets.Text;
18  
19  import com.port80.util.Sprint;
20  
21  /**
22   * A preference field editor to enter color RGB value in hex.
23   * Modified from StringFieldEditor.  Unfortunately, StringFieldEditor.oldValue is private
24   * and make it difficult to just extend StringFieldEditor and override doLoad() ... etc.
25   * 
26   * @author chrisl
27   */
28  public class HexColorFieldEditor extends FieldEditor {
29  
30    ////////////////////////////////////////////////////////////////////////
31  
32    /**
33     * Text limit constant (value <code>-1</code>) indicating unlimited
34     * text limit and width.
35     */
36    public static int UNLIMITED = -1;
37  
38    /**
39     * Old text value.
40     */
41    protected String oldValue;
42  
43    /**
44     * Cached valid state.
45     */
46    private boolean isValid;
47  
48    /**
49     * The text field, or <code>null</code> if none.
50     */
51    private Text textField;
52  
53    /**
54     * Width of text field in characters; initially unlimited.
55     */
56    private int widthInChars = UNLIMITED;
57  
58    /**
59     * Text limit of text field in characters; initially unlimited.
60     */
61    private int textLimit = UNLIMITED;
62  
63    /**
64     * The error message, or <code>null</code> if none.
65     */
66    private String errorMessage;
67  
68    /**
69     * Indicates whether the empty string is legal;
70     * <code>true</code> by default.
71     */
72    private boolean emptyStringAllowed = false;
73  
74    ////////////////////////////////////////////////////////////////////////
75  
76    /**
77     * Constructor for HexColorFieldEditor.
78     */
79    public HexColorFieldEditor() {
80    }
81  
82    /**
83     * Creates a string field editor.
84     * Use the method <code>setTextLimit</code> to limit the text.
85     * 
86     * @param name the name of the preference this field editor works on
87     * @param labelText the label text of the field editor
88     * @param width the width of the text input field in characters,
89     *      or <code>UNLIMITED</code> for no limit
90     * @param parent the parent of the field editor's control
91     * @since 2.0
92     */
93    public HexColorFieldEditor(String name, String labelText, int width, Composite parent) {
94      init(name, labelText);
95      widthInChars = width;
96      isValid = false;
97      errorMessage = UtilPlugin.getResourceString("HexColorFieldEditor.errorMessage"); //$NON-NLS-1$
98      createControl(parent);
99    }
100 
101   /**
102    * Creates a string field editor of unlimited width.
103    * Use the method <code>setTextLimit</code> to limit the text.
104    * 
105    * @param name the name of the preference this field editor works on
106    * @param labelText the label text of the field editor
107    * @param parent the parent of the field editor's control
108    */
109   public HexColorFieldEditor(String name, String labelText, Composite parent) {
110     this(name, labelText, UNLIMITED, parent);
111   }
112 
113   ////////////////////////////////////////////////////////////////////////
114 
115   /**
116    * Returns the error message that will be displayed when and if 
117    * an error occurs.
118    *
119    * @return the error message, or <code>null</code> if none
120    */
121   public String getErrorMessage() {
122     return errorMessage;
123   }
124 
125   /* (non-Javadoc)
126    * Method declared on FieldEditor.
127    */
128   public int getNumberOfControls() {
129     return 2;
130   }
131 
132   /**
133    * Returns the field editor's value.
134    *
135    * @return the current value
136    */
137   public String getStringValue() {
138     if (textField != null)
139       return textField.getText();
140     else
141       return getPreferenceStore().getString(getPreferenceName());
142   }
143 
144   /**
145    * Returns this field editor's text control.
146    * <p>
147    * The control is created if it does not yet exist
148    * </p>
149    *
150    * @param parent the parent
151    * @return the text control
152    */
153   public Text getTextControl(Composite parent) {
154     if (textField == null) {
155       textField = new Text(parent, SWT.SINGLE | SWT.BORDER);
156       textField.setFont(parent.getFont());
157       textField.addKeyListener(new KeyAdapter() {
158         public void keyPressed(KeyEvent e) {
159           valueChanged();
160         }
161       });
162       textField.addFocusListener(new FocusAdapter() {
163         public void focusGained(FocusEvent e) {
164           refreshValidState();
165         }
166         public void focusLost(FocusEvent e) {
167           handleFocusLost();
168         }
169       });
170       textField.addDisposeListener(new DisposeListener() {
171         public void widgetDisposed(DisposeEvent event) {
172           dispose();
173         }
174       });
175       if (textLimit > 0) { //Only set limits above 0 - see SWT spec
176         textField.setTextLimit(textLimit);
177       }
178     } else {
179       checkParent(textField, parent);
180     }
181     return textField;
182   }
183 
184   /**
185    * Returns whether an empty string is a valid value.
186    *
187    * @return <code>true</code> if an empty string is a valid value, and
188    *  <code>false</code> if an empty string is invalid
189    * @see #setEmptyStringAllowed
190    */
191   public boolean isEmptyStringAllowed() {
192     return emptyStringAllowed;
193   }
194   /* (non-Javadoc)
195    * Method declared on FieldEditor.
196    */
197   public boolean isValid() {
198     return isValid;
199   }
200 
201   /**
202    * Sets whether the empty string is a valid value or not.
203    *
204    * @param b <code>true</code> if the empty string is allowed,
205    *  and <code>false</code> if it is considered invalid
206    */
207   public void setEmptyStringAllowed(boolean b) {
208     emptyStringAllowed = b;
209   }
210 
211   /**
212    * Sets the error message that will be displayed when and if 
213    * an error occurs.
214    *
215    * @param message the error message
216    */
217   public void setErrorMessage(String message) {
218     errorMessage = message;
219   }
220   /* (non-Javadoc)
221    * Method declared on FieldEditor.
222    */
223   public void setFocus() {
224     if (textField != null) {
225       textField.setFocus();
226     }
227   }
228 
229   /**
230    * Sets this field editor's value.
231    *
232    * @param value the new value, or <code>null</code> meaning the empty string
233    */
234   public void setStringValue(String value) {
235     if (textField != null) {
236       if (value == null)
237         value = ""; //$NON-NLS-1$
238       oldValue = textField.getText();
239       if (!oldValue.equals(value)) {
240         textField.setText(value);
241         valueChanged();
242       }
243     }
244   }
245 
246   /**
247    * Sets this text field's text limit.
248    *
249    * @param limit the limit on the number of character in the text
250    *  input field, or <code>UNLIMITED</code> for no limit
251   
252    */
253   public void setTextLimit(int limit) {
254     textLimit = limit;
255     if (textField != null)
256       textField.setTextLimit(limit);
257   }
258 
259   /**
260    * Shows the error message set via <code>setErrorMessage</code>.
261    */
262   public void showErrorMessage() {
263     showErrorMessage(errorMessage);
264   }
265 
266   public void dispose() {
267     super.dispose();
268     textField = null;
269   }
270   
271   ////////////////////////////////////////////////////////////////////////
272 
273   /* (non-Javadoc)
274    * Method declared on FieldEditor.
275    */
276   protected void adjustForNumColumns(int numColumns) {
277     GridData gd = (GridData) textField.getLayoutData();
278     gd.horizontalSpan = numColumns - 1;
279     // We only grab excess space if we have to
280     // If another field editor has more columns then
281     // we assume it is setting the width.
282     gd.grabExcessHorizontalSpace = gd.horizontalSpan == 1;
283   }
284 
285   /**
286    * Checks whether the text input field contains a valid value or not.
287    *
288    * @return <code>true</code> if the field value is valid,
289    *   and <code>false</code> if invalid
290    */
291   protected boolean checkState() {
292     boolean result = false;
293     if (textField == null)
294       result = false;
295     String text = textField.getText();
296     if(text.startsWith("#")) text=text.substring(1);
297     if (text == null)
298       result = false;
299     result = (text.trim().length() > 0) || emptyStringAllowed;
300     //
301     // Check for non-hex. digits.
302     char c;
303     for (int i = 0; i < text.length(); ++i) {
304       c = text.charAt(i);
305       if (!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))) {
306         result = false;
307         break;
308       }
309     }
310     //
311     // call hook for subclasses
312     result = result && doCheckState();
313     //
314     if (result)
315       clearErrorMessage();
316     else
317       showErrorMessage(errorMessage);
318     return result;
319   }
320 
321   /**
322    * Hook for subclasses to do additional specific state checks.
323    * <p>
324    * The default implementation of this framework method does
325    * nothing and returns <code>true</code>.  Subclasses should 
326    * override this method to specific state checks.
327    * </p>
328    *
329    * @return <code>true</code> if the field value is valid,
330    *   and <code>false</code> if invalid
331    */
332   protected boolean doCheckState() {
333     return true;
334   }
335 
336   /**
337    * Fills this field editor's basic controls into the given parent.
338    * <p>
339    * The string field implementation of this <code>FieldEditor</code>
340    * framework method contributes the text field. Subclasses may override
341    * but must call <code>super.doFillIntoGrid</code>.
342    * </p>
343    */
344   protected void doFillIntoGrid(Composite parent, int numColumns) {
345     getLabelControl(parent);
346 
347     textField = getTextControl(parent);
348     GridData gd = new GridData();
349     gd.horizontalSpan = numColumns - 1;
350     if (widthInChars != UNLIMITED) {
351       GC gc = new GC(textField);
352       try {
353         Point extent = gc.textExtent("X"); //$NON-NLS-1$
354         gd.widthHint = widthInChars * extent.x;
355       } finally {
356         gc.dispose();
357       }
358     } else {
359       gd.horizontalAlignment = GridData.FILL;
360       gd.grabExcessHorizontalSpace = true;
361     }
362     textField.setLayoutData(gd);
363   }
364   /* (non-Javadoc)
365    * Method declared on FieldEditor.
366    */
367   protected void doLoad() {
368     if (textField != null) {
369       String value = getPreferenceStore().getString(getPreferenceName());
370       RGB rgb = StringConverter.asRGB(value);
371       value = Sprint.f("#%06X").a(rgb.red << 16 | rgb.green << 8 | rgb.blue).end();
372       textField.setText(value);
373       oldValue = value;
374     }
375   }
376   /* (non-Javadoc)
377    * Method declared on FieldEditor.
378    */
379   protected void doLoadDefault() {
380     if (textField != null) {
381       String value = getPreferenceStore().getDefaultString(getPreferenceName());
382       RGB rgb = StringConverter.asRGB(value);
383       value = Sprint.f("#%06X").a(rgb.red << 16 | rgb.green << 8 | rgb.blue).end();
384       textField.setText(value);
385     }
386     valueChanged();
387   }
388   /* (non-Javadoc)
389    * Method declared on FieldEditor.
390    */
391   protected void doStore() {
392     String text = textField.getText();
393     if(text.startsWith("#")) text=text.substring(1);
394     int n = -1;
395     try {
396       n = Integer.parseInt(text, 16);
397     } catch (NumberFormatException e) {
398     }
399     if (n < 0) {
400       text = getPreferenceStore().getDefaultString(getPreferenceName());
401     } else {
402       text = StringConverter.asString(new RGB((n >> 16) & 0xff, (n >> 8) & 0xff, n & 0xff));
403     }
404     getPreferenceStore().setValue(getPreferenceName(), text);
405   }
406 
407   /**
408    * Returns this field editor's text control.
409    *
410    * @param parent the parent
411    * @return the text control, or <code>null</code> if no
412    * text field is created yet
413    */
414   protected Text getTextControl() {
415     return textField;
416   }
417 
418   /* (non-Javadoc)
419    * Method declared on FieldEditor.
420    */
421   protected void refreshValidState() {
422     isValid = checkState();
423   }
424 
425   protected void setValid(boolean isvalid) {
426     isValid = isvalid;
427   }
428 
429   /**
430    * Informs this field editor's listener, if it has one, about a change
431    * to the value (<code>VALUE</code> property) provided that the old and
432    * new values are different.
433    * <p>
434    * This hook is <em>not</em> called when the text is initialized 
435    * (or reset to the default value) from the preference store.
436    * </p>
437    */
438   protected void valueChanged() {
439     setPresentsDefaultValue(false);
440     boolean oldState = isValid;
441     refreshValidState();
442 
443     if (isValid != oldState)
444       fireStateChanged(IS_VALID, oldState, isValid);
445 
446     String newValue = textField.getText();
447     if (!newValue.equals(oldValue)) {
448       fireValueChanged(VALUE, oldValue, newValue);
449       oldValue = newValue;
450     }
451   }
452   
453   void handleFocusLost() {
454     clearErrorMessage();
455   }
456   
457   ////////////////////////////////////////////////////////////////////////
458 
459 }