001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.visualweb.propertyeditors;
042:
043: import java.awt.Color;
044: import java.awt.Component;
045: import java.util.ResourceBundle;
046: import javax.swing.DefaultCellEditor;
047: import javax.swing.JTable;
048: import javax.swing.JTextField;
049: import javax.swing.ListSelectionModel;
050: import javax.swing.UIManager;
051: import javax.swing.event.TableModelEvent;
052: import javax.swing.event.TableModelListener;
053: import javax.swing.table.AbstractTableModel;
054: import javax.swing.table.DefaultTableCellRenderer;
055: import javax.swing.table.TableCellEditor;
056:
057: /**
058: * A custom property editor panel for editing a property that consists of
059: * tabular data.
060: *
061: * @see com.sun.rave.propertyeditors.TabularPropertyEditor
062: * @see com.sun.rave.propertyeditors.TabularPropertyModel
063: * @author gjmurphy
064: */
065:
066: public class TabularPropertyPanel extends PropertyPanelBase implements
067: TableModelListener {
068:
069: static ResourceBundle bundle = ResourceBundle
070: .getBundle(TabularPropertyPanel.class.getPackage()
071: .getName()
072: + ".Bundle"); //NOI18N
073:
074: private TableModelSupport tableModelSupport;
075:
076: /** Creates new form ItemsEditorPanel */
077: public TabularPropertyPanel(TabularPropertyModel tableModel,
078: PropertyEditorBase editor) {
079: super (editor);
080: tableModel.addTableModelListener(this );
081: this .tableModelSupport = new TableModelSupport(tableModel);
082: initComponents();
083:
084: // Have the first row selected by default
085: if (tableModel.getRowCount() > 0)
086: dataTable.changeSelection(0, 0, false, false);
087: }
088:
089: public Object getPropertyValue() throws IllegalStateException {
090: return this .tableModelSupport.getValue();
091: }
092:
093: /**
094: * Called whenever the tabular property model changes itself.
095: */
096: public void tableChanged(TableModelEvent event) {
097: int f = event.getFirstRow();
098: int l = event.getLastRow();
099: if (f == l) {
100: this .tableModelSupport.fireTableCellUpdated(f, event
101: .getColumn());
102: } else if (event.getType() == TableModelEvent.DELETE) {
103: this .tableModelSupport.fireTableRowsDeleted(f, l);
104: } else if (event.getType() == TableModelEvent.INSERT) {
105: this .tableModelSupport.fireTableRowsInserted(f, l);
106: } else {
107: this .tableModelSupport.fireTableRowsUpdated(f, l);
108: }
109:
110: }
111:
112: /** This method is called from within the constructor to initialize the form.
113: * WARNING: Do NOT modify this code. The content of this method is
114: * always regenerated by the Form Editor.
115: */
116: // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
117: private void initComponents() {
118: java.awt.GridBagConstraints gridBagConstraints;
119:
120: helpLabel = new javax.swing.JLabel();
121: dataPane = new javax.swing.JScrollPane();
122: dataTable = new JTable(tableModelSupport);
123:
124: // Only one row selectable at a time
125: dataTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
126:
127: // Create a default cell editor for String values that forces a stop
128: // editing event whenever focus is lost.
129: JTextField textField = new JTextField();
130: final TableCellEditor cellEditor = new CellEditor(dataTable,
131: textField);
132: this .dataTable.setDefaultEditor(String.class, cellEditor);
133: this .dataTable.putClientProperty("terminateEditOnFocusLost",
134: Boolean.TRUE); //NOI18N
135:
136: // Single click to start editing
137: ((DefaultCellEditor) dataTable.getDefaultEditor(String.class))
138: .setClickCountToStart(1);
139:
140: // Create a default cell renderer for String values that consistently renders
141: // background colors.
142: dataTable.setDefaultRenderer(String.class,
143: new HomogonousCellRenderer());
144:
145: // Create a custom renderer for column headers, with background color set to
146: // match NetBeans table header background color
147: DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
148: renderer.setHorizontalAlignment(javax.swing.JLabel.CENTER);
149: renderer.setBackground(new java.awt.Color(212, 208, 200));
150: dataTable.getTableHeader().setDefaultRenderer(renderer);
151: buttonsPanel = new javax.swing.JPanel();
152: newButton = new javax.swing.JButton();
153: deleteButton = new javax.swing.JButton();
154: upButton = new javax.swing.JButton();
155: downButton = new javax.swing.JButton();
156:
157: setLayout(new java.awt.GridBagLayout());
158:
159: helpLabel
160: .setDisplayedMnemonic(java.util.ResourceBundle
161: .getBundle(
162: "org/netbeans/modules/visualweb/propertyeditors/Bundle")
163: .getString("TabularPropertyPanel.helpLabel")
164: .charAt(0));
165: helpLabel.setLabelFor(dataTable);
166: helpLabel.setText(bundle.getString("TablePropertyPanel.help")); // NOI18N
167: gridBagConstraints = new java.awt.GridBagConstraints();
168: gridBagConstraints.gridx = 0;
169: gridBagConstraints.gridy = 3;
170: gridBagConstraints.gridwidth = 2;
171: gridBagConstraints.gridheight = java.awt.GridBagConstraints.RELATIVE;
172: gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
173: gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
174: gridBagConstraints.insets = new java.awt.Insets(6, 10, 10, 10);
175: add(helpLabel, gridBagConstraints);
176: helpLabel.getAccessibleContext().setAccessibleDescription(
177: org.openide.util.NbBundle.getMessage(
178: TabularPropertyPanel.class,
179: "TablePropertyPanel.help.desc")); // NOI18N
180:
181: dataPane.setEnabled(false);
182:
183: dataTable
184: .setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_ALL_COLUMNS);
185: dataTable.setTableHeader(dataTable.getTableHeader());
186: dataPane.setViewportView(dataTable);
187:
188: gridBagConstraints = new java.awt.GridBagConstraints();
189: gridBagConstraints.gridx = 0;
190: gridBagConstraints.gridy = 0;
191: gridBagConstraints.gridheight = 3;
192: gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
193: gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
194: gridBagConstraints.weightx = 1.0;
195: gridBagConstraints.weighty = 1.0;
196: gridBagConstraints.insets = new java.awt.Insets(10, 10, 0, 0);
197: add(dataPane, gridBagConstraints);
198:
199: buttonsPanel.setLayout(new java.awt.GridLayout(4, 1, 0, 5));
200:
201: newButton
202: .setMnemonic(java.util.ResourceBundle
203: .getBundle(
204: "org/netbeans/modules/visualweb/propertyeditors/Bundle")
205: .getString("TabularPropertyPanel").charAt(0));
206: newButton.setText(bundle
207: .getString("SelectOneDomainPanel.button.new")); // NOI18N
208: newButton
209: .addActionListener(new java.awt.event.ActionListener() {
210: public void actionPerformed(
211: java.awt.event.ActionEvent evt) {
212: newActionPerformed(evt);
213: }
214: });
215: buttonsPanel.add(newButton);
216: newButton.getAccessibleContext().setAccessibleDescription(
217: org.openide.util.NbBundle.getMessage(
218: TabularPropertyPanel.class,
219: "TabularPropertyPanel.newButton.desc")); // NOI18N
220:
221: deleteButton
222: .setMnemonic(java.util.ResourceBundle
223: .getBundle(
224: "org/netbeans/modules/visualweb/propertyeditors/Bundle")
225: .getString("TabularPropertyPanel.deleteButton")
226: .charAt(0));
227: deleteButton.setText(bundle
228: .getString("SelectOneDomainPanel.button.delete")); // NOI18N
229: deleteButton
230: .addActionListener(new java.awt.event.ActionListener() {
231: public void actionPerformed(
232: java.awt.event.ActionEvent evt) {
233: deleteActionPerformed(evt);
234: }
235: });
236: buttonsPanel.add(deleteButton);
237: deleteButton.getAccessibleContext().setAccessibleDescription(
238: org.openide.util.NbBundle.getMessage(
239: TabularPropertyPanel.class,
240: "TabularPropertyPanel.deleteButton.desc")); // NOI18N
241:
242: upButton
243: .setMnemonic(java.util.ResourceBundle
244: .getBundle(
245: "org/netbeans/modules/visualweb/propertyeditors/Bundle")
246: .getString("TabularPropertyPanel.upButton")
247: .charAt(0));
248: upButton.setText(bundle
249: .getString("SelectOneDomainPanel.button.up")); // NOI18N
250: upButton.addActionListener(new java.awt.event.ActionListener() {
251: public void actionPerformed(java.awt.event.ActionEvent evt) {
252: upActionPerformed(evt);
253: }
254: });
255: buttonsPanel.add(upButton);
256: upButton.getAccessibleContext().setAccessibleDescription(
257: org.openide.util.NbBundle.getMessage(
258: TabularPropertyPanel.class,
259: "TabularPropertyPanel.upButton.desc")); // NOI18N
260:
261: downButton
262: .setMnemonic(java.util.ResourceBundle
263: .getBundle(
264: "org/netbeans/modules/visualweb/propertyeditors/Bundle")
265: .getString("TabularPropertyPanel.downButton")
266: .charAt(0));
267: downButton.setText(bundle
268: .getString("SelectOneDomainPanel.button.down")); // NOI18N
269: downButton
270: .addActionListener(new java.awt.event.ActionListener() {
271: public void actionPerformed(
272: java.awt.event.ActionEvent evt) {
273: downActionPerformed(evt);
274: }
275: });
276: buttonsPanel.add(downButton);
277: downButton.getAccessibleContext().setAccessibleDescription(
278: org.openide.util.NbBundle.getMessage(
279: TabularPropertyPanel.class,
280: "TabularPropertyPanel.downButton.desc")); // NOI18N
281:
282: gridBagConstraints = new java.awt.GridBagConstraints();
283: gridBagConstraints.gridx = 1;
284: gridBagConstraints.gridy = 0;
285: gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
286: gridBagConstraints.insets = new java.awt.Insets(10, 6, 0, 10);
287: add(buttonsPanel, gridBagConstraints);
288: }// </editor-fold>//GEN-END:initComponents
289:
290: /**
291: * When focus moves from table to a button, make sure that editor for string
292: * cell is done editing (if it was in edit mode), to avoid problems when rows
293: * are moved or added, and to make sure any edited data is saved in the
294: * correct row.
295: */
296: private void downActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_downActionPerformed
297:
298: TableModelSupport tableModel = (TableModelSupport) dataTable
299: .getModel();
300: if (dataTable.getSelectedRowCount() > 0) {
301: int[] selectedRows = dataTable.getSelectedRows();
302: if (selectedRows[0] < dataTable.getRowCount() - 1
303: && tableModel.canMoveRow(selectedRows[0],
304: selectedRows[0] + 1)) {
305: tableModel
306: .moveRow(selectedRows[0], selectedRows[0] + 1);
307: dataTable.setModel(tableModel);
308: dataTable.changeSelection(selectedRows[0] + 1, 0,
309: false, false);
310: }
311: }
312: }//GEN-LAST:event_downActionPerformed
313:
314: private void upActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_upActionPerformed
315: TableModelSupport tableModel = (TableModelSupport) dataTable
316: .getModel();
317: if (dataTable.getSelectedRowCount() > 0) {
318: int[] selectedRows = dataTable.getSelectedRows();
319: if (selectedRows[0] > 0
320: && tableModel.canMoveRow(selectedRows[0],
321: selectedRows[0] - 1)) {
322: tableModel
323: .moveRow(selectedRows[0], selectedRows[0] - 1);
324: dataTable.setModel(tableModel);
325: dataTable.changeSelection(selectedRows[0] - 1, 0,
326: false, false);
327: }
328: }
329: }//GEN-LAST:event_upActionPerformed
330:
331: private void deleteActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteActionPerformed
332: TableModelSupport tableModel = (TableModelSupport) dataTable
333: .getModel();
334: int numRows = tableModel.getRowCount();
335:
336: if (dataTable.getSelectedRowCount() > 0) {
337: int[] selectedRows = dataTable.getSelectedRows();
338: boolean lastRowRemoved = (selectedRows[0] == (numRows - 1)) ? true
339: : false;
340: if (tableModel.canRemoveRow(selectedRows[0])) {
341: tableModel.removeRow(selectedRows[0]);
342: dataTable.setModel(tableModel);
343:
344: // If this is not the last row we removed, have the next row selected
345: if (tableModel.getRowCount() == 0)
346: return;
347: else {
348: if (lastRowRemoved) {
349: // Have the last row selected again
350: dataTable.changeSelection(tableModel
351: .getRowCount() - 1, 0, false, false);
352: } else {
353: // Have the same row index selected again
354: dataTable.changeSelection(selectedRows[0], 0,
355: false, false);
356: }
357: }
358: }
359: }
360: }//GEN-LAST:event_deleteActionPerformed
361:
362: private void newActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newActionPerformed
363: TableModelSupport tableModel = (TableModelSupport) dataTable
364: .getModel();
365: if (tableModel.canAddRow()) {
366: tableModel.addRow();
367: dataTable.setModel(tableModel);
368: dataTable.changeSelection(tableModel.getRowCount() - 1, 0,
369: false, false);
370: dataTable.requestFocusInWindow();
371:
372: // Let's not call this. This makes the new row acting very weird. -dongmei
373: //dataTable.editCellAt(tableModel.getRowCount() - 1, 0);
374: }
375: }//GEN-LAST:event_newActionPerformed
376:
377: // Variables declaration - do not modify//GEN-BEGIN:variables
378: private javax.swing.JPanel buttonsPanel;
379: private javax.swing.JScrollPane dataPane;
380: private javax.swing.JTable dataTable;
381: private javax.swing.JButton deleteButton;
382: private javax.swing.JButton downButton;
383: private javax.swing.JLabel helpLabel;
384: private javax.swing.JButton newButton;
385: private javax.swing.JButton upButton;
386:
387: // End of variables declaration//GEN-END:variables
388:
389: static class TableModelSupport extends AbstractTableModel {
390:
391: TabularPropertyModel tableModel;
392:
393: TableModelSupport(TabularPropertyModel tableModel) {
394: this .tableModel = tableModel;
395: }
396:
397: public Object getValue() {
398: return this .tableModel.getValue();
399: }
400:
401: public Class getColumnClass(int columnIndex) {
402: return tableModel.getColumnClass(columnIndex);
403: }
404:
405: public String getColumnName(int columnIndex) {
406: return tableModel.getColumnName(columnIndex);
407: }
408:
409: public int getColumnCount() {
410: return tableModel.getColumnCount();
411: }
412:
413: public int getRowCount() {
414: return tableModel.getRowCount();
415: }
416:
417: public boolean canRemoveRow(int index) {
418: return tableModel.canRemoveRow(index);
419: }
420:
421: public boolean removeRow(int index) {
422: if (tableModel.removeRow(index)) {
423: this .fireTableRowsDeleted(index, index);
424: return true;
425: }
426: return false;
427: }
428:
429: public boolean removeAllRows() {
430: int numRows = tableModel.getRowCount();
431: if (tableModel.removeAllRows()) {
432: this .fireTableRowsDeleted(0, numRows - 1);
433: return true;
434: }
435: return false;
436: }
437:
438: public void setValueAt(Object newValue, int rowIndex,
439: int columnIndex) {
440: tableModel.setValueAt(newValue, rowIndex, columnIndex);
441: }
442:
443: public Object getValueAt(int rowIndex, int columnIndex) {
444: return tableModel.getValueAt(rowIndex, columnIndex);
445: }
446:
447: public boolean canAddRow() {
448: return tableModel.canAddRow();
449: }
450:
451: public boolean addRow() {
452: if (tableModel.addRow()) {
453: this
454: .fireTableRowsInserted(getRowCount(),
455: getRowCount());
456: return true;
457: }
458: return false;
459: }
460:
461: public boolean canMoveRow(int indexFrom, int indexTo) {
462: return tableModel.canMoveRow(indexFrom, indexTo);
463: }
464:
465: public boolean moveRow(int indexFrom, int indexTo) {
466: if (tableModel.moveRow(indexFrom, indexTo)) {
467: this .fireTableDataChanged();
468: return true;
469: }
470: return false;
471: }
472:
473: public boolean isCellEditable(int rowIndex, int columnIndex) {
474: return tableModel.isCellEditable(rowIndex, columnIndex);
475: }
476:
477: }
478:
479: /**
480: * A delegating renderer class that consistently sets the background color
481: * of cells to reflect "selected" and "unselected" states.
482: */
483: class HomogonousCellRenderer extends DefaultTableCellRenderer {
484:
485: Color SELECTION_BACKGROUND = UIManager.getDefaults().getColor(
486: "TextField.selectionBackground");
487:
488: public Component getTableCellRendererComponent(JTable table,
489: Object value, boolean isSelected, boolean hasFocus,
490: int row, int column) {
491: Component c = super .getTableCellRendererComponent(table,
492: value, isSelected, hasFocus, row, column);
493: if (isSelected)
494: c.setBackground(SELECTION_BACKGROUND);
495: else
496: c.setBackground(Color.WHITE);
497: return c;
498: }
499: }
500:
501: /**
502: * A JTextField cell editor by default all the text is selected
503: */
504: class CellEditor extends DefaultCellEditor {
505:
506: private JTable table;
507:
508: public CellEditor(JTable table, JTextField component) {
509: super (component);
510: this .table = table;
511: component
512: .getAccessibleContext()
513: .setAccessibleName(
514: org.openide.util.NbBundle
515: .getMessage(
516: TabularPropertyPanel.class,
517: "TablePropertyPanel.textField.accessibleName")); // NOI18N
518: component
519: .getAccessibleContext()
520: .setAccessibleDescription(
521: org.openide.util.NbBundle
522: .getMessage(
523: TabularPropertyPanel.class,
524: "TablePropertyPanel.textField.accessibleDesc")); // NOI18N
525: }
526:
527: // This method is called when a cell value is edited by the user.
528: public Component getTableCellEditorComponent(JTable table,
529: Object value, boolean isSelected, int rowIndex,
530: int vColIndex) {
531:
532: // Configure the component with the specified value
533: ((JTextField) super .getComponent()).setText((String) value);
534:
535: if (isSelected) {
536: ((JTextField) super .getComponent()).selectAll();
537: table.repaint();
538: }
539:
540: // Return the configured component
541: return super.getComponent();
542: }
543: }
544: }
|