Saturday, June 04, 2011

Eclipse: Command Key binding Cross Reference

I dusted off an Eclispe Plug-in that I had developed a few years ago. The idea is similar to Emac's describe-key (Ctrl+h) and where-is (Ctrl+w) but applied to Eclipse with some additional bells and whistles.

The  Command Key binding Cross Reference Plug-in shows a pop-up dialog. The dialog can be invoked in two modes:
  • Key binding centric
  • Command centric
Key binding centric mode can be invoked by clicking on the keys icon (Ctrl+Alt+Shift+K) in the status bar. It shows the following pop-up dialog:



The focus is in the Keysequence: field. You can type any modified keys and it shows the key sequence in text for e.g. Ctrl+D in the screenshot above. The BACKSPACE works normally. If you want to enter the BACKSPACE key itself use the small left arrow menu next to the Keysequence: field. In the bottom table it shows all the commands that match the key  sequence text. The current hierarchy of contexts, platform, and some help info is shows in the legend at the bottom. For example, the legend is showing that the Editing Java Source context is the most active context. The commands applicable in the context are shown in normal font. The commands not applicable in any of the active contexts are shown in disabled font. You can invoked the active commands by double clicking on the row or selecting the row and typing Enter key.

Eclipse has different key binding schemes. You can explore the key bindings of other schemes by selecting it in the Scheme: combo box.

You can type the keys without any modifiers. In that case commands matching all modifier variants of the key sequence are shown:



This can help you see if you are defining the key binding modifiers in a consistent fashion.

Command centric mode can be invoked by clicking on the keys icon(Ctrl+Alt+Shift+L) in the status bar. It shows the following pop-up dialog:



In this mode the Command: field has the focus. You can just type part of the command name and it will filter out the matching commands. To anchor the match at the beginning use the ^. You can use the * and ? as the wildcards. You  can easily switch Key binding centric mode by hitting tab.

Lastly, the P column shows the icon of the platform if the command is defined for a specific platform such as Windows, Macor Linux. The U column shows the icon if the user has customized the key binding using Preferences > General > Keys.

You can install the plug-in from it's update site:

http://sandipchitaleseclipseplugins.googlecode.com/svn/trunk/commandkeybinding.xref.updatesite


Please file any issues at:

http://code.google.com/p/sandipchitaleseclipseplugins/issues/list


Works in Eclipse 3.5.x and 3.6.x.

Enjoy!

Sunday, May 29, 2011

Eclipse: Show all instances of selected Java Class

As mentioned in the Eclipse help Java Development User Guide Tips and tricks Debugging section, when debugging with JavaSE-1.6 you can see all instances of a particular class. You can invoke this functionality via the popup menu (All Instances...) of Variables view rows for reference type values or in the Java editor by positioning the cursor on or selecting a reference type expression. However it is not possible to see all instances of an arbitrary class. The All Instances plug-in adds this functionality. It can be invoked using the:
  • Run > All Instances of Java Class... 
  • All Instances of Java Class... toolbar buttons in the Variables and Expressions views
Once invoked it shows the following customized Open Type dialog of JDT.


Once you selects the class it adds the <Java Class> Instances expression to the Expressions view. Please note that instances of sub classes are also shown if the Show instances of subclasses checkbox is selected. For example, when java.io.OutputStream is selected it shows the instances of it's subclasses also. You can further filter out inner and anonymous inner classes using the additional check boxes. This functionality is not provided by Eclipse Java debugger's All Instances... action.


In addition, an expression showing java.security.CodeSource info for the class is also added if that information is available.



NOTE: The selected class (FQN) may have been loaded by different ClassLoaders. Entries for each class loaded by distinct Classloader are shown independently. This is helpful in debugging issues related to class loading and seemingly mysterious ClassCastExceptions.

These expressions are automatically removed from the Expressions view when the debug session terminates.

You can further explore the instances using the All References... popup menu item provided by the Eclipse Expressions view. This can help you track down who is holding on to the instance potentially causing a memory leak.

The functionality works only if you have a active Java debug session, running under a JavaSE-1.6 (and above) that supports the all instances retrieval functionality, selected in the Debug view.

You can install the plug-in from the plug-in's update site:

http://sandipchitaleseclipseplugins.googlecode.com/svn/trunk/AllInstancesUpdateSite

Please file any issues at:

http://code.google.com/p/sandipchitaleseclipseplugins/issues/list

It works in Eclipse 3.5.2, 3.6.x and 3.7.x.

Also available on Eclipse Marketplace!

Enjoy!

Thursday, April 21, 2011

Eclipse: Find/Replace Bar

I prefer NetBeans style Incremental Search Bar interface instead of the usual Find/Replace Dialog. Eclipse only has the Find/Replace Dialog. So I implemented a similar Find/Replace Bar for Eclipse. Here are the screenshots:



Known issue: If you have customized the perspective, the Find bar view will be shown with a tab unlike the above screenshot. Try resetting the perspective and the tab may go away. I had mixed success with that though.

Find/Replace Bar Plug-in is on Eclipse Marketplace !

