Setting checkboxes in a TreeTable

I have Checkboxes as the property in the first (tree) column of my treetable. When a branch (parent) is checked, I want all of its leaves (children) to also be checked. Same thing when the parent’s checkbox is un-checked. However, I cannot seem to access the childrens’ checkboxes when the parent is checked. I’ve written a method that is called when the parent is checked, and here’s where the problem lies:

logger.log(Level.INFO, "Item property is a " + treeTable.getItem(orderDetail.getId()).getItemProperty("Name / Product").getType().getName()); // com.vaadin.ui.CheckBox CheckBox cbod = (CheckBox)treeTable.getItem(orderDetail.getId()).getItemProperty("Name / Product"); cbod.setValue(true); In line 1, the result in the console is
com.vaadin.ui.CheckBox
. However, the next line throws a
ClassCastException
, stating that I cannot cast a
com.vaadin.data.util.IndexedContainer$IndexedContainerProperty
to a
com.vaadin.ui.CheckBox
. Eclipse was the one suggesting that I cast it, even though line #1 above returns a CheckBox anyway. What am I doing wrong?

Can you please share your source code a bit, So that I can help troubleshooting your issue. I have done something similar in my last project using tree table, I would be glad to help you out…

Sure, I’ll show you what I think are the most important parts. And thanks for replying, @Krishna!

Okay, so here is the basic structure of the two main Java Beans:

public class Job {

    // The variables this bean holds.
    private Date shipDate;
    private String jobId;
    private String customerName;
    private String customerPO;
    private Timestamp proofSpecDate;
    private Timestamp jobCompleted;
    private PrintingCompany printingCompany;
    private boolean overruns;
    private List<OrderDetail> orderDetailList;
    private boolean treeExpanded = true;

... (getters and setters) ...
}
public class OrderDetail {

    // The variables this bean holds.
    private int id;
    private String orderId;
    private String productId;
    private String productDetail;
    private PrintType printType;
    private long numColors;
    private long quantity;
    private Timestamp itemCompleted;
    private int proofNum;
    private Timestamp proofDate;
    private String thumbnail;

... (getters and setters) ...
}

As you can see, each Job bean contains a collection of OrderDetail beans. Sometimes, one Job will have only one OrderDetail, but sometimes it will have 2 or 3 or a dozen, etc. And the OrderDetail bean’s
orderId
matches the Job bean’s
jobId
to which it belongs. This forms the hierarchy that will be needed for the TreeTable.

Since it seems
SQLContainer
doesn’t implement
Container.Hierarchical
, and since I have yet to figure out any other
Container
class to use, I decided to just keep them as beans, they way they are in my desktop Swing application.

It may be terribly inefficient, but here’s how I’ve put them into a Vaadin TreeTable (this is in the main
init
method):

// Get a list of jobs on a particular date.
LocalDate tempDate = new LocalDate(2015, 7, 23);
List<Job> jobsList = null;
try {
  jobsList = JobManager.getJobsByDate(tempDate);
} catch (SQLException e1) {
  // TODO Auto-generated catch block
  e1.printStackTrace();
}
if (jobsList != null) {
  // As long as the list of Jobs isn't empty.
  
  for (Job j : jobsList) {
    // Go through each item in the Jobs list and add it
    // (along with all of its OrderDetail items) to the TreeTable.
    Object jobItemId;
    CheckBox cbj = new CheckBox(j.getCustomerName(), j.getJobCompleted() != null);
    cbj.addValueChangeListener(new ValueChangeListener() {
      
      @Override
      public void valueChange(ValueChangeEvent event) {
        // TODO Auto-generated method stub
        layout.addComponent(new Label("Job checkbox changed: " + cbj.getCaption() + ", value is now: " + event.getProperty().getValue()));
        JobManager.jobClicked(event, j, treeTable);
      }
    });
    jobItemId = treeTable.addItem(new Object{
        userCanMarkAsDone ? cbj : j.getCustomerName(),
        j.getJobId(), "", null, null, null}, j.getJobId());
    logger.log(Level.INFO, "This Job's ItemID: " + jobItemId);
    
    for (OrderDetail od : j.getOrderDetailList()) {
      // Add each OrderDetail item to the TreeTable as well,
      // and set their parent.
      CheckBox cbod = new CheckBox(od.getProductId(), od.getItemCompleted() != null);
      cbod.addValueChangeListener(new ValueChangeListener() {
        
        @Override
        public void valueChange(ValueChangeEvent event) {
          // TODO Auto-generated method stub
          layout.addComponent(new Label("OrderDetail checkbox changed: " + cbod.getCaption() + ", value is now: " + event.getProperty().getValue()));
          layout.addComponent(new Label("Number of siblings: " + (j.getOrderDetailList().size() - 1)));
        }
      });
      Object odItemId = treeTable.addItem(new Object{
          userCanMarkAsDone ? cbod : od.getProductId(),
          od.getProductDetail(), od.getPrintType().getValue(), od.getNumColors(), od.getQuantity(), (od.getNumColors() * od.getQuantity())}, od.getId());
      treeTable.setParent(odItemId, jobItemId);
    }
  }
}

