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}