PathTools : Simple Yet Useful Eclipse Plug-in

Tags:
In this article we develop a simple yet useful Eclipse plug-in PathTools.  The plug-in adds the following three actions to Eclipse.

  • CopyPath - this action copies the fully qualified path of selected folders and files into the Clipboard.
  • Explore - this action opens the selected folder or the folder containing the selected file in the OS file explorer.  The user can configure the exact command that is used to launch the file explorer.
  • Open in external editor... - this action opens the selected folder or file using the selected external editor.  The user can configure the exact command that is used to launch the external editor.

The following screenshot shows the CopyPath, Explore and Open in external editor... actions on the second toolbar.  The Activator.java file was selected in the Package Explorer. The Explore action was invoked to show it in the Finder (the Mac OS file explorer). The Open in external editor... action was invoked to show it in the TextEdit.

Implementing Actions

Extension Point


These extensions register the actions 1.  Both actions are enabled for any selected object of type org.eclipse.core.resources.IResource or adaptable as org.eclipse.core.resources.IResource 3.  The Explore path action is enabled when one object (enablesFor="1" 2) is selected.  The CopyPath action is enabled when one or more objects (enablesFor="+" 4) are selected.


   <extension
point="org.eclipse.ui.actionSets">
<actionSet
id="PathTools.actionSet"
label="Path Tools">
<action
1 class="pathtools.EditAction"
2 enablesFor="1"
icon="icons/editpath.gif"
id="PathTools.Edit"
label="Open in external editor..."
menubarPath="File/additions"
style="push"
toolbarPath="PathTools/additions">
<enablement>
<or>
3 <objectClass
name="org.eclipse.core.resources.IResource"/>
<objectClass
name="org.eclipse.core.runtime.IAdaptable"/>
</or>
</enablement>
</action>
<action
1 class="pathtools.ExploreAction"
2 enablesFor="1"
icon="icons/explore.gif"
id="PathTools.Explore"
label="Explore"
menubarPath="File/additions"
style="push"
toolbarPath="PathTools/additions">
<enablement>
<or>
3 <objectClass
name="org.eclipse.core.resources.IResource"/>
<objectClass
name="org.eclipse.core.runtime.IAdaptable"/>
</or>
</enablement>
</action>
<action
1 class="pathtools.CopyPathAction"
4 enablesFor="+"
icon="icons/copypaths.gif"
id="PathTools.CopyPath"
label="Copy Path"
menubarPath="Edit/additions"
style="push"
toolbarPath="Edit/additions">
<enablement>
<or>
3 <objectClass
name="org.eclipse.core.resources.IResource"/>
<objectClass
name="org.eclipse.core.runtime.IAdaptable"/>
</or>
</enablement>
</action>
</actionSet>
</extension>

CopyPath Action

The following code implements the CopyPath action.  The CopyPath action copies the full paths of selected folders or files (one per line) to the Clipboard.

CopyPath.java

package pathtools;

import java.io.File;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;
import org.eclipse.ui.PlatformUI;

/**
* This copies the absolute paths of selected folders and files (one per line)
* into the Clipboard.
*
* @author Sandip V. Chitale
*
*/
public class CopyPathAction implements IWorkbenchWindowActionDelegate {
private List<String> paths = new LinkedList<String>();

public void dispose() {
}

public void init(IWorkbenchWindow window) {

}

public void run(IAction action) {
// Are there any paths selected ?
if (paths.size() > 0) {
// Build a string with each path on separate line
StringBuilder stringBuilder = new StringBuilder();
for (String path : paths) {
stringBuilder.append(path + "\n");
}
// Get Clipboard
Clipboard clipboard = new Clipboard(PlatformUI.getWorkbench()
.getActiveWorkbenchWindow().getShell().getDisplay());
// Put the paths string into the Clipboard
clipboard.setContents(new Object[] { stringBuilder.toString() },
new Transfer[] { TextTransfer.getInstance() });
}
}

@SuppressWarnings("unchecked")
public void selectionChanged(IAction action, ISelection selection) {
// Start with a clear list
paths.clear();
if (selection instanceof IStructuredSelection) {
// Get structured selection
IStructuredSelection structuredSelection = (IStructuredSelection) selection;

// Iterate through selected items
Iterator iterator = structuredSelection.iterator();
while (iterator.hasNext()) {
Object firstElement = iterator.next();
IPath location = null;
if (firstElement instanceof IResource) {
// Is it a IResource ?
IResource resource = (IResource) firstElement;
// Get the location
location = resource.getLocation();
} else if (firstElement instanceof IAdaptable) {
// Is it a IResource adaptable ?
IAdaptable adaptable = (IAdaptable) firstElement;
IResource resource = (IResource) adaptable
.getAdapter(IResource.class);
if (resource != null) {
// Get the location
location = resource.getLocation();
}
}
if (location != null) {
// Get the file for the location
File file = location.toFile();
if (file != null) {
// Add the absolute path to the list
paths.add(file.getAbsolutePath());
}
}
}
}
action.setEnabled(paths.size() > 0);
}
}

