Clover coverage report - clover
Coverage timestamp: Sat Oct 8 2005 22:54:17 EDT
file stats: LOC: 325   Methods: 35
NCLOC: 271   Classes: 5
 
 Source file Conditionals Statements Methods TOTAL
ArrayEditor.java 78.3% 92.3% 94.3% 89.6%
coverage coverage
 1   
 package abbot.editor.widgets;
 2   
 
 3   
 import java.awt.*;
 4   
 import java.awt.event.*;
 5   
 import javax.swing.*;
 6   
 import javax.swing.border.*;
 7   
 import javax.swing.event.*;
 8   
 import javax.swing.text.*;
 9   
 import java.util.*;
 10   
 import java.net.*;
 11   
 
 12   
 import abbot.Log;
 13   
 import abbot.i18n.Strings;
 14   
 import abbot.editor.widgets.TextField;
 15   
 
 16   
 /** Provides editing of a variable-length array of strings.  Actions fired
 17   
     will have the index of the changed item in the ID (or -1 if the list added
 18   
     or removed an element), and the action command be one of
 19   
     ACTION_LIST_CHANGED, ACTION_ITEM_CHANGED, ACTION_ROW_INSERTED or
 20   
     ACTION_ROW_REMOVED.  
 21   
     Allows for a single type of editor, as provided by the createEditor
 22   
     method. 
 23   
 */
 24   
 // TODO: use a model (cf TableModel)
 25   
 public class ArrayEditor extends Box {
 26   
 
 27   
     public static final String ACTION_LIST_CHANGED = "list.changed";
 28   
     public static final String ACTION_ITEM_CHANGED = "item.changed";
 29   
     public static final String ACTION_ITEM_INSERTED = "item.inserted";
 30   
     public static final String ACTION_ITEM_DELETED = "item.deleted";
 31   
 
 32   
     private static final int DEFAULT_COLUMNS = 10;
 33   
     private ArrayList listeners = new ArrayList();
 34   
     private ArrayList data;
 35   
     private boolean adjusting = false;
 36   
     private ArrayList rows = new ArrayList();
 37   
 
 38   
     protected interface ElementEditor {
 39   
         void setValue(Object value);
 40   
         Object getValue();
 41   
         Component getEditorComponent();
 42   
         void addActionListener(ActionListener listener);
 43   
         void removeActionListener(ActionListener listener);
 44   
         void setEnabled(boolean enabled);
 45   
     }
 46   
 
 47   
     /** The default editor for array elements. */
 48   
     protected class TextEditor extends TextField implements ElementEditor {
 49  59
         public TextEditor(Object value) {
 50  59
             super(value.toString(), DEFAULT_COLUMNS);
 51   
         }
 52  49
         public Object getValue() { return getText(); }
 53  5
         public void setValue(Object o) {
 54  5
             setText(o == null ? "" : o.toString());
 55   
         }
 56  59
         public Component getEditorComponent() {
 57  59
             return this;
 58   
         }
 59   
     }
 60   
 
 61   
     /** Encapsulates one row of the entire array, an editor with add/remove
 62   
         buttons.
 63   
     */
 64   
     protected class Row extends JPanel {
 65   
         public ElementEditor elementEditor;
 66   
         public Component editor;
 67   
         public JButton addButton;
 68   
         public JButton removeButton;
 69   
 
 70   
         private class SizedButton extends JButton { 
 71  118
             public SizedButton(String label) {
 72  118
                 super(label);
 73   
             }
 74   
             /** Ensure all insets are equal. */
 75  195
             public Insets getInsets() {
 76  195
                 Insets insets = super.getInsets();
 77  195
                 int min = Math.min(insets.top,
 78   
                                    Math.min(insets.bottom,
 79   
                                             Math.min(insets.right,
 80   
                                                      insets.left)));
 81  195
                 insets.right = insets.left = insets.top = insets.bottom = min;
 82  195
                 return insets;
 83   
             }
 84  230
             public Dimension getMinimumSize() {
 85  230
                 return getPreferredSize();
 86   
             }
 87  230
             public Dimension getMaximumSize() {
 88  230
                 return getPreferredSize();
 89   
             }
 90  690
             public Dimension getPreferredSize() {
 91  690
                 Dimension size = editor.getPreferredSize();
 92  690
                 size.width = size.height;
 93  690
                 return size;
 94   
             }
 95   
         }
 96   
 
 97  59
         public Row(Object value) {
 98  59
             BorderLayout layout = new BorderLayout();
 99  59
             layout.setVgap(0);
 100  59
             setLayout(layout);
 101  59
             elementEditor = createEditor(value);
 102  59
             add(editor = elementEditor.getEditorComponent());
 103  59
             editor.setName("editor");
 104  59
             Box buttons = new Box(BoxLayout.X_AXIS);
 105  59
             add(buttons, BorderLayout.EAST);
 106  59
             buttons.add(removeButton = new SizedButton("-"));
 107  59
             removeButton.setName("remove");
 108  59
             removeButton.setToolTipText(Strings.get("editor.array.remove"));
 109  59
             buttons.add(addButton = new SizedButton("+"));
 110  59
             addButton.setName("add");
 111  59
             addButton.setToolTipText(Strings.get("editor.array.insert"));
 112   
 
 113  59
             addButton.addActionListener(new ActionListener() {
 114  3
                 public void actionPerformed(ActionEvent e) {
 115  3
                     insertRow(getRowCount() == 0
 116   
                               ? 0 : getRowIndex() + 1);
 117   
                 }
 118   
             });
 119  59
             removeButton.addActionListener(new ActionListener() {
 120  2
                 public void actionPerformed(ActionEvent e) {
 121  2
                     removeRow(getRowIndex());
 122   
                 }
 123   
             });
 124  59
             elementEditor.addActionListener(new ActionListener() {
 125  50
                 public void actionPerformed(ActionEvent e) {
 126  50
                     int index = getRowIndex();
 127  50
                     if (!adjusting && index != -1) {
 128  49
                         adjusting = true;
 129  49
                         setValueAt(index, elementEditor.getValue(), true);
 130  49
                         adjusting = false;
 131   
                     }
 132   
                 }
 133   
             });
 134   
         }
 135   
 
 136  84
         public Dimension getMaximumSize() {
 137  84
             Dimension size = super.getMaximumSize();
 138  84
             size.height = super.getPreferredSize().height;
 139  84
             return size;
 140   
         }
 141   
 
 142  54
         protected int getRowIndex() {
 143  54
             Container parent = getParent();
 144  54
             if (parent != null) {
 145  54
                 Component kids[] = parent.getComponents();
 146  59
                 for (int i=0;i < kids.length;i++) {
 147  59
                     if (kids[i] == this) {
 148  54
                         return i;
 149   
                     }
 150   
                 }
 151   
             }
 152  0
             return -1;
 153   
         }
 154   
 
 155  0
         public String toString() {
 156  0
             return super.toString()
 157   
                 + "[" + getRowIndex() + ": " + elementEditor.getValue() + "]";
 158   
         }
 159   
     }
 160   
 
 161   
     /** Creates a default, empty editor. */
 162  4
     public ArrayEditor() {
 163  4
         this(new String[0]);
 164   
     }
 165   
 
 166   
     /** Creates an editor with the given contents. */
 167  34
     public ArrayEditor(Object[] contents) {
 168  34
         super(BoxLayout.Y_AXIS);
 169  34
         setValues(contents, false);
 170   
     }
 171   
 
 172  59
     protected ElementEditor createEditor(Object initialValue) {
 173  59
         return new TextEditor(initialValue);
 174   
     }
 175   
 
 176  11
     private Row getRow(int row) {
 177  11
         return (Row)rows.get(row);
 178   
     }
 179   
 
 180  59
     private Row addRow(int index, Object value) {
 181  59
         Row row = new Row(value);
 182  59
         rows.add(index, row);
 183  59
         add(row, index);
 184  59
         return row;
 185   
     }
 186   
 
 187  41
     private void init() {
 188  41
         removeAll();
 189  41
         rows.clear();
 190  41
         for (int i=0;i < data.size();i++) {
 191  29
             addRow(i, data.get(i));
 192   
         }
 193   
         // Always keep one editing component visible
 194  41
         if (data.size() == 0) {
 195  24
             Row row = addRow(0, "");
 196  24
             row.removeButton.setEnabled(false);
 197  24
             row.elementEditor.setEnabled(false);
 198   
         }
 199  41
         validate();
 200  41
         repaint();
 201   
     }
 202   
 
 203  42
     private void setValues(Object[] contents, boolean fire) {
 204  42
         if (contents == null) {
 205  0
             if (data != null) {
 206  0
                 data = null;
 207  0
                 init();
 208  0
                 if (fire)
 209  0
                     fireActionPerformed(ACTION_LIST_CHANGED, -1);
 210   
             }
 211   
         }
 212  42
         else if (data == null || contents.length != data.size()) {
 213  41
             data = new ArrayList(Arrays.asList(contents));
 214  41
             init();
 215  41
             if (fire)
 216  7
                 fireActionPerformed(ACTION_LIST_CHANGED, -1);
 217   
         }
 218   
         else {
 219  1
             for (int i=0;i < contents.length;i++) {
 220  0
                 setValueAt(i, contents[i], fire);
 221   
             }
 222   
         }
 223   
     }
 224   
 
 225  34
     public int getRowCount() {
 226  34
         return data.size();
 227   
     }
 228   
 
 229  4
     public void insertRow(int row) {
 230  4
         insertRow(row, "");
 231   
     }
 232   
 
 233  9
     public void insertRow(int row, Object value) {
 234  9
         if (row < 0 || row > data.size())
 235  1
             row = data.size();
 236  9
         data.add(row, value);
 237  9
         if (data.size() == 1) {
 238  3
             row = 0;
 239  3
             Row r = getRow(row);
 240  3
             r.elementEditor.setEnabled(true);
 241  3
             r.removeButton.setEnabled(true);
 242  3
             r.elementEditor.setValue(value);
 243   
         }
 244   
         else {
 245  6
             addRow(row, value);
 246   
         }
 247  9
         validate();
 248  9
         repaint();
 249  9
         fireActionPerformed(ACTION_ITEM_INSERTED, row);
 250   
     }
 251   
 
 252  8
     public void removeRow(int index) {
 253  8
         if (index < 0 || index >= getRowCount()) 
 254  1
             throw new IllegalArgumentException("Row " + index
 255   
                                                + " out of bounds ("
 256   
                                                + getRowCount() + ")");
 257  7
         Row r = getRow(index);
 258  7
         data.remove(index);
 259   
         // Always keep one editing component visible
 260  7
         if (data.size() == 0) {
 261   
             // ignore messaging
 262  1
             adjusting = true;
 263  1
             r.elementEditor.setValue(null);
 264  1
             adjusting = false;
 265  1
             r.elementEditor.setEnabled(false);
 266  1
             r.removeButton.setEnabled(false);
 267   
         }
 268   
         else {
 269  6
             rows.remove(r);
 270  6
             remove(r);
 271   
         }
 272  7
         validate();
 273  7
         repaint();
 274  7
         fireActionPerformed(ACTION_ITEM_DELETED, index);
 275   
     }
 276   
 
 277  56
     public Object[] getValues() {
 278  56
         return data.toArray(new Object[data.size()]);
 279   
     }
 280   
 
 281  8
     public void setValues(Object[] contents) {
 282  8
         setValues(contents, true);
 283   
     }
 284   
 
 285  1
     public void setValueAt(int index, Object value) {
 286  1
         setValueAt(index, value, true);
 287   
     }
 288   
 
 289  50
     private void setValueAt(int index, Object value, boolean fire) {
 290  50
         if (index < 0 || index >= data.size())
 291  0
             throw new IndexOutOfBoundsException("Index " + index
 292   
                                                 + " out of range ("
 293   
                                                 + data.size() + ")");
 294  50
         if (value == data.get(index)
 295   
             || (value != null && value.equals(data.get(index))))
 296  4
             return;
 297   
 
 298  46
         data.set(index, value);
 299  46
         if (!adjusting)
 300  1
             getRow(index).elementEditor.setValue(value);
 301  46
         if (fire) 
 302  46
             fireActionPerformed(ACTION_ITEM_CHANGED, index);
 303   
     }
 304   
 
 305  20
     public String getValueAt(int index) {
 306  20
         return (String)data.get(index);
 307   
     }
 308   
 
 309  69
     protected void fireActionPerformed(String action, int index) {
 310  69
         Iterator iter = listeners.iterator();
 311  69
         ActionEvent e = new ActionEvent(this, index, action);
 312  69
         while (iter.hasNext()) {
 313  100
             ((ActionListener)iter.next()).actionPerformed(e);
 314   
         }
 315   
     }
 316   
 
 317  55
     public void addActionListener(ActionListener l) {
 318  55
         listeners.add(l);
 319   
     }
 320   
 
 321  0
     public void removeActionListener(ActionListener l) {
 322  0
         listeners.remove(l);
 323   
     }
 324   
 }
 325