Monday, 12 October 2015

NetBeans Diff API Extracted as a Standalone Project

Inspired by Emilian Bold who extracted the Progress bar API as a separate OSS project out of NetBeans source code, I started to work with the aim of extracting the Diff API out as a separate project. I had this thought in 2012 or so and it has taken 3 years to actually make it (and only the textual part!)

In the meantime, came to know that the amazing Geertjan had done something better at https://github.com/GeertjanWielenga/netbeans-visual-diff-standalone
(which I got to know via a post at http://forums.netbeans.org/viewtopic.php?t=63551&highlight=).

Nevertheless, I went ahead and completed the task that I started and also posted the code in my github repo. You can take a look if you are interested. Also, I created a test project at github repo which you can follow to make use of this library.

Also, would like to note down my experiences when trying to make a NetBeans project into an OSS which might be useful for others:

My idea was to make the diff library work with jut JDK. So, wherever I encountered external dependencies, I modified them, such as:

a) NbBundle replaced with ResourceBundle
NbBundle is used quite a lot. I replaced it with ResourceBundle, like:
ex: return ResourceBundle.getBundle("Bundle").getString("BuiltInDiffProvider.shortDescription");

b) org.openide.ErrorManager
This is used in logging exceptions. The Javadoc provides a general guidline where  clearly provides the simple alternative - "Rather then using the {@link ErrorManager} consider using JDK's {@link Logger}
 * for reporting log events, unwanted exceptions, etc."

So, I followed the advice and did the same.

c) ImageUtilities.loadImage:
This was from the package org.openide.util.ImageUtilities - source shows that class loader and ImageIO are used to load images plus provides caching.
I have simply used classloader with ImageIO.

d) The API uses NetBeans lookup mechanism throughout even though both interfaces and implementations are present in the same diff module. There are however, two ways of using lookup to find services - one is the usage of "@org.openide.util.lookup.ServiceProvider" annotation to mark the implementation. This is pretty straightforward and maps to java.util.ServiceProvider usage.
The other way used is also via using Lookup, but, registration of services is done in an old manner (which I think is deprecated now). This is explained in http://wiki.netbeans.org/DevFaqLookupDefault and http://wiki.netbeans.org/DevFaqSystemFilesystem. 

How did I find this? After reading the above links, I happened to look at the manifest.mf file - which has a reference to "OpenIDE-Module-Layer: org/netbeans/modules/diff/mf-layer.xml"
So, I opened the mf-layer.xml where the DiffProvider implementations are provided and also refer to other .settings file(s). These files in turn have the implementation class name.
It took quite a bit of time to figure this out.

Initially, I started with trying to have the complete visual part as a separate project, but, then decided to do only the textual part. For this, some of the useful code was present as part of the visual stuff. So, while working on this, I also extracted out some inner classes into top-level classes.
For example, the TextDiffVisualizer class has utility method 'differenceToLineDiffText' - which is very useful. I moved this out to a separate class named Util.

Finally, completed this and posted the code at my github repo

Friday, 14 August 2015

If I start a software company

If I start a software company...
I actually want to rant against some stuff being done in software companies...but instead of just sounding negative, I thought about what I would do if I run my own software company.
I list my thoughts about the same - first the rant and then on what I will do...

System:
I have always wondered about this. Executives would be given high-powered brand new Mac, but developers would be given a normal system with 2 GB RAM and a ok processor. Most of the work of executive is in his/her head - system is used mainly for mail access, documents, sheets and ppts. Isnt it?

I never really understood this. Particularly, being from a Java background, typically such systems require higher RAM. Usually, we will run the IDE, and also run the app server in our system along with a database too. I remember when working for a MNC, we got a system with 1 GB RAM and it would take ages to deploy. Request to upgrade to 2 GB RAM would go through a long bureaucratic route with the PM explaining the costs involved.

Isn't a good computer the most important tool for a developer? After the people themselves, it is the system where the most investment should go. And, if the people are the most important asset in software industry (as most companies claim), should we not give them the best tools to work with? Howmuchever you provide a fancy working place with good air conditioning, a good system is the most important thing for a developer - and should I mention that a slow unresponsive system is the most annoying thing for a developer.

So, my first priority would be to give the best system to my developers.

Email, attachments, sharing of files:
These are actually inter-related.

Email:
Yes, the most trivial one. But, the most important one too. In these days of everything-on-web, I just don't understand why companies spend to buy licenses for desktop mail clients. Why can't they just use OSS mail clients in that case? Wouldn't that save a lot of cost?
Or why not simply go for a solution like gmail for business? you just need a browser for that.