Explore Action

The following code implements the Explore action. The explore action launches the OS file explorer with the selected folder or file.

ExploreAction.java
package pathtools;

import java.io.File;
import java.text.MessageFormat;

import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;

/**
* This launches the OS file explorer showing the selected folder or the folder
* containing the selected file.
*
* @author Sandip V. Chitale
*
*/
public class ExploreAction implements IWorkbenchWindowActionDelegate {
private File fileObject;

private static String fileExploreComand = null;
private static String folderExploreComand = null;

public void dispose() {
}

public void init(IWorkbenchWindow window) {

}

public void run(IAction action) {
// Get the configured explorer commands for folder and file
folderExploreComand = Activator.getDefault().getPreferenceStore()
.getString(Activator.FOLDER_EXPLORE_COMMAND_KEY);
fileExploreComand = Activator.getDefault().getPreferenceStore()
.getString(Activator.FILE_EXPLORE_COMMAND_KEY);
if (fileExploreComand == null || folderExploreComand == null) {
return;
}
// Is this a physical file on the disk ?
if (fileObject != null) {
String commandFormat = fileObject.isDirectory() ? folderExploreComand
: fileExploreComand;

// Substitute parameter values ad format the explore command
String command = MessageFormat.format(Utilities
.convertParameters(commandFormat), new Object[] {
fileObject.getAbsolutePath().replace('/',
File.separatorChar).replace('\\',
File.separatorChar),
fileObject.getParentFile().getAbsolutePath().replace('/',
File.separatorChar).replace('\\',
File.separatorChar),
fileObject.getAbsolutePath().replace('\\', '/'),
fileObject.getParentFile().getAbsolutePath().replace('\\',
'/'),
fileObject.getAbsolutePath().replace('/', '\\'),
fileObject.getParentFile().getAbsolutePath().replace('/',
'\\'), });
// Launch the explore command
CommandLauncher.launch(command);
}
}

public void selectionChanged(IAction action, ISelection selection) {
fileObject = null;
action.setEnabled(false);
if (selection instanceof IStructuredSelection) {
IStructuredSelection structuredSelection = (IStructuredSelection) selection;
IPath location = null;
// Is only one item selected?
if (structuredSelection.size() == 1) {
Object firstElement = structuredSelection.getFirstElement();
if (firstElement instanceof IResource) {
// Is this an IResource ?
IResource resource = (IResource) firstElement;
location = resource.getLocation();
} else if (firstElement instanceof IAdaptable) {
IAdaptable adaptable = (IAdaptable) firstElement;
// Is this an IResource adaptable ?
IResource resource = (IResource) adaptable
.getAdapter(IResource.class);
if (resource != null) {
location = resource.getLocation();
}
}
}
if (location != null) {
fileObject = location.toFile();
}
}
action.setEnabled(fileObject != null);
}

}

Open in external editor... Action

The following code implements the Open in external editor... action. The Open in external editor... opens the selected folder or file in the user specified external editor.

EditAction.java

package pathtools;

import java.io.File;
import java.text.MessageFormat;

import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;

