package org.geogebra.desktop.cas.view; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.util.Arrays; import java.util.Vector; import javax.swing.AbstractCellEditor; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.ListSelectionModel; import javax.swing.event.ChangeEvent; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.TableCellEditor; import org.geogebra.common.cas.view.CASSubDialog; import org.geogebra.common.cas.view.CASView; import org.geogebra.common.kernel.geos.GeoCasCell; import org.geogebra.common.main.App; import org.geogebra.common.main.Localization; import org.geogebra.desktop.gui.inputfield.MathTextField; import org.geogebra.desktop.gui.layout.LayoutD; import org.geogebra.desktop.main.AppD; /** * Dialog to substitute expressions in CAS Input. * */ public class CASSubDialogD extends CASSubDialog implements ActionListener { private AppD app; private CASViewD casView; private JButton btSub, btEval, btNumeric; private JScrollPane scrollPane; private JPanel optionPane, btPanel, captionPanel; private JTable replaceTable; private JDialog dialog; private static final int DEFAULT_TABLE_WIDTH = 200; private static final int DEFAULT_TABLE_HEIGHT = 150; private static final int DEFAULT_TABLE_CELL_HEIGHT = 21; private static final double DEFAULT_FONT_SIZE = 12.; /** * Substitute dialog for CAS. * * @param casView * view * @param prefix * before selection, not effected by the substitution * @param evalText * the String which will be substituted * @param postfix * after selection, not effected by the substitution * @param editRow * row to edit */ public CASSubDialogD(CASViewD casView, String prefix, String evalText, String postfix, int editRow) { super(prefix, evalText, postfix, editRow); this.casView = casView; this.app = casView.getApp(); createGUI(); dialog.pack(); dialog.setLocationRelativeTo(casView.getCASViewComponent()); } /** * */ protected void createGUI() { // do not dock the substitution dialog to the main frame: ticket 1832 dialog = new JDialog( (JFrame) ((LayoutD) app.getGuiManager().getLayout()) .getDockManager().getPanel(App.VIEW_CAS).getFrame()); dialog.setModal(false); Localization loc = getApp().getLocalization(); dialog.setTitle(loc.getPlain("Substitute") + " - " + loc.getCommand("Row") + " " + (editRow + 1)); dialog.setResizable(true); GeoCasCell cell = casView.getConsoleTable().getGeoCasCell(editRow); initData(cell); Vector<String> header = new Vector<String>(); header.add(loc.getPlain("OldExpression")); header.add(loc.getPlain("NewExpression")); replaceTable = new JTable(data, header); replaceTable.setDefaultEditor(Object.class, new MathTextCellEditor()); replaceTable.getTableHeader().setReorderingAllowed(false); double fontFactor = Math.max(1, getApp().getGUIFontSize() / DEFAULT_FONT_SIZE); replaceTable .setRowHeight((int) (DEFAULT_TABLE_CELL_HEIGHT * fontFactor)); replaceTable.setPreferredScrollableViewportSize( new Dimension((int) (DEFAULT_TABLE_WIDTH * fontFactor), (int) (DEFAULT_TABLE_HEIGHT * fontFactor))); scrollPane = new JScrollPane(replaceTable); captionPanel = new JPanel(new BorderLayout(5, 0)); captionPanel.add(scrollPane, BorderLayout.CENTER); replaceTable.getSelectionModel() .setSelectionMode(ListSelectionModel.SINGLE_SELECTION); replaceTable.getSelectionModel() .addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent e) { addRow(false); } }); replaceTable.addKeyListener(new KeyAdapter() { @Override public void keyTyped(KeyEvent e) { if (e.getKeyChar() != KeyEvent.CHAR_UNDEFINED && e.getKeyChar() != '\t') { addRow(true); } } }); // buttons btEval = new JButton(EVAL_SYM); btEval.setToolTipText(loc.getMenuTooltip("Evaluate")); btEval.setActionCommand(ACTION_EVALUATE); btEval.addActionListener(this); btNumeric = new JButton(NUM_SYM); btNumeric.setToolTipText(loc.getMenuTooltip("Numeric")); btNumeric.setActionCommand(ACTION_NUMERIC); btNumeric.addActionListener(this); btSub = new JButton(loc.getPlain(SUB_SYM)); btSub.setToolTipText(loc.getMenuTooltip("Substitute")); btSub.setActionCommand(ACTION_SUBSTITUTE); btSub.addActionListener(this); btPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); btPanel.add(btEval); btPanel.add(btNumeric); btPanel.add(btSub); // Create the JOptionPane. optionPane = new JPanel(new BorderLayout(5, 5)); // create object list optionPane.add(captionPanel, BorderLayout.CENTER); optionPane.add(btPanel, BorderLayout.SOUTH); optionPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); // Make this dialog display it. dialog.setContentPane(optionPane); } /** * tests if there should be an empty row appended * * @param inserting * is set: the selected cell will be filled but is not yet */ public void addRow(boolean inserting) { int row = replaceTable.getSelectedRow(); int col = replaceTable.getSelectedColumn(); if (row + 1 == replaceTable.getRowCount() && col >= 0) { boolean[] colSet = new boolean[2]; colSet[0] = !data.lastElement().firstElement().equals(""); colSet[1] = !data.lastElement().lastElement().equals(""); colSet[col] = colSet[col] || inserting; if (colSet[0] && colSet[1]) { TableCellEditor editor = replaceTable.getCellEditor(); if (editor != null) { row = replaceTable.getEditingRow(); col = replaceTable.getEditingColumn(); data.get(row).set(col, editor.getCellEditorValue().toString()); } data.add(new Vector<String>( Arrays.asList(new String[] { "", "" }))); replaceTable.revalidate(); dialog.pack(); Rectangle r = replaceTable.getCellRect( replaceTable.getRowCount() - 1, col, false); scrollPane.getViewport().scrollRectToVisible(r); if (editor != null) { replaceTable.editCellAt(row, col); } } } } @Override public void actionPerformed(ActionEvent ae) { Object src = ae.getSource(); replaceTable.clearSelection(); if (replaceTable.isEditing()) { replaceTable.getCellEditor().stopCellEditing(); } if (src instanceof JComponent) { ((JComponent) src).requestFocusInWindow(); } if (src == btEval) { if (apply(btEval.getActionCommand())) { setVisible(false); } } else if (src == btSub) { if (apply(btSub.getActionCommand())) { setVisible(false); } } else if (src == btNumeric) { if (apply(btNumeric.getActionCommand())) { setVisible(false); } } } /** * @param flag * true to set dialog to visible */ public void setVisible(boolean flag) { casView.setSubstituteDialog(flag ? this : null); dialog.setVisible(flag); if (flag) { // focus top right cell replaceTable.setRowSelectionInterval(0, 0); replaceTable.setColumnSelectionInterval(1, 1); } } /** * if editing insert inStr at current caret position * * @param inStr * string to insert */ public void insertText(String inStr) { if (inStr == null) { return; } TableCellEditor editor = replaceTable.getCellEditor(); if (editor != null && editor instanceof MathTextCellEditor) { ((MathTextCellEditor) editor).insertString(inStr); } } /** * @return the app */ public AppD getApp() { return app; } private class MathTextCellEditor extends AbstractCellEditor implements TableCellEditor { private static final long serialVersionUID = 1L; boolean editing; MathTextField delegate; public MathTextCellEditor() { super(); delegate = new MathTextField(getApp()); editing = false; changeEvent = new ChangeEvent(delegate); delegate.addKeyListener(new KeyAdapter() { @Override public void keyTyped(KeyEvent e) { addRow(true); } }); } @Override public Object getCellEditorValue() { return delegate.getText(); } @Override public boolean stopCellEditing() { if (editing) { fireEditingStopped(); } editing = false; return true; } @Override public void cancelCellEditing() { if (editing) { fireEditingCanceled(); } editing = false; } @Override public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { delegate.setText(value.toString()); delegate.setFont(getApp().getPlainFont()); editing = true; return delegate; } public void insertString(String text) { delegate.insertString(text); } } /** * @param flag * true to set dialog always on top */ public void setAlwaysOnTop(boolean flag) { dialog.setAlwaysOnTop(flag); } /** * @return true if dialog is showing */ public boolean isShowing() { return dialog.isShowing(); } @Override protected CASView getCASView() { return casView; } /** * @return dialog */ public JDialog getDialog() { return dialog; } }