Monday, May 4, 2009

Java: JOptionPane Examples Part 2 - Intermediate

In my previous JOptionPane article, JOptionPane Examples Part 1 - Basic, I covered several examples of basic usage of the JOptionPane dialog. In this installment, we go beyond basic usage and into some functionality that is documented, but not quite so obviously.

In most examples of the JOptionPane dialog, you'll see a String value used for the "message" argument, which is usually the 2nd argument. In the JOptonPane documentation, the "message" argument is listed generically as type Object in the list of methods.

However, if you read at the beginning where the parameters are discussed, the docs state that "message" can not only be a String, but also any subclassed object of the Component class, which is just about any GUI object you could hope to use! But wait there's more!

Not only can it accept practically any GUI object, but it also can accept an array of GUI objects! If an array is provided, the elements of the array are displayed vertically in the dialog box. This is not a very flexible layout, but it is simple and straightforward.

Example 1: Login/Password Dialog

To create a login/password dialog box, we need more than just the login and password fields, but also label fields so the user knows where to type and what goes there.

Here the two field are defined using a JTextField for the login name and a JPassword field for the password. Each field has a corresponding JLabel. Also included, just for fun, is a "remember me" checkbox.

    // Components related to "login" field
JLabel label_loginname = new JLabel("Enter your login name:");
JTextField loginname = new JTextField(15);
// loginname.setText("EnterLoginNameHere"); // Pre-set some text

// Components related to "password" field
JLabel label_password = new JLabel("Enter your password:");
JPasswordField password = new JPasswordField();
// password.setEchoChar('@'); // Sets @ as masking character
// password.setEchoChar('\000'); // Turns off masking

JCheckBox rememberCB = new JCheckBox("Remember me");
 

The components are wrapped up into an Object array.

    Object[] array = { label_loginname, 
loginname,
label_password,
password,
rememberCB };
 

Then the dialog is initiated using showConfirmDialog(), with "OK" and "Cancel" buttons, and without any icon decorations.

    int res = JOptionPane.showConfirmDialog(null, array, "Login", 
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.PLAIN_MESSAGE);
 

We can respond properly to the user's input, by analyzing the int return value of showConfirmDialog().

    // User hit OK
if (res == JOptionPane.OK_OPTION) { System.out.println( "OK_OPTION" ); }

// User hit CANCEL
if (res == JOptionPane.CANCEL_OPTION) { System.out.println( "CANCEL_OPTION" ); }

// User closed the window without hitting any button
if (res == JOptionPane.CLOSED_OPTION) { System.out.println( "CLOSED_OPTION" ); }
 

Even though, at this point, the dialog is gone, we can still interact with the GUI components. We can determine if the user entered values, regardless if the user hit OK, Cancel, or just closed the window without hitting any buttons, by using the methods of the various objects.

For example, we'll use getText() to get the login name from the "login name" JTextField object. The password is obtained using getPassword() from the "password" JPasswordField object. The state of the "remember me" checkbox can be determined using the isSelected() method.

    // Output data in "login" field, if any
String newloginname = loginname.getText();
System.out.println( "newloginname: " + newloginname );

// Output data in "password" field, if any
String newpassword = new String(password.getPassword());
System.out.println( "newpassword: " + newpassword );

// Output state of "remember me" check box
boolean selectedCB = rememberCB.isSelected();
System.out.println( "selectedCB: " + selectedCB );
 

Example 2: Editable JTextArea with JScrollPane scrollbars

In this example, the showMessageDialog() method of the JOptionPane class is used to display a JTextArea, which is going to be pre-populated with some sample text. The size will be set to show 5 rows and 10 columns. The JTextArea is then set to be editable, so the user can change the data.

    JTextArea area = new JTextArea();
area.setText("line1\nline2\nline3\nline4\nline5\nline6");
area.setRows(5);
area.setColumns(10);
area.setEditable(true);
JScrollPane scrollpane = new JScrollPane(area);
 

Along with a JLabel, the JScrollPane object is added to an Object[] array.

    Object[] array = {
new JLabel("Enter some text:"),
scrollpane,
};
 

The showMessageDialog() method produces a dialog with only an "OK" button and does not return any value.

    JOptionPane.showMessageDialog(null, array, "Text", 
JOptionPane.PLAIN_MESSAGE);
 

The JTextArea can still be interrogated to see if the user changed the value, if desired.

    String newtext = area.getText();
System.out.println( "newtext: " + newtext );
 

Example 3: JRadioButton and ButtonGroup