Attachments & File Sharing:
I have done this several times. Let's say we are working on an estimate and prepare a sheet. I will send this to my peer attaching the sheet. They will make changes, rename the file 'v2' and send back to me. I will again rename the file like file_ranga_v2.xls and take another copy. Very soon, there will be numerous copies of the file in my hard disk (not to mention the versions circulating in emails). If I were to revisit this a month later, I would struggle to find out which is the latest version. I will have to look at the modified date and find out. Ditto for docs, ppts. Also, imagine the size of these attachments circulating around filling up mail boxes. It soon becomes a pain.

I worked with Google sheets for some time with a client and I was amazed at how easy it was to share sheets. No hassles, no multiple versions and no sending around attachments wasting space and network bandwidth. On top of it, everything is on cloud and I could access it from my personal system or smart phone too. And, it makes our day-to-day operations easy to manage. Pretty simple, but, I still see many companies (even new ones) opting for say MS-Exchange and then buying license for MS-Outlook. Pray, why?
(Not to mention the license cost for MS-Office - I forgot about that)

Thinking about this, it also helps IS (Information Security) in a way - no data needs to be stored in individual machines.

Issue Tracking via Excel Sheets:
This is similar to the above one. This is actually ironical. Many companies use excel sheets to manage issue tracking, timesheets etc. I thought excel sheets were used 10 years back. Irony is that, we do write software for many customers where requirements go like: 'our folks are currently using excel sheets. we want to replace this with a system'!!
(I think the customers do not know that these companies actually use a excel sheet and not a system - if they come to know about it, they will actually think twice about awarding such projects!)

And imagine doing this in the above mentioned fashion - numerous versions circulating around in mail boxes. And, how do we derive metrics out of these? We will have to first identify the correct version and then gather data. Systems, on the other hand, generate reports with a click of a button. And are searchable too. And, you don't have to re-invent the wheel. Numerous OSS projects are available for such purposes in most technologies. In fact, we are spoilt for choices.

At the least, use something like Google sheets!!

Software and anti-OSS:
Some companies have a policy of no Open Source Software. Yes, it's true. However, you could see such companies using a lot of 'trail' software. I have seen many places where 'EditPlus' (a popular editor) being used - without license being bought. This particular software allows you to use it, but with an annoying warning window when it starts (which clearly states that you can use it only for 30 days). I don't get this. If it is so important for you, why don't you just buy a license. It is not just illegal to use software without buying a license. It is also unethical, unfair & disrespectful in my opinion - what these people are basically saying is: we earn money by writing software for our customer, but, we will not respect the other company/person who has spent lots of time developing this software. If you feel the cost is prohibitive and you won't make any margin, then, just don't take up such projects where there is dependency on high-cost licensed software.
Or, just use OSS and drop all pretensions about the same.

In my own company, I will make maximum use of OSS right from the Operating System. I have myself been using Ubuntu in my home machine for a few years and it is perfect for development - much much better than Windows - I don't have to restart my system after an install not to speak of the breeze to install stuff with apt-get. And, till date I have never seen a command equivalent to grep/egrep/find with  its unmatched speed - try searching for a file in Windows.
This covers all technologies except MicroSoft. Companies working on projects with MS technology should buy appropriate license(s).

Tools/IDE:
I am a tools guy. I believe developers can be more productive using tools. I have seen many companies impose tools/IDE on developers - they call it a 'standard'. And, many companies also buy expensive software/IDE which is such a waste - when the same could be done with OSS tools.

If the build system is independent, why can't we allow the developers to use their favorite tools? And, the sheer number of tools available is very high.

In my own company, I will strive to choose the build system for the project which is based on command-line - this would allow the developers to use their favorite tool to write code. In fact, this is a must. This allows us to introduce CI which helps in achieving higher quality and follow agile.

Laptop/Desktop:
In an earlier life where I worked at an MNC, I was given a desktop (yah, 1 GB RAM). And then, during conference calls, we would go over to a meeting room. I would need frequent access to my system to answer questions efficiently, but obviously, I can't carry my desktop to the meeting room. It used to be a pain. Some companies solve this problem by having a desktop in meeting rooms and doing a RDC to the developer's system.
I would rather provide laptops to all my developers (and not just managers, leads). The cost difference is not much these days. Only problem with laptops is that they have to be guarded against theft.

VOIP calls:
Of course, MNCs have the costly VOIP phones. I would prefer to use GTalk/Skype. I would also like my developer to take calls from home if need be - late evening or early morning calls. It is actually much more productive and helps in work-life balance.


I have tried to cover as much points in a random fashion. Of course, I have not said anything about getting projects. That is because I do not know anything about it. You might of course question me like, 'dude, you need projects to run a software company'. True. I have no idea how to do that. But, I do believe there are online avenues for these. Of course, it won't be easy.

