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
}
}
}