package org.geogebra.desktop.gui.inputfield;
import static java.awt.event.KeyEvent.VK_ENTER;
import static java.awt.event.KeyEvent.VK_ESCAPE;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.SystemColor;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Locale;
import javax.swing.BorderFactory;
import javax.swing.JPopupMenu;
import javax.swing.SwingConstants;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.text.BadLocationException;
import org.geogebra.common.gui.util.SelectionTable;
import org.geogebra.common.gui.util.TableSymbols;
import org.geogebra.desktop.gui.util.SelectionTableD;
import org.geogebra.desktop.main.AppD;
import org.geogebra.desktop.main.LocalizationD;
/**
* Prepares and shows a JPopupMenu containing a symbol table for MyTextField.
*
* @author G. Sturr
*
*/
public class SymbolTablePopupD {
private MyTextFieldD textField;
private JPopupMenu popup;
private KeyListener keyListener;
private KeyListener[] textFieldKeyListeners;
private SelectionTableD symbolTable;
private AppD app;
private Locale locale;
private boolean openUpwards = true;
/******************************************************
* Constructs a symbol table popup.
*
* @param app
* @param textField
*/
public SymbolTablePopupD(AppD app, MyTextFieldD textField) {
this.app = app;
this.textField = textField;
popup = new JPopupMenu();
popup.setFocusable(false);
popup.setBorder(
BorderFactory.createLineBorder(SystemColor.controlShadow));
// created in setLabels(), not needed here
// createSymbolTable();
registerListeners();
locale = app.getLocale();
app.setComponentOrientation(popup);
}
private void createSymbolTable() {
LocalizationD loc = app.getLocalization();
String[][] map = TableSymbols.basicSymbolsMap(loc);
symbolTable = new SelectionTableD(app,
TableSymbols.basicSymbols(loc, map), -1, 10,
new Dimension(24, 24), SelectionTable.MODE_TEXT);
symbolTable.setShowGrid(true);
symbolTable.setHorizontalAlignment(SwingConstants.CENTER);
symbolTable.setSelectedIndex(1);
symbolTable.setFocusable(false);
symbolTable
.setToolTipArray(TableSymbols.basicSymbolsToolTips(loc, map));
symbolTable.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
handleMouseClick(e);
}
});
popup.removeAll();
popup.add(symbolTable);
}
public void setLabels() {
createSymbolTable();
}
private class PopupListener implements PopupMenuListener {
@Override
public void popupMenuCanceled(PopupMenuEvent e) {
}
@Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
// remove text field key listeners and replace with our own;
textFieldKeyListeners = textField.getKeyListeners();
for (KeyListener listener : textFieldKeyListeners) {
textField.removeKeyListener(listener);
}
textField.addKeyListener(keyListener);
}
@Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
// return old key listeners to the text field
textField.removeKeyListener(keyListener);
for (KeyListener listener : textFieldKeyListeners) {
textField.addKeyListener(listener);
}
}
}
private void registerListeners() {
// create key listener (will be added by PopupListener)
keyListener = new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
handleSpecialKeys(e);
}
};
popup.addPopupMenuListener(new PopupListener());
}
// =======================================================
// Handle popup visiblilty
// =======================================================
/**
* Gets the pixel location of the caret. Used to locate the popup.
*/
private Point getCaretPixelPosition() {
int position = textField.getCaretPosition();
Rectangle r;
try {
r = textField.modelToView(position);
} catch (BadLocationException e) {
return null;
}
return new Point(r.x, r.y - popup.getPreferredSize().height - 10);
}
public void showPopup(boolean locateAtFieldEnd) {
getSymbolTable().updateFonts();
if (locale != app.getLocale()) {
locale = app.getLocale();
setLabels();
}
if (locateAtFieldEnd) {
Dimension d = popup.getPreferredSize();
if (openUpwards) {
popup.show(textField,
textField.getX() + textField.getWidth() - d.width,
-d.height);
} else {
popup.show(textField,
textField.getX() + textField.getWidth() - d.width,
textField.getY() + textField.getHeight());
}
} else {
if (openUpwards) {
popup.show(textField, getCaretPixelPosition().x,
getCaretPixelPosition().y);
} else {
popup.show(textField, getCaretPixelPosition().x,
textField.getY() + textField.getHeight());
}
}
}
private SelectionTableD getSymbolTable() {
if (symbolTable == null) {
createSymbolTable();
}
return symbolTable;
}
private boolean isPopupVisible() {
return popup.isVisible();
}
private void hidePopup() {
if (!isPopupVisible()) {
return;
}
popup.setVisible(false);
}
/**
* @param openUpwards
* true => popup opens sitting above the textfield, false =>
* popup opens below
*/
public void setOpenUpwards(boolean openUpwards) {
this.openUpwards = openUpwards;
}
// =======================================================
// Handle key and mouse events
// =======================================================
public void handleMouseClick(MouseEvent e) {
handlePopupSelection();
hidePopup();
}
public void handlePopupSelection() {
if (symbolTable.getSelectedValue() != null) {
textField.insertString((String) symbolTable.getSelectedValue());
}
}
public void handleSpecialKeys(KeyEvent keyEvent) {
if (!isPopupVisible()) {
return;
}
int keyCode = keyEvent.getKeyCode();
switch (keyCode) {
case VK_ESCAPE: // [ESC] cancel the popup and undo any changes
hidePopup();
keyEvent.consume();
break;
case VK_ENTER:
handlePopupSelection();
hidePopup();
keyEvent.consume();
break;
case KeyEvent.VK_UP:
case KeyEvent.VK_DOWN:
case KeyEvent.VK_LEFT:
case KeyEvent.VK_RIGHT:
int row = symbolTable.getSelectedRow();
int column = symbolTable.getSelectedColumn();
if (keyCode == KeyEvent.VK_RIGHT
&& column != symbolTable.getColumnCount() - 1) {
++column;
}
if (keyCode == KeyEvent.VK_LEFT && column >= 0) {
--column;
}
if (keyCode == KeyEvent.VK_DOWN
&& row != symbolTable.getRowCount() - 1) {
++row;
}
if (keyCode == KeyEvent.VK_UP && row >= 0) {
--row;
}
symbolTable.changeSelection(row, column, false, false);
keyEvent.consume();
break;
default:
hidePopup();
}
}
}