The reason I have talked only about operational aspects is simply because - these are the ones that affect me on a day-to-day basis. And, I do strongly believe that, operational efficiency can make a major difference to an organization. You could ask about what is the USP of my software company. True, not much. But, operational efficiency can actually be the difference between success and failure of project(s). At least, that is what I think.

Sunday, 21 December 2014

Swing JTable to JavaFX TableView

Having worked quite a bit with Swing JTable, I explored on how to work with JavaFX TableView. In this post, I describe differences between the two, which, I hope would help Swing developers looking to migrate to JavaFX.

The complete source code is available in my github repo.

I will attempt to build a simple table which displays a list of employees. This will display varied information of the employee, like id (int), name (String), salary (double), part time flag (boolean), doj (LocalDate).

Let us first define the Employee class which uses JavaFX property model (more on this later).

public class Employee {
    private SimpleIntegerProperty id;
    private SimpleStringProperty name;
    private SimpleDoubleProperty salary;
    private SimpleBooleanProperty partTime;
    private SimpleObjectProperty<LocalDate> doj;

    public Employee(int id, String name, double salary, LocalDate doj, boolean partTime) {
        this.id = new SimpleIntegerProperty(id);
        this.name = new SimpleStringProperty(name);
        this.salary = new SimpleDoubleProperty(salary);
        this.partTime = new SimpleBooleanProperty(partTime);
        this.doj = new SimpleObjectProperty<>(doj);
    }

    public String getName() {
        return name.get();
    }

    public void setName(String value) {
        name.set(value);
    }

    public StringProperty nameProperty() {
        return name;
    }

    //other setters and getters...
}

Now, let us write the JavaFX code to build the table. I am directly using the main class to build the GUI (without using FXML).

    @Override
    public void start(Stage stage) throws Exception {
        //define sample Employee objects
        final Employee emp1 = new Employee(1, "Ram", 23123.23, LocalDate.now(), false);
        final Employee emp2 = new Employee(2, "Krishna", 32398.76, LocalDate.now(), true);

        final ObservableList<Employee> data = FXCollections.observableArrayList(emp1, emp2);

        //initialise the TableView
        TableView<Employee> tableView = new TableView<>();        
        //define the columns in the table
        TableColumn idCol = new TableColumn("ID");
        idCol.setCellValueFactory(new PropertyValueFactory<>("id"));

        TableColumn nameCol = new TableColumn("Name");
        nameCol.setPrefWidth(100);
        nameCol.setCellValueFactory(new PropertyValueFactory<>("name"));

        //...likewise for other columns

        //add the columns to the table view
        tableView.getColumns().addAll(idCol, nameCol, salaryCol, partTimeCol, dojCol);

        //Load the data into the table
        tableView.setItems(data);

        StackPane root = new StackPane();
        root.getChildren().add(tableView);
        
        Scene scene = new Scene(root, 450, 300);

        stage.setTitle("JavaFX TableView Sample");
        stage.setScene(scene);
        stage.show();
    }

When I run this application, we get the following output:


Let me now talk about the differences between Swing JTable and JavaFX TableView (I will be numbering the differences throughout the post (I have used a 'minus' against some numbers to indicate that they are negative points)).

1) Generics
The first difference we notice is that the TableView is right-away generified, like:
private TableView<Employee> tableView = new TableView<>();

In 99% of the cases, a table displays homogeneous data, so this is actually good. The Swing components were not generified (sure, Generics came later, but even after they came, this change was done in later versions only). Without this, in Swing, there was always a kind of discomfort - a row not being openly identified with an Object. It was just a physical row.

In JavaFX, due to this, loading data to the table is easy. We basically need to set an ObservableList to the table (more on this in point 8). A convenience class FXCollections is used to build the ObservableList - we can either build this directly from separate instances or use a collection:
final ObservableList<Employee> data = FXCollections.observableArrayList(emp1, emp2);
tableView.setItems(data);

2) Scrollpane
In Swing, when we add a JTable, we will not get any scrollbars. We need to wrap the JTable within a JScrollPane and actually add the scroll pane to the view. Only then will we get the scrollbars. In JavaFX, we get this right away (you can see the horizontal scrollbar in the image). Note that the component is named TableView and not just Table (probably due to the inherent scrollbar).

3) Column names and types:
In Swing, we will usually write a TableModel class which will provide the information about column names and types (via overridden getColumnName() and getColumnClass() methods).
As we don't write a model separately in JavaFX, we add columns directly when creating the table (yes, we don't need to write a separate model - more on that later).
This is done by creating a TableColumn instance and adding the same to the table, like:
TableColumn<Employee, Integer> idCol = new TableColumn<>("ID");