/**
* This launches the external text editor for selected folder or file.
*
* @author Sandip V. Chitale
*
*/
public class EditAction implements IWorkbenchWindowActionDelegate {
private File fileObject;

private static String fileEditComand = null;
private static String folderEditComand = null;

public void dispose() {
}

public void init(IWorkbenchWindow window) {

}

public void run(IAction action) {
// Get the configured explorer commands for folder and file
folderEditComand = Activator.getDefault().getPreferenceStore()
.getString(Activator.FOLDER_EDIT_COMMAND_KEY);
fileEditComand = Activator.getDefault().getPreferenceStore().getString(
Activator.FILE_EDIT_COMMAND_KEY);
if (fileEditComand == null || folderEditComand == null) {
return;
}
// Is this a physical file on the disk ?
if (fileObject != null) {
String commandFormat = fileObject.isDirectory() ? folderEditComand
: fileEditComand;

// Substitute parameter values ad format the explore command
String command = MessageFormat.format(Utilities
.convertParameters(commandFormat), new Object[] {
fileObject.getAbsolutePath().replace('/',
File.separatorChar).replace('\\',
File.separatorChar),
fileObject.getParentFile().getAbsolutePath().replace('/',
File.separatorChar).replace('\\',
File.separatorChar),
fileObject.getAbsolutePath().replace('\\', '/'),
fileObject.getParentFile().getAbsolutePath().replace('\\',
'/'),
fileObject.getAbsolutePath().replace('/', '\\'),
fileObject.getParentFile().getAbsolutePath().replace('/',
'\\'), });
// Launch the explore command
CommandLauncher.launch(command);
}
}

public void selectionChanged(IAction action, ISelection selection) {
fileObject = null;
action.setEnabled(false);
if (selection instanceof IStructuredSelection) {
IStructuredSelection structuredSelection = (IStructuredSelection) selection;
IPath location = null;
// Is only one item selected?
if (structuredSelection.size() == 1) {
Object firstElement = structuredSelection.getFirstElement();
if (firstElement instanceof IResource) {
// Is this an IResource
IResource resource = (IResource) firstElement;
location = resource.getLocation();
} else if (firstElement instanceof IAdaptable) {
IAdaptable adaptable = (IAdaptable) firstElement;
// Is this an IResource adaptable
IResource resource = (IResource) adaptable
.getAdapter(IResource.class);
if (resource != null) {
location = resource.getLocation();
}
}
}
if (location != null) {
fileObject = location.toFile();
}
}
action.setEnabled(fileObject != null);
}

}

Required Plugin dependencies

The manifest file declares the required dependencies. 1

MANIFEST.MF

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Path Tools Plug-in
Bundle-SymbolicName: PathTools;singleton:=true
Bundle-Version: 1.0.0
Bundle-Activator: pathtools.Activator
Bundle-Vendor: Sandip V. Chitale
1Require-Bundle: org.eclipse.ui,
org.eclipse.core.runtime,
org.eclipse.core.resources;bundle-version="3.4.0"
Bundle-RequiredExecutionEnvironment: J2SE-1.5
Bundle-ActivationPolicy: lazy

Implementing Preferences Page

The preferences page allows the user to commands for file explorer and external editor.

Path Tools Preferences

 

Extension Point for Preference Page


This extension registers the preferences page. 1

   <extension
1 point="org.eclipse.ui.preferencePages">
<page
2 class="pathtools.WorkbenchPreferencePage"
id="PathTools.page"
name="Path Tools">
</page>
</extension>


Preference Page

The following class (registred above 2) implements the preferences page using the FieldEditors.

WorkbenchPreferencePage.java
package pathtools;

import org.eclipse.jface.preference.FieldEditorPreferencePage;
import org.eclipse.jface.preference.StringFieldEditor;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;

