| /******************************************************************************* |
| * Copyright (c) 2000, 2016 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.ui.preferences; |
| |
| import java.io.FileInputStream; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Properties; |
| |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.layout.GridLayout; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.FileDialog; |
| |
| import org.eclipse.core.runtime.IStatus; |
| |
| import org.eclipse.core.resources.IProject; |
| |
| import org.eclipse.jface.dialogs.Dialog; |
| import org.eclipse.jface.dialogs.IDialogSettings; |
| import org.eclipse.jface.dialogs.MessageDialog; |
| import org.eclipse.jface.layout.PixelConverter; |
| import org.eclipse.jface.viewers.LabelProvider; |
| import org.eclipse.jface.window.Window; |
| |
| import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer; |
| |
| import org.eclipse.jdt.core.JavaConventions; |
| import org.eclipse.jdt.core.JavaCore; |
| |
| import org.eclipse.jdt.ui.JavaElementImageDescriptor; |
| import org.eclipse.jdt.ui.JavaUI; |
| import org.eclipse.jdt.ui.PreferenceConstants; |
| |
| import org.eclipse.jdt.internal.ui.JavaPlugin; |
| import org.eclipse.jdt.internal.ui.JavaPluginImages; |
| import org.eclipse.jdt.internal.ui.dialogs.StatusInfo; |
| import org.eclipse.jdt.internal.core.manipulation.util.BasicElementLabels; |
| import org.eclipse.jdt.internal.ui.viewsupport.JavaElementImageProvider; |
| import org.eclipse.jdt.internal.ui.wizards.IStatusChangeListener; |
| import org.eclipse.jdt.internal.ui.wizards.dialogfields.DialogField; |
| import org.eclipse.jdt.internal.ui.wizards.dialogfields.IDialogFieldListener; |
| import org.eclipse.jdt.internal.ui.wizards.dialogfields.IListAdapter; |
| import org.eclipse.jdt.internal.ui.wizards.dialogfields.LayoutUtil; |
| import org.eclipse.jdt.internal.ui.wizards.dialogfields.ListDialogField; |
| import org.eclipse.jdt.internal.ui.wizards.dialogfields.SelectionButtonDialogField; |
| import org.eclipse.jdt.internal.ui.wizards.dialogfields.StringDialogField; |
| |
| |
| /** |
| * The page for setting the organize import settings. |
| */ |
| public class ImportOrganizeConfigurationBlock extends OptionsConfigurationBlock { |
| |
| private static final Key PREF_IMPORTORDER= getJDTUIKey(PreferenceConstants.ORGIMPORTS_IMPORTORDER); |
| private static final Key PREF_ONDEMANDTHRESHOLD= getJDTUIKey(PreferenceConstants.ORGIMPORTS_ONDEMANDTHRESHOLD); |
| private static final Key PREF_IGNORELOWERCASE= getJDTUIKey(PreferenceConstants.ORGIMPORTS_IGNORELOWERCASE); |
| private static final Key PREF_STATICONDEMANDTHRESHOLD= getJDTUIKey(PreferenceConstants.ORGIMPORTS_STATIC_ONDEMANDTHRESHOLD); |
| |
| private static final String DIALOGSETTING_LASTLOADPATH= JavaUI.ID_PLUGIN + ".importorder.loadpath"; //$NON-NLS-1$ |
| private static final String DIALOGSETTING_LASTSAVEPATH= JavaUI.ID_PLUGIN + ".importorder.savepath"; //$NON-NLS-1$ |
| |
| private static Key[] getAllKeys() { |
| return new Key[] { |
| PREF_IMPORTORDER, PREF_ONDEMANDTHRESHOLD, PREF_STATICONDEMANDTHRESHOLD, PREF_IGNORELOWERCASE |
| }; |
| } |
| |
| public static class ImportOrderEntry { |
| |
| public final String name; |
| public final boolean isStatic; |
| |
| public ImportOrderEntry(String name, boolean isStatic) { |
| this.name= name; |
| this.isStatic= isStatic; |
| } |
| |
| public String serialize() { |
| return isStatic ? '#' + name : name; |
| } |
| |
| public static ImportOrderEntry fromSerialized(String str) { |
| if (str.length() > 0 && str.charAt(0) == '#') { |
| return new ImportOrderEntry(str.substring(1), true); |
| } |
| return new ImportOrderEntry(str, false); |
| } |
| |
| } |
| |
| |
| private static class ImportOrganizeLabelProvider extends LabelProvider { |
| |
| private final Image PCK_ICON; |
| private final Image STATIC_CLASS_ICON; |
| |
| public ImportOrganizeLabelProvider() { |
| PCK_ICON= JavaPluginImages.get(JavaPluginImages.IMG_OBJS_PACKAGE); |
| STATIC_CLASS_ICON= JavaElementImageProvider.getDecoratedImage(JavaPluginImages.DESC_MISC_PUBLIC, JavaElementImageDescriptor.STATIC, JavaElementImageProvider.SMALL_SIZE); |
| } |
| |
| @Override |
| public Image getImage(Object element) { |
| return ((ImportOrderEntry) element).isStatic ? STATIC_CLASS_ICON : PCK_ICON; |
| } |
| |
| @Override |
| public String getText(Object element) { |
| ImportOrderEntry entry= (ImportOrderEntry) element; |
| String name= entry.name; |
| if (name.length() > 0) { |
| return BasicElementLabels.getJavaElementName(name); |
| } |
| if (entry.isStatic) { |
| return PreferencesMessages.ImportOrganizeConfigurationBlock_other_static; |
| } |
| return PreferencesMessages.ImportOrganizeConfigurationBlock_other_normal; |
| } |
| } |
| |
| private class ImportOrganizeAdapter implements IListAdapter<ImportOrderEntry>, IDialogFieldListener { |
| |
| private boolean canEdit(ListDialogField<ImportOrderEntry> field) { |
| List<ImportOrderEntry> selected= field.getSelectedElements(); |
| return selected.size() == 1; |
| } |
| |
| @Override |
| public void customButtonPressed(ListDialogField<ImportOrderEntry> field, int index) { |
| doButtonPressed(index); |
| } |
| |
| @Override |
| public void selectionChanged(ListDialogField<ImportOrderEntry> field) { |
| fOrderListField.enableButton(IDX_EDIT, canEdit(field)); |
| } |
| |
| @Override |
| public void dialogFieldChanged(DialogField field) { |
| doDialogFieldChanged(field); |
| } |
| |
| @Override |
| public void doubleClicked(ListDialogField<ImportOrderEntry> field) { |
| if (canEdit(field)) { |
| doButtonPressed(IDX_EDIT); |
| } |
| } |
| } |
| |
| private static final int IDX_ADD= 0; |
| private static final int IDX_ADD_STATIC= 1; |
| private static final int IDX_EDIT= 2; |
| private static final int IDX_REMOVE= 3; |
| private static final int IDX_UP= 5; |
| private static final int IDX_DOWN= 6; |
| |
| private ListDialogField<ImportOrderEntry> fOrderListField; |
| private StringDialogField fThresholdField; |
| private StringDialogField fStaticThresholdField; |
| private SelectionButtonDialogField fIgnoreLowerCaseTypesField; |
| private SelectionButtonDialogField fExportButton; |
| private SelectionButtonDialogField fImportButton; |
| |
| private PixelConverter fPixelConverter; |
| |
| public ImportOrganizeConfigurationBlock(IStatusChangeListener context, IProject project, IWorkbenchPreferenceContainer container) { |
| super(context, project, getAllKeys(), container); |
| |
| String[] buttonLabels= new String[] { |
| PreferencesMessages.ImportOrganizeConfigurationBlock_order_add_button, |
| PreferencesMessages.ImportOrganizeConfigurationBlock_order_add_static_button, |
| PreferencesMessages.ImportOrganizeConfigurationBlock_order_edit_button, |
| PreferencesMessages.ImportOrganizeConfigurationBlock_order_remove_button, |
| /* 4 */ null, |
| PreferencesMessages.ImportOrganizeConfigurationBlock_order_up_button, |
| PreferencesMessages.ImportOrganizeConfigurationBlock_order_down_button, |
| }; |
| |
| ImportOrganizeAdapter adapter= new ImportOrganizeAdapter(); |
| |
| fOrderListField= new ListDialogField<>(adapter, buttonLabels, new ImportOrganizeLabelProvider()); |
| fOrderListField.setDialogFieldListener(adapter); |
| fOrderListField.setLabelText(PreferencesMessages.ImportOrganizeConfigurationBlock_order_label); |
| fOrderListField.setUpButtonIndex(IDX_UP); |
| fOrderListField.setDownButtonIndex(IDX_DOWN); |
| fOrderListField.setRemoveButtonIndex(IDX_REMOVE); |
| |
| fOrderListField.enableButton(IDX_EDIT, false); |
| |
| fImportButton= new SelectionButtonDialogField(SWT.PUSH); |
| fImportButton.setDialogFieldListener(adapter); |
| fImportButton.setLabelText(PreferencesMessages.ImportOrganizeConfigurationBlock_order_load_button); |
| |
| fExportButton= new SelectionButtonDialogField(SWT.PUSH); |
| fExportButton.setDialogFieldListener(adapter); |
| fExportButton.setLabelText(PreferencesMessages.ImportOrganizeConfigurationBlock_order_save_button); |
| |
| fThresholdField= new StringDialogField(); |
| fThresholdField.setDialogFieldListener(adapter); |
| fThresholdField.setLabelText(PreferencesMessages.ImportOrganizeConfigurationBlock_threshold_label); |
| |
| fStaticThresholdField= new StringDialogField(); |
| fStaticThresholdField.setDialogFieldListener(adapter); |
| fStaticThresholdField.setLabelText(PreferencesMessages.ImportOrganizeConfigurationBlock_staticthreshold_label); |
| |
| fIgnoreLowerCaseTypesField= new SelectionButtonDialogField(SWT.CHECK); |
| fIgnoreLowerCaseTypesField.setDialogFieldListener(adapter); |
| fIgnoreLowerCaseTypesField.setLabelText(PreferencesMessages.ImportOrganizeConfigurationBlock_ignoreLowerCase_label); |
| |
| updateControls(); |
| } |
| |
| @Override |
| protected Control createContents(Composite parent) { |
| setShell(parent.getShell()); |
| |
| fPixelConverter= new PixelConverter(parent); |
| |
| Composite composite= new Composite(parent, SWT.NONE); |
| composite.setFont(parent.getFont()); |
| |
| GridLayout layout= new GridLayout(); |
| layout.numColumns= 2; |
| layout.marginWidth= 0; |
| layout.marginHeight= 0; |
| |
| composite.setLayout(layout); |
| |
| fOrderListField.doFillIntoGrid(composite, 3); |
| LayoutUtil.setHorizontalSpan(fOrderListField.getLabelControl(null), 2); |
| LayoutUtil.setWidthHint(fOrderListField.getLabelControl(null), fPixelConverter.convertWidthInCharsToPixels(60)); |
| LayoutUtil.setHorizontalGrabbing(fOrderListField.getListControl(null)); |
| |
| Composite importExportComp= new Composite(composite, SWT.NONE); |
| importExportComp.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false, 2, 1)); |
| layout= new GridLayout(); |
| layout.numColumns= 2; |
| layout.marginWidth= 0; |
| layout.marginHeight= 0; |
| |
| importExportComp.setLayout(layout); |
| |
| fImportButton.doFillIntoGrid(importExportComp, 1); |
| fExportButton.doFillIntoGrid(importExportComp, 1); |
| |
| fThresholdField.doFillIntoGrid(composite, 2); |
| ((GridData) fThresholdField.getTextControl(null).getLayoutData()).grabExcessHorizontalSpace= false; |
| fStaticThresholdField.doFillIntoGrid(composite, 2); |
| fIgnoreLowerCaseTypesField.doFillIntoGrid(composite, 2); |
| |
| Dialog.applyDialogFont(composite); |
| |
| return composite; |
| } |
| |
| private boolean doThresholdChanged(String thresholdString) { |
| StatusInfo status= new StatusInfo(); |
| try { |
| int threshold= Integer.parseInt(thresholdString); |
| if (threshold < 0) { |
| status.setError(PreferencesMessages.ImportOrganizeConfigurationBlock_error_invalidthreshold); |
| } |
| } catch (NumberFormatException e) { |
| status.setError(PreferencesMessages.ImportOrganizeConfigurationBlock_error_invalidthreshold); |
| } |
| updateStatus(status); |
| return status.isOK(); |
| } |
| |
| private void doButtonPressed(int index) { |
| if (index == IDX_ADD || index == IDX_ADD_STATIC) { // add new |
| List<ImportOrderEntry> existing= fOrderListField.getElements(); |
| ImportOrganizeInputDialog dialog= new ImportOrganizeInputDialog(getShell(), existing, index == IDX_ADD_STATIC); |
| if (dialog.open() == Window.OK) { |
| List<ImportOrderEntry> selectedElements= fOrderListField.getSelectedElements(); |
| if (selectedElements.size() == 1) { |
| int insertionIndex= fOrderListField.getIndexOfElement(selectedElements.get(0)) + 1; |
| fOrderListField.addElement(dialog.getResult(), insertionIndex); |
| } else { |
| fOrderListField.addElement(dialog.getResult()); |
| } |
| } |
| } else if (index == IDX_EDIT) { // edit |
| List<ImportOrderEntry> selected= fOrderListField.getSelectedElements(); |
| if (selected.isEmpty()) { |
| return; |
| } |
| ImportOrderEntry editedEntry= selected.get(0); |
| |
| List<ImportOrderEntry> existing= fOrderListField.getElements(); |
| existing.remove(editedEntry); |
| |
| ImportOrganizeInputDialog dialog= new ImportOrganizeInputDialog(getShell(), existing, editedEntry.isStatic); |
| dialog.setInitialSelection(editedEntry); |
| if (dialog.open() == Window.OK) { |
| fOrderListField.replaceElement(editedEntry, dialog.getResult()); |
| } |
| } |
| } |
| |
| |
| /* |
| * The import order file is a property file. The keys are |
| * "0", "1" ... last entry. The values must be valid package names. |
| */ |
| private List<ImportOrderEntry> loadFromProperties(Properties properties) { |
| ArrayList<ImportOrderEntry> res= new ArrayList<>(); |
| int nEntries= properties.size(); |
| for (int i= 0 ; i < nEntries; i++) { |
| String curr= properties.getProperty(String.valueOf(i)); |
| if (curr != null) { |
| ImportOrderEntry entry= ImportOrderEntry.fromSerialized(curr); |
| if (entry.name.length() == 0 || !JavaConventions.validatePackageName(entry.name, JavaCore.VERSION_1_3, JavaCore.VERSION_1_5).matches(IStatus.ERROR)) { |
| res.add(entry); |
| } else { |
| return null; |
| } |
| } else { |
| return res; |
| } |
| } |
| return res; |
| } |
| |
| private List<ImportOrderEntry> loadImportOrder() { |
| IDialogSettings dialogSettings= JavaPlugin.getDefault().getDialogSettings(); |
| |
| FileDialog dialog= new FileDialog(getShell(), SWT.OPEN | SWT.SHEET); |
| dialog.setText(PreferencesMessages.ImportOrganizeConfigurationBlock_loadDialog_title); |
| dialog.setFilterExtensions(new String[] {"*.importorder", "*.*"}); //$NON-NLS-1$ //$NON-NLS-2$ |
| String lastPath= dialogSettings.get(DIALOGSETTING_LASTLOADPATH); |
| if (lastPath != null) { |
| dialog.setFilterPath(lastPath); |
| } |
| String fileName= dialog.open(); |
| if (fileName != null) { |
| dialogSettings.put(DIALOGSETTING_LASTLOADPATH, dialog.getFilterPath()); |
| |
| Properties properties= new Properties(); |
| FileInputStream fis= null; |
| try { |
| fis= new FileInputStream(fileName); |
| properties.load(fis); |
| List<ImportOrderEntry> res= loadFromProperties(properties); |
| if (res != null) { |
| return res; |
| } |
| } catch (IOException e) { |
| JavaPlugin.log(e); |
| } finally { |
| if (fis != null) { |
| try { fis.close(); } catch (IOException e) {} |
| } |
| } |
| String title= PreferencesMessages.ImportOrganizeConfigurationBlock_loadDialog_error_title; |
| String message= PreferencesMessages.ImportOrganizeConfigurationBlock_loadDialog_error_message; |
| MessageDialog.openError(getShell(), title, message); |
| } |
| return null; |
| } |
| |
| private void saveImportOrder(List<ImportOrderEntry> elements) { |
| IDialogSettings dialogSettings= JavaPlugin.getDefault().getDialogSettings(); |
| |
| FileDialog dialog= new FileDialog(getShell(), SWT.SAVE | SWT.SHEET); |
| dialog.setText(PreferencesMessages.ImportOrganizeConfigurationBlock_saveDialog_title); |
| dialog.setFilterExtensions(new String[] {"*.importorder", "*.*"}); //$NON-NLS-1$ //$NON-NLS-2$ |
| dialog.setFileName("example"); //$NON-NLS-1$ |
| String lastPath= dialogSettings.get(DIALOGSETTING_LASTSAVEPATH); |
| if (lastPath != null) { |
| dialog.setFilterPath(lastPath); |
| } |
| String fileName= dialog.open(); |
| if (fileName != null) { |
| dialogSettings.put(DIALOGSETTING_LASTSAVEPATH, dialog.getFilterPath()); |
| |
| Properties properties= new Properties(); |
| for (int i= 0; i < elements.size(); i++) { |
| ImportOrderEntry entry= elements.get(i); |
| properties.setProperty(String.valueOf(i), entry.serialize()); |
| } |
| FileOutputStream fos= null; |
| try { |
| fos= new FileOutputStream(fileName); |
| properties.store(fos, "Organize Import Order"); //$NON-NLS-1$ |
| } catch (IOException e) { |
| JavaPlugin.log(e); |
| String title= PreferencesMessages.ImportOrganizeConfigurationBlock_saveDialog_error_title; |
| String message= PreferencesMessages.ImportOrganizeConfigurationBlock_saveDialog_error_message; |
| MessageDialog.openError(getShell(), title, message); |
| } finally { |
| if (fos != null) { |
| try { fos.close(); } catch (IOException e) {} |
| } |
| } |
| } |
| } |
| |
| private void updateStatus(IStatus status) { |
| fContext.statusChanged(status); |
| } |
| |
| @Override |
| protected void validateSettings(Key changedKey, String oldValue, String newValue) { |
| // no validation |
| } |
| |
| @Override |
| protected void updateControls() { |
| ImportOrderEntry[] importOrder= getImportOrderPreference(); |
| int threshold= getImportNumberThreshold(PREF_ONDEMANDTHRESHOLD); |
| int staticThreshold= getImportNumberThreshold(PREF_STATICONDEMANDTHRESHOLD); |
| boolean ignoreLowerCase= Boolean.parseBoolean(getValue(PREF_IGNORELOWERCASE)); |
| |
| fOrderListField.removeAllElements(); |
| for (ImportOrderEntry i : importOrder) { |
| fOrderListField.addElement(i); |
| } |
| fThresholdField.setText(String.valueOf(threshold)); |
| fStaticThresholdField.setText(String.valueOf(staticThreshold)); |
| fIgnoreLowerCaseTypesField.setSelection(ignoreLowerCase); |
| } |
| |
| |
| protected final void doDialogFieldChanged(DialogField field) { |
| // set values in working copy |
| if (field == fOrderListField) { |
| setValue(PREF_IMPORTORDER, packOrderList(fOrderListField.getElements())); |
| } else if (field == fThresholdField) { |
| if (doThresholdChanged(fThresholdField.getText())) { |
| setValue(PREF_ONDEMANDTHRESHOLD, fThresholdField.getText()); |
| } |
| } else if (field == fStaticThresholdField) { |
| if (doThresholdChanged(fStaticThresholdField.getText())) { |
| setValue(PREF_STATICONDEMANDTHRESHOLD, fStaticThresholdField.getText()); |
| } |
| } else if (field == fIgnoreLowerCaseTypesField) { |
| setValue(PREF_IGNORELOWERCASE, fIgnoreLowerCaseTypesField.isSelected()); |
| } else if (field == fImportButton) { |
| List<ImportOrderEntry> order= loadImportOrder(); |
| if (order != null) { |
| fOrderListField.setElements(order); |
| } |
| } else if (field == fExportButton) { |
| saveImportOrder(fOrderListField.getElements()); |
| } |
| } |
| |
| |
| @Override |
| protected String[] getFullBuildDialogStrings(boolean workspaceSettings) { |
| return null; // no build required |
| } |
| |
| private static ImportOrderEntry[] unpackOrderList(String str) { |
| ArrayList<ImportOrderEntry> res= new ArrayList<>(); |
| int start= 0; |
| do { |
| int end= str.indexOf(';', start); |
| if (end == -1) { |
| end= str.length(); |
| } |
| res.add(ImportOrderEntry.fromSerialized(str.substring(start, end))); |
| start= end + 1; |
| } while (start < str.length()); |
| |
| return res.toArray(new ImportOrderEntry[res.size()]); |
| } |
| |
| private static String packOrderList(List<ImportOrderEntry> orderList) { |
| StringBuilder buf= new StringBuilder(); |
| for (ImportOrderEntry entry : orderList) { |
| buf.append(entry.serialize()); |
| buf.append(';'); |
| } |
| return buf.toString(); |
| } |
| |
| private ImportOrderEntry[] getImportOrderPreference() { |
| String str= getValue(PREF_IMPORTORDER); |
| if (str != null) { |
| return unpackOrderList(str); |
| } |
| return new ImportOrderEntry[0]; |
| } |
| |
| private int getImportNumberThreshold(Key key) { |
| String thresholdStr= getValue(key); |
| try { |
| int threshold= Integer.parseInt(thresholdStr); |
| if (threshold < 0) { |
| threshold= Integer.MAX_VALUE; |
| } |
| return threshold; |
| } catch (NumberFormatException e) { |
| return Integer.MAX_VALUE; |
| } |
| } |
| |
| } |
| |
| |