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}