001package jmri.util.swing;
002
003import java.awt.Component;
004import java.awt.event.*;
005
006import javax.swing.*;
007import javax.swing.table.TableCellEditor;
008
009/**
010 * Renderer to edit multiple lines in a JTable cell
011 *
012 * @see jmri.util.swing.MultiLineCellRenderer
013 */
014public class MultiLineCellEditor  extends AbstractCellEditor implements TableCellEditor {
015        
016    public MultiLineCellEditor() {
017        textArea = new JTextArea();
018        
019        // match these to jmri.util.swing.MultiLineCellRenderer
020        textArea.setLineWrap(false);
021        textArea.setWrapStyleWord(true);
022        textArea.setOpaque(true);
023        customize();
024    }
025
026    /**
027     * Allow the creator of one of these objects to customize its
028     * appearance, tooltips, etc
029     */
030    protected void customize() {}
031
032    JTextArea textArea;
033    
034    public Component getTableCellEditorComponent(JTable table,
035                                                 Object value,
036                                                 boolean isSelected,
037                                                 int row, int column) {
038        
039        // formatting
040        if (isSelected) {
041            textArea.setForeground(table.getSelectionForeground());
042            textArea.setBackground(table.getSelectionBackground());
043        } else {
044            textArea.setForeground(table.getForeground());
045            textArea.setBackground(table.getBackground());
046        }
047        textArea.setFont(table.getFont());
048        
049        // handle Enter/Return key, which closes the
050        // editor unless a modifier is down
051
052        // Get the InputMap for WHEN_FOCUSED
053        InputMap inputMap = textArea.getInputMap(JComponent.WHEN_FOCUSED);
054        // Get the ActionMap
055        ActionMap actionMap = textArea.getActionMap();
056        // Define a unique name for your custom action
057        String enterActionKey = "processEnterKey";
058        String enterModifiedActionKey = "processModifiedEnterKey";
059        // Define the KeyStroke for the Enter key with and without modifiers
060        KeyStroke enterKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
061        KeyStroke ctrlEnterKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.CTRL_DOWN_MASK);
062        KeyStroke altEnterKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.ALT_DOWN_MASK);
063        KeyStroke shiftEnterKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.SHIFT_DOWN_MASK);
064        // Create custom Actions to handle these
065        Action customEnterAction = new AbstractAction() {
066            @Override
067            public void actionPerformed(ActionEvent e) {
068                // Done editing
069                stopCellEditing();
070            }
071        };
072        Action customModifiedEnterAction = new AbstractAction() {
073            @Override
074            public void actionPerformed(ActionEvent e) {
075                // Insert a return
076                // Get the current cursor (caret) position
077                int caretPosition = textArea.getCaretPosition();
078                // Insert the new text at that position
079                textArea.insert("\n", caretPosition);
080                // Move the cursor to the end of the newly inserted text
081                textArea.setCaretPosition(caretPosition + 1);
082
083                var model = table.getModel();
084                if (model instanceof ResizableRowDataModel) {
085                
086                    ((ResizableRowDataModel)model).resizeRowToText(row, textArea.getText().split("\n").length);
087                    
088                    table.revalidate();
089                    table.repaint();
090                }
091            }
092        };
093        // Bind the KeyStroke to the action name in the InputMap
094        inputMap.put(enterKeyStroke, enterActionKey);
095        inputMap.put(ctrlEnterKeyStroke, enterModifiedActionKey);
096        inputMap.put(altEnterKeyStroke, enterModifiedActionKey);
097        inputMap.put(shiftEnterKeyStroke, enterModifiedActionKey);
098        // Bind the action name to the custom Action in the ActionMap
099        actionMap.put(enterActionKey, customEnterAction);
100        actionMap.put(enterModifiedActionKey, customModifiedEnterAction);
101        
102        // set value and return the text area for display
103        textArea.setText((String)value);
104        return textArea;
105    }
106  
107    public Object getCellEditorValue() {
108        return textArea.getText();
109    }
110}