package jav.gui.token.edit; import jav.gui.token.display.TokenVisualization; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.plaf.basic.BasicComboBoxUI; import javax.swing.plaf.basic.BasicComboPopup; /** *Copyright (c) 2012, IMPACT working group at the Centrum für Informations- und Sprachverarbeitung, University of Munich. *All rights reserved. *Redistribution and use in source and binary forms, with or without *modification, are permitted provided that the following conditions are met: *Redistributions of source code must retain the above copyright *notice, this list of conditions and the following disclaimer. *Redistributions in binary form must reproduce the above copyright *notice, this list of conditions and the following disclaimer in the *documentation and/or other materials provided with the distribution. *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS *IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT *HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, *DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY *THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE *OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * This file is part of the ocr-postcorrection tool developed * by the IMPACT working group at the Centrum für Informations- und Sprachverarbeitung, University of Munich. * For further information and contacts visit http://ocr.cis.uni-muenchen.de/ * * @author thorsten (thorsten.vobl@googlemail.com) */ public class LargerComboBoxUI extends BasicComboBoxUI { @Override protected BasicComboPopup createPopup() { return new LargerComboPopup(comboBox); } @Override protected void installComponents() { arrowButton = createArrowButton(); if (arrowButton != null) { comboBox.add(arrowButton); configureArrowButton(); } if (comboBox.isEditable()) { addEditor(); } comboBox.add(currentValuePane); } /* * disable arrowbutton */ @Override protected JButton createArrowButton() { return null; } @Override public void installUI(JComponent c) { super.installUI(c); comboBox.setLayout(new lm()); } /* * compute layout */ @Override protected Rectangle rectangleForCurrentValue() { int width = comboBox.getWidth(); int height = comboBox.getHeight(); Insets insets = getInsets(); int buttonSize = 0; return new Rectangle(insets.left, insets.top, width - (insets.left + insets.right + buttonSize), height - (insets.top + insets.bottom)); } /* * compute layout */ @Override public Dimension getMinimumSize(JComponent c) { if (!isMinimumSizeDirty) { return new Dimension(cachedMinimumSize); } Dimension size = getDisplaySize(); Insets insets = getInsets(); size.height += insets.top + insets.bottom; int buttonSize = 0; size.width += insets.left + insets.right + buttonSize; cachedMinimumSize.setSize(size.width, size.height); isMinimumSizeDirty = false; return new Dimension(size); } /* * replace the standard action map to disable popup closing */ @Override public void installKeyboardActions() { InputMap im = new InputMap(); im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "selectNext"); im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "selectPrevious"); im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "enterPressed"); im.put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0), "pageUpPassThrough"); im.put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0), "pageDownPassThrough"); // im.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "spacePopup"); // im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "hidePopup"); im.put(KeyStroke.getKeyStroke(KeyEvent.VK_KP_DOWN, 0), "selectNext"); im.put(KeyStroke.getKeyStroke(KeyEvent.VK_KP_UP, 0), "selectPrevious"); im.put(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0), "homePassThrough"); im.put(KeyStroke.getKeyStroke(KeyEvent.VK_END, 0), "endPassThrough"); SwingUtilities.replaceUIInputMap(comboBox, JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, im); ActionMap am = new ActionMap(); am.put("selectNext", new AbstractAction() { @Override public void actionPerformed(ActionEvent ae) { selectNextPossibleValue(); } }); am.put("selectPrevious", new AbstractAction() { @Override public void actionPerformed(ActionEvent ae) { selectPreviousPossibleValue(); } }); am.put("enterPressed", new AbstractAction() { @Override public void actionPerformed(ActionEvent ae) { } }); am.put("pageUpPassThrough", new AbstractAction() { @Override public void actionPerformed(ActionEvent ae) { int listHeight = comboBox.getMaximumRowCount(); int index = comboBox.getSelectedIndex() - listHeight; if( index < 0) { index = 0; } if (index >= 0 && index < comboBox.getItemCount()) { comboBox.setSelectedIndex(index); } } }); am.put("pageDownPassThrough", new AbstractAction() { @Override public void actionPerformed(ActionEvent ae) { int listHeight = comboBox.getMaximumRowCount(); int index = comboBox.getSelectedIndex() + listHeight; int max = comboBox.getItemCount(); if( index >= max) { index = max - 1; } comboBox.setSelectedIndex(index); } }); am.put("homePassThrough", new AbstractAction() { @Override public void actionPerformed(ActionEvent ae) { comboBox.setSelectedIndex(0); } }); am.put("endPassThrough", new AbstractAction() { @Override public void actionPerformed(ActionEvent ae) { comboBox.setSelectedIndex(comboBox.getItemCount() - 1); } }); SwingUtilities.replaceUIActionMap(comboBox, am); } public class LargerComboPopup extends BasicComboPopup { public LargerComboPopup(JComboBox comboBox) { super(comboBox); } /** * This method creates ListMouseListener to listen to mouse events occuring * in the combo box's item list. * * @return MouseListener to listen to mouse events occuring in the combo * box's items list. */ @Override protected MouseListener createListMouseListener() { return new ListMouseHandler(); } protected class ListMouseHandler extends MouseAdapter { protected ListMouseHandler() { } @Override public void mousePressed(MouseEvent anEvent) { } @Override public void mouseReleased(MouseEvent anEvent) { TokenVisualization tv = (TokenVisualization) comboBox.getParent(); if (anEvent.getButton() == MouseEvent.BUTTON1) { int index = list.locationToIndex(anEvent.getPoint()); if( ((ComboBoxEntry) comboBox.getItemAt(index)).getType() != ComboBoxEntryType.NORMAL ) { comboBox.setSelectedIndex(index); } tv.processEdit((ComboBoxEntry) comboBox.getSelectedItem()); } else if (anEvent.getButton() == MouseEvent.BUTTON3) { tv.abortTokenEditing(); } } } /** * Creates ListMouseMotionlistener to listen to mouse motion events occuring * in the combo box's list. This listener is responsible for highlighting * items in the list when mouse is moved over them. * * @return MouseMotionListener that handles mouse motion events occuring in * the list of the combo box. */ @Override protected MouseMotionListener createListMouseMotionListener() { return new ListMouseMotionHandler(); } /** * ListMouseMotionHandler listens to mouse motion events occuring in the * combo box's list. This class is responsible for highlighting items in * the list when mouse is moved over them */ protected class ListMouseMotionHandler extends MouseMotionAdapter { protected ListMouseMotionHandler() { } @Override public void mouseMoved(MouseEvent anEvent) { // Highlight list cells over which the mouse is located. // This changes list model, but has no effect on combo box's data model int index = list.locationToIndex(anEvent.getPoint()); list.setSelectedIndex(index); list.repaint(); if( ((ComboBoxEntry) comboBox.getItemAt(index)).getType() == ComboBoxEntryType.NORMAL ) { comboBox.setSelectedIndex(index); } } } @Override public void show() { int selectedIndex = comboBox.getSelectedIndex(); if (selectedIndex == -1) { list.clearSelection(); } else { list.setSelectedIndex(selectedIndex); list.ensureIndexIsVisible(selectedIndex); } Insets insets = getInsets(); Dimension listDim = list.getPreferredSize(); boolean hasScrollBar = scroller.getViewport().getViewSize().height != listDim.height; if (hasScrollBar) { JScrollBar scrollBar = scroller.getVerticalScrollBar(); listDim.width += scrollBar.getPreferredSize().getWidth(); } int width = Math.max(listDim.width, comboBox.getWidth() - (insets.right + insets.left)); int height = getPopupHeightForRowCount(comboBox.getMaximumRowCount()); Rectangle popupBounds = computePopupBounds(0, comboBox.getHeight(), width, height); Dimension scrollSize = popupBounds.getSize(); scroller.setMaximumSize(scrollSize); scroller.setPreferredSize(scrollSize); scroller.setMinimumSize(scrollSize); list.revalidate(); show(comboBox, popupBounds.x, popupBounds.y); } } class lm implements LayoutManager { @Override public void addLayoutComponent(String string, Component cmpnt) { } @Override public void removeLayoutComponent(Component cmpnt) { } @Override public Dimension preferredLayoutSize(Container parent) { return parent.getPreferredSize(); } @Override public Dimension minimumLayoutSize(Container parent) { return parent.getMinimumSize(); } @Override public void layoutContainer(Container parent) { Rectangle cvb; if (editor != null) { cvb = rectangleForCurrentValue(); editor.setBounds(cvb); } } } }