Clipboard swap in Java (Ctrl+Exchange or Ctrl+Swap)

After some inspiring Friday afternoon discussion, the following came to mind as nice to have.

Wouldn’t it be nice to have a CTRL+C and CTRL+V in one action, meaning your selected text is put on the clipboard and the previous clipboard is put on screen. In other words, a CTRL+Exchange or CTRL+Swap.

Probably there are dozens of tools like this and surely relatively easy to create in Visual Basic, in C# or in any other Windows (scripting) language, fact is I’m not a Windows developer (yet ;). But with no administrator rights, no possibility to install anything (USB not working either) and a tough e-mail scanner, our options are limited. But “Oracle SQL Developer” is installed (including a JRE).

Secondly, this should work globally in Windows across applications so the system tray comes in mind. Unfortunately, access is denied (later I will create the same for an at home solution in the system tray for sure).
And third, the Java application (while minimized) should be able to capture a CTRL+[key] globally and then exchange it and paste it back (e.g. CTRL+Q).
At last, it should not be too difficult and time consuming, since we are a week before sprint delivery.

Luckily, I came across this nice (although very old) post by Sergei Biletnikov:
http://biletnikov-dev.blogspot.nl/2009/09/global-hotkeys-for-java-applications_25.html
in which Sergei proposes a solution for the global capture of hotkeys using a .dll in Java

Link to the .dll files still works:
https://code.google.com/p/jkeyboard-hook/downloads/list

Loading a .dll in Java is pretty easy, but it should be in one .jar file since the executable should be in the form of “java -jar clipboardexchanger.jar”. For the later-to-build-system-tray-version other options are available. But for now some more Java combining forces are required, this time with Adam Heinrich and:
https://github.com/adamheinrich/native-utils
which allows us to load a .dll from a classpath while developing and from inside a .jar file when deployed.

What should it do by example: ctrl-exchange-2

  • “hello” is currently in the clipboard
  • “world” is selected somewhere in Notepad
  • User presses CTRL+Q
  • Current clipboard is loaded to remember (“hello”)
  • Perform CTRL+C (“hello” is replaced by “world” in clipboard)
  • Current clipboard is loaded to remember (“world”)
  • Put remembered (“hello”) back into the clipboard
  • Perform CTRL+V to paste, user sees “hello”
  • Put remembered “world” into clipboard
  • Other applications can use CTRL+V to paste “world” as well

When you download Sergei’s example and .dll files and add Adam’s native utils to load the .dll, you can add the following code in the
onGlobalHotkeysPressed() method:

public void onGlobalHotkeysPressed() {
  // get our current clipboard content
  String current = getClipboardContents(false); // "hello"

  // perform CTRL+C to fill clipboard with selected text
  r.keyPress(KeyEvent.VK_CONTROL);
  r.keyPress(KeyEvent.VK_C);
  r.delay(50);
  r.keyRelease(KeyEvent.VK_C);
  r.keyRelease(KeyEvent.VK_CONTROL);

  // read the system clipboard again to get the selected text, "world" is now known inside our application
  String selected = getClipboardContents(false);

  // put "hello" back into clipboard to be able to perform CTRL+V on it
  setClipboardContents(current, false);

  // perfor CTRL+V to paste "hello"
  r.keyPress(KeyEvent.VK_CONTROL);
  r.keyPress(KeyEvent.VK_V);
  r.delay(50);
  r.keyRelease(KeyEvent.VK_V);
  r.keyRelease(KeyEvent.VK_CONTROL);

  // put originally selected "world" into clipboard
  setClipboardContents(selected, true);
}

With “r” earlier declared:

java.awt.Robot r
try {
  r = new Robot();
} catch (AWTException e) {
  System.out.println("AWT Robot error");
}

As you can see, I use an old java.awt.Robot class to perform system tasks. Well, why not.

The “getClipboardContents” and “setClipboardContents” are widely known to get and set the system’s clipboard. I added a boolean to the method just to indicate if they should do something to the system tray. They are not really necessary. The methods (simplified):

/**
* Get the clipboard.
*
* @return any text found on the Clipboard; if none found, return an empty String
*/
private static String getClipboardContents(boolean showResult) {
  String result = "";
  Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
  Transferable contents = clipboard.getContents(null);
  boolean hasTransferableText = (contents != null) && contents.isDataFlavorSupported(DataFlavor.stringFlavor);
  if (hasTransferableText) {
    try {
      result = (String) contents.getTransferData(DataFlavor.stringFlavor);
    } catch (UnsupportedFlavorException | IOException ex) {
      result = "";
      System.out.println(ex);
      ex.printStackTrace();
    }
  }
  if (showResult) {
    System.out.println("clipboard contains: " + result);
  }
  return result;
}
/**
* Place a String on the clipboard.
*/
private static void setClipboardContents(String str, boolean showResult) {
  StringSelection stringSelection = new StringSelection(str);
  Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
  clipboard.setContents(stringSelection, stringSelection);
  if (showResult) {
    System.out.println("putting in clipboard: " + str);
  }
}

Finally, you’ll have to create a .jar file. If you’re using an IDE this should be rather easy. After creating the .jar, just add the .dll to the directory where the classes are. The NativeUtils.loadLibraryFromJar method will search in those.

With the following files:
GlobalKeyboardHook.java
GlobalKeyboardListener.java
NativeUtils.java
ClipboardExchanger.java (main method)

Or just download the .jar files (32bit and 64bit versions) and run the inside a command prompt box:
java -jar clipboardexchanger32.jar
and
java -jar clipboardexchanger64.jar

Old school applet, why not embedded in Twitter, Instagram or Tumblr?

