I apologise in advance for the length of this post but I have provided a rather in depth of the design and implementation of my program.
Background
I am currently doing a group (there are 2 of us) programming project for a third year computer science course at university. The goal of this program is to essentially use a spreadsheet program to represent XML file data where each XML file is a historical record.
Design:
Each record(row) in the spreadsheet corresponds to a single XML file and the columns of the record correspond to the elements in the XML file. We deal with repeated elements (i.e. elements with the same tag) by setting the cell component to a button that, when clicked, opens up another spreadsheet which contains a list of all elements with repeated names (for the corresponding file). Child elements are dealt with in a similar manner whereby if an element ha child elements then the corresponding cell in the XML file contains a button which, when clicked, opens up a spreadsheet containing all the child elements of that element.
Implementation:
The implementation of our system is written in Java. Our main class (name SpreadSheetGUI) extends JFrame to which we add a JTable (using the default table model). We have three different cell renderers: one for when a cell just has text, one for when a cell has a button and one for when we have text and a button in a cell. When a button is clicked to open up a new spreadsheet (for either child elements or repeated element names) we make a recursive call to our spreadsheet constructor which will then create our sub-spreadsheet. The renderers are added in the following order: if the cell corresponds to an element with a tag that is used more than once a button is added to the cell, otherwise if the cell corresponds to an element with child nodes we add both text and a button to the cell and if the cell just has text we add the text to that cell.
The constructor for the GUI is as such
/** * Parameterised constructor * @param dataVector - Vector of vectors of objects that represent the cell values * @param columnNames - The vector of objects that represent the column names */ @SuppressWarnings("unchecked") public SpreadSheetGUI(Vector<Vector<LevelElementT>> dataVector, Vector<String> columnNames, boolean hasRepeatedColumns, boolean initialFrame) { this.hasRepeatedColumns = hasRepeatedColumns; this.initialFrame = initialFrame; if (initialFrame) populateTable(dataVector, columnNames); else if (!hasRepeatedColumns) populateTable((Vector<Vector<LevelElementT>>)findRepeatedColumns(dataVector).get(0), (Vector<String>)findRepeatedColumns(dataVector).get(1)); else populateTable(dataVector, columnNames); //Get repeated column names and add to repeated column hashmap //parseElements(dataVector); }
where the populateTable method initialises the table model. And as I stated earlier we have three different renderers and editors for our cells and two of the renderers have buttons in them that, when clicked, create a new spreadsheet (i.e. we make a call to our spreadsheet constructor), for example in our one cell editor has the following code :
public Object getCellEditorValue() { if (isPushed) { //will have the child elements of the current cell element Vector<Vector<LevelElementT>> children = new Vector<Vector<LevelElementT>>(); children.add(new Vector<LevelElementT>()); List<Element> tempChildren = elements.get(row).get(column).getChildren(); for (Element child : tempChildren) children.get(0).add(new LevelElementT(child)); //creates our subspreadsheet new Thread(new SpreadSheetGUI(children, new Vector<String>(), false, false)).start(); } isPushed = false; return new String(bLabel); }
LevelElementT is just a class we made that extends Element (found in the JDOM2 package) that overrides the toString method.
The Problem:
As I mentioned before we have created a set of renderers to handle the adding of buttons to cells but it seems that when a "child" spreadsheet is created the renderers are trying to render cells that are out of bounds in accordance with the child spreadsheets number of rows and columns and throw an array index out of bounds exception.
More specifically the errors are thrown in the following piece of code taken from the populateTable() method. I initialises the JTable with an instance of the defaultTableModel and sets up the methods to determine the renderer of each component:
table = new JTable(tableModel) { private static final long serialVersionUID = 1L; public TableCellRenderer getCellRenderer(int row, int column) { //System.out.println(elements.get(row).get(column).getChildren().size()); if (column == 0) { Class<? extends Object> cellClass = getValueAt(row, column).getClass(); return getDefaultRenderer(cellClass); } else if(repeatedColumns.containsKey(table.getColumnModel().getColumn(column).getIdentifier() + " " + elements.get(row).get(0).getText())) return getDefaultRenderer(JButton.class); else if(!elements.get(row).get(column).getChildren().isEmpty()) return getDefaultRenderer(JPanel.class); else return getDefaultRenderer(JTextArea.class); } public TableCellEditor getCellEditor(int row, int column) { if (column == 0) { Class<? extends Object> cellClass = getValueAt(row, column).getClass(); return getDefaultEditor(cellClass); } else if(repeatedColumns.containsKey(table.getColumnModel().getColumn(column).getIdentifier() + " " + elements.get(row).get(0).getText())) return getDefaultEditor(JButton.class); else if(!elements.get(row).get(column).getChildren().isEmpty()) return getDefaultEditor(JPanel.class); else return getDefaultEditor(JTextArea.class); } };
The errors are thrown at the if statements (depending on the button you clicked) and it is definitely not because of elements (a two dimensional vector of levelElements) or repeatedColumns(a hashtable of with a string as the key and a vector of elements as the value).
I'm guessing the problem extends from the fact that we are making a recursive call to our spreadsheet constructor. A friend also suggested that this problem might be caused by the default table model, should I consider creating a custom table model?
I have been wracking my brains with this one and I have been completely unsuccessful in finding any threads related to this problem. I have posted this problem on StackOverflow with little sucess,