/**
*
* This implements the preferences page using the FieldEditor.
*
* @author Sandip V. Chitale
*
*/
public class WorkbenchPreferencePage extends FieldEditorPreferencePage
implements IWorkbenchPreferencePage {

public WorkbenchPreferencePage() {
super(FieldEditorPreferencePage.GRID);
}

public void init(IWorkbench workbench) {
// Initialize the preference store we wish to use
setPreferenceStore(Activator.getDefault().getPreferenceStore());
}

@Override
public String getDescription() {
return "Specify the commands for exploring folders and fies. You can\n"
+ "use \"\" (quotes) around command arguments with spaces in their value.\n"
+ "You can use the following parameters in the commands:\n\n"
+ Utilities.FILE_PATH
+ " - path of the selected object with default file separator.\n"
+ Utilities.FILE_PARENT_PATH
+ " - path of the parent of selected object with default file separator.\n"
+ Utilities.FILE_PATH_SLASHES
+ " - path of the selected object with / file separator.\n"
+ Utilities.FILE_PARENT_PATH_SLASHES
+ " - path of the parent of selected object with / file separator.\n"
+ Utilities.FILE_PATH_BACKSLASHES
+ " - path of the selected object with \\ File separator.\n"
+ Utilities.FILE_PARENT_PATH_BACKSLASHES
+ "{parent-path-backslashes} - path of the parent of selected object with \\ file separator.\n"
+ "\n";
}

@Override
protected void createFieldEditors() {
// Folder explore command field
StringFieldEditor folderExploreCommad = new StringFieldEditor(
Activator.FOLDER_EXPLORE_COMMAND_KEY, "Explore Folder:",
getFieldEditorParent());
addField(folderExploreCommad);

// File explore command field
StringFieldEditor fileExploreCommad = new StringFieldEditor(
Activator.FILE_EXPLORE_COMMAND_KEY, "Explore File:",
getFieldEditorParent());
addField(fileExploreCommad);

// Folder editor command field
StringFieldEditor folderEditCommad = new StringFieldEditor(
Activator.FOLDER_EDIT_COMMAND_KEY, "Edit Folder:",
getFieldEditorParent());
addField(folderEditCommad);

// File editor command field
StringFieldEditor fileEditCommad = new StringFieldEditor(
Activator.FILE_EDIT_COMMAND_KEY, "Edit File:",
getFieldEditorParent());
addField(fileEditCommad);
}

}

Bundle Activator

The following class implements the bundle activator.  It initializes the default values of the explore commands for folders and files depending on the platform the Eclipse is running on.

Activator.java
package pathtools;

import java.io.File;

import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;

