components/visual-panels/core/src/java/util/com/oracle/solaris/vp/util/swing/EditableTablePanel.java
changeset 3553 f1d133b09a8c
parent 3552 077ebe3d0d24
child 3554 ef58713bafc4
equal deleted inserted replaced
3552:077ebe3d0d24 3553:f1d133b09a8c
     1 /*
       
     2  * CDDL HEADER START
       
     3  *
       
     4  * The contents of this file are subject to the terms of the
       
     5  * Common Development and Distribution License (the "License").
       
     6  * You may not use this file except in compliance with the License.
       
     7  *
       
     8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
       
     9  * or http://www.opensolaris.org/os/licensing.
       
    10  * See the License for the specific language governing permissions
       
    11  * and limitations under the License.
       
    12  *
       
    13  * When distributing Covered Code, include this CDDL HEADER in each
       
    14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
       
    15  * If applicable, add the following below this CDDL HEADER, with the
       
    16  * fields enclosed by brackets "[]" replaced with your own identifying
       
    17  * information: Portions Copyright [yyyy] [name of copyright owner]
       
    18  *
       
    19  * CDDL HEADER END
       
    20  */
       
    21 
       
    22 /*
       
    23  * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
       
    24  */
       
    25 
       
    26 package com.oracle.solaris.vp.util.swing;
       
    27 
       
    28 import java.awt.*;
       
    29 import java.awt.event.*;
       
    30 import java.util.*;
       
    31 import javax.swing.*;
       
    32 import javax.swing.event.*;
       
    33 import javax.swing.table.*;
       
    34 import com.oracle.solaris.vp.util.misc.finder.Finder;
       
    35 import com.oracle.solaris.vp.util.swing.layout.*;
       
    36 
       
    37 @SuppressWarnings({"serial"})
       
    38 public class EditableTablePanel extends JPanel implements DescendantEnabler {
       
    39     //
       
    40     // Inner classes
       
    41     //
       
    42 
       
    43     protected class Table extends ExtTable {
       
    44 	//
       
    45 	// Constructors
       
    46 	//
       
    47 
       
    48 	public Table(TableModel model) {
       
    49 	    super(model);
       
    50 
       
    51 	    setFillsViewportHeight(true);
       
    52 	    setRowSelectionAllowed(true);
       
    53 	    getSelectionModel().setSelectionMode(
       
    54 		ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
       
    55 
       
    56 	    if (model.getColumnCount() == 1) {
       
    57 		setStripeColor(null);
       
    58 		setTableHeader(null);
       
    59 		setShowVerticalLines(false);
       
    60 	    }
       
    61 
       
    62 	    setDragEnabled(true);
       
    63 	    setDropMode(DropMode.INSERT_ROWS);
       
    64 	    setTransferHandler(new EditableTableTransferHandler());
       
    65 
       
    66 	    ActionMap aMap = getActionMap();
       
    67 
       
    68 	    // JTable doesn't call cancelCellEditing on a TableCellEditor when
       
    69 	    // the user hits escape; it simply removes the editor.  Override
       
    70 	    // this behavior by calling cancelCellEditing directly.
       
    71 	    // Unfortunately this action name is not publicly exposed by the
       
    72 	    // API.
       
    73 	    aMap.put("cancel",
       
    74 		new AbstractAction() {
       
    75 		    @Override
       
    76 		    public void actionPerformed(ActionEvent e) {
       
    77 			Object source = e.getSource();
       
    78 			if (source instanceof JTable) {
       
    79 			    JTable table = (JTable)source;
       
    80 			    TableCellEditor editor = table.getCellEditor();
       
    81 			    if (editor != null) {
       
    82 				editor.cancelCellEditing();
       
    83 			    }
       
    84 			}
       
    85 		    }
       
    86 		});
       
    87 
       
    88 	    String actionKey = "deleteSelection";
       
    89 
       
    90 	    getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
       
    91 		KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), actionKey);
       
    92 
       
    93 	    aMap.put(actionKey,
       
    94 		new AbstractAction() {
       
    95 		    @Override
       
    96 		    public void actionPerformed(ActionEvent e) {
       
    97 			getDeleteButton().doClick(0);
       
    98 		    }
       
    99 		});
       
   100 
       
   101 	    // Setting this property to TRUE would almost work, but wouldn't
       
   102 	    // allow the Cancel button to cancel an edit.
       
   103 	    putClientProperty("terminateEditOnFocusLost", Boolean.FALSE);
       
   104 
       
   105 	    // This isn't a spreadsheet
       
   106 	    putClientProperty("JTable.autoStartsEdit", Boolean.FALSE);
       
   107 	}
       
   108 
       
   109 	//
       
   110 	// JTable methods
       
   111 	//
       
   112 
       
   113 	@Override
       
   114 	protected void configureEnclosingScrollPane() {
       
   115 	    // Do nothing
       
   116 	}
       
   117 
       
   118 	@Override
       
   119 	public boolean editCellAt(int row, int column, EventObject e) {
       
   120 	    boolean success = super.editCellAt(row, column, e);
       
   121 	    if (success) {
       
   122 		TableCellEditor editor = getCellEditor();
       
   123 		if (editor != null) {
       
   124 		    ((CardLayout)buttonPanel.getLayout()).show(
       
   125 			buttonPanel, BUTTONS_ACCEPT);
       
   126 		}
       
   127 	    }
       
   128 	    return success;
       
   129 	}
       
   130 
       
   131 	@Override
       
   132 	public Component prepareEditor(
       
   133 	    TableCellEditor editor, int row, int column) {
       
   134 
       
   135 	    Component c = super.prepareEditor(editor, row, column);
       
   136 
       
   137 	    // Make sure there's only one instance
       
   138 	    c.removeFocusListener(stopEditFocusListener);
       
   139 	    c.addFocusListener(stopEditFocusListener);
       
   140 
       
   141 	    return c;
       
   142 	}
       
   143 
       
   144 	@Override
       
   145 	public Component prepareRenderer(
       
   146 	    TableCellRenderer renderer, int row, int column) {
       
   147 
       
   148 	    Component c = super.prepareRenderer(renderer, row, column);
       
   149 	    c.setEnabled(isEnabled());
       
   150 
       
   151 	    return c;
       
   152 	}
       
   153 
       
   154 	@Override
       
   155 	public void removeEditor() {
       
   156 	    int row = getEditingRow();
       
   157 	    int column = getEditingColumn();
       
   158 
       
   159 	    super.removeEditor();
       
   160 	    ((CardLayout)buttonPanel.getLayout()).show(
       
   161 		buttonPanel, BUTTONS_EDIT);
       
   162 	}
       
   163     }
       
   164 
       
   165     //
       
   166     // Static data
       
   167     //
       
   168 
       
   169     private static final String BUTTONS_EDIT = "edit";
       
   170     private static final String BUTTONS_ACCEPT = "accept";
       
   171 
       
   172     //
       
   173     // Instance data
       
   174     //
       
   175 
       
   176     private boolean enabled = true;
       
   177     private ExtTable table;
       
   178     private JButton moveUpButton;
       
   179     private JButton moveDownButton;
       
   180     private JButton addButton;
       
   181     private JButton editButton;
       
   182     private JButton deleteButton;
       
   183     private JButton okayButton;
       
   184     private JButton cancelButton;
       
   185     private JPanel buttonPanel;
       
   186     private JScrollPane scroll;
       
   187 
       
   188     private ListSelectionListener buttonEnableListener =
       
   189 	new ListSelectionListener() {
       
   190 	    @Override
       
   191 	    public void valueChanged(ListSelectionEvent e) {
       
   192 		setButtonsEnabledState();
       
   193 	    }
       
   194 	};
       
   195 
       
   196     private FocusListener stopEditFocusListener =
       
   197 	new FocusAdapter() {
       
   198 	    @Override
       
   199 	    public void focusLost(FocusEvent e) {
       
   200 		// If the table is in the middle of a cell edit, and the
       
   201 		// Component that just got focus is not part of this
       
   202 		// EditableTablePanel, stop the edit.
       
   203 
       
   204 		TableCellEditor editor = getTable().getCellEditor();
       
   205 		if (editor != null) {
       
   206 		    Component c = e.getOppositeComponent();
       
   207 		    if (c != null) {
       
   208 			Container parent;
       
   209 			while ((parent = c.getParent()) != null) {
       
   210 			    if (parent == EditableTablePanel.this) {
       
   211 				return;
       
   212 			    }
       
   213 			    c = parent;
       
   214 			}
       
   215 			editor.stopCellEditing();
       
   216 		    }
       
   217 		}
       
   218 	    }
       
   219 	};
       
   220 
       
   221     //
       
   222     // Constructors
       
   223     //
       
   224 
       
   225     public EditableTablePanel(EditableTableModel model) {
       
   226 	setOpaque(false);
       
   227 
       
   228 	scroll = createTable(model);
       
   229 
       
   230 	createAddButton();
       
   231 	createEditButton();
       
   232 	createDeleteButton();
       
   233 	createOkayButton();
       
   234 	createCancelButton();
       
   235 	createMoveDownButton();
       
   236 	createMoveUpButton();
       
   237 
       
   238 	// Set initial button states
       
   239 	setEnabled(true);
       
   240 
       
   241 	table.getSelectionModel().addListSelectionListener(
       
   242 	    buttonEnableListener);
       
   243 
       
   244 	int gap = GUIUtil.getHalfGap();
       
   245 
       
   246 	JPanel movePanel = new JPanel(new GridLayout(2, 0, 0, gap));
       
   247 	movePanel.setOpaque(false);
       
   248 	movePanel.add(moveUpButton);
       
   249 	movePanel.add(moveDownButton);
       
   250 
       
   251 	JPanel moveNorthPanel = new JPanel(new BorderLayout());
       
   252 	moveNorthPanel.setOpaque(false);
       
   253 	moveNorthPanel.add(movePanel, BorderLayout.NORTH);
       
   254 
       
   255 	RowLayoutConstraint r = new RowLayoutConstraint().setGap(gap);
       
   256 
       
   257 	JPanel editPanel = new JPanel(new RowLayout());
       
   258 	editPanel.setOpaque(false);
       
   259 	editPanel.add(addButton, r);
       
   260 	editPanel.add(editButton, r);
       
   261 	editPanel.add(deleteButton, r);
       
   262 
       
   263 	JPanel acceptPanel = new JPanel(new RowLayout());
       
   264 	acceptPanel.setOpaque(false);
       
   265 	acceptPanel.add(cancelButton, r);
       
   266 	acceptPanel.add(okayButton, r);
       
   267 
       
   268 	buttonPanel = new JPanel(new CardLayout());
       
   269 	buttonPanel.setOpaque(false);
       
   270 	buttonPanel.add(editPanel, BUTTONS_EDIT);
       
   271 	buttonPanel.add(acceptPanel, BUTTONS_ACCEPT);
       
   272 
       
   273 	setLayout(new BorderLayout(gap, gap));
       
   274 	add(scroll, BorderLayout.CENTER);
       
   275 	add(moveNorthPanel, BorderLayout.EAST);
       
   276 	add(buttonPanel, BorderLayout.SOUTH);
       
   277     }
       
   278 
       
   279     public EditableTablePanel() {
       
   280 	this(new DefaultEditableTableModel());
       
   281     }
       
   282 
       
   283     //
       
   284     // Component methods
       
   285     //
       
   286 
       
   287     @Override
       
   288     public boolean isEnabled() {
       
   289 	return enabled;
       
   290     }
       
   291 
       
   292     @Override
       
   293     public void setEnabled(boolean enabled) {
       
   294 	JTable table = getTable();
       
   295 
       
   296 	if (enabled != this.enabled) {
       
   297 	    table.clearSelection();
       
   298 	}
       
   299 
       
   300 	for (Component component : getComponents()) {
       
   301 	    GUIUtil.setEnabledRecursive(component, enabled);
       
   302 	}
       
   303 
       
   304 	if (enabled) {
       
   305 	    // Set appropriate enabled/disabled button status
       
   306 	    buttonEnableListener.valueChanged(null);
       
   307 	}
       
   308 
       
   309 	this.enabled = enabled;
       
   310     }
       
   311 
       
   312     //
       
   313     // EditableTablePanel methods
       
   314     //
       
   315 
       
   316     protected void createAddButton() {
       
   317 	addButton = new JButton(Finder.getString("list.button.add"));
       
   318 	addButton.addActionListener(
       
   319 	    new ActionListener() {
       
   320 		@Override
       
   321 		public void actionPerformed(ActionEvent e) {
       
   322 		    JTable table = getTable();
       
   323 		    final EditableTableModel model =
       
   324 			(EditableTableModel)table.getModel();
       
   325 
       
   326 		    final int index = model.getRowCount();
       
   327 		    Object[] row = model.getTemplateRow();
       
   328 		    if (model.attemptAddRow(row)) {
       
   329 
       
   330 			int col = model.getAutoEditedColumn();
       
   331 			if (col != -1) {
       
   332 
       
   333 			    table.scrollRectToVisible(
       
   334 				table.getCellRect(index, col, false));
       
   335 
       
   336 			    if (table.editCellAt(index, col)) {
       
   337 				table.getEditorComponent().
       
   338 				    requestFocusInWindow();
       
   339 
       
   340 				final CellEditor editor = table.getCellEditor();
       
   341 				editor.addCellEditorListener(
       
   342 				    new  CellEditorListener() {
       
   343 					@Override
       
   344 					public void editingCanceled(
       
   345 					    ChangeEvent e) {
       
   346 					    editor.removeCellEditorListener(
       
   347 						this);
       
   348 					    model.removeRow(index);
       
   349 					}
       
   350 
       
   351 					@Override
       
   352 					public void editingStopped(
       
   353 					    ChangeEvent e) {
       
   354 					    editor.removeCellEditorListener(
       
   355 						this);
       
   356 					}
       
   357 				    });
       
   358 			    }
       
   359 			}
       
   360 		    }
       
   361 		}
       
   362 	    });
       
   363     }
       
   364 
       
   365     protected void createCancelButton() {
       
   366 	cancelButton = new JButton(Finder.getString("list.button.cancel"));
       
   367 	cancelButton.addActionListener(
       
   368 	    new ActionListener() {
       
   369 		@Override
       
   370 		public void actionPerformed(ActionEvent e) {
       
   371 		    TableCellEditor editor = getTable().getCellEditor();
       
   372 		    if (editor != null) {
       
   373 			editor.cancelCellEditing();
       
   374 		    }
       
   375 		}
       
   376 	    });
       
   377     }
       
   378 
       
   379     protected void createDeleteButton() {
       
   380 	deleteButton = new JButton(Finder.getString("list.button.delete"));
       
   381 	deleteButton.addActionListener(
       
   382 	    new ActionListener() {
       
   383 		@Override
       
   384 		public void actionPerformed(ActionEvent e) {
       
   385 		    JTable table = getTable();
       
   386 		    int[] selected = table.getSelectedRows();
       
   387 		    Arrays.sort(selected);
       
   388 
       
   389 		    EditableTableModel model =
       
   390 			(EditableTableModel)table.getModel();
       
   391 		    for (int i = selected.length - 1; i >= 0; i--) {
       
   392 			model.removeRow(selected[i]);
       
   393 		    }
       
   394 		}
       
   395 	    });
       
   396     }
       
   397 
       
   398     protected void createEditButton() {
       
   399 	editButton = new JButton(Finder.getString("list.button.edit"));
       
   400 	editButton.addActionListener(
       
   401 	    new ActionListener() {
       
   402 		@Override
       
   403 		public void actionPerformed(ActionEvent e) {
       
   404 		    JTable table = getTable();
       
   405 		    int row = table.getSelectedRow();
       
   406 
       
   407 		    if (row != -1) {
       
   408 			EditableTableModel model =
       
   409 			    (EditableTableModel)table.getModel();
       
   410 			int col = model.getAutoEditedColumn();
       
   411 
       
   412 			if (col != -1) {
       
   413 			    if (table.editCellAt(row, col)) {
       
   414 				table.getEditorComponent().
       
   415 				    requestFocusInWindow();
       
   416 			    }
       
   417 			}
       
   418 		    }
       
   419 		}
       
   420 	    });
       
   421     }
       
   422 
       
   423     protected void createOkayButton() {
       
   424 	okayButton = new JButton(Finder.getString("list.button.okay"));
       
   425 	okayButton.addActionListener(
       
   426 	    new ActionListener() {
       
   427 		@Override
       
   428 		public void actionPerformed(ActionEvent e) {
       
   429 		    TableCellEditor editor = getTable().getCellEditor();
       
   430 		    if (editor != null) {
       
   431 			editor.stopCellEditing();
       
   432 		    }
       
   433 		}
       
   434 	    });
       
   435     }
       
   436 
       
   437     protected void createMoveDownButton() {
       
   438 	moveDownButton = new JButton(Finder.getString("list.button.movedown"),
       
   439 	    Finder.getIcon("images/button/movedown.png"));
       
   440 
       
   441 	moveDownButton.addMouseListener(
       
   442 	    new MouseHeldHandler() {
       
   443 		@Override
       
   444 		public void mouseHeld(MouseEvent e) {
       
   445 		    JTable table = getTable();
       
   446 		    int[] selected = table.getSelectedRows();
       
   447 		    if (selected.length != 0) {
       
   448 			Arrays.sort(selected);
       
   449 
       
   450 			if (selected[selected.length - 1] !=
       
   451 			    table.getRowCount() - 1) {
       
   452 
       
   453 			    EditableTableModel model =
       
   454 				(EditableTableModel)table.getModel();
       
   455 
       
   456 			    for (int i = selected.length - 1; i >= 0; i--) {
       
   457 				int row = selected[i];
       
   458 				table.removeRowSelectionInterval(row, row);
       
   459 				model.moveRow(row, row, row + 1);
       
   460 				table.addRowSelectionInterval(row + 1, row + 1);
       
   461 			    }
       
   462 
       
   463 			    table.scrollRectToVisible(table.getCellRect(
       
   464 				selected[selected.length - 1] + 1, 0, false));
       
   465 			}
       
   466 		    }
       
   467 		}
       
   468 	    });
       
   469     }
       
   470 
       
   471     protected void createMoveUpButton() {
       
   472 	moveUpButton = new JButton(Finder.getString("list.button.moveup"),
       
   473 	    Finder.getIcon("images/button/moveup.png"));
       
   474 
       
   475 	moveUpButton.addMouseListener(
       
   476 	    new MouseHeldHandler() {
       
   477 		@Override
       
   478 		public void mouseHeld(MouseEvent e) {
       
   479 		    JTable table = getTable();
       
   480 		    int[] selected = table.getSelectedRows();
       
   481 		    if (selected.length != 0) {
       
   482 			Arrays.sort(selected);
       
   483 
       
   484 			if (selected[0] != 0) {
       
   485 			    EditableTableModel model =
       
   486 				(EditableTableModel)table.getModel();
       
   487 
       
   488 			    for (int i = 0; i < selected.length; i++) {
       
   489 				int row = selected[i];
       
   490 				table.removeRowSelectionInterval(row, row);
       
   491 				model.moveRow(row, row, row - 1);
       
   492 				table.addRowSelectionInterval(row - 1, row - 1);
       
   493 			    }
       
   494 
       
   495 			    table.scrollRectToVisible(table.getCellRect(
       
   496 				selected[0] - 1, 0, false));
       
   497 			}
       
   498 		    }
       
   499 		}
       
   500 	    });
       
   501     }
       
   502 
       
   503     protected JScrollPane createTable(EditableTableModel model) {
       
   504 	table = new Table(model);
       
   505 	JScrollPane scroll = new ExtScrollPane(table);
       
   506 	scroll.setColumnHeaderView(table.getTableHeader());
       
   507 	return scroll;
       
   508     }
       
   509 
       
   510     public JButton getAddButton() {
       
   511 	return addButton;
       
   512     }
       
   513 
       
   514     public JButton getDeleteButton() {
       
   515 	return deleteButton;
       
   516     }
       
   517 
       
   518     public JButton getEditButton() {
       
   519 	return editButton;
       
   520     }
       
   521 
       
   522     public JButton getMoveDownButton() {
       
   523 	return moveDownButton;
       
   524     }
       
   525 
       
   526     public JButton getMoveUpButton() {
       
   527 	return moveUpButton;
       
   528     }
       
   529 
       
   530     public boolean getOrderable() {
       
   531 	return moveUpButton.isVisible() && moveDownButton.isVisible();
       
   532     }
       
   533 
       
   534     public JPanel getButtonPanel() {
       
   535 	return buttonPanel;
       
   536     }
       
   537 
       
   538     public JScrollPane getScrollPane() {
       
   539 	return scroll;
       
   540     }
       
   541 
       
   542     public ExtTable getTable() {
       
   543 	return table;
       
   544     }
       
   545 
       
   546     protected void setButtonsEnabledState() {
       
   547 	JTable table = getTable();
       
   548 	int[] selected = table.getSelectedRows();
       
   549 	Arrays.sort(selected);
       
   550 	boolean isSelected = selected.length != 0;
       
   551 
       
   552 	moveUpButton.setEnabled(isSelected && selected[0] != 0);
       
   553 
       
   554 	moveDownButton.setEnabled(isSelected &&
       
   555 	    selected[selected.length - 1] !=
       
   556 	    table.getRowCount() - 1);
       
   557 
       
   558 	editButton.setEnabled(isSelected && selected.length == 1);
       
   559 	deleteButton.setEnabled(isSelected);
       
   560     }
       
   561 
       
   562     public void setOrderable(boolean orderable) {
       
   563 	moveUpButton.setVisible(orderable);
       
   564 	moveDownButton.setVisible(orderable);
       
   565     }
       
   566 
       
   567     //
       
   568     // Static methods
       
   569     //
       
   570 
       
   571     // XXX - Remove
       
   572     public static void main(String[] args) {
       
   573 	Object[][] data = {
       
   574 	    new Object[] {"0 zero"},
       
   575 	    new Object[] {"1 one"},
       
   576 	    new Object[] {"2 two"},
       
   577 	    new Object[] {"3 three"},
       
   578 	    new Object[] {"4 four"},
       
   579 	    new Object[] {"5 five"},
       
   580 	};
       
   581 
       
   582 	JFrame frame = new JFrame();
       
   583 	Container c = frame.getContentPane();
       
   584 	c.setLayout(new GridLayout());
       
   585 
       
   586 	for (int i = 0; i < 2; i++) {
       
   587 	    DefaultEditableTableModel model = new DefaultEditableTableModel(
       
   588 		data, new String[] {"String"});
       
   589 
       
   590 	    EditableTablePanel panel = new EditableTablePanel(model);
       
   591 	    panel.setEnabled(false);
       
   592 	    panel.setEnabled(true);
       
   593 	    c.add(panel);
       
   594 	}
       
   595 
       
   596 	frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
       
   597 	frame.pack();
       
   598 	frame.setVisible(true);
       
   599     }
       
   600 }