Permalink
Browse files

Created a preferences page for Scion. Added the location of the Scion…

… server binary to this page.

Ignore-this: 14088ddae7142aac0c354f98e8b7df7e

darcs-hash:20090615161403-04e1b-0c2addab79d0abe9f4beadeffbcb37cd350e7789.gz
  • Loading branch information...
ttencate committed Jun 15, 2009
1 parent a11d8fd commit c7d386650911273f6495c263b719756d7646b063
@@ -14,6 +14,7 @@
import java.util.LinkedList;
import java.util.List;
+import net.sf.eclipsefp.haskell.scion.client.preferences.IPreferenceConstants;
import net.sf.eclipsefp.haskell.scion.commands.CommandStatus;
import net.sf.eclipsefp.haskell.scion.commands.ScionCommand;
@@ -54,7 +55,7 @@
private CommandQueue commandQueue;
public ScionClientThread(CommandQueue commandQueue) {
- super("Scion server thread");
+ super("Scion client thread");
this.commandQueue = commandQueue;
setUncaughtExceptionHandler(this);
}
@@ -130,7 +131,7 @@ private void startServerProcess() throws IOException {
Trace.trace(THREAD_PREFIX, "Starting server");
// Construct the command line
- String executable = "/home/thomas/.cabal/bin/scion_server"; // TODO autodetect, make configurable
+ String executable = ScionPlugin.getDefault().getPreferenceStore().getString(IPreferenceConstants.SCION_SERVER_EXECUTABLE);
List<String> command = new LinkedList<String>();
command.add(executable);
@@ -139,10 +140,13 @@ private void startServerProcess() throws IOException {
builder.redirectErrorStream(true); // send server's stderr to its stdout
process = builder.start();
+ if (process == null) {
+ throw new ScionServerException("Scion server process could not be started");
+ }
+
// Connect to the process's stdout to capture messages
// Assume that status messages and such will be ASCII only
serverStdOutReader = new BufferedReader(new InputStreamReader(process.getInputStream(), "US-ASCII"));
-
Trace.trace(THREAD_PREFIX, "Server started");
}
@@ -175,6 +179,8 @@ private void stopServerProcess() {
* If not, it throws a {@link ScionServerException}.
*/
private void checkRunning() {
+ if (process == null)
+ throw new ScionServerException(String.format("Scion server did not start"));
// There is no way to ask a Process directly whether it is still running,
// so this is the best we can do...
int exitValue;
@@ -194,6 +200,8 @@ private void checkRunning() {
*/
private String lastWords() {
// Collect a post-mortem by reading all that's left in the server's output stream
+ if (serverStdOutReader == null)
+ return "";
StringBuffer lastWords = new StringBuffer();
String line;
do {
@@ -3,14 +3,20 @@
// version 1.0 (EPL). See http://www.eclipse.org/legal/epl-v10.html
package net.sf.eclipsefp.haskell.scion.client;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
import org.eclipse.core.runtime.Platform;
-import org.eclipse.core.runtime.Plugin;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
-public class ScionPlugin extends Plugin {
+public class ScionPlugin extends AbstractUIPlugin {
+ private static final String BUNDLE_NAME = "net.sf.eclipsefp.haskell.scion.client";
private static ScionPlugin instance;
+ private ResourceBundle resourceBundle;
+
public ScionPlugin() {
instance = this;
}
@@ -19,6 +25,8 @@ public ScionPlugin() {
public void start(BundleContext context) throws Exception {
super.start(context);
+ resourceBundle = ResourceBundle.getBundle("plugin");
+
// Preload the server in anticipation of its use
Scion.initializeClient();
}
@@ -34,7 +42,19 @@ private static String getPluginId() {
if (instance != null) {
return instance.getBundle().getSymbolicName();
} else {
- return "net.sf.eclipsefp.haskell.scion.client"; // fallback, but bad for mantainability...
+ return BUNDLE_NAME; // fallback, but bad for mantainability...
+ }
+ }
+
+ public static ScionPlugin getDefault() {
+ return instance;
+ }
+
+ public String getString(String key) {
+ try {
+ return resourceBundle.getString(key);
+ } catch (MissingResourceException ex) {
+ return key;
}
}
@@ -47,5 +67,5 @@ public static boolean isTracing(String optionId) {
String value = Platform.getDebugOption(option);
return value != null && value.equalsIgnoreCase("true");
}
-
+
}
@@ -0,0 +1,242 @@
+package net.sf.eclipsefp.haskell.scion.client.preferences;
+
+import java.io.File;
+import java.io.IOException;
+
+import net.sf.eclipsefp.haskell.scion.client.ScionPlugin;
+
+import org.eclipse.jface.preference.FileFieldEditor;
+import org.eclipse.jface.preference.StringButtonFieldEditor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.FileDialog;
+
+/**
+ * A specialized {@link StringFieldEditor} that only allows executable files to be entered.
+ * On Unix systems, this means that the file must be executable for the current user.
+ * On Windows systems, it must have one of the common file extensions (.exe, .bat, ...).
+ *
+ * Ideally, this would inherit from {@link FileFieldEditor}, but that class was not written
+ * with subclassing in mind. For example, it overrides {@link #checkState} with a version
+ * that does not call {@link #doCheckState}, and it does not allow reading of its
+ * <code>enforceAbsolute</code> setting.
+ *
+ * @author thomas
+ */
+public class ExecutableFileFieldEditor extends StringButtonFieldEditor {
+
+ /**
+ * List of legal file extension suffixes, or <code>null</code>
+ * for system defaults.
+ */
+ private String[] extensions = null;
+
+ /**
+ * Indicates whether the path must be absolute;
+ * <code>false</code> by default.
+ */
+ private boolean enforceAbsolute = false;
+
+ /**
+ * Creates a new file field editor
+ */
+ protected ExecutableFileFieldEditor() {
+ }
+
+ /**
+ * Creates a file field editor.
+ *
+ * @param name the name of the preference this field editor works on
+ * @param labelText the label text of the field editor
+ * @param parent the parent of the field editor's control
+ */
+ public ExecutableFileFieldEditor(String name, String labelText, Composite parent) {
+ this(name, labelText, false, parent);
+ }
+
+ /**
+ * Creates a file field editor.
+ *
+ * @param name the name of the preference this field editor works on
+ * @param labelText the label text of the field editor
+ * @param enforceAbsolute <code>true</code> if the file path
+ * must be absolute, and <code>false</code> otherwise
+ * @param parent the parent of the field editor's control
+ */
+ public ExecutableFileFieldEditor(String name, String labelText, boolean enforceAbsolute, Composite parent) {
+ this(name, labelText, enforceAbsolute, VALIDATE_ON_FOCUS_LOST, parent);
+ }
+
+ /**
+ * Creates a file field editor.
+ *
+ * @param name the name of the preference this field editor works on
+ * @param labelText the label text of the field editor
+ * @param enforceAbsolute <code>true</code> if the file path
+ * must be absolute, and <code>false</code> otherwise
+ * @param validationStrategy either {@link StringButtonFieldEditor#VALIDATE_ON_KEY_STROKE}
+ * to perform on the fly checking, or {@link StringButtonFieldEditor#VALIDATE_ON_FOCUS_LOST}
+ * (the default) to perform validation only after the text has been typed in
+ * @param parent the parent of the field editor's control.
+ * @since 3.4
+ * @see StringButtonFieldEditor#VALIDATE_ON_KEY_STROKE
+ * @see StringButtonFieldEditor#VALIDATE_ON_FOCUS_LOST
+ */
+ public ExecutableFileFieldEditor(String name, String labelText,
+ boolean enforceAbsolute, int validationStrategy, Composite parent) {
+ init(name, labelText);
+ this.enforceAbsolute = enforceAbsolute;
+ loadErrorMessage("ExecutableFileFieldEditor.errorDoesNotExist");//$NON-NLS-1$
+ setChangeButtonText(JFaceResources.getString("openBrowse"));//$NON-NLS-1$
+ setValidateStrategy(validationStrategy);
+ createControl(parent);
+ }
+
+ /* (non-Javadoc)
+ * Method declared on StringButtonFieldEditor.
+ * Opens the file chooser dialog and returns the selected file.
+ */
+ protected String changePressed() {
+ File f = new File(getTextControl().getText());
+ if (!f.exists()) {
+ f = null;
+ }
+ File d = getFile(f);
+ if (d == null) {
+ return null;
+ }
+
+ return d.getAbsolutePath();
+ }
+
+ /**
+ * Checks whether the text input field contains a valid value or not.
+ *
+ * @return <code>true</code> if the field value is valid,
+ * and <code>false</code> if invalid
+ */
+ protected boolean checkState() {
+ if (getTextControl() == null) {
+ return false;
+ }
+ String txt = getTextControl().getText();
+
+ boolean result = isEmptyStringAllowed() || (txt.trim().length() > 0);
+ result = result && doCheckState();
+
+ if (result) {
+ clearErrorMessage();
+ } else {
+ showErrorMessage(getErrorMessage());
+ }
+
+ return result;
+ }
+
+ /**
+ * Helper to open the file chooser dialog.
+ * @param startingDirectory the directory to open the dialog on.
+ * @return File The File the user selected or <code>null</code> if they
+ * do not.
+ */
+ private File getFile(File startingDirectory) {
+
+ FileDialog dialog = new FileDialog(getShell(), SWT.OPEN | SWT.SHEET);
+ if (startingDirectory != null) {
+ dialog.setFileName(startingDirectory.getPath());
+ }
+ if (extensions != null) {
+ dialog.setFilterExtensions(extensions);
+ }
+ String file = dialog.open();
+ if (file != null) {
+ file = file.trim();
+ if (file.length() > 0) {
+ return new File(file);
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Sets this file field editor's file extension filter.
+ *
+ * @param extensions a list of file extension, or <code>null</code>
+ * to set the filter to the system's default value
+ */
+ public void setFileExtensions(String[] extensions) {
+ this.extensions = extensions;
+ }
+
+ /**
+ * Returns true if the current value is an existing file that is executable.
+ * If this cannot be determined with certainty, true is returned.
+ * If false is returned, the error message is set.
+ */
+ @Override
+ protected boolean doCheckState() {
+ String fileName = getTextControl().getText();
+ File file = new File(fileName);
+ return checkFileExists(file) && checkFileAbsolute(file) && checkFileExecutable(file);
+ }
+
+ /**
+ * Checks whether the file exists and is a normal file.
+ * If not, returns false and sets the error message.
+ */
+ protected boolean checkFileExists(File file) {
+ if (!file.isFile()) {
+ loadErrorMessage("ExecutableFileFieldEditor.errorDoesNotExist");
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Checks wether the file path is absolute if that was requested.
+ * If not, returns false and sets the error message.
+ * Assumes that the file exists.
+ */
+ protected boolean checkFileAbsolute(File file) {
+ if (enforceAbsolute && !file.isAbsolute()) {
+ loadErrorMessage("ExecutableFileFieldEditor.errorNotAbsolute");
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Checks whether the file is executable.
+ * If not, returns false and sets the error message.
+ * Assumes that the file exists.
+ */
+ protected boolean checkFileExecutable(File file) {
+ // if (we are on Unix) {
+ // Until Java 7, there is no way to check the executable bit of a file.
+ // Apart from writing a JNI function (hassle), this is the best we can do...
+ try {
+ Process process = Runtime.getRuntime().exec(new String[] {"test", "-x", file.getAbsolutePath()});
+ int exitValue = process.waitFor();
+ if (exitValue != 0) {
+ loadErrorMessage("ExecutableFileFieldEditor.errorNotExecutable");
+ return false;
+ }
+ } catch (IOException ex) {
+ // pretend it succeeded
+ } catch (InterruptedException ex) {
+ // pretend it succeeded
+ }
+ // } else if (we are on Windows) {
+ // TODO implement this for Windows
+ // }
+ return true; // all checks succeeded
+ }
+
+ private void loadErrorMessage(String key) {
+ String message = ScionPlugin.getDefault().getString(key);
+ setErrorMessage(message);
+ }
+
+}
@@ -0,0 +1,10 @@
+package net.sf.eclipsefp.haskell.scion.client.preferences;
+
+/**
+ * Constant definitions for plug-in preferences.
+ */
+public interface IPreferenceConstants {
+
+ public static final String SCION_SERVER_EXECUTABLE = "SCION_SERVER_EXECUTABLE";
+
+}
@@ -0,0 +1,26 @@
+package net.sf.eclipsefp.haskell.scion.client.preferences;
+
+import net.sf.eclipsefp.haskell.scion.client.ScionPlugin;
+
+import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
+import org.eclipse.jface.preference.IPreferenceStore;
+
+/**
+ * Class used to initialize default preference values. Referenced from plugin.xml.
+ *
+ * @author Thomas ten Cate
+ */
+public class PreferenceInitializer extends AbstractPreferenceInitializer implements IPreferenceConstants {
+
+ /**
+ * Initializes the preferences for the Scion plugin.
+ *
+ * @see org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer#initializeDefaultPreferences()
+ */
+ public void initializeDefaultPreferences() {
+ IPreferenceStore store = ScionPlugin.getDefault().getPreferenceStore();
+ store.setDefault(SCION_SERVER_EXECUTABLE,
+ "/usr/local/bin/scion_server");
+ }
+
+}
Oops, something went wrong.

0 comments on commit c7d3866

Please sign in to comment.