This declaration of the column provides information about the type of the column and also the name of the column (display name). And then we add this to the table, like:
tableView.getColumns().add(idCol);

4) Display of values:
In Swing, the getValueAt() method defined in the TableModel is queried and is used to display the data for the cells. So, we have to write the getValueAt() usually checking the column number and returning the appropriate value (Object). The toString() method will then be invoked and displayed (by the default renderer).

In JavaFX, this is made easier. After we create a TableColumn, we need to then set a 'cellValueFactory' which will calculate the value for the cell, like:
idCol.setCellValueFactory(new PropertyValueFactory<>("id"));

This probably uses reflection to invoke the getter method and get the value. Similar to Swing JTable, the toString() is invoked on the object and the value displayed. Note that reading and displaying the values is not related to the JavaFX property model. This would work with any POJO (JavaBean model) except for the CheckBox control (which I think is a bug - JavaFX TableView does not pick the correct value of the Boolean value when a POJO is used. Even when using a JavaFX property model, the value is picked and displayed correctly only when the xxxProperty() method is present in addition to the regular getter and setter).

In our Employee class, we have a LocalDate field doj. When we add this to the table, we see that the date is displayed by it's default toString() notation.

The other alternative is to set a cell factory on our own. This is a little verbose and we will have to return an ObservableValue (the verbosity can be reduced largely with lambdas though).

5) Sorting
Sorting is supported right out-of-the-box. This is good as this was a pain point in Swing JTable.

6) Alternate Row colors and CSS:
The TableView by default uses alternate colors for rows. We can customize the colors using CSS.

-7) Alignment (Integer and Double):
In our Employee class, we have an Integer field (id) and a Double field (salary). When these are added to TableView, they are not right-aligned. This would generally be the need. In Swing JTable, this would be done automatically which was cool (achieving this in JavaFX is easy though).

8) Updating the view:
In Swing, we would usually need to write a TableModel class (that usually extends AbstractTableModel). This class will provide all information about the data of the table (including column names, row count, and the row data themselves). We can load and show the data in the JTable with this. But, what happens when the data changes?
Normally, we would need to invoke the various 'fireXXX' methods from within this class which will in turn instruct the JTable update its view. Most starters with JTable miss this out and it takes some learning curve to get this working.

JavaFX TableView handles this right from the beginning. We simply supply the table via an ObservableList and rest is taken care of. From here on, whenever the data changes, view gets updated automatically (this happens because TableView 'observes' the passed in ObservableList).
(note that this works fine with using the JavaFX property model and PropertyValueFactory. If PropertyValueFactory is used along with regular POJO, this does not work).

This is really good. Along with generified TableView, this means that we simply need to build the list and pass it by wrapping it in an ObservableList. Building the data is also more cleanly separated.

-9) Boolean values
In our Employee class, we have a Boolean field (isPartTime). When we add this to the TableView, the simple toString() representation of this value is displayed. In Swing JTable, as soon as a column type is declared as Boolean, it right-away shows the value as a check box which is really cool. In JavaFX, we need to set a cell factory to do the same (see point 11.Editing).

10) Renderers:
Writing renderers for columns is similar to that of Swing. We write an implementation separately.

11) Editing
In Swing, we need to implement the setValueAt() method where we can set the value from the edited cell to the actual object (this works in combination with isCellEditable() method which dictates which cell is editable). We can also add custom editors like JComboBox etc.

In JavaFX, we need to set a CellFactory to the column to make it editable. This is made even more easier with the ready availability of several implementations - TextFieldTableCell for String values for example.

In our example, we simply set one for the nameColumn with the call 'TextFieldTableCell.forTableColumn()'. For the ID column though, as the data type is Integer and a TextField by default deals with String, we need to use a StringConverter. We can make use of the convenience method which takes an implementation of the abstract StringConverter class as the argument. Luckily, JavaFX comes with ready implementations like NumberStringConverter (which deal with java.lang.Number from which the wrappers descend). We simply use them.

For the Boolean column, ideally we need a CheckBox which is a different control. So, we use the available CheckBoxTableCell.

Note that editing works well with the JavaFX property model with minimal code. Otherwise we would need to write custom editor code (when we use a usual POJO, the editing will still work and the table cell will also display the edited value, but, the edit will not be updated back to the object!).