Recently I archived some old directories and came along some ancient 1.3 stuff.
Just for fun I was wondering if they would still work (in Java 8). After some copy-pasting, they ran right away, how nice!

(You might want to accept the domain in your Java security setting). Ay caramba, probably you’re not seeing the glass on your mobile.

Sooo, wouldn’t it be nice to allow Java applets or midlets in Twitter, Instagram or Tumblr. Opening tons of new possibilities (and security issues).
Sidenote: The glass you see is a Duralex glass, when I was a student we used to drink from these.

Filtered type ahead JComboBox

Swing offers nice possibilities to use a JComboBox with some sort of pre-selecting or type ahead features. One of the major drawbacks is, it does not remove items who don-not match at all (when typing).

In one of my projects it was required to filter out possibilities from the JComboBox when the user starts typing, so the list gets smaller when the user starts typing (large lists!). Of course the list grows back again when backspace is pressed(*).

I’ve found several solutions around, but non of them are completely satisfactory for me, mostly because they are to specific or to complex (maybe my solution isn’t the best either).

Some features and some drawbacks are known for the version presented in this issue:

  • because of using backspace and rebuilding the JComboBox, all items must be present when an instance is created (* as shown earlier)
  • because the user can enter text, the first item should be an empty one to hold the search term
  • when no match occurs, getSelectedItem(0) is there to get the users query

For me it was important to use the getSelectedItem() method instead of the getSelectedIndex() method on an ActionEvent, since the user might have typed some text which was not present yet. The text from getSelectedItem() then is added to the database (in my application). Because of the filtering, double occurrences are minimized this way.

Link: FilteredTypeAheadComboBox.java
Link: FilteredTypeAheadDemo.java
Javawebstart: FilteredTypeAheadDemo.jnlp
(You might want to accept the domain in your Java security setting).
 

Connect to Oracle from JVM inside database using a grid or RAC

Was:
ods.setDriverType("thin");
ods.setServerName("ocwgrid01.nbd.local");
ods.setDatabaseName("SCXD2");
ods.setPortNumber(1521);
ods.setUser("system");
ods.setPassword("ali120");

Is:
OracleDataSource ods = new OracleDataSource();
ods.setUser("system");
ods.setPassword("ali120");
ods.setConnectionCachingEnabled(true);
ods.setConnectionCacheName("MyCache");
ods.setFastConnectionFailoverEnabled(true);
ods.setONSConfiguration("nodes=ser1:4200,ser2:4200");
ods.setURL("jdbc:oracle:thin:@(DESCRIPTION=(LOAD_BALANCE=on)(ADDRESS=(PROTOCOL=TCP)(HOST=owlndb260)(PORT=1521))(ADDRESS=(PROTOCOL=TCP)(HOST=owlndb260)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=SCXD2)))");
Connection conn = ods.getConnection();

Different tooltip for each word in JTextField

It is possible to set a tooltip for a JTextField no doubt. It’s also possible to set a tooltip based on what you have typed directly, like:
private JTextField searchTxt = new JTextField(20);
private final Document searchTxtDoc;
..
searchTxtDoc = searchTxt.getDocument();
searchTxtDoc.addDocumentListener(new searchTxtListener());
..
private class searchTxtListener implements DocumentListener {
  public void changedUpdate(DocumentEvent de) { checkTxtContent(); }
  public void insertUpdate(DocumentEvent de) { checkTxtContent(); }
  public void removeUpdate(DocumentEvent de) { checkTxtContent(); }
};

In checkTxtContent(); it’s possible to do what’s necessary with the JTextField content and set a tooltip. In fact, I use this listener often to present more information.

But what if it’s required to set tooltips on the JTextField based on every single word typed. Maybe the mouse position is useful to show a tooltip along the word the mouse is hoovering. Is it possible to gather the mouse information in checkTxtContent(); but it’s not the proper event to catch from the DocumentListener since it is fired on a document event.

In a GUI everything is event driven, so a good way to catch the mouse is using a MouseAdapter and add a MouseListener to the JTextField: searchTxt.addMouseListener(new searchMouseListener());
and:
private class searchMouseListener() extends MouseAdapter {
  public void mouseClicked(MouseEvent me) {
    // e.g. if right mouse button clicked (or me.isPopupTrigger())
    if(SwingUtilities.isRightMouseButton(me)) {
      
    }
    // e.g. show popup
    menuItem.show(JComponent, me.getX(), me.getY());
  }
}

With this MouseEvent it is possible to use me.getPoint(); or me.getX(); and me.getY();

But… The methods available are: mouseClicked, mouseEntered, mouseExited, mousePressed and mouseReleased. mouseEntered and mouseExited only deliver coordinates at one moment (their name says it all), not continuously.

So… not sufficient, best way to catch the mouse position is to use the MouseMotionListener. This class provides the following two methods: mouseDragged and mouseMoved. The latter is just what we needed:
searchTxt.addMouseMotionListener(new searchMouseMotionListener());

and

private class searchMouseMotionListener implements MouseMotionListener {
  public void mouseDragged(MouseEvent mouseEvent) {}
  public void mouseMoved(MouseEvent me) {
    String wrd = "";
    String txt = searchTxt.getText();
    int end = txt.length();
    if(end>0) {
      int pos = searchTxt.viewToModel(me.getPoint());
      if(pos>=0) {
        StringTokenizer st = new StringTokenizer(txt);
        int cur_pos = 1;
        while(st.hasMoreTokens()) {
          wrd = st.nextToken();
          cur_pos = cur_pos + wrd.length() + 1;
          if(cur_pos>=(pos+2)) {
            // wrd contains the word we're looking for,
            // so create a tooltip based on this catch
            break;
          }
        }
      }
    } // implement other stuff in else branches
  }
}

Hope it works for you.