001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 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: *******************************************************************************/package org.eclipse.jdt.internal.ui.preferences;
011:
012: import java.io.FileInputStream;
013: import java.io.FileOutputStream;
014: import java.io.IOException;
015: import java.util.ArrayList;
016: import java.util.List;
017: import java.util.Properties;
018:
019: import org.eclipse.core.runtime.IStatus;
020:
021: import org.eclipse.core.resources.IProject;
022:
023: import org.eclipse.swt.SWT;
024: import org.eclipse.swt.graphics.Image;
025: import org.eclipse.swt.layout.GridData;
026: import org.eclipse.swt.layout.GridLayout;
027: import org.eclipse.swt.widgets.Composite;
028: import org.eclipse.swt.widgets.Control;
029: import org.eclipse.swt.widgets.FileDialog;
030:
031: import org.eclipse.jface.dialogs.Dialog;
032: import org.eclipse.jface.dialogs.IDialogSettings;
033: import org.eclipse.jface.dialogs.MessageDialog;
034: import org.eclipse.jface.viewers.LabelProvider;
035: import org.eclipse.jface.window.Window;
036:
037: import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
038:
039: import org.eclipse.jdt.core.JavaConventions;
040: import org.eclipse.jdt.core.JavaCore;
041:
042: import org.eclipse.jdt.ui.JavaElementImageDescriptor;
043: import org.eclipse.jdt.ui.JavaUI;
044: import org.eclipse.jdt.ui.PreferenceConstants;
045:
046: import org.eclipse.jdt.internal.ui.JavaPlugin;
047: import org.eclipse.jdt.internal.ui.JavaPluginImages;
048: import org.eclipse.jdt.internal.ui.dialogs.StatusInfo;
049: import org.eclipse.jdt.internal.ui.util.PixelConverter;
050: import org.eclipse.jdt.internal.ui.viewsupport.JavaElementImageProvider;
051: import org.eclipse.jdt.internal.ui.wizards.IStatusChangeListener;
052: import org.eclipse.jdt.internal.ui.wizards.dialogfields.DialogField;
053: import org.eclipse.jdt.internal.ui.wizards.dialogfields.IDialogFieldListener;
054: import org.eclipse.jdt.internal.ui.wizards.dialogfields.IListAdapter;
055: import org.eclipse.jdt.internal.ui.wizards.dialogfields.LayoutUtil;
056: import org.eclipse.jdt.internal.ui.wizards.dialogfields.ListDialogField;
057: import org.eclipse.jdt.internal.ui.wizards.dialogfields.SelectionButtonDialogField;
058: import org.eclipse.jdt.internal.ui.wizards.dialogfields.StringDialogField;
059:
060: /*
061: * The page for setting the organize import settings
062: */
063: public class ImportOrganizeConfigurationBlock extends
064: OptionsConfigurationBlock {
065:
066: private static final Key PREF_IMPORTORDER = getJDTUIKey(PreferenceConstants.ORGIMPORTS_IMPORTORDER);
067: private static final Key PREF_ONDEMANDTHRESHOLD = getJDTUIKey(PreferenceConstants.ORGIMPORTS_ONDEMANDTHRESHOLD);
068: private static final Key PREF_IGNORELOWERCASE = getJDTUIKey(PreferenceConstants.ORGIMPORTS_IGNORELOWERCASE);
069: private static final Key PREF_STATICONDEMANDTHRESHOLD = getJDTUIKey(PreferenceConstants.ORGIMPORTS_STATIC_ONDEMANDTHRESHOLD);
070:
071: private static final String DIALOGSETTING_LASTLOADPATH = JavaUI.ID_PLUGIN
072: + ".importorder.loadpath"; //$NON-NLS-1$
073: private static final String DIALOGSETTING_LASTSAVEPATH = JavaUI.ID_PLUGIN
074: + ".importorder.savepath"; //$NON-NLS-1$
075:
076: private static Key[] getAllKeys() {
077: return new Key[] { PREF_IMPORTORDER, PREF_ONDEMANDTHRESHOLD,
078: PREF_STATICONDEMANDTHRESHOLD, PREF_IGNORELOWERCASE };
079: }
080:
081: public static class ImportOrderEntry {
082:
083: public final String name;
084: public final boolean isStatic;
085:
086: public ImportOrderEntry(String name, boolean isStatic) {
087: this .name = name;
088: this .isStatic = isStatic;
089: }
090:
091: public String serialize() {
092: return isStatic ? '#' + name : name;
093: }
094:
095: public static ImportOrderEntry fromSerialized(String str) {
096: if (str.length() > 0 && str.charAt(0) == '#') {
097: return new ImportOrderEntry(str.substring(1), true);
098: }
099: return new ImportOrderEntry(str, false);
100: }
101:
102: }
103:
104: private static class ImportOrganizeLabelProvider extends
105: LabelProvider {
106:
107: private final Image PCK_ICON;
108: private final Image STATIC_CLASS_ICON;
109:
110: public ImportOrganizeLabelProvider() {
111: PCK_ICON = JavaPluginImages
112: .get(JavaPluginImages.IMG_OBJS_PACKAGE);
113: STATIC_CLASS_ICON = JavaElementImageProvider
114: .getDecoratedImage(
115: JavaPluginImages.DESC_MISC_PUBLIC,
116: JavaElementImageDescriptor.STATIC,
117: JavaElementImageProvider.SMALL_SIZE);
118: }
119:
120: public Image getImage(Object element) {
121: return ((ImportOrderEntry) element).isStatic ? STATIC_CLASS_ICON
122: : PCK_ICON;
123: }
124:
125: public String getText(Object element) {
126: ImportOrderEntry entry = (ImportOrderEntry) element;
127: String name = entry.name;
128: if (name.length() > 0) {
129: return name;
130: }
131: if (entry.isStatic) {
132: return PreferencesMessages.ImportOrganizeConfigurationBlock_other_static;
133: }
134: return PreferencesMessages.ImportOrganizeConfigurationBlock_other_normal;
135: }
136: }
137:
138: private class ImportOrganizeAdapter implements IListAdapter,
139: IDialogFieldListener {
140:
141: private boolean canEdit(ListDialogField field) {
142: List selected = field.getSelectedElements();
143: return selected.size() == 1;
144: }
145:
146: public void customButtonPressed(ListDialogField field, int index) {
147: doButtonPressed(index);
148: }
149:
150: public void selectionChanged(ListDialogField field) {
151: fOrderListField.enableButton(IDX_EDIT, canEdit(field));
152: }
153:
154: public void dialogFieldChanged(DialogField field) {
155: doDialogFieldChanged(field);
156: }
157:
158: public void doubleClicked(ListDialogField field) {
159: if (canEdit(field)) {
160: doButtonPressed(IDX_EDIT);
161: }
162: }
163: }
164:
165: private static final int IDX_ADD = 0;
166: private static final int IDX_ADD_STATIC = 1;
167: private static final int IDX_EDIT = 2;
168: private static final int IDX_REMOVE = 3;
169: private static final int IDX_UP = 5;
170: private static final int IDX_DOWN = 6;
171:
172: private ListDialogField fOrderListField;
173: private StringDialogField fThresholdField;
174: private StringDialogField fStaticThresholdField;
175: private SelectionButtonDialogField fIgnoreLowerCaseTypesField;
176: private SelectionButtonDialogField fExportButton;
177: private SelectionButtonDialogField fImportButton;
178:
179: private PixelConverter fPixelConverter;
180:
181: public ImportOrganizeConfigurationBlock(
182: IStatusChangeListener context, IProject project,
183: IWorkbenchPreferenceContainer container) {
184: super (context, project, getAllKeys(), container);
185:
186: String[] buttonLabels = new String[] {
187: PreferencesMessages.ImportOrganizeConfigurationBlock_order_add_button,
188: PreferencesMessages.ImportOrganizeConfigurationBlock_order_add_static_button,
189: PreferencesMessages.ImportOrganizeConfigurationBlock_order_edit_button,
190: PreferencesMessages.ImportOrganizeConfigurationBlock_order_remove_button,
191: /* 4 */null,
192: PreferencesMessages.ImportOrganizeConfigurationBlock_order_up_button,
193: PreferencesMessages.ImportOrganizeConfigurationBlock_order_down_button, };
194:
195: ImportOrganizeAdapter adapter = new ImportOrganizeAdapter();
196:
197: fOrderListField = new ListDialogField(adapter, buttonLabels,
198: new ImportOrganizeLabelProvider());
199: fOrderListField.setDialogFieldListener(adapter);
200: fOrderListField
201: .setLabelText(PreferencesMessages.ImportOrganizeConfigurationBlock_order_label);
202: fOrderListField.setUpButtonIndex(IDX_UP);
203: fOrderListField.setDownButtonIndex(IDX_DOWN);
204: fOrderListField.setRemoveButtonIndex(IDX_REMOVE);
205:
206: fOrderListField.enableButton(IDX_EDIT, false);
207:
208: fImportButton = new SelectionButtonDialogField(SWT.PUSH);
209: fImportButton.setDialogFieldListener(adapter);
210: fImportButton
211: .setLabelText(PreferencesMessages.ImportOrganizeConfigurationBlock_order_load_button);
212:
213: fExportButton = new SelectionButtonDialogField(SWT.PUSH);
214: fExportButton.setDialogFieldListener(adapter);
215: fExportButton
216: .setLabelText(PreferencesMessages.ImportOrganizeConfigurationBlock_order_save_button);
217:
218: fThresholdField = new StringDialogField();
219: fThresholdField.setDialogFieldListener(adapter);
220: fThresholdField
221: .setLabelText(PreferencesMessages.ImportOrganizeConfigurationBlock_threshold_label);
222:
223: fStaticThresholdField = new StringDialogField();
224: fStaticThresholdField.setDialogFieldListener(adapter);
225: fStaticThresholdField
226: .setLabelText(PreferencesMessages.ImportOrganizeConfigurationBlock_staticthreshold_label);
227:
228: fIgnoreLowerCaseTypesField = new SelectionButtonDialogField(
229: SWT.CHECK);
230: fIgnoreLowerCaseTypesField.setDialogFieldListener(adapter);
231: fIgnoreLowerCaseTypesField
232: .setLabelText(PreferencesMessages.ImportOrganizeConfigurationBlock_ignoreLowerCase_label);
233:
234: updateControls();
235: }
236:
237: protected Control createContents(Composite parent) {
238: setShell(parent.getShell());
239:
240: fPixelConverter = new PixelConverter(parent);
241:
242: Composite composite = new Composite(parent, SWT.NONE);
243: composite.setFont(parent.getFont());
244:
245: GridLayout layout = new GridLayout();
246: layout.numColumns = 2;
247: layout.marginWidth = 0;
248: layout.marginHeight = 0;
249:
250: composite.setLayout(layout);
251:
252: fOrderListField.doFillIntoGrid(composite, 3);
253: LayoutUtil.setHorizontalSpan(fOrderListField
254: .getLabelControl(null), 2);
255: LayoutUtil.setWidthHint(fOrderListField.getLabelControl(null),
256: fPixelConverter.convertWidthInCharsToPixels(60));
257: LayoutUtil.setHorizontalGrabbing(fOrderListField
258: .getListControl(null));
259:
260: Composite importExportComp = new Composite(composite, SWT.NONE);
261: importExportComp.setLayoutData(new GridData(GridData.FILL,
262: GridData.FILL, true, false, 2, 1));
263: layout = new GridLayout();
264: layout.numColumns = 2;
265: layout.marginWidth = 0;
266: layout.marginHeight = 0;
267:
268: importExportComp.setLayout(layout);
269:
270: fImportButton.doFillIntoGrid(importExportComp, 1);
271: fExportButton.doFillIntoGrid(importExportComp, 1);
272:
273: fThresholdField.doFillIntoGrid(composite, 2);
274: ((GridData) fThresholdField.getTextControl(null)
275: .getLayoutData()).grabExcessHorizontalSpace = false;
276: fStaticThresholdField.doFillIntoGrid(composite, 2);
277: fIgnoreLowerCaseTypesField.doFillIntoGrid(composite, 2);
278:
279: Dialog.applyDialogFont(composite);
280:
281: return composite;
282: }
283:
284: private boolean doThresholdChanged(String thresholdString) {
285: StatusInfo status = new StatusInfo();
286: try {
287: int threshold = Integer.parseInt(thresholdString);
288: if (threshold < 0) {
289: status
290: .setError(PreferencesMessages.ImportOrganizeConfigurationBlock_error_invalidthreshold);
291: }
292: } catch (NumberFormatException e) {
293: status
294: .setError(PreferencesMessages.ImportOrganizeConfigurationBlock_error_invalidthreshold);
295: }
296: updateStatus(status);
297: return status.isOK();
298: }
299:
300: private void doButtonPressed(int index) {
301: if (index == IDX_ADD || index == IDX_ADD_STATIC) { // add new
302: List existing = fOrderListField.getElements();
303: ImportOrganizeInputDialog dialog = new ImportOrganizeInputDialog(
304: getShell(), existing, index == IDX_ADD_STATIC);
305: if (dialog.open() == Window.OK) {
306: List selectedElements = fOrderListField
307: .getSelectedElements();
308: if (selectedElements.size() == 1) {
309: int insertionIndex = fOrderListField
310: .getIndexOfElement(selectedElements.get(0)) + 1;
311: fOrderListField.addElement(dialog.getResult(),
312: insertionIndex);
313: } else {
314: fOrderListField.addElement(dialog.getResult());
315: }
316: }
317: } else if (index == IDX_EDIT) { // edit
318: List selected = fOrderListField.getSelectedElements();
319: if (selected.isEmpty()) {
320: return;
321: }
322: ImportOrderEntry editedEntry = (ImportOrderEntry) selected
323: .get(0);
324:
325: List existing = fOrderListField.getElements();
326: existing.remove(editedEntry);
327:
328: ImportOrganizeInputDialog dialog = new ImportOrganizeInputDialog(
329: getShell(), existing, editedEntry.isStatic);
330: dialog.setInitialSelection(editedEntry);
331: if (dialog.open() == Window.OK) {
332: fOrderListField.replaceElement(editedEntry, dialog
333: .getResult());
334: }
335: }
336: }
337:
338: /*
339: * The import order file is a property file. The keys are
340: * "0", "1" ... last entry. The values must be valid package names.
341: */
342: private List loadFromProperties(Properties properties) {
343: ArrayList res = new ArrayList();
344: int nEntries = properties.size();
345: for (int i = 0; i < nEntries; i++) {
346: String curr = properties.getProperty(String.valueOf(i));
347: if (curr != null) {
348: ImportOrderEntry entry = ImportOrderEntry
349: .fromSerialized(curr);
350: if (entry.name.length() == 0
351: || !JavaConventions.validatePackageName(
352: entry.name, JavaCore.VERSION_1_3,
353: JavaCore.VERSION_1_5).matches(
354: IStatus.ERROR)) {
355: res.add(entry);
356: } else {
357: return null;
358: }
359: } else {
360: return res;
361: }
362: }
363: return res;
364: }
365:
366: private List loadImportOrder() {
367: IDialogSettings dialogSettings = JavaPlugin.getDefault()
368: .getDialogSettings();
369:
370: FileDialog dialog = new FileDialog(getShell(), SWT.OPEN);
371: dialog
372: .setText(PreferencesMessages.ImportOrganizeConfigurationBlock_loadDialog_title);
373: dialog.setFilterExtensions(new String[] {
374: "*.importorder", "*.*" }); //$NON-NLS-1$ //$NON-NLS-2$
375: String lastPath = dialogSettings
376: .get(DIALOGSETTING_LASTLOADPATH);
377: if (lastPath != null) {
378: dialog.setFilterPath(lastPath);
379: }
380: String fileName = dialog.open();
381: if (fileName != null) {
382: dialogSettings.put(DIALOGSETTING_LASTLOADPATH, dialog
383: .getFilterPath());
384:
385: Properties properties = new Properties();
386: FileInputStream fis = null;
387: try {
388: fis = new FileInputStream(fileName);
389: properties.load(fis);
390: List res = loadFromProperties(properties);
391: if (res != null) {
392: return res;
393: }
394: } catch (IOException e) {
395: JavaPlugin.log(e);
396: } finally {
397: if (fis != null) {
398: try {
399: fis.close();
400: } catch (IOException e) {
401: }
402: }
403: }
404: String title = PreferencesMessages.ImportOrganizeConfigurationBlock_loadDialog_error_title;
405: String message = PreferencesMessages.ImportOrganizeConfigurationBlock_loadDialog_error_message;
406: MessageDialog.openError(getShell(), title, message);
407: }
408: return null;
409: }
410:
411: private void saveImportOrder(List elements) {
412: IDialogSettings dialogSettings = JavaPlugin.getDefault()
413: .getDialogSettings();
414:
415: FileDialog dialog = new FileDialog(getShell(), SWT.SAVE);
416: dialog
417: .setText(PreferencesMessages.ImportOrganizeConfigurationBlock_saveDialog_title);
418: dialog.setFilterExtensions(new String[] {
419: "*.importorder", "*.*" }); //$NON-NLS-1$ //$NON-NLS-2$
420: dialog.setFileName("example.importorder"); //$NON-NLS-1$
421: String lastPath = dialogSettings
422: .get(DIALOGSETTING_LASTSAVEPATH);
423: if (lastPath != null) {
424: dialog.setFilterPath(lastPath);
425: }
426: String fileName = dialog.open();
427: if (fileName != null) {
428: dialogSettings.put(DIALOGSETTING_LASTSAVEPATH, dialog
429: .getFilterPath());
430:
431: Properties properties = new Properties();
432: for (int i = 0; i < elements.size(); i++) {
433: ImportOrderEntry entry = (ImportOrderEntry) elements
434: .get(i);
435: properties.setProperty(String.valueOf(i), entry
436: .serialize());
437: }
438: FileOutputStream fos = null;
439: try {
440: fos = new FileOutputStream(fileName);
441: properties.store(fos, "Organize Import Order"); //$NON-NLS-1$
442: } catch (IOException e) {
443: JavaPlugin.log(e);
444: String title = PreferencesMessages.ImportOrganizeConfigurationBlock_saveDialog_error_title;
445: String message = PreferencesMessages.ImportOrganizeConfigurationBlock_saveDialog_error_message;
446: MessageDialog.openError(getShell(), title, message);
447: } finally {
448: if (fos != null) {
449: try {
450: fos.close();
451: } catch (IOException e) {
452: }
453: }
454: }
455: }
456: }
457:
458: private void updateStatus(IStatus status) {
459: fContext.statusChanged(status);
460: }
461:
462: /* (non-Javadoc)
463: * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#validateSettings(java.lang.String, java.lang.String)
464: */
465: protected void validateSettings(Key changedKey, String oldValue,
466: String newValue) {
467: // no validation
468: }
469:
470: /* (non-Javadoc)
471: * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#updateControls()
472: */
473: protected void updateControls() {
474: ImportOrderEntry[] importOrder = getImportOrderPreference();
475: int threshold = getImportNumberThreshold(PREF_ONDEMANDTHRESHOLD);
476: int staticThreshold = getImportNumberThreshold(PREF_STATICONDEMANDTHRESHOLD);
477: boolean ignoreLowerCase = Boolean.valueOf(
478: getValue(PREF_IGNORELOWERCASE)).booleanValue();
479:
480: fOrderListField.removeAllElements();
481: for (int i = 0; i < importOrder.length; i++) {
482: fOrderListField.addElement(importOrder[i]);
483: }
484: fThresholdField.setText(String.valueOf(threshold));
485: fStaticThresholdField.setText(String.valueOf(staticThreshold));
486: fIgnoreLowerCaseTypesField.setSelection(ignoreLowerCase);
487: }
488:
489: protected final void doDialogFieldChanged(DialogField field) {
490: // set values in working copy
491: if (field == fOrderListField) {
492: setValue(PREF_IMPORTORDER, packOrderList(fOrderListField
493: .getElements()));
494: } else if (field == fThresholdField) {
495: if (doThresholdChanged(fThresholdField.getText())) {
496: setValue(PREF_ONDEMANDTHRESHOLD, fThresholdField
497: .getText());
498: }
499: } else if (field == fStaticThresholdField) {
500: if (doThresholdChanged(fStaticThresholdField.getText())) {
501: setValue(PREF_STATICONDEMANDTHRESHOLD,
502: fStaticThresholdField.getText());
503: }
504: } else if (field == fIgnoreLowerCaseTypesField) {
505: setValue(PREF_IGNORELOWERCASE, fIgnoreLowerCaseTypesField
506: .isSelected());
507: } else if (field == fImportButton) {
508: List order = loadImportOrder();
509: if (order != null) {
510: fOrderListField.setElements(order);
511: }
512: } else if (field == fExportButton) {
513: saveImportOrder(fOrderListField.getElements());
514: }
515: }
516:
517: /* (non-Javadoc)
518: * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#getFullBuildDialogStrings(boolean)
519: */
520: protected String[] getFullBuildDialogStrings(
521: boolean workspaceSettings) {
522: return null; // no build required
523: }
524:
525: private static ImportOrderEntry[] unpackOrderList(String str) {
526: ArrayList res = new ArrayList();
527: int start = 0;
528: do {
529: int end = str.indexOf(';', start);
530: if (end == -1) {
531: end = str.length();
532: }
533: res.add(ImportOrderEntry.fromSerialized(str.substring(
534: start, end)));
535: start = end + 1;
536: } while (start < str.length());
537:
538: return (ImportOrderEntry[]) res
539: .toArray(new ImportOrderEntry[res.size()]);
540: }
541:
542: private static String packOrderList(List orderList) {
543: StringBuffer buf = new StringBuffer();
544: for (int i = 0; i < orderList.size(); i++) {
545: ImportOrderEntry entry = (ImportOrderEntry) orderList
546: .get(i);
547: buf.append(entry.serialize());
548: buf.append(';');
549: }
550: return buf.toString();
551: }
552:
553: private ImportOrderEntry[] getImportOrderPreference() {
554: String str = getValue(PREF_IMPORTORDER);
555: if (str != null) {
556: return unpackOrderList(str);
557: }
558: return new ImportOrderEntry[0];
559: }
560:
561: private int getImportNumberThreshold(Key key) {
562: String thresholdStr = getValue(key);
563: try {
564: int threshold = Integer.parseInt(thresholdStr);
565: if (threshold < 0) {
566: threshold = Integer.MAX_VALUE;
567: }
568: return threshold;
569: } catch (NumberFormatException e) {
570: return Integer.MAX_VALUE;
571: }
572: }
573:
574: }
|