/******************************************************************************* * Copyright (c) 2012 The PDT Extension Group (https://github.com/pdt-eg) * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html ******************************************************************************/ package org.pdtextensions.semanticanalysis.ui.preferences.csfixer; import java.io.File; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; import org.eclipse.core.resources.IProject; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.CheckStateChangedEvent; import org.eclipse.jface.viewers.CheckboxTableViewer; import org.eclipse.jface.viewers.ICheckStateListener; import org.eclipse.jface.viewers.ICheckStateProvider; import org.eclipse.jface.viewers.IFontProvider; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.ILabelProviderListener; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.ViewerSorter; import org.eclipse.jface.window.Window; import org.eclipse.php.internal.ui.preferences.IStatusChangeListener; import org.eclipse.php.internal.ui.preferences.util.Key; import org.eclipse.php.internal.ui.util.PixelConverter; import org.eclipse.php.internal.ui.wizards.fields.DialogField; import org.eclipse.php.internal.ui.wizards.fields.IDialogFieldListener; import org.eclipse.php.internal.ui.wizards.fields.IListAdapter; import org.eclipse.php.internal.ui.wizards.fields.ListDialogField; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer; import org.pdtextensions.core.ui.preferences.PreferenceConstants; import org.pdtextensions.core.ui.preferences.launcher.LauncherConfigurationBlock; import org.pdtextensions.core.ui.preferences.launcher.LauncherKeyBag; import org.pdtextensions.semanticanalysis.PEXAnalysisPlugin; import org.pdtextensions.semanticanalysis.ui.PEXAnalysisUIPlugin; import org.pdtextensions.semanticanalysis.ui.preferences.PEXPreferenceNames; @SuppressWarnings("restriction") public class PHPCSFixerConfigurationBlock extends LauncherConfigurationBlock { private static final Key PREF_PHPCS_PHAR_LOCATION = getPEXKey(PreferenceConstants.PREF_PHPCS_PHAR_LOCATION); private static final Key PREF_PHPCS_PHAR_NAME = getPEXKey(PreferenceConstants.PREF_PHPCS_PHAR_NAME); private static final Key PREF_PHPCS_CUSTOM_PHAR_LOCATIONS = getPEXKey(PreferenceConstants.PREF_PHPCS_CUSTOM_PHAR_LOCATIONS); private static final Key PREF_PHPCS_CUSTOM_PHAR_NAMES = getPEXKey(PreferenceConstants.PREF_PHPCS_CUSTOM_PHAR_NAMES); private static final Key PREF_PHPCS_USE_DEFAULT_FIXERS = getPEXKey(PreferenceConstants.PREF_PHPCS_USE_DEFAULT_FIXERS); private static final Key PREF_PHPCS_CONFIG = getPEXKey(PreferenceConstants.PREF_PHPCS_CONFIG); private static final int IDX_ADD = 0; private static final int IDX_EDIT = 1; private static final int IDX_REMOVE = 2; private static final int IDX_DEFAULT = 4; private ListDialogField<FixerPhar> pharField; private CheckboxTableViewer fixerList; private List<FixerOption> fixerOptions = new ArrayList<FixerOption>(); public PHPCSFixerConfigurationBlock(IStatusChangeListener context, IProject project, IWorkbenchPreferenceContainer container, LauncherKeyBag keyBag) { super(context, project, container, keyBag); unpackFixerOptions(); initPharList(); } protected void initPharList() { PharListAdapter adapter = new PharListAdapter(); PharLabelProvider provider = new PharLabelProvider(); String[] buttons = new String[] { "New...", "Edit...", "Remove", null, "Default", null }; pharField = new ListDialogField<PHPCSFixerConfigurationBlock.FixerPhar>( adapter, buttons, provider); pharField.setDialogFieldListener(adapter); pharField.setRemoveButtonIndex(IDX_REMOVE); String[] columnsHeaders = new String[] { "Name", "Path" }; pharField.setTableColumns(new ListDialogField.ColumnsDescription( columnsHeaders, true)); pharField.setViewerSorter(new ViewerSorter()); unpackPhars(); } @Override public void createExtraContent(Composite parent) { Composite content = new Composite(parent, SWT.NONE); FillLayout layout = new FillLayout(SWT.VERTICAL); content.setLayout(layout); createFixerOptions(content); createPharOptions(content); // return content; } protected void createPharOptions(Composite parent) { Composite pharContent = new Composite(parent, SWT.NONE); // pharContent.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); PixelConverter conv = new PixelConverter(pharContent); GridLayout pharListLayout = new GridLayout(); pharListLayout.marginHeight = 2; pharListLayout.marginWidth = 0; pharListLayout.numColumns = 3; pharContent.setLayout(pharListLayout); Label pharLabel = new Label(pharContent, SWT.NONE); pharLabel.setText("Phar used for running the cs-fixer"); GridData labelData = new GridData(GridData.VERTICAL_ALIGN_END); labelData.horizontalSpan = 3; pharLabel.setLayoutData(labelData); GridData listData = new GridData(GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_BEGINNING); listData.widthHint = conv.convertWidthInCharsToPixels(50); listData.heightHint = conv.convertHeightInCharsToPixels(12); Control listControl = pharField.getListControl(pharContent); listControl.setLayoutData(listData); Control buttonsControl = pharField.getButtonBox(pharContent); buttonsControl.setLayoutData(new GridData( GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_BEGINNING)); } protected void createFixerOptions(Composite parent) { Composite fixerContent = new Composite(parent, SWT.NONE); GridLayout fixerLayout = new GridLayout(); fixerLayout.marginHeight = 10; fixerLayout.marginWidth = 0; fixerContent.setLayout(fixerLayout); Group fixerGroup = new Group(fixerContent, SWT.NONE); fixerGroup.setLayout(new GridLayout()); fixerGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); fixerGroup.setText("CodingStandard Fixer Configuration"); addComboBox(fixerGroup, "Configuration", PREF_PHPCS_CONFIG, PEXPreferenceNames.getPHPCSFixerConfig(), PEXPreferenceNames.getPHPCSFixerConfigLabels(), 0); final Button defaultFixers = addCheckBox(fixerGroup, "Use default PHP-CS fixer options", PREF_PHPCS_USE_DEFAULT_FIXERS, new String[] { "yes", "no" }, 0); defaultFixers.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { fixerList.getTable().setEnabled( defaultFixers.getSelection() == false); } }); fixerList = CheckboxTableViewer.newCheckList(fixerGroup, SWT.BORDER); fixerList.getTable().setLayoutData(new GridData(GridData.FILL_BOTH)); fixerList.setContentProvider(new ArrayContentProvider()); fixerList.setLabelProvider(new FixerOptionLabelProvider()); fixerList.setCheckStateProvider(new ICheckStateProvider() { @Override public boolean isGrayed(Object element) { return false; } @Override public boolean isChecked(Object element) { FixerOption option = (FixerOption) element; return "true".equals(option.active); } }); fixerList.addCheckStateListener(new ICheckStateListener() { @Override public void checkStateChanged(CheckStateChangedEvent event) { FixerOption option = (FixerOption) event.getElement(); Boolean bool = new Boolean(event.getChecked()); option.active = bool.toString(); setValue(getPEXKey(option.internal), packOption(option)); } }); fixerList.setInput(fixerOptions.toArray()); if ("yes".equals(getValue(PREF_PHPCS_USE_DEFAULT_FIXERS))) { fixerList.getTable().setEnabled(false); } } private class PharListAdapter<Object> implements IListAdapter<Object>, IDialogFieldListener { @Override public void customButtonPressed(ListDialogField<Object> field, int index) { doStandardButtonPressed(index); } private boolean canEdit(List<Object> selectedElements) { return selectedElements.size() == 1 && !isInternalPhar((FixerPhar) selectedElements.get(0)); } private boolean canSetToDefault(List<Object> selectedElements) { return selectedElements.size() == 1 && !isDefaultPhar((FixerPhar) selectedElements.get(0)); } private boolean canRemove(List<Object> selectedElements) { int count = selectedElements.size(); if (count == 0) return false; for (int i = 0; i < count; i++) { if (isInternalPhar((FixerPhar) selectedElements.get(i))) return false; } return true; } @Override public void selectionChanged(ListDialogField<Object> field) { List<Object> selectedElements = field.getSelectedElements(); field.enableButton(IDX_EDIT, canEdit(selectedElements)); field.enableButton(IDX_DEFAULT, canSetToDefault(selectedElements)); field.enableButton(IDX_REMOVE, canRemove(selectedElements)); } @Override public void doubleClicked(ListDialogField<Object> field) { if (canEdit(field.getSelectedElements())) { doStandardButtonPressed(IDX_EDIT); } } @Override public void dialogFieldChanged(DialogField field) { updatePharModel(field); } } final boolean isDefaultPhar(FixerPhar lib) { return pharField.getIndexOfElement(lib) == 0; } private class PharLabelProvider extends LabelProvider implements ITableLabelProvider, IFontProvider { @Override public Font getFont(Object element) { if (isDefaultPhar((FixerPhar) element)) { return JFaceResources.getFontRegistry().getBold( JFaceResources.DIALOG_FONT); } return null; } @Override public Image getColumnImage(Object element, int columnIndex) { return null; } @Override public String getText(Object element) { return getColumnText(element, 0); } @Override public String getColumnText(Object element, int columnIndex) { FixerPhar lib = (FixerPhar) element; if (columnIndex == 0) { String name = lib.name; if (isDefaultPhar(lib)) { name = MessageFormat.format("{0} (default)", new Object[] { name }); } return name; } else if (columnIndex == 1) { return lib.path; } else { return ""; } } } public static class FixerPhar { public String name; public boolean custom; public String path; public String toString() { return name; } } final boolean isInternalPhar(FixerPhar phar) { return phar.path == ""; } protected final void updatePharModel(DialogField field) { if (field == pharField) { StringBuffer customLibs = new StringBuffer(); StringBuffer customPaths = new StringBuffer(); List<FixerPhar> list = pharField.getElements(); for (int i = 0; i < list.size(); i++) { FixerPhar elem = list.get(i); if (elem.custom) { if (customLibs.length() > 0) { customLibs.append(';'); customPaths.append(';'); } customLibs.append(elem.name); customPaths.append(elem.path); } } FixerPhar defaultLibrary = (FixerPhar) pharField.getElement(0); if (defaultLibrary != null) { setValue(PREF_PHPCS_PHAR_NAME, defaultLibrary.name); setValue(PREF_PHPCS_PHAR_LOCATION, defaultLibrary.path); } setValue(PREF_PHPCS_CUSTOM_PHAR_NAMES, customLibs.toString()); setValue(PREF_PHPCS_CUSTOM_PHAR_LOCATIONS, customPaths.toString()); // validateSettings(PREF_CUSTOM_LIBRARY_NAMES, null, null); } } private FixerOption unpackOption(String option) { if (option == null || option.indexOf("::") == -1) { return null; } String[] values = option.split("::"); FixerOption opt = new FixerOption(); opt.internal = values[0]; opt.option = values[1]; opt.name = values[2]; opt.active = values[3]; return opt; } private String packOption(FixerOption option) { return String.format("%s::%s::%s::%s", option.internal, option.option, option.name, option.active); } private void unpackFixerOptions() { for (String key : PEXPreferenceNames.getPHPCSFixerOptions()) { FixerOption option = unpackOption(getValue(getPEXKey(key))); if (option != null) { fixerOptions.add(option); } } } private void unpackPhars() { String defaultName = getValue(PREF_PHPCS_PHAR_NAME); FixerPhar defaultLibrary = null; String customStandardPrefs = getValue(PREF_PHPCS_CUSTOM_PHAR_NAMES); String[] customStandards = {}; String[] customPaths = {}; if (customStandardPrefs != null) { customStandards = getTokens(customStandardPrefs, ";"); //$NON-NLS-1$ String customPathPrefs = getValue(PREF_PHPCS_CUSTOM_PHAR_LOCATIONS); customPaths = getTokens(customPathPrefs, ";"); //$NON-NLS-1$ } ArrayList<FixerPhar> elements = new ArrayList<FixerPhar>( customStandards.length + 1); // internal lib FixerPhar lib = new FixerPhar(); lib.name = "<Internal>"; lib.custom = false; lib.path = ""; elements.add(lib); if (lib.name.equals(defaultName)) defaultLibrary = lib; // Custom libs for (int i = 0; i < customStandards.length; i++) { lib = new FixerPhar(); lib.name = customStandards[i].trim(); lib.custom = true; lib.path = customPaths[i].trim(); elements.add(lib); if (lib.name.equals(defaultName)) defaultLibrary = lib; } pharField.setElements(elements); if (defaultLibrary != null) setToDefaultPhar(defaultLibrary); } private void setToDefaultPhar(FixerPhar lib) { List<FixerPhar> elements = pharField.getElements(); elements.remove(lib); elements.add(0, lib); pharField.setElements(elements); pharField.enableButton(IDX_DEFAULT, false); } private void doStandardButtonPressed(int index) { FixerPhar edited = null; if (index != IDX_ADD) { edited = pharField.getSelectedElements().get(0); } if (index == IDX_ADD || index == IDX_EDIT) { LibraryInputDialog dialog = new LibraryInputDialog(getShell(), edited, pharField.getElements()); if (dialog.open() == Window.OK) { if (edited != null) { pharField.replaceElement(edited, dialog.getResult()); } else { pharField.addElement(dialog.getResult()); } } } else if (index == IDX_DEFAULT) { setToDefaultPhar(edited); } } class FixerOptionLabelProvider implements ILabelProvider { @Override public void addListener(ILabelProviderListener listener) { } @Override public void dispose() { } @Override public boolean isLabelProperty(Object element, String property) { return false; } @Override public void removeListener(ILabelProviderListener listener) { } @Override public Image getImage(Object element) { return null; } @Override public String getText(Object element) { return ((FixerOption) element).option; } } static class FixerOption { public String name; public String internal; public String option; public String active; public String toString() { return option; } } @Override protected String getPluginId() { return PEXAnalysisUIPlugin.PLUGIN_ID; } @Override protected void afterSave() { // TODO Auto-generated method stub } @Override protected void beforeSave() { // TODO Auto-generated method stub } @Override protected String getHeaderLabel() { return "Select the PHP executable to be used for running cs-fixer binaries."; } @Override protected String getProjectChoiceLabel() { return "Download cs-fixer.phar per project"; } @Override protected String getGlobalChoiceLabel() { return "Use global cs-fixer"; } @Override protected String getScriptLabel() { return "CS-fixer binary"; } @Override protected String getButtonGroupLabel() { return "CS-fixer selection"; } @Override protected String getScriptFieldLabel() { return "Custom cs-fixer binary"; } @Override protected boolean validateScript(String text) { File file = new File(text); return file.exists() /*&& file.canExecute()*/; } protected final static Key getPEXKey(String key) { return getKey(PEXAnalysisPlugin.PLUGIN_ID, key); } }