/**
* The activator class controls the plug-in life cycle
*
* @author Sandip V. Chitale
*
*/
public class Activator extends AbstractUIPlugin {
static final String FOLDER_EXPLORE_COMMAND_KEY = "folderExploreCommand";
static final String FILE_EXPLORE_COMMAND_KEY = "fileExploreCommand";

static String defaultFolderExploreCommand = "";
static String defaultFileExploreCommand = "";

static final String FOLDER_EDIT_COMMAND_KEY = "folderEditCommand";
static final String FILE_EDIT_COMMAND_KEY = "fileEditCommand";

static String defaultFolderEditCommand = "";
static String defaultFileEditCommand = "";

static {
if (Platform.OS_MACOSX.equals(Platform.getOS())) {
defaultFolderExploreCommand = "/usr/bin/open -a /System/Library/CoreServices/Finder.app \""
+ Utilities.FILE_PATH + "\"";
defaultFileExploreCommand = "/usr/bin/open -a /System/Library/CoreServices/Finder.app \""
+ Utilities.FILE_PARENT_PATH + "\"";
defaultFolderEditCommand = "/usr/bin/open -a /System/Library/CoreServices/Finder.app \""
+ Utilities.FILE_PATH + "\"";
defaultFileEditCommand = "/usr/bin/open -a /Applications/TextEdit.app \""
+ Utilities.FILE_PATH + "\"";
} else if (Platform.OS_WIN32.equals(Platform.getOS())) {
defaultFolderExploreCommand = "cmd /C start explorer /select,/e \""
+ Utilities.FILE_PATH + "\"";
defaultFileExploreCommand = "cmd /C start explorer /select,/e \""
+ Utilities.FILE_PARENT_PATH + "\"";
defaultFolderEditCommand = "cmd /C start explorer /select,/e \""
+ Utilities.FILE_PATH + "\"";
defaultFileEditCommand = "cmd /C start notepad \""
+ Utilities.FILE_PATH + "\"";
} else if (Platform.OS_LINUX.equals(Platform.getOS())) {
if (new File("/usr/bin/konqueror").exists()) {
defaultFolderExploreCommand = "/usr/bin/konqueror \""
+ Utilities.FILE_PATH + "\"";
defaultFileExploreCommand = "/usr/bin/konqueror \""
+ Utilities.FILE_PARENT_PATH + "\"";
defaultFolderEditCommand = "/usr/bin/konqueror \""
+ Utilities.FILE_PATH + "\"";
} else if (new File("/usr/bin/nautilus").exists()) {
defaultFolderExploreCommand = "/usr/bin/nautilus \""
+ Utilities.FILE_PATH + "\"";
defaultFileExploreCommand = "/usr/bin/nautilus \""
+ Utilities.FILE_PARENT_PATH + "\"";
defaultFolderEditCommand = "/usr/bin/nautilus \""
+ Utilities.FILE_PATH + "\"";
}
if (new File("/usr/bin/kedit").exists()) {
defaultFileEditCommand = "/usr/bin/kedit \""
+ Utilities.FILE_PATH + "\"";
} else if (new File("/usr/bin/gedit").exists()) {
defaultFileEditCommand = "/usr/bin/gedit \""
+ Utilities.FILE_PATH + "\"";
}
} else if (Platform.OS_SOLARIS.equals(Platform.getOS())) {
if (new File("/usr/bin/konqueror").exists()) {
defaultFolderExploreCommand = "/usr/bin/konqueror \""
+ Utilities.FILE_PATH + "\"";
defaultFileExploreCommand = "/usr/bin/konqueror \""
+ Utilities.FILE_PARENT_PATH + "\"";
defaultFolderEditCommand = "/usr/bin/konqueror \""
+ Utilities.FILE_PATH + "\"";
} else if (new File("/usr/bin/nautilus").exists()) {
defaultFolderExploreCommand = "/usr/bin/nautilus \""
+ Utilities.FILE_PATH + "\"";
defaultFileExploreCommand = "/usr/bin/nautilus \""
+ Utilities.FILE_PARENT_PATH + "\"";
defaultFolderEditCommand = "/usr/bin/nautilus \""
+ Utilities.FILE_PATH + "\"";
} else {
defaultFolderExploreCommand = "filemgr -c -d \""
+ Utilities.FILE_PATH + "\"";
defaultFolderExploreCommand = "filemgr -c -d \""
+ Utilities.FILE_PATH + "\"";
defaultFileEditCommand = "filemgr -c -d \""
+ Utilities.FILE_PARENT_PATH + "\"";
}
}
}

// The plug-in ID
public static final String PLUGIN_ID = "PathTools";

// The shared instance
private static Activator plugin;

/**
* The constructor
*/
public Activator() {
}

/*
* (non-Javadoc)
*
* @see
* org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext
* )
*/
public void start(BundleContext context) throws Exception {
super.start(context);
plugin = this;
}

/*
* (non-Javadoc)
*
* @see
* org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext
* )
*/
public void stop(BundleContext context) throws Exception {
plugin = null;
super.stop(context);
}

@SuppressWarnings("deprecation")
@Override
protected void initializeDefaultPreferences(IPreferenceStore store) {
store.setDefault(FOLDER_EXPLORE_COMMAND_KEY,
defaultFolderExploreCommand);
store.setDefault(FILE_EXPLORE_COMMAND_KEY, defaultFileExploreCommand);
store.setDefault(FOLDER_EDIT_COMMAND_KEY, defaultFolderEditCommand);
store.setDefault(FILE_EDIT_COMMAND_KEY, defaultFileEditCommand);
super.initializeDefaultPreferences(store);
}

/**
* Returns the shared instance
*
* @return the shared instance
*/
public static Activator getDefault() {
return plugin;
}

}

Utilities

The following class implements the parameter substitution as well as parsing the quoted parameters and splitting the commands into String arrays.

Utilities.java
package pathtools;

import java.util.LinkedList;
import java.util.List;
import java.util.regex.Pattern;

