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()).addNavigationListeners(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}