/* * Freeplane - mind map editor * Copyright (C) 2008 Joerg Mueller, Daniel Polansky, Christian Foltin, Dimitry Polivaev * * @author <a href="mailto:labe@users.sourceforge.net">Lars Berning</a> * This file is modified by Dimitry Polivaev in 2008. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.freeplane.core.ui.components; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.Frame; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.List; import javax.swing.BorderFactory; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.KeyStroke; import javax.swing.WindowConstants; import javax.swing.border.BevelBorder; import org.freeplane.core.resources.ResourceController; import org.freeplane.core.util.TextUtils; import org.freeplane.features.icon.IIconInformation; public class IconSelectionPopupDialog extends JDialog implements KeyListener, MouseListener { static class Position { final private int x, y; public Position(final int x, final int y) { this.x = x; this.y = y; } /** * @return Returns the x. */ public int getX() { return x; } /** * @return Returns the y. */ public int getY() { return y; } @Override public String toString() { return ("(" + getX() + "," + getY() + ")"); } } /** * */ private static final long serialVersionUID = 1L; final private JLabel descriptionLabel; final private JLabel[] iconLabels; final private JPanel iconPanel = new JPanel(); final private List<? extends IIconInformation> icons; private int mModifiers; final private int numOfIcons; private int result; private Position selected = new Position(0, 0); final private int xDimension; private int yDimension; public IconSelectionPopupDialog(final Frame frame, final List<? extends IIconInformation> icons) { super(frame, TextUtils.getText("select_icon")); getContentPane().setLayout(new BorderLayout()); this.icons = icons; setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); addWindowListener(new WindowAdapter() { @Override public void windowClosing(final WindowEvent we) { close(); } }); numOfIcons = icons.size(); xDimension = (int) Math.ceil(Math.sqrt(numOfIcons)); if (numOfIcons <= xDimension * (xDimension - 1)) { yDimension = xDimension - 1; } else { yDimension = xDimension; } final GridLayout gridlayout = new GridLayout(0, xDimension); gridlayout.setHgap(3); gridlayout.setVgap(3); iconPanel.setLayout(gridlayout); iconLabels = new JLabel[numOfIcons]; for (int i = 0; i < numOfIcons; ++i) { final IIconInformation icon = icons.get(i); iconPanel.add(iconLabels[i] = new JLabel(icon.getIcon())); iconLabels[i].setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED)); iconLabels[i].addMouseListener(this); } final int perIconSize = 27; iconPanel.setPreferredSize(new Dimension(xDimension * perIconSize, yDimension * perIconSize)); iconPanel.setMinimumSize(new Dimension(xDimension * perIconSize, yDimension * perIconSize)); iconPanel.setMaximumSize(new Dimension(xDimension * perIconSize, yDimension * perIconSize)); iconPanel.setSize(new Dimension(xDimension * perIconSize, yDimension * perIconSize)); getContentPane().add(iconPanel, BorderLayout.CENTER); descriptionLabel = new JLabel(" "); getContentPane().add(descriptionLabel, BorderLayout.SOUTH); setSelectedPosition(new Position(0, 0)); select(getSelectedPosition()); addKeyListener(this); pack(); } private void addIcon(final int pModifiers) { result = calculateIndex(getSelectedPosition()); mModifiers = pModifiers; this.dispose(); } private int calculateIndex(final Position position) { return position.getY() * xDimension + position.getX(); } private boolean canSelect(final Position position) { return ((position.getX() >= 0) && (position.getX() < xDimension) && (position.getY() >= 0) && (position.getY() < yDimension) && (calculateIndex(position) < numOfIcons)); } private void close() { result = -1; mModifiers = 0; this.dispose(); } private void cursorDown() { final Position newPosition = new Position(getSelectedPosition().getX(), getSelectedPosition().getY() + 1); if (canSelect(newPosition)) { select(newPosition); } } private void cursorLeft() { final Position newPosition = new Position(getSelectedPosition().getX() - 1, getSelectedPosition().getY()); if (canSelect(newPosition)) { select(newPosition); } } private void cursorRight() { final Position newPosition = new Position(getSelectedPosition().getX() + 1, getSelectedPosition().getY()); if (canSelect(newPosition)) { select(newPosition); } } private void cursorUp() { final Position newPosition = new Position(getSelectedPosition().getX(), getSelectedPosition().getY() - 1); if (canSelect(newPosition)) { select(newPosition); } } private int findIndexByKeyEvent(final KeyEvent keyEvent) { for (int i = 0; i < icons.size(); i++) { final IIconInformation info = icons.get(i); final KeyStroke iconKeyStroke = info.getKeyStroke(); if (iconKeyStroke != null && (keyEvent.getKeyCode() == iconKeyStroke.getKeyCode() && keyEvent.getKeyCode() != 0 && (iconKeyStroke.getModifiers() & InputEvent.SHIFT_MASK) == (keyEvent.getModifiers() & InputEvent.SHIFT_MASK) || keyEvent .getKeyChar() == iconKeyStroke.getKeyChar()) && keyEvent.getKeyChar() != 0 && keyEvent.getKeyChar() != KeyEvent.CHAR_UNDEFINED) { return i; } } return -1; } /** * Transfer shift masks from InputEvent to ActionEvent. But, why don't they * use the same constants???? Java miracle. */ public int getModifiers() { int m = mModifiers; if ((mModifiers & (ActionEvent.SHIFT_MASK | InputEvent.SHIFT_DOWN_MASK)) != 0) { m |= ActionEvent.SHIFT_MASK; } if ((mModifiers & (ActionEvent.CTRL_MASK | InputEvent.CTRL_DOWN_MASK)) != 0) { m |= ActionEvent.CTRL_MASK; } if ((mModifiers & (ActionEvent.META_MASK | InputEvent.META_DOWN_MASK)) != 0) { m |= ActionEvent.META_MASK; } if ((mModifiers & (ActionEvent.ALT_MASK | InputEvent.ALT_DOWN_MASK)) != 0) { m |= ActionEvent.ALT_MASK; } return m; } private Position getPosition(final JLabel caller) { int index = 0; for (index = 0; index < iconLabels.length; index++) { if (caller == iconLabels[index]) { break; } } return new Position(index % xDimension, index / xDimension); } public int getResult() { return result; } private Position getSelectedPosition() { return selected; } private void highlight(final Position position) { iconLabels[calculateIndex(position)].setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED)); } /* * (non-Javadoc) * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent) */ public void keyPressed(final KeyEvent keyEvent) { switch (keyEvent.getKeyCode()) { case KeyEvent.VK_RIGHT: case KeyEvent.VK_KP_RIGHT: cursorRight(); return; case KeyEvent.VK_LEFT: case KeyEvent.VK_KP_LEFT: cursorLeft(); return; case KeyEvent.VK_DOWN: case KeyEvent.VK_KP_DOWN: cursorDown(); return; case KeyEvent.VK_UP: case KeyEvent.VK_KP_UP: cursorUp(); return; case KeyEvent.VK_ESCAPE: keyEvent.consume(); close(); return; case KeyEvent.VK_ENTER: case KeyEvent.VK_SPACE: keyEvent.consume(); addIcon(keyEvent.getModifiers()); return; } final int index = findIndexByKeyEvent(keyEvent); if (index != -1) { result = index; mModifiers = keyEvent.getModifiers(); keyEvent.consume(); this.dispose(); } } /* * (non-Javadoc) * @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent) */ public void keyReleased(final KeyEvent arg0) { } /* * (non-Javadoc) * @see java.awt.event.KeyListener#keyTyped(java.awt.event.KeyEvent) */ public void keyTyped(final KeyEvent arg0) { } /* * (non-Javadoc) * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent) */ public void mouseClicked(final MouseEvent mouseEvent) { addIcon(mouseEvent.getModifiers()); } /* * (non-Javadoc) * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent) */ public void mouseEntered(final MouseEvent arg0) { select(getPosition((JLabel) arg0.getSource())); } /* * (non-Javadoc) * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent) */ public void mouseExited(final MouseEvent arg0) { } /* * (non-Javadoc) * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent) */ public void mousePressed(final MouseEvent arg0) { } /* * (non-Javadoc) * @see * java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent) */ public void mouseReleased(final MouseEvent arg0) { } private void select(final Position position) { unhighlight(getSelectedPosition()); setSelectedPosition(position); highlight(position); final int index = calculateIndex(position); final IIconInformation iconInformation = icons.get(index); final String keyStroke = ResourceController.getResourceController().getProperty(iconInformation.getShortcutKey()); if (keyStroke != null) { descriptionLabel.setText(iconInformation.getDescription() + ", " + keyStroke); } else { descriptionLabel.setText(iconInformation.getDescription()); } } private void setSelectedPosition(final Position position) { selected = position; } private void unhighlight(final Position position) { iconLabels[calculateIndex(position)].setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED)); } }