/**
* This implements some utility methods.
*
* @author Sandip V. Chitale
*
*/
public class Utilities {
static final String FILE_PATH = "{path}";
static final String FILE_PARENT_PATH = "{parent-path}";
static final String FILE_PATH_SLASHES = "{path-slashes}";
static final String FILE_PARENT_PATH_SLASHES = "{parent-path-slashes}";
static final String FILE_PATH_BACKSLASHES = "{path-backslashes}";
static final String FILE_PARENT_PATH_BACKSLASHES = "{parent-path-backslashes}";

static String convertParameters(String command) {
return command.replaceAll(Pattern.quote(FILE_PATH), "{0}").replaceAll(
Pattern.quote(FILE_PARENT_PATH), "{1}").replaceAll(
Pattern.quote(FILE_PATH_SLASHES), "{2}").replaceAll(
Pattern.quote(FILE_PARENT_PATH_SLASHES), "{3}").replaceAll(
Pattern.quote(FILE_PATH_BACKSLASHES), "{4}").replaceAll(
Pattern.quote(FILE_PARENT_PATH_BACKSLASHES), "{5}");
}

/**
* Parses parameters from a given string in shell-like manner. Users of the
* Bourne shell (e.g. on Unix) will already be familiar with the behavior.
* For example, when using <code>java.lang.ProcessBuilder</code> (Execution
* API) you should be able to:
* <ul>
* <li>Include command names with embedded spaces, such as
* <code>c:\Program Files\jdk\bin\javac</code>.
* <li>Include extra command arguments, such as <code>-Dname=value</code>.
* <li>Do anything else which might require unusual characters or
* processing. For example:
* <p>
* <code><pre>
* "c:\program files\jdk\bin\java" -Dmessage="Hello /\\/\\ there!" -Xmx128m
* </pre></code>
* <p>
* This example would create the following executable name and arguments:
* <ol>
* <li> <code>c:\program files\jdk\bin\java</code>
* <li> <code>-Dmessage=Hello /\/\ there!</code>
* <li> <code>-Xmx128m</code>
* </ol>
* Note that the command string does not escape its backslashes--under the
* assumption that Windows users will not think to do this, meaningless
* escapes are just left as backslashes plus following character.
* </ul>
* <em>Caveat</em>: even after parsing, Windows programs (such as the Java
* launcher) may not fully honor certain characters, such as quotes, in
* command names or arguments. This is because programs under Windows
* frequently perform their own parsing and unescaping (since the shell
* cannot be relied on to do this). On Unix, this problem should not occur.
*
* Copied from org.openide.util.Utilities.
*
* @param s
* a string to parse
* @return an array of parameters
*/
public static String[] parseParameters(String s) {
int NULL = 0x0; // STICK + whitespace or NULL + non_"
int INPARAM = 0x1; // NULL + " or STICK + " or INPARAMPENDING + "\ //
// NOI18N
int INPARAMPENDING = 0x2; // INPARAM + \
int STICK = 0x4; // INPARAM + " or STICK + non_" // NOI18N
int STICKPENDING = 0x8; // STICK + \
List<String> params = new LinkedList<String>();
char c;

int state = NULL;
StringBuffer buff = new StringBuffer(20);
int slength = s.length();

for (int i = 0; i < slength; i++) {
c = s.charAt(i);

if (Character.isWhitespace(c)) {
if (state == NULL) {
if (buff.length() > 0) {
params.add(buff.toString());
buff.setLength(0);
}
} else if (state == STICK) {
params.add(buff.toString());
buff.setLength(0);
state = NULL;
} else if (state == STICKPENDING) {
buff.append('\\');
params.add(buff.toString());
buff.setLength(0);
state = NULL;
} else if (state == INPARAMPENDING) {
state = INPARAM;
buff.append('\\');
buff.append(c);
} else { // INPARAM
buff.append(c);
}

continue;
}

if (c == '\\') {
if (state == NULL) {
++i;

if (i < slength) {
char cc = s.charAt(i);

if ((cc == '"') || (cc == '\\')) {
buff.append(cc);
} else if (Character.isWhitespace(cc)) {
buff.append(c);
--i;
} else {
buff.append(c);
buff.append(cc);
}
} else {
buff.append('\\');

break;
}

continue;
} else if (state == INPARAM) {
state = INPARAMPENDING;
} else if (state == INPARAMPENDING) {
buff.append('\\');
state = INPARAM;
} else if (state == STICK) {
state = STICKPENDING;
} else if (state == STICKPENDING) {
buff.append('\\');
state = STICK;
}

continue;
}

if (c == '"') {
if (state == NULL) {
state = INPARAM;
} else if (state == INPARAM) {
state = STICK;
} else if (state == STICK) {
state = INPARAM;
} else if (state == STICKPENDING) {
buff.append('"');
state = STICK;
} else { // INPARAMPENDING
buff.append('"');
state = INPARAM;
}

continue;
}

if (state == INPARAMPENDING) {
buff.append('\\');
state = INPARAM;
} else if (state == STICKPENDING) {
buff.append('\\');
state = STICK;
}

buff.append(c);
}

// collect
if (state == INPARAM) {
params.add(buff.toString());
} else if ((state & (INPARAMPENDING | STICKPENDING)) != 0) {
buff.append('\\');
params.add(buff.toString());
} else { // NULL or STICK

if (buff.length() != 0) {
params.add(buff.toString());
}
}

String[] ret = params.toArray(new String[0]);

return ret;
}

}
CommandLauncher.java
package pathtools;