Everything works including editing except for the DOJ field. For the Date, similar to the Double field, we need to use a converter. JavaFX comes with a DateStringFormatter, but unfortunately, it works with the older java.util.Date and not the LocalDate which is what we want to use. So, to make this work, we simply need to write a converter by extending the StringConverter, like:
dojCol.setCellFactory(TextFieldTableCell.forTableColumn(new StringConverter<LocalDate>(){
    @Override
    public String toString(LocalDate object)
    {
        if(null == object)
            return "";
        return object.toString();
    }

    @Override
    public LocalDate fromString(String value)
    {
        if (value == null) {
            return null;
        }                
        return LocalDate.parse(value);
    }
}));

This is a very simple converter which works with the default LocalDate pattern. So, while editing, the same pattern should be used. Using a DatePicker for the same would be cool, but that needs altogether an implementation of TableCell.

The complete source code used in this post is available in my github repo.

Saturday, 26 July 2014

ServiceLoader API Sample

In this post, I am going to discuss the ServiceLoader API introduced in JSE 6. This is an API to load services where the definition and implementation of the services are decoupled. For example, I might define a service via an interface named Logger which has a method named log(String s). I might later write an implementation named FileLog which will log the messages to a file. Later on, someone else might write a DBLog which will log the messages to a database. Here, there are different implementations of the service available and as an user, I can choose to use one of the available implementations.

The important point to note is that, the person who defines the service need not be the one who provides implementations of the services. There are several such usages in JDK itself - for example, the ResultSet interface just defines the methods - different DB vendors provide implementations of this interface.

Now, the question is, how to load and use the implementations without a direct dependency on the implementations? That is where the ServiceLoader API comes in. Let us see a simple example to see how this works:

Let us first define the interface which is in a separate project:

public interface ServiceInterface {
    public String serviceMethod();
}

Now, let us write the implementation in a different project (this project would refer the interface definition project in its library or in the case of Maven will need to declare a dependency):

public class ServiceProviderImpl1 implements ServiceInterface {
    @Override
    public String serviceMethod() {
        return "Sun";
    }
}

The above class is a sample implementation named 'impl1'. Likewise, let us write a different implementation (in a different project which again depends on the interface project):

public class ServiceProviderImpl2 implements ServiceInterface {
    @Override
    public String serviceMethod() {
        return "Moon";
    }
}

We have two different implementations of the interface now.

Problem:
Let us try and develop the client which will actually use one of the implementations:

import java.util.ServiceLoader;
import <blog package>;

public class App {
    public static void main( String[] args ) {
        ServiceInterface si;
        si = new ???();
        si.serviceMethod();
    }
}

In OOPS, the general guideline is to program to interfaces. So, we declare a variable of the type ServiceInterface (and not of implementation). And then when creating an object, we have to create an instance of one of the implementations. Now, whichever implementation we decide to use, we have to hardcode the class name here (in place of the question mark).
What if we want to change the implementation tomorrow? We will be forced to make a code change.

Note: In the above case, this client project has to include both the interface and impl1 in the referenced libraries (dependencies in Maven).

Solution:
The solution is to use the ServiceLoader API. First let us look at the client code:

import java.util.ServiceLoader;
import com.blogspot.javanbswing.sp.api.ServiceInterface;

public class ClientTest {
    public static void main( String[] args ) {
        ServiceLoader<ServiceInterface> serviceLoader
            = ServiceLoader.load(ServiceInterface.class);
        ServiceInterface api = serviceLoader.iterator().next();
        System.out.println("from " + api.serviceMethod());
    }
}

Now, we are using the ServiceLoader API. This has a load method which will search for a implementation and use it. This method actually returns a collection of available implementations. But in our case, as we have included only the impl1 dependency, the search will return that implementation. And that will be the one used.

But, how does the API search and find the implementation? For this, the implementation jars should follow a mechanism called as provider-configuration file. This file is a simple text file which should be placed under META-INF/services folder. The file should be named exactly as the fully qualified name of the service interface.

For example, in our case, the service interface name is 'ServiceInterface'. And the fully qualified name is 'com.blogspot.javanbswing.sp.api.ServiceInterface'. We should create a file with this name. This file should in turn contain the fully qualified class name of the implementation. For example in impl1, the implementation class name is 'ServiceProviderImpl1' and the fully qualified name is 'com.blogspot.javanbswing.sp.impl1.ServiceProviderImpl1'. This is the only text that should be present in this file. Same should be done for impl2.

So, when we include the 'impl1' as the dependency for the client project, it will look for this file under the 'META-INF/services' folder in the jar and then pickup the implementation class name from within the text file.

