/******************************************************************************************** * Copyright (c) 2014, 2016 Fabian Steeg (hbz), and others. * * 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 * * Contributors: * Fabian Steeg (hbz) - initial API & implementation * Tamas Miklossy (itemis AG) - Refactoring of preferences (bug #446639) * - Exporting *.dot files in different formats (bug #446647) * *********************************************************************************************/ package org.eclipse.gef.dot.internal.ui; import java.io.File; import java.util.Arrays; import org.eclipse.core.runtime.preferences.ConfigurationScope; import org.eclipse.gef.dot.internal.DotExecutableUtils; import org.eclipse.gef.dot.internal.ui.language.internal.DotActivator; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.preference.FieldEditorPreferencePage; import org.eclipse.jface.preference.FileFieldEditor; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.preference.PreferenceDialog; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Link; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchPreferencePage; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.dialogs.PreferencesUtil; import org.eclipse.ui.preferences.ScopedPreferenceStore; import org.osgi.service.prefs.Preferences; /** * Store and access the path to the 'dot' executable in the preference store. * The path can be set by the user, using a file selection dialog. The selected * location is stored in the bundle's preferences and available from there after * the initial setting. */ public class GraphvizPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage { private static final String DOT_SELECT_SHORT = DotUiMessages.GraphvizPreference_0; private static final String DOT_SELECT_LONG = DotUiMessages.GraphvizPreference_1; private static final String INVALID_DOT_EXECUTABLE = DotUiMessages.GraphvizPreference_2; private static final String INVALID_GRAPHVIZ_CONF = DotUiMessages.GraphvizPreference_3; private static final String GRAPHVIZ_CONF_HINT = DotUiMessages.GraphvizPreference_4; private static final String DOT_EXPORT_FORMAT = DotUiMessages.GraphvizPreference_5; private static final String DOT_EXPORT_FORMAT_HINT = DotUiMessages.GraphvizPreference_6; public static final String DOT_PATH_PREF_KEY = "dotpath"; //$NON-NLS-1$ public static final String DOT_EXPORTFORMAT_PREF_KEY = "dotexportformat"; //$NON-NLS-1$ private static final String DOT_EXPORTFORMAT_DEFAULT = "pdf"; //$NON-NLS-1$ private DotExportRadioGroupFieldEditor radioGroupFieldEditor; public GraphvizPreferencePage() { super(GRID); } public static boolean isGraphvizConfigured() { return getDotExecutablePath().length() != 0; } public static void showGraphvizConfigurationDialog() { Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow() .getShell(); new GraphvizConfigurationDialog(shell).open(); } public static String getDotExecutablePath() { return dotUiPrefs().get(DOT_PATH_PREF_KEY, "");//$NON-NLS-1$ } public static String getDotExportFormat() { return dotUiPrefs().get(DOT_EXPORTFORMAT_PREF_KEY, ""); //$NON-NLS-1$ } private static boolean isValidDotExecutable(String path) { if (path == null || path.isEmpty()) { return false; } File file = new File(path); return file.getName().equals("dot") || file.getName().equals("dot.exe"); //$NON-NLS-1$//$NON-NLS-2$ } // TODO: move to activator protected static Preferences dotUiPrefs() { return ConfigurationScope.INSTANCE.getNode( DotActivator.getInstance().getBundle().getSymbolicName()); } // TODO: move to activator protected static IPreferenceStore dotUiPrefStore() { return new ScopedPreferenceStore(ConfigurationScope.INSTANCE, DotActivator.getInstance().getBundle().getSymbolicName()); } @Override public void init(IWorkbench workbench) { setPreferenceStore(dotUiPrefStore()); setDescription(DOT_SELECT_LONG); } @Override protected void createFieldEditors() { // this method will be invoked if the user clicks on the Graphviz // Preference Page for the first time FileFieldEditor fileFieldEditor = new FileFieldEditor(DOT_PATH_PREF_KEY, DOT_SELECT_SHORT, true, FileFieldEditor.VALIDATE_ON_KEY_STROKE, getFieldEditorParent()) { { setErrorMessage(INVALID_DOT_EXECUTABLE); } @Override public boolean isValid() { boolean isValid = super.isValid(); String currentValue = getStringValue(); if (!currentValue.isEmpty()) { isValid = isValid && isValidDotExecutable(currentValue); } return isValid; } @Override protected void refreshValidState() { super.refreshValidState(); if (!isValid()) { showErrorMessage(getErrorMessage()); } checkState(); } @Override public boolean doCheckState() { String currentValue = getStringValue(); if (!currentValue.isEmpty()) { return isValidDotExecutable(currentValue); } return super.doCheckState(); } @Override public String changePressed() { // this method will be invoked if the user clicks on the // "Browse" button of the fileFieldEditor of the DOT Executable // path String dotExecutablePath = super.changePressed(); if (dotExecutablePath == null) { // If the returned value is null, the currently displayed // value remains. return null; } adaptDotExportUI(dotExecutablePath); return dotExecutablePath; } }; addField(fileFieldEditor); getPreferenceStore() .addPropertyChangeListener(new IPropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent event) { // this method will be invoked if the user clicks on the // Apply/OK button of the Preference Page if (event.getProperty().equals(DOT_PATH_PREF_KEY)) { String dotExecutablePath = (String) event .getNewValue(); adaptDotExportUI(dotExecutablePath); } } }); String dotExecutablePath = getDotExecutablePath(); addDotExportUI(dotExecutablePath); } private String[] getSupportedExportFormats(String dotExecutablePath) { String[] supportedExportFormats = null; supportedExportFormats = DotExecutableUtils .getSupportedExportFormats(dotExecutablePath); return supportedExportFormats; } private String getDefaultExportFormat(String[] supportedExportFormats) { if (supportedExportFormats == null) { return null; } return Arrays.asList(supportedExportFormats) .contains(DOT_EXPORTFORMAT_DEFAULT) ? DOT_EXPORTFORMAT_DEFAULT : supportedExportFormats[0]; } private String[][] getLabelsAndValues(String[] supportedExportFormats) { String[][] labelsAndValues = null; if (supportedExportFormats != null) { labelsAndValues = new String[supportedExportFormats.length][2]; for (int i = 0; i < supportedExportFormats.length; i++) { labelsAndValues[i] = new String[] { supportedExportFormats[i], supportedExportFormats[i] }; } } return labelsAndValues; } private void adaptDotExportUI(String dotExecutablePath) { if (isValidDotExecutable(dotExecutablePath)) { if (radioGroupFieldEditor == null) { addDotExportUI(dotExecutablePath); } else { updateDotExportUI(dotExecutablePath); } } else { removeDotExportUI(); } } private void addDotExportUI(String dotExecutablePath) { String[] supportedExportFormats = null; if (!dotExecutablePath.isEmpty()) { supportedExportFormats = getSupportedExportFormats( dotExecutablePath); } String[][] labelsAndValues = getLabelsAndValues(supportedExportFormats); radioGroupFieldEditor = new DotExportRadioGroupFieldEditor( DOT_EXPORTFORMAT_PREF_KEY, DOT_EXPORT_FORMAT, DOT_EXPORT_FORMAT_HINT, 5, labelsAndValues, getFieldEditorParent()); if (getDotExportFormat().isEmpty()) { String defaultExportFormat = getDefaultExportFormat( supportedExportFormats); if (defaultExportFormat != null) { dotUiPrefs().put(DOT_EXPORTFORMAT_PREF_KEY, defaultExportFormat); } } addField(radioGroupFieldEditor); } private void updateDotExportUI(String dotExecutablePath) { String[] supportedExportFormats = getSupportedExportFormats( dotExecutablePath); String defaultExportFormat = getDefaultExportFormat( supportedExportFormats); String[][] labelsAndValues = getLabelsAndValues(supportedExportFormats); dotUiPrefs().put(DOT_EXPORTFORMAT_PREF_KEY, defaultExportFormat); radioGroupFieldEditor.update(labelsAndValues); } private void removeDotExportUI() { if (radioGroupFieldEditor != null) { radioGroupFieldEditor.clear(); dotUiPrefs().remove(DOT_EXPORTFORMAT_PREF_KEY); } } @Override protected void performDefaults() { // this method will be invoked if the user clicks on the "Restore // Defaults" button super.performDefaults(); removeDotExportUI(); } public static class GraphvizConfigurationDialog extends MessageDialog { public GraphvizConfigurationDialog(Shell parentShell) { super(parentShell, INVALID_GRAPHVIZ_CONF, null, GRAPHVIZ_CONF_HINT, WARNING, new String[] { IDialogConstants.CANCEL_LABEL }, 0); } @Override protected Control createMessageArea(Composite composite) { // prevent creation of messageLabel by super implementation String linkText = message; message = null; super.createMessageArea(composite); message = linkText; Link messageLink = new Link(composite, SWT.WRAP); messageLink.setText(message); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) .grab(true, false).applyTo(messageLink); messageLink.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event event) { Shell shell = PlatformUI.getWorkbench() .getActiveWorkbenchWindow().getShell(); PreferenceDialog pref = PreferencesUtil .createPreferenceDialogOn(shell, "org.eclipse.gef.dot.internal.ui.GraphvizPreferencePage", //$NON-NLS-1$ null, null); if (pref != null) { close(); pref.open(); } } }); return composite; } } }