import java.io.IOException;
import java.util.Arrays;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;

/**
* A simple external process launcher.
*
* @author Sandip V. Chitale
*
*/
public class CommandLauncher {

public static void launch(String command) {
Activator activator = Activator.getDefault();
String[] commandArray = Utilities.parseParameters(command);
try {
Process process = Runtime.getRuntime().exec(commandArray);
// TODO Should handle STDOUT and STDERR here.
int status = process.waitFor();
if (status == 0) {
// Good
} else {
activator.getLog().log(
new Status(IStatus.ERROR, activator.getBundle()
.getSymbolicName(), "Process '"
+ Arrays.asList(commandArray).toString()
+ "' exited with status: " + status));
}
} catch (InterruptedException ex) {
activator.getLog()
.log(
new Status(IStatus.ERROR, activator.getBundle()
.getSymbolicName(),
"Exception while executing '"
+ Arrays.asList(commandArray)
.toString() + "'", ex));
} catch (IOException ioe) {
activator.getLog()
.log(
new Status(IStatus.ERROR, activator.getBundle()
.getSymbolicName(),
"Exception while executing '"
+ Arrays.asList(commandArray)
.toString() + "'", ioe));
}
}

}

Installation

The resources section has the link to the plugin jar which can be dropped into your Eclipse installation's plugins directory. Once installed you will have to make the  PathTools actions visible by going to the Window:Customize Perspectives:Commands tab and selecting the Path Tools action set.

Source Code

The source code is bundled in the plug-in's jar file. In fact you can import the source plug-in project into  PDE  and hack it further.

Conclusion

In this tutorial we built a simple yet useful Eclipse plug-in called - PathTools. It makes use of the actionSet and preference page extension points to add useful functionality to Eclipse. It also demonstrates how easy it is to build the preferences pages.

Java and all Java-based trademarks and logos are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States, other countries, or both.

Resources

Notes on the Eclipse Plug-in Architecture
PDE Does Plug-ins
Contributing Actions to the Eclipse Workbench
Preferences in the Eclipse Workbench UI

PathTools_1.0.0.jar
Subtitle: 
In this article we develop a simple yet useful Eclipse plug-in PathTools. The plug-in adds CopyPath, Explore and Open in external editor... actions to Eclipse.
Article Type: 
How-to
0

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Anuradha Gunasekara replied on Wed, 2008/08/20 - 8:48am

