package org.geogebra.desktop.cas.view; import java.awt.Component; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.ArrayList; import java.util.EventObject; import java.util.Vector; import javax.swing.JTable; import javax.swing.event.CellEditorListener; import javax.swing.event.ChangeEvent; import javax.swing.table.TableCellEditor; import javax.swing.text.JTextComponent; import org.geogebra.common.cas.view.CASTableCellEditor; import org.geogebra.common.kernel.StringTemplate; import org.geogebra.common.kernel.geos.GeoCasCell; import org.geogebra.desktop.main.AppD; /** * Cell editor; handles keystrokes */ public class CASTableCellEditorD extends CASTableCell implements TableCellEditor, KeyListener, CASTableCellEditor { private static final long serialVersionUID = 1L; private JTable table; private GeoCasCell cellValue; private boolean editing = false; private int editingRow; private String inputOnEditingStart; private boolean isUseAsTextOnEditingStart; private ArrayList<CellEditorListener> listeners = new ArrayList<CellEditorListener>(); /** * @param view * CAS view */ public CASTableCellEditorD(CASViewD view) { super(view); getInputArea().addKeyListener(this); } @Override public Component getTableCellEditorComponent(JTable casTable, Object value, boolean isSelected, int row, int column) { if (value instanceof GeoCasCell) { editing = true; editingRow = row; // make sure we keep the substitution list // needed for TRAC-5522 if (cellValue != null) { ArrayList<Vector<String>> substList = cellValue.getSubstList(); if (!substList.isEmpty()) { ((GeoCasCell) value).setSubstList(cellValue.getSubstList()); } } // set CASTableCell value this.cellValue = (GeoCasCell) value; this.table = casTable; inputOnEditingStart = cellValue .getInput(StringTemplate.defaultTemplate); isUseAsTextOnEditingStart = cellValue.isUseAsText(); setValue(cellValue); boolean isUseAsText = cellValue.isUseAsText(); getInputArea().enableColoring(!isUseAsText); getInputArea().setAutoComplete(!isUseAsText); // update font and row height setFont(view.getCASViewComponent().getFont()); updateTableRowHeight(casTable, row); // Set width of editor to the width of the table column. // This will allow scrolling of strings that are wider than the // cell. setInputPanelWidth(casTable.getParent().getWidth()); } return this; } /** * @return input text */ public String getInputText() { return getInputArea().getText(); } @Override public String getInputSelectedText() { return getInputArea().getSelectedText(); } @Override public int getInputSelectionStart() { return getInputArea().getSelectionStart(); } @Override public int getInputSelectionEnd() { return getInputArea().getSelectionEnd(); } @Override public void setInputSelectionStart(int pos) { getInputArea().setSelectionStart(pos); } @Override public void setInputSelectionEnd(int pos) { getInputArea().setSelectionEnd(pos); } public int getCaretPosition() { return getInputArea().getCaretPosition(); } public void setCaretPosition(int i) { getInputArea().setCaretPosition(i); } /** * Replaces selection with given text * * @param text * text */ public void insertText(String text) { getInputArea().replaceSelection(text); // getInputArea().requestFocusInWindow(); } /** * Clears input area */ public void clearInputSelectionText() { getInputArea().setText(null); } @Override public boolean stopCellEditing() { // update cellValue's input using editor content if (editing && cellValue != null) { String newInput = getInput(); if (!newInput.equals(inputOnEditingStart) || cellValue.isUseAsText() != isUseAsTextOnEditingStart) { cellValue.setInput(getInput()); } fireEditingStopped(); } return true; } @Override public void cancelCellEditing() { // update cellValue's input using editor content if (editing && cellValue != null) { String newInput = getInput(); if (!newInput.equals(inputOnEditingStart) || cellValue.isUseAsText() != isUseAsTextOnEditingStart) { cellValue.setInput(getInput()); } fireEditingCanceled(); } } /** * @return whether this cell is being edited */ public boolean isEditing() { return editing; // && hasFocus(); } @Override public Object getCellEditorValue(int idx) { // idx is not used in Desktop return cellValue; } @Override public Object getCellEditorValue() { return cellValue; } /** * Editing canceled */ protected void fireEditingCanceled() { if (editing && editingRow < table.getRowCount()) { ChangeEvent ce = new ChangeEvent(this); for (int i = 0; i < listeners.size(); i++) { CellEditorListener l = listeners.get(i); l.editingCanceled(ce); } } editing = false; } /** * Editing stopped */ protected void fireEditingStopped() { if (editing && editingRow < table.getRowCount()) { ChangeEvent ce = new ChangeEvent(this); for (int i = 0; i < listeners.size(); i++) { CellEditorListener l = listeners.get(i); l.editingStopped(ce); } } editing = false; } @Override public boolean isCellEditable(EventObject anEvent) { return true; } @Override public void removeCellEditorListener(CellEditorListener l) { listeners.remove(l); } @Override public void addCellEditorListener(CellEditorListener l) { if (!listeners.contains(l)) { listeners.add(l); } } @Override public boolean shouldSelectCell(EventObject anEvent) { return true; } /** * @return index of editing row */ public final int getEditingRow() { return editingRow; } @Override public void keyPressed(KeyEvent e) { int keyCode = e.getKeyCode(); switch (keyCode) { default: // do nothing break; case KeyEvent.VK_ESCAPE: e.consume(); getInputArea().setText(""); break; case KeyEvent.VK_V: if (AppD.isControlDown(e)) { // make sure Ctrl-V isn't passed on to Euclidian View getInputArea().paste(); e.consume(); } break; // case KeyEvent.VK_ENTER: // e.consume(); // stopCellEditing(); // break; } } @Override public void keyReleased(KeyEvent arg0) { // do nothing } @Override public void keyTyped(KeyEvent e) { char ch = e.getKeyChar(); JTextComponent inputArea = getInputArea(); String text = inputArea.getText(); // check for special characters, which insert some text // from the previous cell if (editingRow == 0 || text.length() != 0) { return; } GeoCasCell selCellValue = view.getConsoleTable() .getGeoCasCell(editingRow - 1); if (!selCellValue.isError()) { switch (ch) { default: // do nothing break; case ' ': case '|': // insert output of previous row (not in parentheses) inputArea.setText(selCellValue .getOutputRHS(StringTemplate.defaultTemplate) + " "); e.consume(); break; case ')': // insert output of previous row in parentheses String prevOutput = selCellValue .getOutputRHS(StringTemplate.defaultTemplate); inputArea.setText("(" + prevOutput + ")"); e.consume(); break; } } // insert input of previous row // should work on errors also if ('=' == ch) { inputArea.setText( selCellValue.getInput(StringTemplate.defaultTemplate)); e.consume(); } } @Override public void clearInputText() { clearInputSelectionText(); } @Override public void ensureEditing() { // only in web } public void onEnter(boolean b) { // only used in web } }