In this example, a dialog will be created consisting of three JRadioButtons and a JTextField. The radio buttons will be associated with a ButtonGroup, which will cause only one of them to be selected at a time.

Create the button objects and make the first button selected by default.

    JRadioButton b1 = new JRadioButton("Option 1");
JRadioButton b2 = new JRadioButton("Option 2");
JRadioButton b3 = new JRadioButton("Option 3");
b1.setSelected(true);
 

Tie the JRadioButtons together into a group, allowing only one of the group to be selected.

    ButtonGroup group = new ButtonGroup();
group.add(b1);
group.add(b2);
group.add(b3);
 

Define a "name" field as well.

    JTextField name = new JTextField(30);
 

Add the elements together in an array with a few JLabels.

    Object[] array = {
new JLabel("Select an option:"),
b1,
b2,
b3,
new JLabel("Enter a name:"),
name
};
 

Make the dialog appear using showConfirmDialog().

    int res = JOptionPane.showConfirmDialog(null, array, "Select", 
JOptionPane.OK_CANCEL_OPTION);
 

As in the first example, we can analyze the int return value of showConfirmDialog().

    // User hit OK
if (res == JOptionPane.OK_OPTION) { System.out.println( "OK_OPTION" ); }

// User hit CANCEL
if (res == JOptionPane.CANCEL_OPTION) { System.out.println( "CANCEL_OPTION" ); }

// User closed the window without hitting any button
if (res == JOptionPane.CLOSED_OPTION) { System.out.println( "CLOSED_OPTION" ); }
 

The selected button can be determined using the isSelected() method.

    // User selected button 1
if (b1.isSelected()) { System.out.println( "Selected: Option 1" ); }

// User selected button 2
if (b2.isSelected()) { System.out.println( "Selected: Option 2" ); }

// User selected button 3
if (b3.isSelected()) { System.out.println( "Selected: Option 3" ); }
 

The name field can be extracted using getText().

    System.out.println( "name=" + name.getText() );
 

These are just a few examples showing how the JOptionPane class was designed to be very versatile and flexible, allowing for moderately complicated GUI dialog to be created quite easily. Perhaps this usage would have been more obvious if the documentation was clearer, but it is documented.

next time ... part 3 advanced

Monday, April 27, 2009

Intralink Scripting: Commonspace Folder Info, Part 1

A lot of administrative tasks in Intralink 3.x are much more difficult than necessary, and in some cases nearly impossible. Folder information is one of those tasks. Without running the DSMU, getting information on folders can be extremely tedious.

Fortunately with the right Java code, we can put some of the internal features of the Intralink client to use. These are the same data model classes that the client Java code uses, but now we can use them to get the information that you want, how you want it, and whenever you want it. Remember, it's your data.


To traverse the Commonspace folder structure, my utility method getFolderList() will be used. It uses an ILFolderTreeModel object, which is a folder tree data model class, and a TreeNode, which is a node within a tree structure. The method calls itself recursively to traverse a folder tree, which need not start at the Commonspace root folder.

Initially, the method builds a new ArrayList. Then, the root node is added to the ArrayList. The method then iterates over the children, if any, of the current node. If there are child nodes, the method calls itself using the same ILFolderTreeModel object, but this time with the child node. The resulting ArrayList of the child node recursion is added to the higher level ArrayList. The child ArrayList is then cleared and nulled. The first ArrayList is returned when recursion has completed.

  public List getFolderList ( ILFolderTreeModel treemodel, TreeNode tree ) throws Exception {

List list = new ArrayList();
list.add(tree.getKeyName());

for (int i=0; i<treemodel.getChildCount(tree); i++) {

TreeNode child = (TreeNode)treemodel.getChild(tree,i);

List sublist = getFolderList(treemodel, child);
list.addAll(sublist);
sublist.clear();
sublist = null;

}

return list;

}
 

In order to call this function, an ILFolderTreeModel and a TreeNode object are required.

For the ILFolderTreeModel object, we can simply call the constructor:
    ILFolderTreeModel tm = new ILFolderTreeModel();
 

If the root node is the Commonspace Root Folder, then the TreeNode object is obtained as follows from the ILFolderTreeModel object:
    TreeNode tree = (TreeRootNode)tm.getRoot();
 

If another folder is the root for the TreeNode, things get a bit more complicated. First, an ILAppObject is created representing the folder of interest, then TreeObject.createCSTree() is executed using the ILAppObject. Running the getRoot() method of the resulting TreeObject gives us a TreeNode that we can use.
    String startFolderName = "Root Folder/ProjectX";