So each Job, then each Job’s OrderDetail gets added to the TreeTable. The key part is on line 24 in that last bit of code, which calls a method which will (hopefully) write to the bean and database whenever someone checks/unchecks a Job. (I’ll need to do the same for the OrderDetail part, too.) I think I can do that bit, but I also need it to check each of its children (OrderDetail) items. Here’s what I’ve got so far:

@SuppressWarnings("unchecked")
public static void jobClicked(ValueChangeEvent event, Job job, TreeTable treeTable) {
  
  if ((boolean)event.getProperty().getValue()) {
    logger.log(Level.INFO, "Job " + job.getJobId() + " checked, setting to timestamp: " + System.currentTimeMillis());
    // TODO Here is where the code goes for setting the Job bean's completed property to the current time,
    // then updating the database.
    
    // Also set each of the job's OrderDetail items to the same timestamp if they haven't already been set.
    for (OrderDetail orderDetail : job.getOrderDetailList()) {
      if (orderDetail.getItemCompleted() == null) {
        // Only set the current OrderDetail item to completed if it isn't already set as completed.
        logger.log(Level.INFO, "Setting the OrderDetail " + orderDetail.getProductId() + " to completion at " + System.currentTimeMillis());
        
        // TODO Somehow set the checkbox as checked.
        logger.log(Level.INFO, "Item property is a " + treeTable.getItem(orderDetail.getId()).getItemProperty("Name / Product").getType().getName()); // com.vaadin.ui.CheckBox
        CheckBox cbod = (CheckBox)treeTable.getItem(orderDetail.getId()).getItemProperty("Name / Product");
        cbod.setValue(true);
      }
    }
  } else {
    logger.log(Level.INFO, "Job " + job.getJobId() + " unchecked, clearing timestamp.");
    // TODO Code here for setting the Job bean's completed property to null,
    // then updating the database.

    // Also set each of the job's OrderDetail items to the same timestamp if they haven't already been set.
    for (OrderDetail orderDetail : job.getOrderDetailList()) {
      if (orderDetail.getItemCompleted() != null) {
        // Only set the current OrderDetail item to completed if it isn't already set as completed.
        logger.log(Level.INFO, "Clearing the OrderDetail " + orderDetail.getProductId() + "'s completion date.");
        
        // TODO Somehow set the checkbox as checked.
        treeTable.getItem(orderDetail.getId()).getItemProperty("Name / Product").setValue(false);
      }
    }
  }
}

And, of course, the error that I mentioned in the original post happens on line 17.

Now, I know this is a lot of code and, despite my efforts to comment it up, it is still difficult to follow, so please don’t hesitate to ask questions about it if you’re confused by why I did one thing or another. And thanks again for the offer to help! I greatly appreciate it!


EDIT 07/22/2015@11:43

Replacing line 16 in that last block of code with these three lines, I get some unusual (to me) results:

logger.log(Level.INFO, "Item property is of type " + treeTable.getItem(orderDetail.getId()).getItemProperty("Name / Product").getType().getName()); // com.vaadin.ui.CheckBox
logger.log(Level.INFO, "And its class is " + treeTable.getItem(orderDetail.getId()).getItemProperty("Name / Product").getClass().getName()); // com.vaadin.data.util.IndexedContainer$IndexedContainerProperty
logger.log(Level.INFO, "And its value is currently " + treeTable.getItem(orderDetail.getId()).getItemProperty("Name / Product").getValue()); // com.vaadin.ui.CheckBox@489b213b

Especially that third line, where I was expecting a
true
or
false
, I get–I think–a
CheckBox
object instance. So, I changed the problem line to:

CheckBox cbod = (CheckBox)treeTable.getItem(orderDetail.getId()).getItemProperty("Name / Product").getValue();

and it actually seems to work! So, to get to the
actual
checkbox, I have to get the ItemProperty’s
value
first.
Wow
, that was confusing!