Now, run the client program and you can see that 'Sun' is displayed. But, how do we switch the implementation? Simply change the dependency to impl2 (in the client's pom.xml). Now, run the program again and you should see 'Moon' displayed. 

In production, we will simply place the implementation jar based on what we want (place either the impl1.jar or impl2.jar in the classpath and we are done). So, without any code change in the client program, we can switch to a different implementation. Simple and cool!

The complete source code including the client is available in my github repo.

Thursday, 5 September 2013

A FAQ for JSR

When I initially came to know about JSR (Java Specification Request), I had some difficulties in understanding that. And, I had several questions too. So, at JavaRanch/CodeRanch (where I am a moderator in some of the forums), I created a FAQ about JSR which is now publicly available: JSR FAQ

Swing TreeTable Example with root using JXTreeTable

In my earlier post, I blogged about using different objects with a HAS-A relationship to be displayed in a tree table. However, I made the root node invisible and used a dummy object for the root.

In this post, I am going to use an object to represent the root and also display it. I am going to continue from where I left off by introducing an Organization object. This Organization object will contain a List<Department> object. Each Department object will in turn contain a List<Employee> object. This is same as in my earlier post. I think this reflects a real-world scenario of an organization with several departments and each department having many employees.

The Department and Employee classes remain the same. The Organization class looks as follows:

import java.util.List;

public class Organization {

    private String name;
    private List<Department> departmentList;

    public Organization(String name, List<Department> departmentList) {
        this.name = name;
        this.departmentList = departmentList;
    }

    public List<Department> getDepartmentList() {
        return departmentList;
    }

    public String getName() {
        return name;
    }
}

Changes to the tree-table model are along expected lines. Instead of using a dummy object for the row, I pass the Organization object itself to be considered as root, like (I have a different class name now):
public MyTreeTableModel(Organization organization) {
    super(organization);
}

The getValueAt() has an extra if condition to account for one more object in the hierarchy:
@Override
public Object getValueAt(Object node, int column) {
    if (node instanceof Organization) {
        if (1 == column) {
            return ((Organization) node).getName();
        }
    }
    if (node instanceof Department) {
        Department dept = (Department) node;
        switch (column) {
            case 0:
                return dept.getId();
            case 1:
                return dept.getName();
        }
    } else if (node instanceof Employee) {
        Employee emp = (Employee) node;
        switch (column) {
            case 0:
                return emp.getId();
            case 1:
                return emp.getName();
            case 2:
                return emp.getDoj();
            case 3:
                return emp.getPhoto();
        }
    }
    return null;
}
As the Organization has only one value to be displayed, I use the first column to do it.

Same way, the getChild() and getChildCount() methods have an extra condition:
@Override
public Object getChild(Object parent, int index) {
    if (parent instanceof Organization) {
        Organization org = (Organization) parent;
        return org.getDepartmentList().get(index);
    } else {
        Department dept = (Department) parent;
        return dept.getEmployeeList().get(index);
    }
}

@Override
public int getChildCount(Object parent) {
    if (parent instanceof Organization) {
        Organization org = (Organization) parent;
        return org.getDepartmentList().size();
    } else {
        Department dept = (Department) parent;
        return dept.getEmployeeList().size();
    }
}


Now, as I have 2 levels of hierarchy, the parent could be either Organization or Department. So, I do an instanceof check and return the corresponding child (or the child count).

Same goes for the getIndexOfChild() method. This method implementation is slightly more complex. Based on the parent, I do a cast and get the exact parent and child objects. Then, I call the appropriate method to get the list from which I can get the index of the child.

@Override
public int getIndexOfChild(Object parent, Object child) {
    if(parent instanceof Organization) {
        Organization org = (Organization) parent;
        Department dept = (Department) child;
        return org.getDepartmentList().indexOf(dept);
    }
    else {
        Department dept = (Department) parent;
        Employee emp = (Employee) child;
        return dept.getEmployeeList().indexOf(emp);
    }
}

While using this model in our GUI, we need to make the root visible. This can be done by calling treeTable.setRootVisible(true). And, we will be building the Organization object in addition to what we did earlier. The complete GUI code looks like:

public class TreeTableMainWithRoot extends JFrame {

    private JXTreeTable treeTable;
    
    public TreeTableMainWithRoot() {
        //sample doj
        final Date doj = Calendar.getInstance().getTime();
        List<Department> departmentList = new ArrayList<Department>();

        List<Employee> empList1 = new ArrayList<Employee>();
        empList1.add(new Employee(1, "Kiran", doj, "emp1.jpg"));
        empList1.add(new Employee(2, "Prabhu", doj, "emp2.jpg"));
        empList1.add(new Employee(3, "Murugavel", doj, "emp1.jpg"));
        departmentList.add(new Department(1, "Sales", empList1));

        List<Employee> empList2 = new ArrayList<Employee>();
        empList2.add(new Employee(4, "Deiveegan", doj, "emp2.jpg"));
        empList2.add(new Employee(5, "Saravanan", doj, "emp1.jpg"));
        departmentList.add(new Department(2, "Production", empList2));
        
        Organization organization = new Organization("ABC XYZ Corporation", departmentList);
        
        MyTreeTableModel myTreeTableModel = new MyTreeTableModel(organization);
        treeTable = new JXTreeTable(myTreeTableModel);
        treeTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        treeTable.setRootVisible(true);
        treeTable.getColumnModel().getColumn(3).setCellRenderer(new PhotoRenderer());
        treeTable.setRowHeight(50);

        add(new JScrollPane(treeTable));

        setTitle("JXTreeTable Example");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        pack();
        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new TreeTableMainWithRoot();
            }
        });
    }
}

