Kontrollkästchen in einer JXTreeTable

Immer noch ein Java-Neuling hier, der versucht, zu meinem eigenen Besten viel zu fortgeschrittene Dinge zu erledigen. Trotzdem muss ich Folgendes tun: Ein Kontrollkästchen in einer JXTreeTable. Meine Hauptklasse:

package info.chrismcgee.sky.production;

import info.chrismcgee.sky.production.treetable.NoRootTreeTableModel;

import java.awt.Checkbox;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.border.EmptyBorder;
import javax.swing.border.EtchedBorder;

import net.miginfocom.swing.MigLayout;

import org.jdesktop.swingx.JXTreeTable;

public class TestFrame extends JFrame {

    /**
     * 
     */
    private static final long serialVersionUID = -1899673458785493250L;
    private JXTreeTable treeTable;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    TestFrame frame = new TestFrame();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the frame.
     */
    public TestFrame() {
        setMinimumSize(new Dimension(600, 600));
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 546, 600);
        JPanel contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        setContentPane(contentPane);
        contentPane.setLayout(new MigLayout("", "[grow][grow][grow][100px:n,grow][grow][grow][grow]", "[][251.00,grow][]"));

        List<Job> jobList = new ArrayList<Job>();

        List<ItemDetail> itemList = new ArrayList<ItemDetail>();
        itemList.add(new ItemDetail("N10", "N10", 2, 1000, PrintType.PAD, true));
        itemList.add(new ItemDetail("N13", "N13", 2, 2000, PrintType.PAD, true));

        // create and add the first job with its list of ItemDetail objects
        jobList.add(new Job(new Checkbox("Print Solutions"), "123456", ShipDate.getDate("02/28/14"), itemList));

        List<ItemDetail> itemList2 = new ArrayList<ItemDetail>();
        itemList2.add(new ItemDetail("P12", "Green", 1, 250, PrintType.SCREEN, true));
        itemList2.add(new ItemDetail("P12", "Purple", 1, 250, PrintType.SCREEN, true));
        itemList2.add(new ItemDetail("P12", "Gray", 1, 250, PrintType.SCREEN, true));

        // create and add a second job with its list of ItemDetail objects
        jobList.add(new Job(new Checkbox("Innovators Inc"), "246801", ShipDate.getDate("03/10/14"), itemList2));

        // we use a no root model
        NoRootTreeTableModel noRootTreeTableModel = new NoRootTreeTableModel(jobList);
        treeTable = new JXTreeTable(noRootTreeTableModel);
        treeTable.setEditable(false);
        treeTable.setRootVisible(false);
        treeTable.setBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null));
        treeTable.getTableHeader().setReorderingAllowed(false);
        treeTable.getColumn(0).setPreferredWidth(200);
        treeTable.getColumn(1).setPreferredWidth(75);
        treeTable.getColumn(2).setPreferredWidth(15);
            treeTable.getColumn(2).setMinWidth(15);
            treeTable.getColumn(2).setMaxWidth(15);
        treeTable.getColumn(3).setPreferredWidth(50);
            treeTable.getColumn(3).setMaxWidth(50);
        treeTable.getColumn(4).setPreferredWidth(25);
        JScrollPane scrollPane = new JScrollPane(treeTable);
        scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        contentPane.add(scrollPane, "cell 0 1 7 1,grow");

    }       
}

Die Job-Klasse (Verzweigungen in der TreeTable):

package info.chrismcgee.sky.production;

import java.awt.Checkbox;
import java.util.List;

import org.joda.time.LocalDate;

public class Job {

    private Checkbox cbJob;
    private String idNumber;
    private LocalDate shipDate;
    private List<ItemDetail> itemList;

    public Job(Checkbox cbJob, String idNumber, LocalDate shipDate, List<ItemDetail> itemList)
    {
        this.cbJob = cbJob;
        this.idNumber = idNumber;
        this.shipDate = shipDate;
        this.itemList = itemList;
    }

    public List<ItemDetail> getItemList()
    {
        return itemList;
    }

    public void setItemList(List<ItemDetail> itemList)
    {
        this.itemList = itemList;
    }

    /**
     * @return the cbJob
     */
    public Checkbox getCbJob() {
        return cbJob;
    }

    /**
     * @param cbJob the cbJob to set
     */
    public void setCbJob(Checkbox cbJob) {
        this.cbJob = cbJob;
    }

    /**
     * @return the idNumber
     */
    public String getIdNumber() {
        return idNumber;
    }

    /**
     * @param idNumber the idNumber to set
     */
    public void setIdNumber(String idNumber) {
        this.idNumber = idNumber;
    }

    /**
     * @return the shipDate
     */
    public LocalDate getShipDate() {
        return shipDate;
    }