ILAppObject start_fol_ao = ObjectInfo.getObjectByKey( ObjectInfo.tFolder, startFolderName );
TreeNode tree = TreeObject.createCSTree(start_fol_ao).getRoot();
 

To get the ArrayList, getFolderList() is executed:
    List folders = getFolderList(tm, tree);
 

To iterate over the resulting ArrayList, use code like this:
    for (int i=0; i<folders.size(); i++) {
String folderName = folders.get(i).toString();
System.out.println( " " + (i+1) + ": " + folderName );
}
 

The output will appear in the .proi.log file on Unix or the most recent .pro.log.N file on Windows.


Here is the complete program. Please note the addition of three import statements beyong the typical two that Intralink provides in each Intralink Scripting application.

import com.ptc.intralink.client.script.*;
import com.ptc.intralink.script.*;

import com.ptc.intralink.client.admin.folder.*;
import com.ptc.intralink.ila.*;
import java.util.*;


public class Folder_List extends ILIntralinkScript {

ILIntralinkScriptInterface IL = (ILIntralinkScriptInterface)getScriptInterface();


public void run () throws Exception {

TreeNode tree = null;
ILFolderTreeModel tm = new ILFolderTreeModel();

String startFolderName = null;
startFolderName = "";
startFolderName = "/";
startFolderName = "Root Folder";
startFolderName = "Root Folder/ProjectX";

if ( startFolderName == null || startFolderName.matches("^/?$") ) {
tree = (TreeNode)tm.getRoot(); // Casting to TreeNode required
}
else {
ILAppObject start_fol_ao = ObjectInfo.getObjectByKey( ObjectInfo.tFolder, startFolderName );
tree = TreeObject.createCSTree(start_fol_ao).getRoot();
}

System.out.println( " tree: " + tree );
List folders = getFolderList(tm, tree);

for (int i=0; i<folders.size(); i++) {
String folderName = folders.get(i).toString();
System.out.println( " " + (i+1) + ": " + folderName );
System.out.flush();
}

folders.clear();
folders = null;
tm = null;

}


public List getFolderList ( ILFolderTreeModel treemodel, TreeNode tree ) throws Exception {

List list = new ArrayList();
list.add(tree.getKeyName());

for (int i=0; i<treemodel.getChildCount(tree); i++) {

TreeNode child = (TreeNode)treemodel.getChild(tree,i);

List sublist = getFolderList(treemodel, child);
list.addAll(sublist);
sublist.clear();
sublist = null;

}

return list;

}

}
 


In the next installment, I'll show how more information about folders can be gathered, along with a more sophisticated presentation of the data.

Tuesday, March 31, 2009

Book Review: Head First Java

Head First Java, 2nd Edition by Kathy Sierra and Bert Bates is the introductory Java entry in O'Reilly Media's Head First Series. The approach of this unique series is to inject humor, imagery, basic explanations, and a lot of fun into their subject matter. While not for everyone, the series does provide a solid learning experience.

The ideal reader of Head First Java is someone that has done some programming (maybe even some Java), but is fairly new to Java and/or Object Oriented programming. Advanced Java developers are probably not going to get a lot out of this book, but the topics covered are pretty extensive. The topics include: objects and classes, object oriented design, inheritance, polymorphism, constructors, garbage collection, static classes and methods, swing, multithreading, generics, java web start, and RMI. That may sound like a lot of topics, but each one is explained very effectively.

The Head First Series strives to break topics down into very easy to understand explanations, with numerous code examples and exercises. In fact, complex topics are explained multiple times to cover all facets of the subject matter. You won't become an expert, but you will have a very solid understanding and be able to code simple applications right away. More importantly, you will understand why Java developers uses language features in specific ways.

The authors of Head First Java avoid tool distractions by designing the book around using only the JDK and a simple text editor. No other tools or applications are required to use the examples in the book. The major code examples in the book concern two programs that are incrementaly developed through the chapters. One is a very primitive battleship game, focusing on game design logic, rather than a GUI (there is no GUI). The other is a beatbox midi sequencer, which includes functionality from the Java Sound API, a Swing GUI, and a client/server architecture.


Chapter Summary:

Chapter 1 (Breaking the Surface) discusses basic details on classes, and how to interface with the main() method. Also included is more basic programming details on conditionals, looping and and other flow control mechanisms.

Chapter 2 (A Trip to Objectville) gets into objects, object oriented principles, and the importance of unit testing. Garbage collection is briefly discussed.

Chapter 3 (Know Your Variables) covers variables including primitives and object references. Both primitive and object arrays are mentioned and their limitations discussed. More details on the garbage collection system is detaled. There is also a useful table showing all of Java's reserved keywords.