When we run the code and expand all nodes, we get an output like:

The complete source code is available in the form of a Maven project in my github repo.

Tuesday, 20 August 2013

Swing TreeTable Example using JXTreeTable

This post provides an example using JXTreeTable which is a tree-table component in SwingX. SwingX is an open source Swing extension toolkit from SwingLabs.

Most of the examples using tree-table that we find usually have only one type of entity - for example, showing a 'folder' view is most common. But, in this case, the file and the folder share some common traits and would have a IS-A relationship (from an OOPS perspective). However, in a real scenario, we may have to deal with objects that are not directly related.

For example, think of a Department object which has a list of Employee objects. These may share a relationship at the db level, but it will be a HAS-A relationship. So, in a tree-table component, the parent is one type of object and child (leaf) is another. This leads to handling of different conditions in most methods. Added to this, we might have a completely different object represent the root component - say, an Organization object.

However, for the moment, let us deal with an example where the root is not shown. This example displays the departments in an organization. Under each department, there may be n number of employees working.

Let us first create two classes representing the employee and department:

public class Employee {

    private int id;
    private String name;
    private Date doj;
    private String photo;

    public Employee(int id, String name, Date doj, String photo) {
        this.id = id;
        ...
    }
    //setters and getters not shown for brevity
}

public class Department {

    private int id;
    private String name;
    private List<Employee> employeeList;

    public Department(int id, String name, List<Employee> empList) {
        this.id = id;        
        ...
    }

    public List<Employee> getEmployeeList() {
        return employeeList;
    }

    public void setEmployeeList(List<Employee> employeeList) {
        this.employeeList = employeeList;

    }

    //other setters and getters
}

Let us now write the tree-table model. We need to extend the org.jdesktop.swingx.treetable.AbstractTreeTableModel and override the methods (this is an abstract implementation of org.jdesktop.swingx.treetable.TreeTableModel):

import java.util.List;
import org.jdesktop.swingx.treetable.AbstractTreeTableModel;

public class NoRootTreeTableModel extends AbstractTreeTableModel {
    private final static String[] COLUMN_NAMES = {"Id", "Name", "Doj", "Photo"};
    
    private List<Department> departmentList;

    public NoRootTreeTableModel(List<Department> departmentList) {
        super(new Object());
        this.departmentList = departmentList;
    }

    @Override
    public int getColumnCount() {
        return COLUMN_NAMES.length;
    }

    @Override
    public String getColumnName(int column) {
        return COLUMN_NAMES[column];
    }
    
    @Override
    public boolean isCellEditable(Object node, int column) {
        return false;
    }

    @Override
    public boolean isLeaf(Object node) {
        return node instanceof Employee;
    }
    ...

}

The treetable is going to show a list of departments. So, in our implementation of the model, we declare a constructor that takes a List<Department>. The getColumnCount(), getColumnName() and isCellEditable() implementations are same as we do for a JTable. The isLeaf() method is implemented for trees. This method should return a boolean to indicate whether the node is a leaf. In our case, the employee objects should be displayed as leaf, so, we simply do an instanceof check on the Employee object. Note the usage of a dummy object to indicate the root.

Let us continue with other methods:

    @Override
    public int getChildCount(Object parent) {
        if (parent instanceof Department) {
            Department dept = (Department) parent;
            return dept.getEmployeeList().size();
        }
        return departmentList.size();
    }

    @Override
    public Object getChild(Object parent, int index) {
        if (parent instanceof Department) {
            Department dept = (Department) parent;
            return dept.getEmployeeList().get(index);
        }
        return departmentList.get(index);
    }

The getChildCount() and getChild() methods are similar to what we do for a JTree model. The getChildCount() should return the number of departments first. In case the parent is a department itself, it should return the number of employees present in the department. So, we handle this with an if condition. 

