001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.conflict.tags; 003 004import java.awt.event.ActionEvent; 005import java.awt.event.KeyEvent; 006 007import javax.swing.AbstractAction; 008import javax.swing.JComponent; 009import javax.swing.JTable; 010import javax.swing.KeyStroke; 011import javax.swing.ListSelectionModel; 012 013import org.openstreetmap.josm.gui.widgets.JosmComboBox; 014 015/** 016 * The main table displayed in the {@link RelationMemberConflictResolver} 017 * 018 * @see RelationMemberConflictResolverColumnModel 019 */ 020public class RelationMemberConflictResolverTable extends JTable implements MultiValueCellEditor.NavigationListener { 021 022 private SelectNextColumnCellAction selectNextColumnCellAction; 023 private SelectPreviousColumnCellAction selectPreviousColumnCellAction; 024 025 public RelationMemberConflictResolverTable(RelationMemberConflictResolverModel model) { 026 super(model, new RelationMemberConflictResolverColumnModel()); 027 build(); 028 } 029 030 protected final void build() { 031 setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); 032 setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 033 putClientProperty("terminateEditOnFocusLost", Boolean.TRUE); 034 035 // make ENTER behave like TAB 036 // 037 getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put( 038 KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, false), "selectNextColumnCell"); 039 040 // install custom navigation actions 041 // 042 selectNextColumnCellAction = new SelectNextColumnCellAction(); 043 selectPreviousColumnCellAction = new SelectPreviousColumnCellAction(); 044 getActionMap().put("selectNextColumnCell", selectNextColumnCellAction); 045 getActionMap().put("selectPreviousColumnCell", selectPreviousColumnCellAction); 046 047 setRowHeight((int) new JosmComboBox<String>().getPreferredSize().getHeight()); 048 } 049 050 /** 051 * Action to be run when the user navigates to the next cell in the table, for instance by 052 * pressing TAB or ENTER. The action alters the standard navigation path from cell to cell: <ul> 053 * <li>it jumps over cells in the first column</li> <li>it automatically add a new empty row 054 * when the user leaves the last cell in the table</li></ul> 055 * 056 * 057 */ 058 class SelectNextColumnCellAction extends AbstractAction { 059 @Override 060 public void actionPerformed(ActionEvent e) { 061 run(); 062 } 063 064 public void run() { 065 int col = getSelectedColumn(); 066 int row = getSelectedRow(); 067 if (getCellEditor() != null) { 068 getCellEditor().stopCellEditing(); 069 } 070 071 if (col == 2 && row < getRowCount() - 1) { 072 row++; 073 } else if (row < getRowCount() - 1) { 074 col = 2; 075 row++; 076 } 077 changeSelection(row, col, false, false); 078 editCellAt(getSelectedRow(), getSelectedColumn()); 079 getEditorComponent().requestFocusInWindow(); 080 } 081 } 082 083 /** 084 * Action to be run when the user navigates to the previous cell in the table, for instance by 085 * pressing Shift-TAB 086 * 087 */ 088 class SelectPreviousColumnCellAction extends AbstractAction { 089 090 @Override 091 public void actionPerformed(ActionEvent e) { 092 run(); 093 } 094 095 public void run() { 096 int col = getSelectedColumn(); 097 int row = getSelectedRow(); 098 if (getCellEditor() != null) { 099 getCellEditor().stopCellEditing(); 100 } 101 102 if (col <= 0 && row <= 0) { 103 // change nothing 104 } else if (row > 0) { 105 col = 2; 106 row--; 107 } 108 changeSelection(row, col, false, false); 109 editCellAt(getSelectedRow(), getSelectedColumn()); 110 getEditorComponent().requestFocusInWindow(); 111 } 112 } 113 114 @Override 115 public void gotoNextDecision() { 116 selectNextColumnCellAction.run(); 117 } 118 119 @Override 120 public void gotoPreviousDecision() { 121 selectPreviousColumnCellAction.run(); 122 } 123}