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