Same way, in the getChild() implementation, we check if the passed in node is an instance of Department object. If so, we return an Department object by getting if from the list with the index number. If not, Employee object is returned. Note that, the getChild() and getChildCount() methods are closely related.

Next is the getIndexOfChild() method which is a bit tricky. The getIndexofChild() method should return the index of an Employee object within a Department object.

    @Override
    public int getIndexOfChild(Object parent, Object child) {
        Department dept = (Department) parent;
        Employee emp = (Employee) child;
        return dept.getEmployeeList().indexOf(emp);
    }

Finally, the most important method:

    @Override
    public Object getValueAt(Object node, int column) {
        if (node instanceof Department) {
            Department dept = (Department) node;
            switch (column) {
                case 0:
                    return dept.getId();
                case 1:
                    return dept.getName();
            }
        } else if (node instanceof Employee) {
            Employee emp = (Employee) node;
            switch (column) {
                case 0:
                    return emp.getId();
                case 1:
                    return emp.getName();
                case 2:
                    return emp.getDoj();
                case 3:
                    return emp.getPhoto();
            }
        }
        return null;
    }

The getValueAt() method is the one that returns the value of every cell in a JTable. Note that the JXTreeTable extends JTable, so correct implementation of this method is important.

In our case, the node might be a Department or Employee. So, an instanceof check is first applied on the node. Then, based on the column number, the corresponding method is called (this is similar to what we do for JTable). Note that the Department has only 2 columns of data to display and the Employee 4. The final "return null" statement takes care of the missing columns.

Let us now use this model by building our GUI (I have used the current time for the doj of all the records as this is just a demonstration):

import java.util.*;
import javax.swing.*;
import org.jdesktop.swingx.JXTreeTable;

public class TreeTableTest extends JFrame {

    private JXTreeTable treeTable;

    public TreeTableTest() {
        //sample doj
        final Date doj = Calendar.getInstance().getTime();        
        List<Department> departmentList = new ArrayList<Department>();

        //create and add the first department with its list of Employee objects
        List<Employee> empList1 = new ArrayList<Employee>();
        empList1.add(new Employee(1, "Kiran", doj, "emp1.jpg"));
        empList1.add(new Employee(2, "Prabhu", doj, "emp2.jpg"));
        empList1.add(new Employee(3, "Murugavel", doj, "emp1.jpg"));        
        departmentList.add(new Department(1, "Sales", empList1));

        //create and add the second department with its list of Employee objects
        List<Employee> empList2 = new ArrayList<Employee>();
        empList2.add(new Employee(4, "Deiveegan", doj, "emp2.jpg"));
        empList2.add(new Employee(5, "Saravanan", doj, "emp1.jpg"));
        departmentList.add(new Department(2, "Production", empList2));
        
        //we use a no root model
        NoRootTreeTableModel noRootTreeTableModel = new NoRootTreeTableModel(departmentList);
        treeTable = new JXTreeTable(noRootTreeTableModel);
        treeTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);        
        treeTable.setRootVisible(false);  // hide the root

        add(new JScrollPane(treeTable));

        setTitle("JXTreeTable Example");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        pack();
        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {        
                new TreeTableTest();
            }
        });
    }
}

When we run the example and expand both the department nodes, we get an output like:

Note that the doj and the photo column for department row(s) are empty. This is a practical example of a tree-table.

Edit: As per the request of some readers, am providing code for showing an image. The Employee class has a member 'photo' which has the name of the image of the employee. Currently, it shows only as a text value. To show the photo as an actual image, we need to write an renderer. This is similar to what we do for JTable:

public class PhotoRenderer extends JLabel
                           implements TableCellRenderer {
    public Component getTableCellRendererComponent(
                            JTable table, Object photo,
                            boolean isSelected, boolean hasFocus,
                            int row, int column) {
        if(photo != null) {
            ImageIcon imageIcon = ...;
            setIcon(imageIcon);
        }
        else {
            setIcon(null);
        }
        return this;
    }
}

This renderer extends JLabel as we can set an icon for a JLabel. So, we can freely call the setIcon method of the JLabel to set the icon.

Next, we need to set this renderer to the particular column, like:
treeTable.getColumnModel().getColumn(3).setCellRenderer(new PhotoRenderer());

As the photo column is the 4h column, I am using the index 3 to get the TableColumn and set the renderer. When I run the code, I get the following output (I used some dummy images for photos):



Although the image is successfully displayed, it is not sufficient as we are not able to see the full image. To correct this, we need to increase the 'row height' of the table, like:
treeTable.setRowHeight(50);

Now, when I run the program, I get the following output:


The complete source code is available in the form of a Maven project in my github repo.

In a subsequent post, I have shown a similar example with root being visible (for example root represented by an Organization).