Currently the Find/Replace Bar supports the following features:
  • Find as you type
  • Find Next/Find Previous
    • same key bindings as Eclipse
  • Show the total number of occurrences in the document
  • Case sensitive mode
  • Whole word only mode
  • Regular Expression mode
    • Indicate illegal regular expression
  • Show Find/Replace dialog by pressing CTRL+F on Windows and Linux and COMMAND+F on Mac
  • Enable/Disable Find/Replace Bar using preferences
    • Show Preferences button on the Find/Replace Bar
  • Optionally override the standard Find/Replace Dialog of Eclipse. Control the override through preference page.
  • Press CTRL+F on Windows and Linux and COMMAND+F on Mac to show the Find/Replace Bar
    • Press ESCAPE to hide the Find/Replace bar
    • Find/Replace Bar works with text editors inside a Multi page editor e.g. plugin.xml XML editor inside the Plug-in Manifest editor.
    • Show the preceding and succeeding match count
    • Show text matching groups in regular expressions in a combobox
    I am planning to implement the following enhancements:
    • Full Replace/Find,Replace and Replace All support
    • Find in selection
    • Highlight current and other occurrences of the matched text
      • Highlight groups in regular expressions in different colors
    • Show current line number and column range of the match
    • Make it work in Console and other views where Find/Replace dialog is applicable
      You can install it from the plug-in's update site:

      http://sandipchitaleseclipseplugins.googlecode.com/svn/trunk/FindReplaceBarUpdateSite/

      Please file any issues at:

      http://code.google.com/p/sandipchitaleseclipseplugins/issues/list

      After installing the plug-in, go the Find/Replace Bar preferences page to enable the Find/Replace Bar as shown in the screenshot below:



      Works on Eclipse 3.6 and 3.5.2

      Enjoy!

      Wednesday, March 30, 2011

      One-click editor splitting in Eclipse

      [Note: Does not work in Eclipse 4.x]
      UPDATE: Eclipse Luna 4.4 M4 now supports editor splitting... NEW and NOTEWORTHY.

      You may know that one can split layout the editors in Eclipse by dragging the editor tab to any edge of the editor area. This works only if you have more than one editor. However there are times when I want to work on two parts of the same file. To do that I first do Window > New Editor to duplicate the editor and then drag it to split the editor in a side-by-side or top-bottom layout. But that is too many clicks and drags. I developed a simple Eclipse Plugin which will help you split the active editor either horizontally or vertically with a single click. It is based on some code I found here that was written by Dimitri Missoh (thanks Dimitri - I have given you credit in the source code of the plug-in). I adapted his code to suite our purpose.

      Here is the screenshot:


      Split Editor Plug-in is available on Eclipse Marketplace!

      You can install it from the plug-in's update site:

      http://sandipchitaleseclipseplugins.googlecode.com/svn/trunk/SplitEditorFeatureUpdateSite

      Source code is here.

      Works in Eclipse 3.4, 3.5, 3.6, 3.7 and 3.8.

      Also available on Eclipse Marketplace.

      Enjoy!

      Tuesday, March 15, 2011

      XCode: Corrected user scripts - Delete Line, Copy/Move line Up/Down

      [Note: It is a shame that XCode 4 does not have the Scripts menu]

      XCode has the following scripts:
      • Delete Line
      • Move Line Up
      • Move Line Down
      I added two more (as described in this post):
      • Copy Line Up
      • Copy Line Down
      However there was a problem. The script always worked on the first text document. That meant that when you had multiple documents open, the commands sometimes modified the document which did not have focus (baaad!).

      It turns out the window 1 is always the window which has the focus. I corrected the scripts to make use of this fact. Here is the general strategy behind the modifications I made to the scripts:
      :
      :
      using terms from application "Xcode"
       set selectedDocument to missing value
       repeat with index from 1 to (count of text documents)
        if (associated file name of window 1 as string) is equal to (path of text document index) then
         -- found the document
         set selectedDocument to (text document index)
         exit repeat
        end if
       end repeat
       if (selectedDocument is not missing value) then
        tell selectedDocument
         -- do the modifications to document
        end tell
       else
        beep 1
       end if
      end using terms from
      

      Download the scripts here. Just unzip and drop the scripts in /Developer/Library/Xcode/User Scripts/ .

      I have filed a bug at http://radar.apple.com for this. The problem Id is 9138643. I have attached the fixed scripts to the problem.

      Wednesday, March 09, 2011

      XCode: Copy/Move Up/Down line


      [Note: Please see this post for corrected scripts]

      XCode already has the following scripts under Script Menu > Text
      • Delete Line
      • Move Line Up
      • Move Line Down
      I added the following two scripts:
      • Copy Line Up
      • Copy Line Down
      Basically I started by creating the following Applescript files:

      /Developer/Library/Xcode/User Scripts/Copy Line Up.scpt with content:

      --
      (*
      To edit this script, choose Save As... and save it in your home directory, then re-add it to the User Scripts list.
      *)
      using terms from application "Xcode"
      tell first text document
      set {startLine, endLine} to selected paragraph range
      if startLine > 1 then
      set theText to (paragraphs startLine through endLine)
      set theText to (theText as string)
      make new paragraph at beginning of paragraph (startLine) with data theText
      set selected paragraph range to {startLine, endLine}
      else
      beep 1
      end if
      end tell
      end using terms from
      --

      /Developer/Library/Xcode/User Scripts/Copy Line Down.scpt with content:

      --
      (*
      To edit this script, choose Save As... and save it in your home directory, then re-add it to the User Scripts list.
      *)
      using terms from application "Xcode"
      tell first text document
      set {startLine, endLine} to selected paragraph range
      if endLine < (count paragraphs) then
      set theText to (paragraphs startLine through endLine)
      set theText to (theText as string)
      make new paragraph at beginning of paragraph (startLine + 1) with data theText
      set selected paragraph range to {endLine + 1, endLine + 1}
      else
      beep 1
      end if
      end tell
      end using terms from
      --

      and then added those scripts using the Script Menu > Edit User Scripts... dialog.


      While I was at it I added the following keybindings:

      Delete Line Command+D
      Move Line Up Alt+UP
      Copy Line Up Control+Alt+UP
      Move Line Down Alt+Down
      Copy Line Down Control+Alt+Down

      Note: The Command+D keybinding for Delete Line conflicts with the default Add Bookmark keybinding. I changed that keybinding to something else in Preference > Key Bindings > Menu Key Bindings > Edit section.

      Here is the screenshot:


      Now I have my LineTools NetBeans plugin like functionality in XCode. Yay!

      Sunday, September 05, 2010

      Updated Path Tools Eclipse plug-in

      What's new?
      • The Custom commands can now we edited using the table editor which allows you to use a display labels and wildcard patterns for the command. The display label is used in the menu items that invoke the commands. The wildcard patterns are used to determine if the command applies to the selected file.

      • The Path Tools commands remain enabled even if there is no file selected in the Eclipse workbench. The commands operate on the workspace folder when no file is selected in the workbench.
      Read more about Path Tools here.

      Tuesday, May 11, 2010

      LinearLayout gravity and layout_gravity explained

      Recently I started hacking on Android. Android uses Java as the development language which made it very easy to get started :) .

      I am very familiar with Swing and SWT GUI layout mechanism of Layout Managers and Layouts respectively. I was happy to find out that Android also uses a notion of View Groups which are analogous to the Layout Managers. The Android supports several View Groups, LinearLayout, RelativeLayout to name a few. There many more.

      The Android View Groups employ a notion of LayoutParams that are analogous to layout constraints used by Swing Layout Managers. The LayoutParams configure the way the Android View Group lays out it's children views. In Android the GUI can be either built programmatically using Java code or using an XML file. The structure of the XML elements parallels the structure of View object you may build programatically. The XML attributes are used to configure the Layout Params.

      LinearLayout

      The LinearLayout is a commonly used View Group that lays out it's children views either horizontally or vertically. More details of LinearLayout read this.

      android:gravity and android:layout_gravity

      After reading the documentation I set out to use the Linear Layout and I came across the the following layout params:
      • android:gravity
      • android:layout_gravity
      I must say that my initial experience was a little frustrating. Based on the documentation it was not very clear how the above layout parameters work. After a little bit of googling I soon found out that many people have run into this. So I dove in to find out more details and finally understood how to use these layout parameters with Linear Layout. I will explain using an example layout:
      <?xml version="1.0" encoding="utf-8"?>
      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_width="fill_parent" android:layout_height="fill_parent"
      android:orientation="vertical" android:background="#666666">
      <TextView android:layout_width="fill_parent"
      android:layout_height="wrap_content" android:text="Linear Layout - horizontal, gravity=center"
      android:textColor="#FFFFFF" android:padding="2dip" />
      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_width="fill_parent" android:orientation="horizontal"
      android:layout_height="0dip" android:layout_weight="1"
      android:gravity="center" android:background="#EEEEEE">

      <Button android:id="@+id/Button01" android:layout_width="wrap_content"
      android:layout_height="wrap_content" android:layout_gravity="top"
      android:text="top"></Button>
      <Button android:id="@+id/Button02" android:layout_width="wrap_content"
      android:layout_height="wrap_content" android:layout_gravity="center"
      android:text="center"></Button>
      <Button android:id="@+id/Button03" android:layout_width="wrap_content"
      android:layout_height="wrap_content" android:text="bottom"
      android:layout_gravity="bottom"></Button>
      </LinearLayout>
      <TextView android:layout_width="fill_parent"
      android:layout_height="wrap_content" android:text="Linear Layout - vertical, gravity=center"
      android:textColor="#FFFFFF" android:padding="2dip" />
      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_width="fill_parent" android:orientation="vertical"
      android:layout_height="0dip" android:layout_weight="1"
      android:gravity="center" android:background="#DDDDDD">

      <Button android:id="@+id/Button04" android:layout_width="wrap_content"
      android:layout_height="wrap_content" android:layout_gravity="left"
      android:text="left"></Button>
      <Button android:id="@+id/Button05" android:layout_width="wrap_content"
      android:layout_height="wrap_content" android:layout_gravity="center"
      android:text="center"></Button>
      <Button android:id="@+id/Button06" android:layout_height="wrap_content"
      android:text="right" android:layout_gravity="right"
      android:layout_width="wrap_content"></Button>
      </LinearLayout>
      </LinearLayout>
      This results in the following layout:


      android:gravity attribute

      Strictly speaking android:gravity is not a Layout Param. The android:gravity is really an attribute of the View Group. It controls the way the contents of the View Group will be positioned horizontally and vertically.

      In the above example the top Linear Layout is a horizontal Linear Layout. So setting the android:gravity=center has an effect of positioning the set of buttons in the horizontal center.

      In the above example the bottom Linear Layout is a vertical Linear Layout. So setting the android:gravity=center has an effect of positioning the set of buttons in the vertical center.

      android:layout_gravity Layout Param

      The android:layout_gravity is a Layout Param. Not all View Groups support this Layout Param. See the documentation to find out which Layout Params are supported by a particular View Group. Linear Layout does support android:layout_gravity Layout Param.

      For a horizontal Linear Layout the following values make sense:
      • top
      • center
      • bottom
      That is because the children of a horizontal Linear Layout are layed out horizontally one after the other. Only thing can be controlled using the android:layout_gravity is how a child view is positioned vertically.

      In the above example the top Linear Layout is a horizontal Linear Layout. Setting the android:layout_gravity=top on the l_g=top Button has an effect of positioning it at the top. Setting the android:layout_gravity=center on the l_g=center Button has an effect of positioning it at the vertical center. Setting the android:layout_gravity=bottom on the l_g=bottom Button has an effect of positioning it at the bottom.

      For a vertical Linear Layout the following values make sense:
      • left
      • center
      • right
      That is because the children of a vertical Linear Layout are layed out vertically one below the other. Only thing can be controlled using the android:layout_gravity is how a child view is positioned horizontally.

      In the about example the bottom Linear Layout is a vertical Linear Layout. Setting the android:layout_gravity=left on the l_g=left Button has an effect of positioning it at the left. Setting the android:layout_gravity=center on the l_g=center Button has an effect of positioning it at the horizontal center. Setting the android:layout_gravity=right on the l_g=right Button has an effect of positioning it at the right.

      Wednesday, December 23, 2009

      Mac Win Man - a unified Mac OS X Desktop Window and Application Manager

      • Hide/Unhide Application
      • Minimize/Unminimize Window
      • Show window with same action no matter it was minimized or hidden
      • Zoom/Unzoom Window
      • Move and Resize windows using keyboard and mouse
        • Resize windows by dragging on the window edges and corners
        • Snap window to edges and center of the display using keystrokes
        • Precisely position and size the windows by entering the location and size values
      • Tile Windows Vertically
      • Tile Windows Horizontally
      • Cascade Windows
      • Close Window
      • Quit Application
      Now works with multiple displays.

      Screenshots

      Switcher (Command TAB replacement)


      Move and Resize using mouse and keyboard


      Read more and Download...

      Friday, October 16, 2009

      TIP:Applescript to invoke All Windows function of Exposé and bind it to key you please

      Here is the applescript to invoke the All Windows function of Exposé :
      on run
      -- delay is needed so that keybindings defined in
      -- tools like Fastscripts works
      delay 0.1
      tell application "System Events"
      -- 101 is key code for F9 key
      key code 101
      end tell
      end run
      Assuming you have bound Exposé:All Windows function to F9 key.

      So you say - what is the big deal?

      Well, if you look at System Preferences... > Exposé and Spaces pane > Exposé Tab , you will see that it allows you to bind various functions to limited set of keys. The script enables you to bind it to any key such as Option+Tab. How? Heres how:

      Save the above script in ~/Library/Scripts/Expose.app . Then bind it to Option+Tab using Quicksilver or Launchbar or Fastscripts.

      Saturday, October 03, 2009

      Un-minimize minimized windows and bring them to front using Applescript

      While implementing the AWS tool that I talked about in the last post - I learned a cool new Applescript technique to unminimize minimized windows. Here it is:

      -- assuming you have name of a minimized window
      set theWindowName to ....

      -- is it minimized?
      if (value of attribute "AXMinimized" of window theWindowName is true) then
      -- first un-minimize the window
      value of attribute "AXMinimized" of window theWindowName to false
      end if

      -- raise it
      perform action "AXRaise" of window theWindowName

      I had not much documentation on attributes such as "AXMinimized" and perform action "AXRaise".

      Friday, October 02, 2009

      Ruby on Rails : Injecting routes from a separate file

      I am currently working on a Ruby on Rails (RoR) application and needed a mechanism to load routes that are generated into a file by another tool. After some experimentation I came up with the following solution.

      In a Ruby on Rails application the routing is configured using the config/routes.rb file. The routes are defined using the draw method of ActionController::Routing::Routes class like this:
      ActionController::Routing::Routes.draw do |map|
      ...
      map.connect ':controller/:action/:id'
      map.connect ':controller/:action/:id.:format'
      end
      The block is executed with a local variable map in the scope. I wanted to insert routes defined in a separate file that is generated by another tool. To do that I tried to use the load or require methods. However I realized that it will not work because the load or require methods reset the scope to the top level. So I came up with the following:


      # insert routes from generated file
      instance_eval(File.read(File.expand_path(File.dirname(__FILE__)) + "/generated-routes.rb"))


      Basically it is evaluating the contents of a file in the instance (current) scope. The File.expand_path(File.dirname(__FILE__)) simply computes the path to folder that contains routes.rb file. To that I append the name of generated routes file which lives next to routes.rb file.

      Is there a better/idiomtic way to do this?

      AWS - a unified Application and Window Switcher i.e. a Command TAB alternative

      My other pet peeve with Mac OS X is how it deals differently with Applications and Windows that are minimized or hidden when one navigates using Command TAB( TAB)/Command Shift Tab ( TAB).

      When on asked about any alternatives to the IMHO broken Command Tab behavior, frequently Mac-heads respond condescendingly about:

      For me it does not matter if it is a window or application...I want to be able to switch to various windows where I want to work - hidden, minimized or what ever. Using Command TAB ( TAB)/Command Shift Tab ( TAB) to switch between applications and Command ~ ( ~)/Command Shift ~ ( ~) to switch between windows of an application is just plain wrong.

      Once again, I was aggravated enough to make me write a tool to address just those issue. I wrote the AWS tool.

      Read more...

      Thursday, May 28, 2009

      A Swing component to display last keystroke and keystroke history

      A Swing component to display last keystroke. Also shows the keystroke history.

      How it works

      The KeyLabel component registers a global listener for KeyEvents using:
      Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.KEY_EVENT_MASK);
      On receiving KEY_RELEASED event formats the KeyStroke as a string and displays it. The dropdown shows history of last 100 keystrokes. Clicking on the X (Clear KeyStroke History) button clears the keystroke history. The KeyEvent listening can be suspended by deseleting the checkbox.

      Usage
      JComponent keyLabel = KeyLabelFactory.createKeyLabel();
      // Use keyLabel in your application's statusbar
      Demo

      Download (KeyLabel.jar)
      > java -jar KeyLabel.jar
      Screenshot of KeyLabel Demo



      Source Code

      Wednesday, May 27, 2009

      Error launching Mozilla (only from inside Eclipse) using simple Runtime.exec() on Ubuntu.

      I discovered that, on Ubuntu 9.04, I cannot launch mozilla browser using the simple invocation of Runtime.getRuntime().exec("/usr/bin/mozilla"). It turns out, I have to use the variant of exec() where I can pass in some environment variables explicitly.

      Here is the program that I used to test it:
      import java.io.IOException;

      public class MB {

      /**
      * @param args
      */
      public static void main(String[] args) {
      try {
      Process exec = Runtime.getRuntime().exec("/usr/bin/mozilla"
      // Uncommenting out following line will launch mozilla browser on Ubuntu
      //, new String[] {"DISPLAY=:0.0", "HOME="+System.getProperty("user.home")}
      );
      System.out.println(exec.waitFor());
      } catch (IOException e) {
      e.printStackTrace();
      } catch (InterruptedException e) {
      e.printStackTrace();
      }
      }

      }
      Very interesting. May be that is why Eclipse has trouble launching help in default external browser on Ubuntu.

      UPDATE: It turns out that this fails only if I run the above program from inside Eclipse. If I run it from a terminal window it works. It turns out that Eclipse sets an environment variable MOZILLA_FIVE_HOME to point to /usr/lib[64]/xulrunner-addon to make the SWT's embedded browser widget work correctly. However this environment variable is inherited by any process that is launched from within Eclipse. And apparently MOZILLA_FIVE_HOME inteferes with the Mozilla browser (/usr/bin/mozilla) launch.

      Two issues have been filed in Eclipse Bugzilla:

      https://bugs.eclipse.org/bugs/show_bug.cgi?id=278415
      https://bugs.eclipse.org/bugs/show_bug.cgi?id=278296

      Sunday, May 17, 2009

      MultiPage Editor Tab Traverse Eclipse Plug-in

      The MultiPage editors such as plug-in manifest editor do not support navigation of tabs (pages of the editor) using keyboard. This plug-in implements that functionality for any MultiPage editor that subclasses org.eclipse.ui.part.MultiPageEditorPart and uses org.eclipse.swt.custom.CTabFolder to implement the tab folder.

      Screenshots:

      Starting with Overview tab:



      Type CTRL+TAB to go to Dependencies tab:



      Type CTRL+SHIFT+TAB instead to go to build.properties tab:

      Saturday, April 25, 2009

      Move and Resize windows on Mac OS X

      I have been always extremely annoyed by the fact that one cannot resize the windows on Mac OS X using all four edges of the window. In fact that is one of the most aggravating thing for me about using a Mac. Another issue is that one cannot use the keyboard to move and resize the windows. I was aggravated enough to make me write a tool to address just those issue. I wrote the MoveResize tool. It make synergistic use of Applescript and Java to fix IMHO a major usability flaw in Mac OS.

      How it works (Swing version)

      The implementation uses Applescript to get the frontmost window and it's bound. It sends the bounds rectangle to a server implemented in Java over a socket connection. The Java server takes the screen shot of the full Desktop and uses it as the Image label (a JLabel with ImageIcon) as the content pane of an undecorated JFrame which has the same bounds as the Desktop. A JPanel with semitransparent background and a dark rounded rectangular border is given the same bounds that were received over the socket. This JPanel is added to the PALETTE_LAYER of the JFrame's layered pane - which makes it appear floating in front of the front window. Mouse and Key listeners on the JPanel allows moving and resizing of the JPanel. When the user types the ENTER key the JFrame is hidden and the new bounds of the JPanel are sent back to the Applescript over the socket connection which moves and resizes the frontmost window.

      Initially I had implemented the original version using SWT. However, it turns out that it is implementable in Swing also - once again proving that Swing is a very good toolkit. Added advantage is that Swing is part of the JDK making the implementation much much smaller. BTW the Swing implementation is much faster and plays nicely with log off and shutdown.

      Watch Screencast


      Here is a screenshot:



      Saturday, April 18, 2009

      Wednesday, April 15, 2009

      Check out the Mac OS X Finder and Terminal scripts here.



      Screencast

      Sunday, March 29, 2009

      Sampler Eclipse Plug-in

      Check out the Sampler Eclipse Plug-in. The sampler plug-in adds a Color Sampler Toolbar. Color of any pixel on the desktop can be sampled by simply dragging the cursor from the Color Sampler label and copied to the clipboard in various formats as shown in the pop-up menu.

      Saturday, March 21, 2009

      Reverse Text Selection Eclipse Plug-in

      Check out the Reverse Text Selection Eclipse Plug-in.

      The following screencast shows how you can start with a initial selection and then extend it in both directions using the Reverse Text Selection command (Alt+Shift+/).

      Thursday, March 12, 2009

      Thursday, January 01, 2009

      Copy paths of selected items in Mac OS X Finder to clipboard

      copypaths.app

      (*
      Script: copypaths.app

      This script sets the clipboard to the paths of items selected in Finder window.
      If there is no selection the clipboard is set to the path of the target
      of the Finder window.

      Installation:

      1. Paste this script in Script editor
      2. Save it as an application - ~/scripts/finder/copypaths.app
      3. Drag and drop copypaths.app onto the Finder widow toolbar.

      @author Sandip V. Chitale
      @version 1.0
      @date 1/1/2009
      *)
      tell application "Finder"
      set paths to ""
      set selected to selection
      if (count of selected) is 0 then
      set paths to POSIX path of (target of front window as alias)
      else
      repeat with aPath in every item in selected
      set aPathString to POSIX path of (aPath as alias)
      if paths is "" then
      set paths to aPathString
      else
      set paths to paths & "
      " & aPathString
      end if
      end repeat
      end if
      if paths is not "" then
      set the clipboard to paths as text
      end if
      end tell

      Go to parent folder in Mac OS X Finder

      up.app

      (*
      Script: up.app

      This script sets the target of the Finder window to the
      parent of the current target of the Finder window.

      Installation:

      1. Paste this script in Script editor
      2. Save it as an application - ~/scripts/finder/up.app
      3. Drag and drop up.app onto the Finder widow toolbar.

      @author Sandip V. Chitale
      @version 1.0
      @date 1/1/2009
      *)
      tell application "Finder"
      set target of front window to (parent of target of front window)
      end tell

      Keep Mac OS X Finder and Terminal in sync

      findercd.scpt

      (*
      Script: findercd.scpt

      This script sets the target of the front window of Finder
      to the directory path passed as the first argument. If
      there is no Finder window, one is created. Optionally
      the finder window can be activated by passing in "true"
      as second argument. If no argument is passed
      the user is prompted to select a directory
      to go to.

      The following two bash functions can be used to
      invoke this script from bash running in Terminal
      window:

      # Change the directory of front window of
      # Finder to pwd of shell
      fcd() {
      cd "${1}"
      osascript ~/scripts/finder/findercd.scpt "`pwd`" ${2}
      }

      # Change the directory of front window of
      # Finder to pwd of shell and activate the
      # Finder window
      fcda() {
      fcd "${1}" true
      }

      Installation:

      1. Paste this script in Script editor
      2. Save it as a script - ~/scripts/finder/findercd.scpt
      3. Add the fcd() and fcda() functions mentioned above
      to your .bashrc or .bashrc_profile

      This script complements the terminalcd.scpt script.

      @author Sandip V. Chitale
      @version 1.0
      @date 1/1/2009
      *)
      on run argv
      if (count of argv) is 0 then
      try
      set directory to POSIX path of (choose folder with prompt "Go to")
      on error
      return
      end try
      else
      set directory to (item 1 of argv)
      end if
      set doActivate to false
      if (count of argv) is greater than 1 then
      set doActivate to (item 2 of argv)
      end if
      tell application "Finder"
      if (count of windows) is 0 then
      make new Finder window
      end if
      set target of front window to (POSIX file directory)
      if doActivate = "true" then
      activate
      end if
      end tell
      end run

      terminalcd.app

      (*
      Script: terminalcd.app

      This script sets the directory of the shell in front window of Terminal to the
      target directory of front window of Finder. If there is no Terminal window
      is there a new window is created. If the the front window of
      Terminal is busy new window is created.

      Installation:

      1. Paste this script in Script editor
      2. Save it as an application - ~/scripts/finder/temrinalcd.app
      3. Drag and drop terminalcd.app onto the Finder widow toolbar.

      This script compliments the findercd.scpt script.

      @author Sandip V. Chitale
      @version 1.0
      @date 1/1/2009
      *)
      tell application "Finder"
      if (count of windows) is greater than 0 then
      set cdTo to POSIX path of (target of front window as alias)
      set terminalWasRunning to false
      tell application "System Events"
      if exists process "Terminal" then
      set terminalWasRunning to true
      end if
      end tell
      tell application "Terminal"
      activate
      if (count of windows) is 0 then
      do script ""
      else if window 1 is busy then
      do script ""
      end if
      do script "cd '" & cdTo & "'" in front window
      end tell
      end if
      end tell

      Tuesday, December 16, 2008

      Sunday, December 07, 2008

      Hooking into Eclipse command execution

      When I was working on implementing the Clips plug-in I wanted to intercept the Cut and Copy actions and automatically create clips from the selection. To my delight I discovered the necessary mechanism to exactly do that. Basically I had to add the following listener:
      // Add listener to monitor Cut and Copy commands
      ICommandService commandService = (ICommandService) PlatformUI
      .getWorkbench().getAdapter(ICommandService.class);
      if (commandService != null) {
      commandService.addExecutionListener(new IExecutionListener() {

      public void notHandled(String commandId,
      NotHandledException exception) {
      }

      public void postExecuteFailure(String commandId,
      ExecutionException exception) {
      }

      public void postExecuteSuccess(String commandId,
      Object returnValue) {
      // Is it a Cut or Copy command
      if ("org.eclipse.ui.edit.copy".equals(commandId)
      || "org.eclipse.ui.edit.cut".equals(commandId)) {
      Clipboard clipboard = new Clipboard(PlatformUI
      .getWorkbench().getActiveWorkbenchWindow()
      .getShell().getDisplay());
      Object contents = clipboard
      .getContents(TextTransfer.getInstance());
      if (contents instanceof String) {
      // Now do something with text selection
      }
      }

      }

      public void preExecute(String commandId, ExecutionEvent event) {
      }

      });
      }

      Cool huh?

      Thursday, November 27, 2008

      Graphical cd

      The following bash function allows you to change directory using a Directory chooser:
      gcd() {
      local CDTO=`zenity --title="cd" --file-selection --directory`
      if [ -n "${CDTO}" ] ; then
      cd "${CDTO}"
      fi
      }

      Clips Eclipse Plug-in

      Check out the new Clips Eclipse plug-in here.

      Clips View


      Clips Preferences

      Thursday, November 13, 2008

      Zero length Java array cache

      Many times I find myself declaring private static final zero length array fields of some type or the other. Some times the zero length arrays for a same type are declared in more than one place. To avoid this, I came up with the simple zero length array cache backed by a WeakHashMap. The beauty of this is that it does not require a cast because it uses the generic method which uses the Class
      as a type token.

      import java.util.Map;
      import java.util.WeakHashMap;

      /**
      * A simple cache using WeakHashMap of zero length arrays of a given class.
      *
      * @author schitale
      *
      */
      public class ZeroLength {
      private static Map map = new WeakHashMap();

      @SuppressWarnings("unchecked")
      public static T[] array(Class c) {
      T[] array = (T[]) map.get(c);
      if (array == null) {
      array = (T[]) java.lang.reflect.Array.newInstance(c, 0);
      map.put(c, array);
      }
      return array;
      }

      public static void main(String[] args) {
      System.out.println(array(String.class).getClass().getCanonicalName()
      + " of length " + array(String.class).length);
      System.out.println(array(String[].class).getClass().getCanonicalName()
      + " of length " + array(String.class).length);
      }
      }
      The output is:
      java.lang.String[] of length 0
      java.lang.String[][] of length 0

      If you want to rely on the identity of the zero length array instance (e.g. == based comparison) then replace the WeakHashMap with HashMap. However, in that case you have to watch out for memory leaks through static fields of array component classes. You may want to add a method to remove the reference to the array from the HashMap.

      Is there a better way to do this?

      IMHO the java.lang.Class class should provide such factory method. This is along the lines of factory method:
      public static final T  List T java.util.Collections.emptyList();


      The implementation in java.lang.Class may look like:

      private static T[] zeroLengthArray;

      public static synchronized T[] emptyArray() {
      if (zeroLengthArray == null) {
      zeroLengthArray = (T[]) java.lang.reflect.Array.newInstance(this, 0);
      }
      return zeroLengthArray;
      }

      Thursday, October 23, 2008

      Bundles, Extension Points, Extensions View for Eclipse 3.4

      The BEPEB View is replacement for PDE's Plug-ins view. It allows you to explore:
      • Bundles
      • Extensions Points
      • Extensions

      You can start with any one of these at the top level by using the toolbar settings. You can continue to expand the relationships between these objects to any level.

      Several actions are supported in the context menu:

      • Open plugin.xml
      • Copy extension and extension element trees
      • Open Java Type specified by attributes which specify implementing Java classes.
      For example, the Copy Extension action copied the following xml to the Clipboard:







      Export a file containing the names and locations of the shared projects in the workspace.







      I plan to make more enhancements to this view.

      You can download it here.

      DISCLAIMER:
      This plug-in is experimental. So no guarantees. Use the plug-in at your own risk.

      Tuesday, October 14, 2008

      Reclaim Ctrl+C and Ctrl+V for familiar Copy and Paste in gnome-terminal

      Most people work with graphical desktops. Most desktop (GUI) applications use the Ctrl+C and Ctrl+V for Copy and Paste actions respectively. One gets use to these really fast. However, when working with bash shell running inside a gnome-terminal those key bindings mean something different i.e. Ctrl+C sends the kill signal to the foreground process and Ctrl+V is used for quoted insert functionality (i.e. to enter control keys literally). This is the legacy of the command line oriented Unix terminals based on tty (stty - program that controls the settings of tty devices).

      In this entry I describe how to make Ctrl+C and Ctrl+V do Copy and Paste in gnome-terminals. Here is how to do it:

      Open a gnome-terminal window and type the following commands:

      > stty intr ^K # free Ctrl+C for copy
      > stty lnext ^- # free Ctrl+V for paste
      > stty -g
      > stty -g > ~/.stty # store the settings in home directory
      Add the following to .bashrc
      case $- in
      *i*)
      stty `cat ~/.stty` # reload the stored stty settings
      bind -u quoted-insert # unbind the quoted-insert function of bash - free Ctrl+V for paste
      esac
      Now using the gconf-editor, edit the gnome-terminal's key bindings (@ /apps/gnome-terminal/keybindings key).

      Close and reopen the terminal window. And now Ctrl+C will copy and Ctrl+V will paste.

      Sunday, October 12, 2008

      Launching the Open Type dialog

      You can use the following code to launch the JDT's Open Type dialog to select a Java Type name and then open it in the Java editor programmatically:


      OpenTypeSelectionDialog dialog = new OpenTypeSelectionDialog(
      PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
      true,
      PlatformUI.getWorkbench().getProgressService(),
      null,
      IJavaSearchConstants.TYPE);
      dialog.setTitle(JavaUIMessages.OpenTypeAction_dialogTitle);
      dialog.setMessage(JavaUIMessages.OpenTypeAction_dialogMessage);
      dialog.setInitialPattern("java.lang.String");

      int result= dialog.open();
      if (result != IDialogConstants.OK_ID)
      {
      return;
      }

      Object[] types= dialog.getResult();
      if (types != null && types.length > 0) {
      IType type= null;
      for (int i= 0; i < types.length; i++) {
      type= (IType) types[i];
      try {
      JavaUI.openInEditor(type, true, true);
      } catch (CoreException x) {
      // Handle exception
      }
      }
      }

      Enhanced Plug-in Registry View

      The Plug-in Registry View Enhancements Plug-in enhances the Plug-in Registry View.

      The Plug-in Registry View has a mode (Show Extension Content only) to show:

      • extension-points
      • extensions
      • extension elements
      • extension attributes

      This plug-in adds some additional actions on the Plug-in Registry View's tool bar. The following screen shot shows the example of the additional actions.

      For attributes with values that look like Java Type name - the Open action opens the Open Type dialog:

      This works well if you have added all the plug-in classes to your Java search using the tip - Extending the Java search scope.


      The other supported action is:

      • Open plugin.xml

      You can download the plug-in here.


      BTW this plug-in makes use of the technique described in the entry - Add pulldown actions to Eclipse View's Toolbars.


      DISCLAIMER: This plug-in is experimental. So no guarantees. Use the plug-in at your own risk.

      Sunday, September 28, 2008

      Template Tools Eclipse plug-in

      UPDATE:
      Template Tools Eclipse plug-in enhances the functionality of code templates:
      • ${clipboard} template variable - replaced by the contents of the clipboard.
      • ${prompt(input|file|directory|enumeration, value [, value]*|color|font)}
        • input - the user is prompted to enter a value
        • file - the user is prompted to select a file
        • directory - the user is prompted to select a directory
        • enumeration - the user is prompted to select a value from the list of values
        • color - the user is prompted to select a color using a color dialog. The color value can be formatted using java.util.Formatter strings. The parameters passed to the format are red, green or blue color component values. If no format is specified the value is formatted as the org.eclipse.swt.graphics.RGB.toString() value of the color.
        • font - the user is prompted to select a font using a FontDialog. The returned value is the org.eclipse.swt.graphics.FontData.toString() value returned by the font dialog.

      This plug-in also supports extension-point promptProviders. Here is an example:

        <extension
      point="TemplateTools.promptProviders">
      <promptProvider
      class="templatetools.InputPrompt"
      type="input">
      </promptProvider>
      :
      :
      </extension>

      Here is the implementation:


      package templatetools;

      import java.util.Formatter;
      import java.util.List;

      import org.eclipse.swt.graphics.RGB;
      import org.eclipse.swt.widgets.ColorDialog;
      import org.eclipse.ui.PlatformUI;

      public class ColorPrompt implements IPrompt {

      @SuppressWarnings("unchecked")
      public String getValue(String name, List params) {
      ColorDialog colorDilaog = new ColorDialog(PlatformUI.getWorkbench()
      .getActiveWorkbenchWindow().getShell());
      RGB color = colorDilaog.open();
      if (color != null) {
      if (params.size() > 0) {
      Object format = params.get(0);
      if (format instanceof String) {
      StringBuffer formatBuffer = new StringBuffer();
      new Formatter(formatBuffer).format((String) format,
      color.red, color.green, color.blue);
      return formatBuffer.toString();
      }
      } else {
      return color.toString();
      }
      }
      return null;
      }

      }

      You can download the plug-in here.

      DISCLAIMER: This plug-in is experimental. So no guarantees. Use the plug-in at your own risk.


      Monday, September 15, 2008

      Reorder Eclipse Plug-in : How does it work?

      In the last entry I published the Reorder Eclipse plug-in. In this entry I will talk about how it works.

      Basically, the Reorder plug-in uses the AST APIs to get parsed structure of the Java source code surrounding the caret in the Java editor.
      • It gets the ASTNode at caret position using NodeFinder API and starts traversing the parent ASTNodes until it find a Class Instance Creation, Method Invocation, Method Declaration or an Array initializer node.
      • Once found it gets the ASTNode's list of arguments, parameters or array initialization elements and stores the text of each node in a ordered list of items. While doing so, it also records the intervening white spaces as items.
      • It also records which item's extent surrounds the caret position. It records it as a current item.
      • Then, it swaps the current item with the following or preceding non-whitespace item in the list based on the action that was invoked - forward or backward swap.
      • Lastly it builds the string from the list of items and replaces the original text with the new string.
      That's it.

      Sunday, September 14, 2008

      Reorder Eclipse Plug-in for Java Editor

      The asymmetrical way in which the , (comma) is used to separate the items in parameter and arguments lists always causes problem when one wants to reorder that list in Java editor. Is that why Java allows trailing commas in array initializer? ;) may be. The Reorder plug-in supports single click swapping of a parameter, argument or array initializer expressions with previous or next item in the list. Each item of the sequence can be a simple literal, an identifier or a more complex function call expression. The comma delimiter is correctly handled.

      This plug-in adds two toolbar buttons to the Java editor:

      • Swap backward
      • Swap forward


      Usage

      With the caret at | in:

      void method(int iii, String |sss, boolean bbb){}
      pressing the Swap forward button yields:
      void method(int iii, boolean bbb, String |sss){}
      or pressing Swap backward button with the original source yields:
      void method(String |sss, int iii, boolean bbb){}


      You can download the plug-in from here.


      TODO

      • Key bindings for the actions
      • Generalization of the concept to other language editors

      DISCLAIMER: This plug-in is experimental. So no guarantees. Use the plug-in at your own risk.

      Saturday, September 13, 2008

      Add pulldown actions to Eclipse View's Toolbars

      The actions added to the org.eclipse.ui.actionSets extension point (which allows contribution to the Wokbench Window's toolbars) allow the pulldown style. However the actions added to the org.eclipse.ui.viewActions extension point do not allow the pulldown style. IMHO this is a annoying limitation. It may be that the original reason for this limitation was to avoid confusion with the drop down menu in the View toolbars. However the visual of a pulldown action down action is different enough that it is not confusing. Besides the pull down actions are used in View toolbars of many Eclipse provided Views e.g. Open Console action on the as Console view's toolbar. So how are such actions created? Well such actions are programatically created during the View's createPartControl() invocation. However that is not always the case. You may want to contribute a pulldown action to a View created elsewhere. In this entry I show you how to do exactly that programatically.

      The basic idea behind this is to watch for opening of the view that you are interested in and programatically add the pulldown style action when the view is opened. Just put the following code in your plug-in's Activator. One thing to keep in mind is that your plug-in may get activated some time after the View that you are contributing a pull down action to - was already created. To handle that we process all the exiting windows that are already present when our code activates. We monitor the opening of the views in the Workbench windows by adding the IPartListener to the Window's PartService. What happens if the user creates more Workbench windows and then openes the View of interest in that Workbench window. Well, we monitor creation of new Workbench windows by adding the IWindowListener to the Workbench. We keep track of the fact that the action was added to the View's toolbar in a WeakHashMap (keyed by the IViewPart) so that we add the action only once. This is because the addActions() is called from multiple places in the following code. One more thing...the action you add must use SWT.AS_DROP_DOWN_MENU style and also implement the IMenuCreator intreface. That's it. Here is the code:
      private static WeakHashMap actionsAddedToView = new WeakHashMap();
      private static void addActions(IViewPart viewPart)
      {
      Boolean added = actionsAddedToView.get(viewPart);
      if (added == null) {
      // The actions were not added yet
      final IToolBarManager toolBarManager = viewPart.getViewSite().getActionBars().getToolBarManager();

      // SomePulldownAction extends Action implements IMenuCreator
      // public SomePulldownAction() {
      // super("Some Action...", IAction.AS_DROP_DOWN_MENU);
      // }
      // Also implement the getMenu() action.
      // public Menu getMenu(Control parent) {
      // create menu
      // add menu items
      // return the menu
      // }
      SomePulldownAction someDownloadAction = new SomePulldownAction();
      someDownloadAction.init(viewPart);
      toolBarManager.insertAfter("id-of-an-exiting-action-on-views-toolbar", someDownloadAction); //$NON-NLS-1$

      // Add more actions
      // ...
      // ...
      // ...

      toolBarManager.update(true);
      actionsAddedToView.put(viewPart, Boolean.TRUE);
      }
      }

      // Listner for monitoring the view opening
      private static final IPartListener partListener = new PartListenerAdapter()
      {
      @Override
      public void partOpened(IWorkbenchPart part)
      {
      if (part instanceof IViewPart)
      {
      IViewPart viewPart = (IViewPart) part;
      if ("-id-of-the-view-to-which-you-want-to-add-the-pulldown-action".equals(viewPart.getSite().getId()))
      {
      addActions(viewPart);
      }
      }
      }

      @Override
      public void partClosed(IWorkbenchPart part)
      {
      if (part instanceof IViewPart)
      {
      IViewPart viewPart = (IViewPart) part;
      if ("-id-of-the-view-to-which-you-want-to-add-the-pulldown-action".equals(viewPart.getSite().getId()))
      {
      // forget the view's actions added state
      actionsAddedToView.remove(viewPart);
      }
      }
      }
      };

      private static void processWindow(IWorkbenchWindow window)
      {
      IWorkbenchPage[] pages = window.getPages();
      for (IWorkbenchPage workbenchPage : pages)
      {
      IViewPart viewPart = workbenchPage.findView("-id-of-the-view-to-which-you-want-to-add-the-pulldown-action");
      if viewPart != null && viewPart.getSite() != null)
      {
      addActions(viewPart);
      break;
      }
      }

      // Monitor furture view creation in case the view
      // is closed and reopened
      window.getPartService().addPartListener(partListener);
      }

      static {
      // Add pulldown action to the view that may be already present in
      // exiting Workbench windows.
      IWorkbenchWindow[] workbenchWindows = PlatformUI.getWorkbench().getWorkbenchWindows();
      for (IWorkbenchWindow workbenchWindow : workbenchWindows)
      {
      processWindow(workbenchWindow);
      }

      // Monitor future Workbench windows
      PlatformUI.getWorkbench().addWindowListener(new IWindowListener()
      {
      public void windowActivated(IWorkbenchWindow window) {}
      public void windowClosed(IWorkbenchWindow window) {}
      public void windowDeactivated(IWorkbenchWindow window) {}
      public void windowOpened(IWorkbenchWindow window)
      {
      processWindow(window);
      }
      });
      }

      Tuesday, September 09, 2008

      An enhanced ListEditor implementation

      As discussed in this article on Eclipse.org, the Eclipse FieldEditors make it easy to implement the preferences pages. The ListEditor is one of the many imlementations provided by Eclipse which allows editing of list like values. However it has a serious limitation. It only allows addition, deletion and reordering of the values. It does not allow editing of the values already in the list. The following subclass of ListEditor overcomes that limitation by providing the functionality of editing any one value in the list of values. To use it you have to subclass and implement the following additional abstract method:

      /**
      * The subclasses must override this to return the modified entry.
      *
      * @param original the new entry
      * @return the modified entry. Return null to prevent modification.
      */
      protected abstract String getModifiedEntry(String original);

      One possible implementation could look something like this:

      @Override
      protected String getModifiedEntry(String original) {
      InputDialog entryDialog = new InputDialog(
      PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
      "Edit entry", "Edit entry:", original, null);
      if (entryDialog.open() == InputDialog.OK) {
      return entryDialog.getValue();
      }
      return null;
      }

      In fact, I make use of this in my Path Tools Eclipse Plug-in to edit the custom commands for folders and files. Here is the screenshot:


      Here is the full code:

      package somepackage;

      import org.eclipse.jface.dialogs.IDialogConstants;
      import org.eclipse.jface.preference.ListEditor;
      import org.eclipse.swt.SWT;
      import org.eclipse.swt.events.DisposeEvent;
      import org.eclipse.swt.events.DisposeListener;
      import org.eclipse.swt.events.SelectionAdapter;
      import org.eclipse.swt.events.SelectionEvent;
      import org.eclipse.swt.layout.GridData;
      import org.eclipse.swt.widgets.Button;
      import org.eclipse.swt.widgets.Composite;
      import org.eclipse.swt.widgets.List;

      /**
      * This class extends {@link ListEditor} to enable editing of entries.
      *
      * @author Sandip V. Chitale
      *
      */
      public abstract class EntryModifiableListEditor extends ListEditor {

      public EntryModifiableListEditor(String name, String labelText, Composite parent) {
      super(name, labelText, parent);
      }

      /**
      * The subclasses must override this to return the modified entry.
      *
      * @param original the new entry
      * @return the modified entry. Return null to prevent modification.
      */
      protected abstract String getModifiedEntry(String original);

      private Button editButton;
      private List commandListControl;

      @Override
      public Composite getButtonBoxControl(Composite parent) {
      Composite buttonBoxControl = super.getButtonBoxControl(parent);
      if (editButton == null) {
      editButton = createPushButton(buttonBoxControl, "Edit..."); // TODO I18N
      editButton.setEnabled(false);
      editButton.addSelectionListener(new SelectionAdapter() {
      @Override
      public void widgetSelected(SelectionEvent e) {
      if (commandListControl.getSelectionCount() == 1) {
      String modified = getModifiedEntry(commandListControl.getSelection()[0]);
      if (modified != null) {
      int selectedIndex = commandListControl.getSelectionIndex();
      commandListControl.remove(selectedIndex);
      commandListControl.add(modified, selectedIndex);
      }
      }
      }
      });
      buttonBoxControl.addDisposeListener(new DisposeListener() {
      public void widgetDisposed(DisposeEvent event) {
      editButton = null;
      }
      });
      }
      return buttonBoxControl;
      }

      /**
      * Helper method to create a push button.
      *
      * @param parent the parent control
      * @param key the resource name used to supply the button's label text
      * @return Button
      */
      private Button createPushButton(Composite parent, String key) {
      Button button = new Button(parent, SWT.PUSH);
      button.setText(key);
      button.setFont(parent.getFont());
      GridData data = new GridData(GridData.FILL_HORIZONTAL);
      int widthHint = convertHorizontalDLUsToPixels(button,
      IDialogConstants.BUTTON_WIDTH);
      data.widthHint = Math.max(widthHint, button.computeSize(SWT.DEFAULT,
      SWT.DEFAULT, true).x);
      button.setLayoutData(data);
      return button;
      }

      @Override
      public List getListControl(Composite parent) {
      List listControl = super.getListControl(parent);
      if (commandListControl == null) {
      commandListControl = listControl;
      commandListControl.addSelectionListener(new SelectionAdapter() {
      @Override
      public void widgetSelected(SelectionEvent e) {
      editButton.setEnabled(commandListControl.getSelectionCount() == 1);
      }
      });
      }
      return listControl;
      }

      }

      Sunday, September 07, 2008

      Perspectives and Views Toolbar Plugin for Eclipse

      In Eclipse IDE, I find it very inconvenient to go to the the Window:Open Perspective or Window:Show View submenu, and then select the one I want in dialog that is shown. I was inconvenienced enough that I wrote a simple Eclipse Plug-in called - Perspectives and Views Toolbar. The basic idea is that it adds two drop down menus to the toolbar. Using the drop down you can directly select the Perspective or the View that you want to show.












      Get the Eclipse 3.4 compatible Perspectives and Views Toolbar Plug-in here.

      DISCLAIMER: This plug-in is experimental. So no guarantees. Use the plug-in at your own risk.