    /**
     * @param shipDate the shipDate to set
     */
    public void setShipDate(LocalDate shipDate) {
        this.shipDate = shipDate;
    }

}

Die OrderDetail-Klasse (Leaves in the TreeTable):

package info.chrismcgee.sky.production;


public class ItemDetail {

    private String productId;
    private String detail;
    private long numColors;
    private long numQuantity;
    private PrintType printType;
    private boolean active;

    public ItemDetail(String productId, String detail, long numColors, long numQuantity, PrintType printType, boolean active)
    {
        this.productId = productId;
        this.detail = detail;
        this.numColors = numColors;
        this.numQuantity = numQuantity;
        this.printType = printType;
        this.active = active;
    }

    /**
     * @return the productId
     */
    public String getProductId() {
        return productId;
    }

    /**
     * @param productId the productId to set
     */
    public void setProductId(String productId) {
        this.productId = productId;
    }

    /**
     * @return the detail
     */
    public String getDetail() {
        return detail;
    }

    /**
     * @param detail the detail to set
     */
    public void setDetail(String detail) {
        this.detail = detail;
    }

    /**
     * @return the numColors
     */
    public long getNumColors() {
        return numColors;
    }

    /**
     * @param numColors the numColors to set
     */
    public void setNumColors(long numColors) {
        this.numColors = numColors;
    }

    /**
     * @return the numQuantity
     */
    public long getNumQuantity() {
        return numQuantity;
    }

    /**
     * @param numQuantity the numQuantity to set
     */
    public void setNumQuantity(long numQuantity) {
        this.numQuantity = numQuantity;
    }

    /**
     * @return the printType
     */
    public PrintType getPrintType() {
        return printType;
    }

    /**
     * @param printType the printType to set
     */
    public void setPrintType(PrintType printType) {
        this.printType = printType;
    }

    /**
     * @return the active
     */
    public boolean isActive() {
        return active;
    }

    /**
     * @param active the active to set
     */
    public void setActive(boolean active) {
        this.active = active;
    }

}

und schließlich die NoRootTreeTableModel-Klasse, die die AbstractTreeTableModel-Klasse erweitert, sodass die Wurzel des Baums nicht angezeigt wird:

package info.chrismcgee.sky.production.treetable;

import info.chrismcgee.sky.production.ItemDetail;
import info.chrismcgee.sky.production.Job;

import java.util.List;

import org.jdesktop.swingx.treetable.AbstractTreeTableModel;

public class NoRootTreeTableModel extends AbstractTreeTableModel {

    private final static String[] COLUMN_NAMES = {"Name/Product", "Job # / Detail", "T",
        "Colors", "Quantity", "Total"};

    private List<Job> jobList;

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

    @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 ItemDetail;
    }

    @Override
    public int getChildCount(Object parent) {
        if (parent instanceof Job) {
            Job job = (Job) parent;
            return job.getItemList().size();
        }
        return jobList.size();
    }

    @Override
    public Object getChild(Object parent, int index) {
        if (parent instanceof Job) {
            Job job = (Job) parent;
            return job.getItemList().get(index);
        }
        return jobList.get(index);
    }

    @Override
    public int getIndexOfChild(Object parent, Object child) {
        Job job = (Job) parent;
        ItemDetail item = (ItemDetail) child;
        return job.getItemList().indexOf(item);
    }

    @Override
    public Object getValueAt(Object node, int column) {
        if (node instanceof Job) {
            Job job = (Job) node;
            switch (column) {
                case 0:
                    return job.getCbJob();
                case 1:
                    return job.getIdNumber();
            }
        } else if (node instanceof ItemDetail) {
            ItemDetail item = (ItemDetail) node;
            switch (column) {
                case 0:
                    return item.getProductId();
                case 1:
                    return item.getDetail();
                case 2:
                    return item.getPrintType();
                case 3:
                    return item.getNumColors();
                case 4:
                    return item.getNumQuantity();
                case 5:
                    return item.getNumColors() * item.getNumQuantity();
            }
        }
        return null;
    }

}

Ich weiß, dass das eine Menge Code ist, aber ich konnte mir keine schnelle Möglichkeit vorstellen, es zu reduzieren und es trotzdem so arbeiten zu lassen, wie ich es brauche. Und tatsächlich ist es schon einiges gekürzt. (Ich habe ein paar Dinge ausgelassen, die normalerweise auch in diesem JFrame enthalten sind.)

Wenn der Code ausgeführt wird, wird kein Kontrollkästchen für die Zweige angezeigt. Stattdessen erhalte ich eine Art String-Darstellung des Kontrollkästchen-Codes:Kontrollkästchen in einem TreeTable http://imageshack.com/a/img713/250/dl87.jpg

Huh? Wie ist das passiert und was noch wichtiger ist, wie kann ich dafür sorgen, dass das Kontrollkästchen angezeigt wird?