Chapter 4 (How Objects Behave) mentions more details on classes, methods (parameters vs arguments, return values, and pass-by-value), and encapsulation. Included is a discussion on instance vs. local variables.

Chapter 5 (Extra-Strength Methods) contains a more detailed discussion on object oriented design and unit testing. The new Java 5 enhanced for loop syntax is mentioned along with type casting of primitives.

Chapter 6 (Using the Java Library) dives into Java standard libraries with ArrayLists, importing, and packages. Also mentioned are parameterized types and boolean expressions.

Chapter 7 (Better Living in Objectville) continues the object oriented discussion with inheritance (both what it is and how to use it properly) and polymorphism. Both method overriding and method overloading are covered as well.

Chapter 8 (Serious Polymorphism) covers abstract classes and methods. More details on polymorphism and object casting is discussed. Java's version of multiple inheritance called interfaces is introduced.

Chapter 9 (Life and Death of an Object) details the stack and the heap, and how they impact objects and local variables. The chapter also discusses object constructors and superclass constructors, including the use of overloaded constructors. This is followed by a decription of the scoping rules of local variables and factors affecting object lifetime and when garbage collection kicks in.

Chapter 10 (Numbers Matter) provides details on the static and final, when used with both variables and methods. Also included is a mention of wrapper classes for primitive to object conversion (and vice versa), how this conversion can be automatic with autoboxing in Java5.0+. The discussion continues with number formatting, dates, and calendars. Methods from the Math class are covered briefly at the beginning of the chapter.

Chapter 11 (Risky Behavior) discusses details on exception handling, how to use try/catch/finally blocks to deal with exceptions, and how to declare that your method can throw exceptions. Exception objects are explained including exception inheritance, polymorphism, and how to properly catch different types of exceptions. Development on the MIDI application continues with details on the JavaSound API and MIDI events.

Chapter 12 (A Very Graphic Story) gets into the swing of things with coverage of the Swing GUI library. Included in the discussion is an introduction to frames, buttons, listening to events with event listeners, and drawing graphics with Graphics2D. How to utilize inner classes with event listeners for increased flexibility is also covered.

Chapter 13 (Work on Your Swing) gives examples of the use of a few different swing components and several GUI layout managers. Components discussed include JButton, JTextField, JTextArea, JCheckBox, JList, and JPanel. Detailed descriptions on the use of BorderLayout, FlowLayout, and BoxLayout are also included.

Chapter 14 (Saving Objects) covers saving (and restoring) objects through serialization via Serializable. Included is a discussion of the input and output streams of the Java I/O libraries. The Java I/O File and BufferedReader classes are also mentioned.

Chapter 15 (Make a Connection) has details on sockets, multithreading, and synchronization. The chapter builds an example (client and server) chat program to illustrate use of the Socket class, specifically how to read from and write to a socket. A excellent discussion of multithreading is covered in great detail with example code using the Runnable and Thread classes. Also included are details on the unpredictability of the thread scheduler. The chapter wraps up with solid coverge of concurrencies issues when using multithreading and how to avoid it with synchronization.

Chapter 16 (Data Structures) mentions sorting of collection objects using the Comparable class. The collections discussed include ArrayList, HashSet, TreeSet, and HashMap. The concept of generics is explained in greater detail, along with generic method declaration syntax to support polymorphism. Also included is brief mention on the difference between Sets and Maps.

Chapter 17 (Release Your Code) is all about setting up your application for distribution. This includes details on JAR files, how to structure them, what special files they need to contain, and how executable JAR files work. The importance of using packages is covered as well, along with the command line compiler syntax required. Use of Java Web Start to distribute your application to end users is discussed briefly.

Chapter 18 (Distributed Computing) touches on distributed computing topics such as RMI (Remote Method Invocation), servlets, EJB, and Jini. For RMI, the chapter provides a detailed explanation of how the proxy concept works and a dicussion of the process for setting up the remote implementation, the stubs and skeletons required, and the RMI registry. The concept of servlets and EJB are covered but only very briefly (be sure to read Head First Servlets for extensive converage on servlets). The chapter goes on to discuss Jini in great detail, including the discovery process and self-healing nature of the technology. It covers what you need to make it work, then adds the necessary code to enable Jini in the beat box program, both client and server versions.


If you're new to Java, Head First Java will get you started right away. It's approach utilizing humor and imagery may seem childish at first, but once you get started, you'll realize how effective the Head First Series learning series is.

Other topics in the Head First Series: