001: /*******************************************************************************
002: * Copyright (c) 2004, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: * Daniel Megert daniel_megert@ch.ibm.com Bug 169696
011: *******************************************************************************/package org.eclipse.ui.ide.dialogs;
012:
013: import java.nio.charset.Charset;
014: import java.nio.charset.IllegalCharsetNameException;
015: import java.util.List;
016:
017: import org.eclipse.jface.preference.FieldEditor;
018: import org.eclipse.jface.preference.IPreferenceStore;
019: import org.eclipse.osgi.util.NLS;
020: import org.eclipse.swt.SWT;
021: import org.eclipse.swt.events.KeyAdapter;
022: import org.eclipse.swt.events.KeyEvent;
023: import org.eclipse.swt.events.SelectionAdapter;
024: import org.eclipse.swt.events.SelectionEvent;
025: import org.eclipse.swt.layout.GridData;
026: import org.eclipse.swt.layout.GridLayout;
027: import org.eclipse.swt.widgets.Button;
028: import org.eclipse.swt.widgets.Combo;
029: import org.eclipse.swt.widgets.Composite;
030: import org.eclipse.swt.widgets.Group;
031: import org.eclipse.ui.WorkbenchEncoding;
032: import org.eclipse.ui.ide.IDEEncoding;
033: import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
034:
035: /**
036: * The abstract superclass of field editors used to set an encoding. Any user
037: * entered encodings will be added to the list of encodings available via
038: * {@link org.eclipse.ui.ide.IDEEncoding}.
039: * <p>
040: * Subclasses may extend, but must call <code>createEncodingGroup</code>
041: * during <code>doFillIntoGrid</code>.
042: * </p>
043: *
044: * @see org.eclipse.ui.ide.IDEEncoding
045: * @since 3.1
046: */
047: public abstract class AbstractEncodingFieldEditor extends FieldEditor {
048:
049: private Composite container;
050:
051: private Button defaultEncodingButton;
052:
053: private String defaultEnc;
054:
055: private Button otherEncodingButton;
056:
057: private Combo encodingCombo;
058:
059: private boolean isValid = true;
060:
061: private String oldSelectedEncoding;
062:
063: private String groupTitle = IDEWorkbenchMessages.WorkbenchPreference_encoding;
064:
065: /**
066: * Creates a new encoding field editor with no settings set.
067: */
068: protected AbstractEncodingFieldEditor() {
069: super ();
070: }
071:
072: /**
073: * Creates a new encoding field editor with the given preference name, label
074: * and parent.
075: *
076: * @param name
077: * the name of the preference this field editor works on
078: * @param labelText
079: * the label text of the field editor
080: * @param parent
081: * the parent of the field editor's control
082: */
083: protected AbstractEncodingFieldEditor(String name,
084: String labelText, Composite parent) {
085: super (name, labelText, parent);
086: }
087:
088: /**
089: * Creates a new encoding field editor with the given preference name, label
090: * and parent.
091: *
092: * @param name
093: * the name of the preference this field editor works on
094: * @param labelText
095: * the label text of the field editor
096: * @param groupTitle
097: * the title for the field editor's control. If groupTitle is
098: * <code>null</code> the control will be unlabelled
099: * (by default a {@link Composite} instead of a {@link Group}.
100: * @param parent
101: * the parent of the field editor's control
102: * @see AbstractEncodingFieldEditor#setGroupTitle(String)
103: * @since 3.3
104: */
105: protected AbstractEncodingFieldEditor(String name,
106: String labelText, String groupTitle, Composite parent) {
107: init(name, labelText);
108: this .groupTitle = groupTitle;
109: createControl(parent);
110: }
111:
112: /*
113: * (non-Javadoc)
114: *
115: * @see org.eclipse.jface.preference.FieldEditor#adjustForNumColumns(int)
116: */
117: protected void adjustForNumColumns(int numColumns) {
118: ((GridData) getContainer().getLayoutData()).horizontalSpan = numColumns;
119: }
120:
121: /*
122: * (non-Javadoc)
123: *
124: * @see org.eclipse.jface.preference.FieldEditor#doFillIntoGrid(org.eclipse.swt.widgets.Composite,
125: * int)
126: */
127: protected void doFillIntoGrid(Composite parent, int numColumns) {
128: container = createEncodingGroup(parent, numColumns);
129: }
130:
131: /*
132: * (non-Javadoc)
133: *
134: * @see org.eclipse.jface.preference.FieldEditor#doLoad()
135: */
136: protected void doLoad() {
137: if (encodingCombo != null) {
138: List encodings = IDEEncoding.getIDEEncodings();
139: String resourcePreference = getStoredValue();
140: populateEncodingsCombo(encodings, resourcePreference);
141: updateEncodingState(resourcePreference == null);
142: }
143: }
144:
145: /**
146: * Returns the value that is currently stored for the encoding.
147: *
148: * @return the currently stored encoding
149: */
150: protected abstract String getStoredValue();
151:
152: /*
153: * (non-Javadoc)
154: *
155: * @see org.eclipse.jface.preference.FieldEditor#doLoadDefault()
156: */
157: protected void doLoadDefault() {
158: updateEncodingState(true);
159: }
160:
161: /*
162: * (non-Javadoc)
163: *
164: * @see org.eclipse.jface.preference.FieldEditor#getNumberOfControls()
165: */
166: public int getNumberOfControls() {
167: return 1;
168: }
169:
170: /*
171: * (non-Javadoc)
172: *
173: * @see org.eclipse.jface.preference.FieldEditor#isValid()
174: */
175: public boolean isValid() {
176: return isValid;
177: }
178:
179: /*
180: * (non-Javadoc)
181: *
182: * @see org.eclipse.jface.preference.FieldEditor#refreshValidState()
183: */
184: protected void refreshValidState() {
185: updateValidState();
186: }
187:
188: /*
189: * (non-Javadoc)
190: *
191: * @see org.eclipse.jface.preference.FieldEditor#setPreferenceStore(org.eclipse.jface.preference.IPreferenceStore)
192: */
193: public void setPreferenceStore(IPreferenceStore store) {
194: super .setPreferenceStore(store);
195: defaultEnc = store.getDefaultString(getPreferenceName());
196: updateDefaultEncoding();
197: }
198:
199: private void updateDefaultEncoding() {
200: defaultEncodingButton.setText(defaultButtonText());
201: }
202:
203: private Composite getContainer() {
204: return container;
205: }
206:
207: /**
208: * Creates a composite with all the encoding controls.
209: * <p>
210: * Subclasses may extend.
211: * </p>
212: *
213: * @param parent
214: * the parent widget
215: * @param numColumns
216: * the number of columns in the parent
217: * @return the group control
218: */
219: protected Composite createEncodingGroup(Composite parent,
220: int numColumns) {
221:
222: Composite topControl;
223: GridLayout layout = new GridLayout();
224: layout.numColumns = 2;
225:
226: if (groupTitle == null) {
227: topControl = new Composite(parent, SWT.NONE);
228: layout.marginWidth = 0;
229: layout.marginHeight = 0;
230: } else {
231: Group top = new Group(parent, SWT.NONE);
232: top.setText(groupTitle);
233: topControl = top;
234: }
235:
236: GridData data = new GridData(GridData.FILL_HORIZONTAL);
237: topControl.setLayoutData(data);
238: topControl.setLayout(layout);
239:
240: SelectionAdapter buttonListener = new SelectionAdapter() {
241: public void widgetSelected(SelectionEvent e) {
242: updateEncodingState(defaultEncodingButton
243: .getSelection());
244: updateValidState();
245: }
246: };
247:
248: defaultEncodingButton = new Button(topControl, SWT.RADIO);
249: defaultEnc = findDefaultEncoding();
250: defaultEncodingButton.setText(defaultButtonText());
251: data = new GridData();
252: data.horizontalSpan = 2;
253: defaultEncodingButton.setLayoutData(data);
254: defaultEncodingButton.addSelectionListener(buttonListener);
255:
256: otherEncodingButton = new Button(topControl, SWT.RADIO);
257: otherEncodingButton
258: .setText(IDEWorkbenchMessages.WorkbenchPreference_otherEncoding);
259: otherEncodingButton.addSelectionListener(buttonListener);
260:
261: encodingCombo = new Combo(topControl, SWT.NONE);
262: data = new GridData();
263: encodingCombo.setLayoutData(data);
264: encodingCombo.addSelectionListener(new SelectionAdapter() {
265: /*
266: * (non-Javadoc)
267: *
268: * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
269: */
270: public void widgetSelected(SelectionEvent e) {
271: updateValidState();
272: }
273: });
274: encodingCombo.addKeyListener(new KeyAdapter() {
275: /*
276: * (non-Javadoc)
277: *
278: * @see org.eclipse.swt.events.KeyListener#keyReleased(org.eclipse.swt.events.KeyEvent)
279: */
280: public void keyReleased(KeyEvent e) {
281: updateValidState();
282: }
283: });
284:
285: return topControl;
286: }
287:
288: /*
289: * (non-Javadoc)
290: *
291: * @see org.eclipse.jface.preference.FieldEditor#setEnabled(boolean,
292: * org.eclipse.swt.widgets.Composite)
293: * @since 3.3
294: */
295: public void setEnabled(boolean enabled, Composite parent) {
296: if (container != null)
297: container.setEnabled(enabled);
298: if (defaultEncodingButton != null)
299: defaultEncodingButton.setEnabled(enabled);
300: if (otherEncodingButton != null)
301: otherEncodingButton.setEnabled(enabled);
302: if (encodingCombo != null)
303: encodingCombo.setEnabled(enabled);
304:
305: }
306:
307: /**
308: * Returns the default encoding for the object being shown.
309: *
310: * @return the default encoding for the object being shown
311: */
312: protected String findDefaultEncoding() {
313: return WorkbenchEncoding.getWorkbenchDefaultEncoding();
314: }
315:
316: /**
317: * Returns the text for the default encoding button.
318: *
319: * @return the text for the default encoding button
320: */
321: protected String defaultButtonText() {
322: return NLS
323: .bind(
324: IDEWorkbenchMessages.WorkbenchPreference_defaultEncoding,
325: defaultEnc);
326: }
327:
328: /**
329: * Populates the encodings combo. Sets the text based on the selected
330: * encoding. If there is no selected encoding, the text is set to the
331: * default encoding.
332: *
333: * @param encodings
334: * the list of encodings (list of String)
335: * @param selectedEncoding
336: * the selected encoding, or <code>null</code>
337: */
338: private void populateEncodingsCombo(List encodings,
339: String selectedEncoding) {
340: String[] encodingStrings = new String[encodings.size()];
341: encodings.toArray(encodingStrings);
342: encodingCombo.setItems(encodingStrings);
343:
344: if (selectedEncoding == null) {
345: encodingCombo.setText(getDefaultEnc());
346: } else {
347: encodingCombo.setText(selectedEncoding);
348: }
349: }
350:
351: private void updateEncodingState(boolean useDefault) {
352: defaultEncodingButton.setSelection(useDefault);
353: otherEncodingButton.setSelection(!useDefault);
354: if (useDefault) {
355: encodingCombo.setText(getDefaultEnc());
356: }
357: encodingCombo.setEnabled(!useDefault);
358: setPresentsDefaultValue(useDefault);
359: updateValidState();
360: }
361:
362: private void updateValidState() {
363: boolean isValidNow = isEncodingValid();
364: if (isValidNow != isValid) {
365: isValid = isValidNow;
366: if (isValid) {
367: clearErrorMessage();
368: } else {
369: showErrorMessage(IDEWorkbenchMessages.WorkbenchPreference_unsupportedEncoding);
370: }
371: fireStateChanged(IS_VALID, !isValid, isValid);
372: }
373: String newValue = getSelectedEncoding();
374: if (isValid && !newValue.equals(oldSelectedEncoding)) {
375: fireValueChanged(VALUE, oldSelectedEncoding, newValue);
376: oldSelectedEncoding = newValue;
377: }
378: }
379:
380: /**
381: * Returns the currently selected encoding.
382: *
383: * @return the currently selected encoding
384: */
385: protected String getSelectedEncoding() {
386: if (defaultEncodingButton.getSelection()) {
387: return defaultEnc;
388: }
389: return encodingCombo.getText();
390: }
391:
392: private boolean isEncodingValid() {
393: return defaultEncodingButton.getSelection()
394: || isValidEncoding(encodingCombo.getText());
395: }
396:
397: /**
398: * Returns whether or not the given encoding is valid.
399: *
400: * @param enc
401: * the encoding to validate
402: * @return <code>true</code> if the encoding is valid, <code>false</code>
403: * otherwise
404: */
405: private boolean isValidEncoding(String enc) {
406: try {
407: return Charset.isSupported(enc);
408: } catch (IllegalCharsetNameException e) {
409: // This is a valid exception
410: return false;
411: }
412:
413: }
414:
415: /**
416: * Returns the default encoding.
417: *
418: * @return the default encoding
419: */
420: protected String getDefaultEnc() {
421: return defaultEnc;
422: }
423:
424: /**
425: * Returns whether or not the encoding setting changed.
426: *
427: * @param encodingSetting
428: * the setting from the page.
429: * @return boolean <code>true</code> if the resource encoding is the same
430: * as before.
431: */
432: protected boolean hasSameEncoding(String encodingSetting) {
433:
434: String current = getStoredValue();
435:
436: if (encodingSetting == null) {
437: // Changed if default is selected and there is no setting
438: return current == null || current.length() == 0;
439: }
440: return encodingSetting.equals(current);
441: }
442:
443: /**
444: * Return whether or not the default has been selected.
445: *
446: * @return <code>true</code> if the default button has been selected.
447: */
448: boolean isDefaultSelected() {
449: return defaultEncodingButton.getSelection();
450: }
451:
452: /**
453: * Set the title of the group to groupTitle. If this is not called a default
454: * title is used. If groupTitle is <code>null</code> the control will be
455: * unlabelled (by default a {@link Composite} instead of a {@link Group}.
456: *
457: * <strong>NOTE</strong> this value must be set before
458: * {@link #createControl(Composite)} is called or it will be ignored.
459: *
460: * @param groupTitle
461: * The groupTitle to set.
462: * @since 3.3
463: */
464: public void setGroupTitle(String groupTitle) {
465: this.groupTitle = groupTitle;
466: }
467:
468: }
|