Hey Sandip,

 Now you on  Eclipse ;-) we miss you on Netbeans :-(

sandipchitale replied on Wed, 2008/08/20 - 1:36pm

I have created a Google Code project for PathTools.

 You can download the latest plugin here.

sandipchitale replied on Thu, 2008/08/21 - 1:51pm

Hi Anuradha,

Yup... I will be working on Eclipse now. I use to work on Eclipse before I joined Sun also. However I will continue to support my NetBeans modules and also download and build NetBeans once in a while.

Regards,

Sandip

toyinf replied on Fri, 2008/08/22 - 8:34am

Hi your article was great.

I got a problem. 

I've got elements A (ScrapItemEditPart), B, C (Folder) in my model on the workspace,  I want to be able to replace element A with element C. This is my problem: When I select element A and hit the replace button, element C appears but element A becomes faded (not properly deleted) and the remaining elements B, C and D becomes unmovable (static) on the workspace. I cant even create any new elements. Do you have a code that can change a shape to another?

Here is my code:

public class CreateShape implements IObjectActionDelegate {

public final static String ID = "org.eclipse.scrapbook.custom.newAction";

private ScrapItemEditPart selectedElement;

public void run(IAction action) {

//CompoundCommand cc = new CompoundCommand("Create another shape");

 // we will combine all of these commands together

CompoundCommand cc = new CompoundCommand("A compound command");

//add it to the compound command

 

// Create the new shape.

CreateViewRequest shapeRequest = CreateViewRequestFactory.getCreateShapeRequest(ScrapBuukElementTypes.Folder_1001, selectedElement.getDiagramPreferencesHint());

Point p = selectedElement.getFigure().getBounds().getTopRight().getCopy();

selectedElement.getFigure().translateToAbsolute(p);

int edgeCount = selectedElement.getNotationView().getSourceEdges().size();

// A quick hack to get element to layout to the right, from top to bottom

int offset = (edgeCount * 0);

shapeRequest.setLocation(p.translate(-45, offset));

 

ScrapBookDiagramEditPart scrapbookmodelEditPart = (ScrapBookDiagramEditPart) selectedElement.getParent();

Command createShapeCmd = scrapbookmodelEditPart.getCommand(shapeRequest);

cc.add(createShapeCmd);  

// try this code to destroy the element to be replaced

DestroyElementRequest request2 = new DestroyElementRequest (selectedElement.resolveSemanticElement(), false);

Command destroy = selectedElement.getCommand(new EditCommandRequestWrapper(request2) );

cc.add(destroy);

// you can then execute the command

selectedElement.getDiagramEditDomain().getDiagramCommandStack().execute(cc);

 

}

 

public void selectionChanged(IAction action, ISelection selection) {

selectedElement = null;

if (selection instanceof IStructuredSelection) {

IStructuredSelection Selection = (IStructuredSelection) selection;

if (Selection.getFirstElement() instanceof ScrapItemEditPart) {

selectedElement = (ScrapItemEditPart) Selection.getFirstElement();

}

}

}

public void setActivePart(IAction action, IWorkbenchPart targetPart) {

}

 

}

 

Thanks 


sandipchitale replied on Fri, 2008/08/22 - 1:05pm

@toyfun Sorry I am not familiar with that code.

sandipchitale replied on Tue, 2008/08/26 - 10:47pm

PathTools 1.0.6 now supports custom commands. Get it.

Eric replied on Fri, 2008/09/05 - 10:05am

I don't see where you can access the custom commands. Meaning I create a file custom command. Now how do I run it when I am viewing a file? If I can figure this out, I think I am going to find this very useful. Thanks for the article and of course the plugin.

sandipchitale replied on Fri, 2008/09/05 - 6:45pm in response to: etoelz

The commands appear in the Custom commands action's (fourth icon) dropdown:

PathTools Toolbar

sandipchitale replied on Sat, 2008/10/25 - 2:26pm

Added a lot more functionality to Path Tools plug-in. Check it out here.

musharrif replied on Tue, 2008/12/02 - 3:48am in response to: sandipchitale

Hi Sandip

For my project I have my own 2 XML files. One file is responsible for formatting and other one is for checkstyle. Every time when i change the work space or view, the links to these files disappear and I get default configuration for checkstyle. I have tried to cope this situation by setting preferences but it  I didn't succeed.

Please give me solution for this problem if there is any.

 

R/
Musharrif

sandipchitale replied on Wed, 2008/12/03 - 12:38am

Musharrif,

Get the latest version of the plug-in here:

http://code.google.com/p/pathtools/

I think this will solve your issue.

--

Sandip

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.