You are viewing a plain text version of this content. The canonical link for it is here.
Posted to batik-commits@xmlgraphics.apache.org by ca...@apache.org on 2007/11/13 01:40:58 UTC
svn commit: r594367 [7/9] - in /xmlgraphics/batik/trunk: ./
resources/org/apache/batik/apps/svgbrowser/resources/
resources/org/apache/batik/util/gui/resources/
sources-1.3/org/apache/batik/util/ sources-1.3/org/apache/batik/util/gui/
sources-1.4/org/a...
Added: xmlgraphics/batik/trunk/sources/org/apache/batik/util/gui/DropDownComponent.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/apache/batik/util/gui/DropDownComponent.java?rev=594367&view=auto
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/apache/batik/util/gui/DropDownComponent.java (added)
+++ xmlgraphics/batik/trunk/sources/org/apache/batik/util/gui/DropDownComponent.java Mon Nov 12 16:40:53 2007
@@ -0,0 +1,869 @@
+/*
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package org.apache.batik.util.gui;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.GridLayout;
+import java.awt.Point;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.EventListener;
+import java.util.EventObject;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+import javax.swing.BorderFactory;
+import javax.swing.Icon;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.JScrollPane;
+import javax.swing.ScrollPaneConstants;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.event.EventListenerList;
+import javax.swing.plaf.basic.BasicButtonUI;
+
+import org.apache.batik.util.resources.ResourceManager;
+
+/**
+ * The drop down menu component. Supports drop down popup menu and the main
+ * button.
+ *
+ * @version $Id$
+ */
+public class DropDownComponent extends JPanel {
+
+ /**
+ * The main button for this component.
+ */
+ private JButton mainButton;
+
+ /**
+ * The drop down button. When clicked the dropdown popup menu appears.
+ */
+ private JButton dropDownButton;
+
+ /**
+ * The icon for enabled drop down button.
+ */
+ private Icon enabledDownArrow;
+
+ /**
+ * The icon for disabled drop down button.
+ */
+ private Icon disabledDownArrow;
+
+ /**
+ * The scrollable pop up menu.
+ */
+ private ScrollablePopupMenu popupMenu;
+
+ /**
+ * If drop down menu appears when clicked on dropdown button.
+ */
+ private boolean isDropDownEnabled;
+
+ /**
+ * Creates the dropdown menu with the given main button.
+ *
+ * @param mainButton
+ * the components main button
+ */
+ public DropDownComponent(JButton mainButton) {
+ super(new BorderLayout());
+
+ // Initializes pop up menu
+ popupMenu = getPopupMenu();
+
+ this.mainButton = mainButton;
+ add(this.mainButton, BorderLayout.WEST);
+ this.mainButton.setMaximumSize(new Dimension(24, 24));
+ this.mainButton.setPreferredSize(new Dimension(24, 24));
+
+ // Initializes dropdown button and icons for dropdown button
+ enabledDownArrow = new SmallDownArrow();
+ disabledDownArrow = new SmallDisabledDownArrow();
+ dropDownButton = new JButton(disabledDownArrow);
+ dropDownButton.setDisabledIcon(disabledDownArrow);
+ dropDownButton.addMouseListener(new DropDownListener());
+ dropDownButton.setMaximumSize(new Dimension(18, 24));
+ dropDownButton.setMinimumSize(new Dimension(18, 10));
+ dropDownButton.setPreferredSize(new Dimension(18, 10));
+ dropDownButton.setFocusPainted(false);
+ add(dropDownButton, BorderLayout.EAST);
+
+ setEnabled(false);
+ }
+
+ /**
+ * Gets the dropdown popup menu.
+ *
+ * @return ScrollablePopupMenu
+ */
+ public ScrollablePopupMenu getPopupMenu() {
+ if (popupMenu == null) {
+ popupMenu = new ScrollablePopupMenu(this);
+ popupMenu.setEnabled(false);
+ // If the pop up menu gets disabled,
+ // the dropdown buttons should be disabled as well
+ popupMenu.addPropertyChangeListener
+ ("enabled",
+ new PropertyChangeListener() {
+ public void propertyChange(PropertyChangeEvent evt) {
+ setEnabled
+ (((Boolean) evt.getNewValue()).booleanValue());
+ }
+ });
+
+ // Listens for the changes in the scrollable pop up menu
+ popupMenu.addListener
+ (new ScrollablePopupMenuAdapter() {
+
+ public void itemsWereAdded(ScrollablePopupMenuEvent ev) {
+ updateMainButtonTooltip(ev.getDetails());
+ }
+
+ public void itemsWereRemoved(ScrollablePopupMenuEvent ev) {
+ updateMainButtonTooltip(ev.getDetails());
+ }
+ });
+ }
+ return popupMenu;
+ }
+
+ public void setEnabled(boolean enable) {
+ isDropDownEnabled = enable;
+ mainButton.setEnabled(enable);
+ dropDownButton.setEnabled(enable);
+ dropDownButton.setIcon(enable ? enabledDownArrow : disabledDownArrow);
+ }
+
+ public boolean isEnabled() {
+ return isDropDownEnabled;
+ }
+
+ /**
+ * Sets new tooltip text to the main button.
+ *
+ * @param newTooltip
+ * the new tooltip text
+ */
+ public void updateMainButtonTooltip(String newTooltip) {
+ mainButton.setToolTipText(newTooltip);
+ }
+
+ /**
+ * Shows the pop up menu when clicked.
+ */
+ private class DropDownListener extends MouseAdapter {
+ public void mousePressed(MouseEvent e) {
+ if (popupMenu.isShowing() && isDropDownEnabled) {
+ popupMenu.setVisible(false);
+ } else if (isDropDownEnabled) {
+ popupMenu.showMenu
+ ((Component) e.getSource(), DropDownComponent.this);
+ }
+ }
+ }
+
+ /**
+ * A small downward-pointing arrow icon.
+ */
+ private static class SmallDownArrow implements Icon {
+
+ /**
+ * The arrow color.
+ */
+ protected Color arrowColor = Color.black;
+
+ public void paintIcon(Component c, Graphics g, int x, int y) {
+ g.setColor(arrowColor);
+ g.drawLine(x, y, x + 4, y);
+ g.drawLine(x + 1, y + 1, x + 3, y + 1);
+ g.drawLine(x + 2, y + 2, x + 2, y + 2);
+ }
+
+ public int getIconWidth() {
+ return 6;
+ }
+
+ public int getIconHeight() {
+ return 4;
+ }
+ }
+
+ /**
+ * A disabled small downward-pointing arrow icon.
+ */
+ private static class SmallDisabledDownArrow extends SmallDownArrow {
+
+ /**
+ * Constructor.
+ */
+ public SmallDisabledDownArrow() {
+ arrowColor = new Color(140, 140, 140);
+ }
+
+ public void paintIcon(Component c, Graphics g, int x, int y) {
+ super.paintIcon(c, g, x, y);
+ g.setColor(Color.white);
+ g.drawLine(x + 3, y + 2, x + 4, y + 1);
+ g.drawLine(x + 3, y + 3, x + 5, y + 1);
+ }
+ }
+
+ /**
+ * The scrollable pop up menu item.
+ */
+ public static interface ScrollablePopupMenuItem {
+
+ /**
+ * Selects and deselects the item.
+ *
+ * @param selected
+ * is selected
+ */
+ void setSelected(boolean selected);
+
+ /**
+ * Checks if the item is selected.
+ *
+ * @return True if selected
+ */
+ boolean isSelected();
+
+ /**
+ * Returns the item name.
+ *
+ * @return the name
+ */
+ String getText();
+
+ /**
+ * Sets the item name.
+ *
+ * @param text
+ * The new item name
+ */
+ void setText(String text);
+
+ /**
+ * Enables / disables the item
+ *
+ * @param enabled
+ * True - enables the item
+ */
+ void setEnabled(boolean enabled);
+ }
+
+ /**
+ * Default implementation of the scrollable popup menu item.
+ */
+ public static class DefaultScrollablePopupMenuItem extends JButton
+ implements ScrollablePopupMenuItem {
+
+ /**
+ * The selected item background color.
+ */
+ public static final Color MENU_HIGHLIGHT_BG_COLOR =
+ UIManager.getColor("MenuItem.selectionBackground");
+
+ /**
+ * The selected item foreground color.
+ */
+ public static final Color MENU_HIGHLIGHT_FG_COLOR =
+ UIManager.getColor("MenuItem.selectionForeground");
+
+ /**
+ * The item background color.
+ */
+ public static final Color MENUITEM_BG_COLOR =
+ UIManager.getColor("MenuItem.background");
+
+ /**
+ * The item foreground color.
+ */
+ public static final Color MENUITEM_FG_COLOR =
+ UIManager.getColor("MenuItem.foreground");
+
+ /**
+ * The parent scrollable popup menu.
+ */
+ private ScrollablePopupMenu parent;
+
+ /**
+ * Constructor.
+ */
+ public DefaultScrollablePopupMenuItem(ScrollablePopupMenu parent,
+ String text) {
+ super(text);
+ this.parent = parent;
+ init();
+ }
+
+ /**
+ * Initializes this item.
+ */
+ private void init() {
+ this.setUI(BasicButtonUI.createUI(this));
+ setBorder(BorderFactory.createEmptyBorder(5, 15, 5, 20));
+ setMenuItemDefaultColors();
+ this.setAlignmentX(JButton.LEFT_ALIGNMENT);
+ setSelected(false);
+
+ this.addMouseListener
+ (new MouseAdapter() {
+
+ public void mouseEntered(MouseEvent e) {
+ if (DefaultScrollablePopupMenuItem.this.isEnabled()) {
+ setSelected(true);
+ parent.selectionChanged
+ (DefaultScrollablePopupMenuItem.this, true);
+ }
+ }
+
+ public void mouseExited(MouseEvent e) {
+ if (DefaultScrollablePopupMenuItem.this.isEnabled()) {
+ setSelected(false);
+ parent.selectionChanged
+ (DefaultScrollablePopupMenuItem.this, false);
+ }
+ }
+
+ public void mouseClicked(MouseEvent e) {
+ parent.processItemClicked();
+ }
+ });
+ }
+
+ /**
+ * Sets the default item colors.
+ */
+ private void setMenuItemDefaultColors() {
+ setBackground(MENUITEM_BG_COLOR);
+ setForeground(MENUITEM_FG_COLOR);
+ }
+
+ public void setSelected(boolean selected) {
+ super.setSelected(selected);
+ if (selected) {
+ setBackground(MENU_HIGHLIGHT_BG_COLOR);
+ setForeground(MENU_HIGHLIGHT_FG_COLOR);
+ } else {
+ setMenuItemDefaultColors();
+ }
+ }
+
+ public String getText() {
+ return super.getText();
+ }
+
+ public void setText(String text) {
+ super.setText(text);
+ }
+
+ public void setEnabled(boolean b) {
+ super.setEnabled(b);
+ }
+ }
+
+ /**
+ * The scrollable popup menu model.
+ */
+ public static interface ScrollablePopupMenuModel {
+
+ /**
+ * Gets the footer text for the ScrollablePopupMenu's footer item.
+ * @return the footer text.
+ */
+ String getFooterText();
+
+ /**
+ * Processes the click on the pop up menu item.
+ */
+ void processItemClicked();
+
+ /**
+ * Processes the showing of the pop up menu. Invoked before showing the
+ * pop up menu
+ */
+ void processBeforeShowed();
+
+ /**
+ * Processes the showing of the pop up menu. Invoked after showing the
+ * pop up menu
+ */
+ void processAfterShowed();
+ }
+
+ /**
+ * The Scrollable Popup Menu Component.
+ */
+ public static class ScrollablePopupMenu extends JPopupMenu {
+
+ /**
+ * The resource file name.
+ */
+ private static final String RESOURCES =
+ "org.apache.batik.util.gui.resources.ScrollablePopupMenuMessages";
+
+ /**
+ * The resource bundle.
+ */
+ private static ResourceBundle bundle;
+
+ /**
+ * The resource manager.
+ */
+ private static ResourceManager resources;
+ static {
+ bundle = ResourceBundle.getBundle(RESOURCES, Locale.getDefault());
+ resources = new ResourceManager(bundle);
+ }
+
+ /**
+ * The menu panel.
+ */
+ private JPanel menuPanel = new JPanel();
+
+ /**
+ * The scroll pane.
+ */
+ private JScrollPane scrollPane;
+
+ /**
+ * Max menu height.
+ */
+ private int preferredHeight = resources.getInteger("PreferredHeight");
+
+ /**
+ * The model for this component.
+ */
+ private ScrollablePopupMenuModel model;
+
+ /**
+ * The owner component.
+ */
+ private JComponent ownerComponent;
+
+ /**
+ * Footer item. Should be always shown at the bottom of this pop up.
+ */
+ private ScrollablePopupMenuItem footer;
+
+ /**
+ * Listeners list.
+ */
+ private EventListenerList eventListeners = new EventListenerList();
+
+ /**
+ * Constructor.
+ *
+ * @param owner
+ * The owner component
+ */
+ public ScrollablePopupMenu(JComponent owner) {
+ super();
+ this.setLayout(new BorderLayout());
+ menuPanel.setLayout(new GridLayout(0, 1));
+ ownerComponent = owner;
+ init();
+ }
+
+ /**
+ * Initializes this popup menu.
+ */
+ private void init() {
+ super.removeAll();
+ scrollPane = new JScrollPane();
+ scrollPane.setViewportView(menuPanel);
+ scrollPane.setBorder(null);
+ int minWidth = resources.getInteger("ScrollPane.minWidth");
+ int minHeight = resources.getInteger("ScrollPane.minHeight");
+ int maxWidth = resources.getInteger("ScrollPane.maxWidth");
+ int maxHeight = resources.getInteger("ScrollPane.maxHeight");
+ scrollPane.setMinimumSize(new Dimension(minWidth, minHeight));
+ scrollPane.setMaximumSize(new Dimension(maxWidth, maxHeight));
+ scrollPane.setHorizontalScrollBarPolicy
+ (ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
+ add(scrollPane, BorderLayout.CENTER);
+ addFooter(new DefaultScrollablePopupMenuItem(this, ""));
+ }
+
+ /**
+ * Shows this popup menu.
+ *
+ * @param invoker
+ * The popup menu invoker component
+ * @param refComponent
+ * The dropdown component that containts this menu
+ */
+ public void showMenu(Component invoker, Component refComponent) {
+ model.processBeforeShowed();
+
+ Point abs = new Point(0, refComponent.getHeight());
+ SwingUtilities.convertPointToScreen(abs, refComponent);
+ this.setLocation(abs);
+ this.setInvoker(invoker);
+ this.setVisible(true);
+ this.revalidate();
+ this.repaint();
+
+ model.processAfterShowed();
+ }
+
+ /**
+ * Adds the item to this component at the specified location.
+ *
+ * @param menuItem
+ * the item to add
+ */
+ public void add(ScrollablePopupMenuItem menuItem, int index,
+ int oldSize, int newSize) {
+ menuPanel.add((Component) menuItem, index);
+ if (oldSize == 0) {
+ this.setEnabled(true);
+ }
+ }
+
+ /**
+ * Removes the item from this component.
+ *
+ * @param menuItem
+ * the item to remove
+ */
+ public void remove(ScrollablePopupMenuItem menuItem, int oldSize,
+ int newSize) {
+ menuPanel.remove((Component) menuItem);
+ if (newSize == 0) {
+ this.setEnabled(false);
+ }
+ }
+
+ /**
+ * Gets the preferred width of this pop up menu.
+ *
+ * @return the preferred width
+ */
+ private int getPreferredWidth() {
+ Component[] components = menuPanel.getComponents();
+ int maxWidth = 0;
+ for (int i = 0; i < components.length; i++) {
+ int currentWidth = components[i].getPreferredSize().width;
+ if (maxWidth < currentWidth) {
+ maxWidth = currentWidth;
+ }
+ }
+ int footerWidth = ((Component) footer).getPreferredSize().width;
+ if (footerWidth > maxWidth) {
+ maxWidth = footerWidth;
+ }
+ int widthOffset = 30;
+ return maxWidth + widthOffset;
+ }
+
+ /**
+ * Gets the preferred height of this component.
+ *
+ * @return the preferred height
+ */
+ private int getPreferredHeight() {
+ if (scrollPane.getPreferredSize().height < preferredHeight) {
+ int heightOffset = 10;
+ return scrollPane.getPreferredSize().height
+ + ((Component) footer).getPreferredSize().height
+ + heightOffset;
+ }
+ return preferredHeight
+ + ((Component) footer).getPreferredSize().height;
+ }
+
+ public Dimension getPreferredSize() {
+ return new Dimension(getPreferredWidth(), getPreferredHeight());
+ }
+
+ /**
+ * Invoked when item selection changes.
+ */
+ public void selectionChanged(ScrollablePopupMenuItem targetItem,
+ boolean wasSelected) {
+ Component[] comps = menuPanel.getComponents();
+ int n = comps.length;
+ // Deselect all if something was selected
+ if (!wasSelected) {
+ for (int i = n - 1; i >= 0; i--) {
+ ScrollablePopupMenuItem item = (ScrollablePopupMenuItem) comps[i];
+ item.setSelected(wasSelected);
+ }
+ } else {
+ for (int i = 0; i < n; i++) {
+ ScrollablePopupMenuItem item = (ScrollablePopupMenuItem) comps[i];
+ if (item == targetItem) {
+ break;
+ }
+ item.setSelected(true);
+ }
+ }
+ footer.setText(model.getFooterText() + getSelectedItemsCount());
+ repaint();
+ }
+
+ /**
+ * Sets the ScrollablePopupMenuModel.
+ *
+ * @param model
+ * the model to set
+ */
+ public void setModel(ScrollablePopupMenuModel model) {
+ this.model = model;
+ this.footer.setText(model.getFooterText());
+ }
+
+ /**
+ * Gets the ScrollablePopupMenuModel
+ *
+ * @return the ScrollablePopupMenuModel model
+ */
+ public ScrollablePopupMenuModel getModel() {
+ return model;
+ }
+
+ /**
+ * Gets the number of the selected items.
+ *
+ * @return number of selected items
+ */
+ public int getSelectedItemsCount() {
+ int selectionCount = 0;
+ Component[] components = menuPanel.getComponents();
+ for (int i = 0; i < components.length; i++) {
+ ScrollablePopupMenuItem item = (ScrollablePopupMenuItem) components[i];
+ if (item.isSelected()) {
+ selectionCount++;
+ }
+ }
+ return selectionCount;
+ }
+
+ /**
+ * Processes click on the pop up menu item.
+ */
+ public void processItemClicked() {
+ footer.setText(model.getFooterText() + 0);
+ setVisible(false);
+ model.processItemClicked();
+ }
+
+ /**
+ * Gets the owner component.
+ * @return the owner component
+ */
+ public JComponent getOwner() {
+ return ownerComponent;
+ }
+
+ /**
+ * Adds the footer item to this pop up menu.
+ */
+ private void addFooter(ScrollablePopupMenuItem footer) {
+ this.footer = footer;
+ this.footer.setEnabled(false);
+ add((Component)this.footer, BorderLayout.SOUTH);
+ }
+
+ /**
+ * Gets the footer item.
+ * @return the footer
+ */
+ public ScrollablePopupMenuItem getFooter() {
+ return footer;
+ }
+
+ /**
+ * Adds the listener to the listener list.
+ *
+ * @param l
+ * The listener to add
+ */
+ public void addListener(ScrollablePopupMenuListener listener) {
+ eventListeners.add(ScrollablePopupMenuListener.class, listener);
+ }
+
+ /**
+ * Fires the itemsWereAdded event, when the items are added to this pop
+ * up menu.
+ *
+ * @param event
+ * The associated ScrollablePopupMenuEvent event
+ */
+ public void fireItemsWereAdded(ScrollablePopupMenuEvent event) {
+ Object[] listeners = eventListeners.getListenerList();
+ int length = listeners.length;
+ for (int i = 0; i < length; i += 2) {
+ if (listeners[i] == ScrollablePopupMenuListener.class) {
+ ((ScrollablePopupMenuListener) listeners[i + 1])
+ .itemsWereAdded(event);
+ }
+ }
+ }
+
+ /**
+ * Fires the itemsWereRemove event, when the items are removed from this
+ * pop up menu.
+ *
+ * @param event
+ * The associated ScrollablePopupMenuEvent event
+ */
+ public void fireItemsWereRemoved(ScrollablePopupMenuEvent event) {
+ Object[] listeners = eventListeners.getListenerList();
+ int length = listeners.length;
+ for (int i = 0; i < length; i += 2) {
+ if (listeners[i] == ScrollablePopupMenuListener.class) {
+ ((ScrollablePopupMenuListener) listeners[i + 1])
+ .itemsWereRemoved(event);
+ }
+ }
+ }
+ }
+
+ // Custom event support for ScrollablePopupMenu
+
+ /**
+ * Event to pass to listener.
+ */
+ public static class ScrollablePopupMenuEvent extends EventObject {
+
+ // The codes for the event type
+ public static final int ITEMS_ADDED = 1;
+ public static final int ITEMS_REMOVED = 2;
+
+ /**
+ * The event type.
+ */
+ private int type;
+
+ /**
+ * The number of items that were added / removed.
+ */
+ private int itemNumber;
+
+ /**
+ * The details about the event.
+ */
+ private String details;
+
+ /**
+ * Creates the ScrollablePopupMenuEvent.
+ *
+ * @param source
+ * The source component
+ * @param type
+ * The event type
+ * @param itemNumber
+ * The item number
+ * @param details
+ * The event details
+ */
+ public ScrollablePopupMenuEvent(Object source, int type,
+ int itemNumber, String details) {
+ super(source);
+ initEvent(type, itemNumber, details);
+ }
+
+ /**
+ * Initializes this event.
+ */
+ public void initEvent(int type, int itemNumber, String details) {
+ this.type = type;
+ this.itemNumber = itemNumber;
+ this.details = details;
+ }
+
+ /**
+ * Gets the event details.
+ *
+ * @return the details
+ */
+ public String getDetails() {
+ return details;
+ }
+
+ /**
+ * Gets the item number.
+ *
+ * @return the item number
+ */
+ public int getItemNumber() {
+ return itemNumber;
+ }
+
+ /**
+ * Gets the event type.
+ *
+ * @return the type
+ */
+ public int getType() {
+ return type;
+ }
+ }
+
+ /**
+ * The ScrollablePopupMenu listener. Handles the events that
+ * ScrollablePopupMenu fires
+ */
+ public static interface ScrollablePopupMenuListener extends EventListener {
+
+ /**
+ * Handles the 'itemsWereAdded' event.
+ *
+ * @param ev
+ * The associated event
+ */
+ void itemsWereAdded(ScrollablePopupMenuEvent ev);
+
+ /**
+ * Handles the 'itemsWereRemoved' event.
+ *
+ * @param ev
+ * The associated event
+ */
+ void itemsWereRemoved(ScrollablePopupMenuEvent ev);
+ }
+
+ /**
+ * The adapter for the ScrollablePopupMenuListener.
+ */
+ public static class ScrollablePopupMenuAdapter
+ implements ScrollablePopupMenuListener {
+
+ public void itemsWereAdded(ScrollablePopupMenuEvent ev) {
+ }
+
+ public void itemsWereRemoved(ScrollablePopupMenuEvent ev) {
+ }
+ }
+}
Modified: xmlgraphics/batik/trunk/sources/org/apache/batik/util/gui/resource/ButtonFactory.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/apache/batik/util/gui/resource/ButtonFactory.java?rev=594367&r1=594366&r2=594367&view=diff
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/apache/batik/util/gui/resource/ButtonFactory.java (original)
+++ xmlgraphics/batik/trunk/sources/org/apache/batik/util/gui/resource/ButtonFactory.java Mon Nov 12 16:40:53 2007
@@ -28,6 +28,7 @@
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JRadioButton;
+import javax.swing.JToggleButton;
import org.apache.batik.util.resources.ResourceFormatException;
import org.apache.batik.util.resources.ResourceManager;
@@ -120,6 +121,31 @@
result = new JToolbarButton(getString(name+TEXT_SUFFIX));
} catch (MissingResourceException e) {
result = new JToolbarButton();
+ }
+ initializeButton(result, name);
+ return result;
+ }
+
+ /**
+ * Creates and returns a new swing button initialised
+ * to be used as a toolbar toggle button
+ * @param name the name of the button in the resource bundle
+ * @throws MissingResourceException if key is not the name of a button.
+ * It is not thrown if the mnemonic and the action keys are missing
+ * @throws ResourceFormatException if the mnemonic is not a single
+ * character
+ * @throws MissingListenerException if the button action is not found in
+ * the action map
+ */
+ public JToggleButton createJToolbarToggleButton(String name)
+ throws MissingResourceException,
+ ResourceFormatException,
+ MissingListenerException {
+ JToggleButton result;
+ try {
+ result = new JToolbarToggleButton(getString(name+TEXT_SUFFIX));
+ } catch (MissingResourceException e) {
+ result = new JToolbarToggleButton();
}
initializeButton(result, name);
return result;
Added: xmlgraphics/batik/trunk/sources/org/apache/batik/util/gui/resource/JToolbarToggleButton.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/apache/batik/util/gui/resource/JToolbarToggleButton.java?rev=594367&view=auto
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/apache/batik/util/gui/resource/JToolbarToggleButton.java (added)
+++ xmlgraphics/batik/trunk/sources/org/apache/batik/util/gui/resource/JToolbarToggleButton.java Mon Nov 12 16:40:53 2007
@@ -0,0 +1,82 @@
+/*
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package org.apache.batik.util.gui.resource;
+
+import java.awt.Insets;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+
+import javax.swing.JToggleButton;
+import javax.swing.UIManager;
+
+/**
+ * This class represents the buttons used in toolbars.
+ *
+ * @version $Id: JToolbarButton.java 498555 2007-01-22 08:09:33Z cam $
+ */
+public class JToolbarToggleButton extends JToggleButton {
+
+ /**
+ * Creates a new toolbar button.
+ */
+ public JToolbarToggleButton() {
+ initialize();
+ }
+
+ /**
+ * Creates a new toolbar button.
+ * @param txt The button text.
+ */
+ public JToolbarToggleButton(String txt) {
+ super(txt);
+ initialize();
+ }
+
+ /**
+ * Initializes the button.
+ */
+ protected void initialize() {
+ if (!System.getProperty("java.version").startsWith("1.3")) {
+ setOpaque(false);
+ setBackground(new java.awt.Color(0, 0, 0, 0));
+ }
+ setBorderPainted(false);
+ setMargin(new Insets(2, 2, 2, 2));
+
+ // Windows XP look and feel seems to have a bug due to which the
+ // size of the parent container changes when the border painted
+ // property is set. Temporary fix: disable mouseover behavior if
+ // installed lnf is Windows XP
+ if (!UIManager.getLookAndFeel().getName().equals("Windows")) {
+ addMouseListener(new MouseListener());
+ }
+ }
+
+ /**
+ * To manage the mouse interactions.
+ */
+ protected class MouseListener extends MouseAdapter {
+ public void mouseEntered(MouseEvent ev) {
+ setBorderPainted(true);
+ }
+ public void mouseExited(MouseEvent ev) {
+ setBorderPainted(false);
+ }
+ }
+}
Added: xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/DefaultInputHandler.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/DefaultInputHandler.java?rev=594367&view=auto
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/DefaultInputHandler.java (added)
+++ xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/DefaultInputHandler.java Mon Nov 12 16:40:53 2007
@@ -0,0 +1,347 @@
+/*
+ * DefaultInputHandler.java - Default implementation of an input handler
+ * Copyright (C) 1999 Slava Pestov
+ *
+ * You may use and modify this package for any purpose. Redistribution is
+ * permitted, in both source and binary form, provided that this notice
+ * remains intact in all source distributions of this package.
+ */
+package org.gjt.sp.jedit.textarea;
+
+import javax.swing.KeyStroke;
+import java.awt.event.*;
+import java.awt.Toolkit;
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+
+/**
+ * The default input handler. It maps sequences of keystrokes into actions
+ * and inserts key typed events into the text area.
+ * @author Slava Pestov
+ * @version $Id: DefaultInputHandler.java,v 1.18 1999/12/13 03:40:30 sp Exp $
+ */
+public class DefaultInputHandler extends InputHandler
+{
+ /**
+ * Creates a new input handler with no key bindings defined.
+ */
+ public DefaultInputHandler()
+ {
+ bindings = currentBindings = new Hashtable();
+ }
+
+ /**
+ * Sets up the default key bindings.
+ */
+ public void addDefaultKeyBindings()
+ {
+ addKeyBinding("BACK_SPACE",BACKSPACE);
+ addKeyBinding("C+BACK_SPACE",BACKSPACE_WORD);
+ addKeyBinding("DELETE",DELETE);
+ addKeyBinding("C+DELETE",DELETE_WORD);
+
+ addKeyBinding("ENTER",INSERT_BREAK);
+ addKeyBinding("TAB",INSERT_TAB);
+
+ addKeyBinding("INSERT",OVERWRITE);
+ addKeyBinding("C+\\",TOGGLE_RECT);
+
+ addKeyBinding("HOME",HOME);
+ addKeyBinding("END",END);
+ addKeyBinding("S+HOME",SELECT_HOME);
+ addKeyBinding("S+END",SELECT_END);
+ addKeyBinding("C+HOME",DOCUMENT_HOME);
+ addKeyBinding("C+END",DOCUMENT_END);
+ addKeyBinding("CS+HOME",SELECT_DOC_HOME);
+ addKeyBinding("CS+END",SELECT_DOC_END);
+
+ addKeyBinding("PAGE_UP",PREV_PAGE);
+ addKeyBinding("PAGE_DOWN",NEXT_PAGE);
+ addKeyBinding("S+PAGE_UP",SELECT_PREV_PAGE);
+ addKeyBinding("S+PAGE_DOWN",SELECT_NEXT_PAGE);
+
+ addKeyBinding("LEFT",PREV_CHAR);
+ addKeyBinding("S+LEFT",SELECT_PREV_CHAR);
+ addKeyBinding("C+LEFT",PREV_WORD);
+ addKeyBinding("CS+LEFT",SELECT_PREV_WORD);
+ addKeyBinding("RIGHT",NEXT_CHAR);
+ addKeyBinding("S+RIGHT",SELECT_NEXT_CHAR);
+ addKeyBinding("C+RIGHT",NEXT_WORD);
+ addKeyBinding("CS+RIGHT",SELECT_NEXT_WORD);
+ addKeyBinding("UP",PREV_LINE);
+ addKeyBinding("S+UP",SELECT_PREV_LINE);
+ addKeyBinding("DOWN",NEXT_LINE);
+ addKeyBinding("S+DOWN",SELECT_NEXT_LINE);
+
+ addKeyBinding("C+ENTER",REPEAT);
+ }
+
+ /**
+ * Adds a key binding to this input handler. The key binding is
+ * a list of white space separated key strokes of the form
+ * <i>[modifiers+]key</i> where modifier is C for Control, A for Alt,
+ * or S for Shift, and key is either a character (a-z) or a field
+ * name in the KeyEvent class prefixed with VK_ (e.g., BACK_SPACE)
+ * @param keyBinding The key binding
+ * @param action The action
+ */
+ public void addKeyBinding(String keyBinding, ActionListener action)
+ {
+ Hashtable current = bindings;
+
+ StringTokenizer st = new StringTokenizer(keyBinding);
+ while(st.hasMoreTokens())
+ {
+ KeyStroke keyStroke = parseKeyStroke(st.nextToken());
+ if(keyStroke == null)
+ return;
+
+ if(st.hasMoreTokens())
+ {
+ Object o = current.get(keyStroke);
+ if(o instanceof Hashtable)
+ current = (Hashtable)o;
+ else
+ {
+ o = new Hashtable();
+ current.put(keyStroke,o);
+ current = (Hashtable)o;
+ }
+ }
+ else
+ current.put(keyStroke,action);
+ }
+ }
+
+ /**
+ * Removes a key binding from this input handler. This is not yet
+ * implemented.
+ * @param keyBinding The key binding
+ */
+ public void removeKeyBinding(String keyBinding)
+ {
+ throw new InternalError("Not yet implemented");
+ }
+
+ /**
+ * Removes all key bindings from this input handler.
+ */
+ public void removeAllKeyBindings()
+ {
+ bindings.clear();
+ }
+
+ /**
+ * Returns a copy of this input handler that shares the same
+ * key bindings. Setting key bindings in the copy will also
+ * set them in the original.
+ */
+ public InputHandler copy()
+ {
+ return new DefaultInputHandler(this);
+ }
+
+ /**
+ * Handle a key pressed event. This will look up the binding for
+ * the key stroke and execute it.
+ */
+ public void keyPressed(KeyEvent evt)
+ {
+ int keyCode = evt.getKeyCode();
+ int modifiers = evt.getModifiers();
+
+ if(keyCode == KeyEvent.VK_CONTROL ||
+ keyCode == KeyEvent.VK_SHIFT ||
+ keyCode == KeyEvent.VK_ALT ||
+ keyCode == KeyEvent.VK_META)
+ return;
+
+ if((modifiers & ~KeyEvent.SHIFT_MASK) != 0
+ || evt.isActionKey()
+ || keyCode == KeyEvent.VK_BACK_SPACE
+ || keyCode == KeyEvent.VK_DELETE
+ || keyCode == KeyEvent.VK_ENTER
+ || keyCode == KeyEvent.VK_TAB
+ || keyCode == KeyEvent.VK_ESCAPE)
+ {
+ if(grabAction != null)
+ {
+ handleGrabAction(evt);
+ return;
+ }
+
+ KeyStroke keyStroke = KeyStroke.getKeyStroke(keyCode,
+ modifiers);
+ Object o = currentBindings.get(keyStroke);
+ if(o == null)
+ {
+ // Don't beep if the user presses some
+ // key we don't know about unless a
+ // prefix is active. Otherwise it will
+ // beep when caps lock is pressed, etc.
+ if(currentBindings != bindings)
+ {
+ Toolkit.getDefaultToolkit().beep();
+ // F10 should be passed on, but C+e F10
+ // shouldn't
+ repeatCount = 0;
+ repeat = false;
+ evt.consume();
+ }
+ currentBindings = bindings;
+ return;
+ }
+ else if(o instanceof ActionListener)
+ {
+ currentBindings = bindings;
+
+ executeAction(((ActionListener)o),
+ evt.getSource(),null);
+
+ evt.consume();
+ return;
+ }
+ else if(o instanceof Hashtable)
+ {
+ currentBindings = (Hashtable)o;
+ evt.consume();
+ return;
+ }
+ }
+ }
+
+ /**
+ * Handle a key typed event. This inserts the key into the text area.
+ */
+ public void keyTyped(KeyEvent evt)
+ {
+ int modifiers = evt.getModifiers();
+ char c = evt.getKeyChar();
+ if(c != KeyEvent.CHAR_UNDEFINED &&
+ (modifiers & KeyEvent.ALT_MASK) == 0)
+ {
+ if(c >= 0x20 && c != 0x7f)
+ {
+ KeyStroke keyStroke = KeyStroke.getKeyStroke(
+ Character.toUpperCase(c));
+ Object o = currentBindings.get(keyStroke);
+
+ if(o instanceof Hashtable)
+ {
+ currentBindings = (Hashtable)o;
+ return;
+ }
+ else if(o instanceof ActionListener)
+ {
+ currentBindings = bindings;
+ executeAction((ActionListener)o,
+ evt.getSource(),
+ String.valueOf(c));
+ return;
+ }
+
+ currentBindings = bindings;
+
+ if(grabAction != null)
+ {
+ handleGrabAction(evt);
+ return;
+ }
+
+ // 0-9 adds another 'digit' to the repeat number
+ if(repeat && Character.isDigit(c))
+ {
+ repeatCount *= 10;
+ repeatCount += (c - '0');
+ return;
+ }
+
+ executeAction(INSERT_CHAR,evt.getSource(),
+ String.valueOf(evt.getKeyChar()));
+
+ repeatCount = 0;
+ repeat = false;
+ }
+ }
+ }
+
+ /**
+ * Converts a string to a keystroke. The string should be of the
+ * form <i>modifiers</i>+<i>shortcut</i> where <i>modifiers</i>
+ * is any combination of A for Alt, C for Control, S for Shift
+ * or M for Meta, and <i>shortcut</i> is either a single character,
+ * or a keycode name from the <code>KeyEvent</code> class, without
+ * the <code>VK_</code> prefix.
+ * @param keyStroke A string description of the key stroke
+ */
+ public static KeyStroke parseKeyStroke(String keyStroke)
+ {
+ if(keyStroke == null)
+ return null;
+ int modifiers = 0;
+ int index = keyStroke.indexOf('+');
+ if(index != -1)
+ {
+ for(int i = 0; i < index; i++)
+ {
+ switch(Character.toUpperCase(keyStroke
+ .charAt(i)))
+ {
+ case 'A':
+ modifiers |= InputEvent.ALT_MASK;
+ break;
+ case 'C':
+ modifiers |= InputEvent.CTRL_MASK;
+ break;
+ case 'M':
+ modifiers |= InputEvent.META_MASK;
+ break;
+ case 'S':
+ modifiers |= InputEvent.SHIFT_MASK;
+ break;
+ }
+ }
+ }
+ String key = keyStroke.substring(index + 1);
+ if(key.length() == 1)
+ {
+ char ch = Character.toUpperCase(key.charAt(0));
+ if(modifiers == 0)
+ return KeyStroke.getKeyStroke(ch);
+ else
+ return KeyStroke.getKeyStroke(ch,modifiers);
+ }
+ else if(key.length() == 0)
+ {
+ System.err.println("Invalid key stroke: " + keyStroke);
+ return null;
+ }
+ else
+ {
+ int ch;
+
+ try
+ {
+ ch = KeyEvent.class.getField("VK_".concat(key))
+ .getInt(null);
+ }
+ catch(Exception e)
+ {
+ System.err.println("Invalid key stroke: "
+ + keyStroke);
+ return null;
+ }
+
+ return KeyStroke.getKeyStroke(ch,modifiers);
+ }
+ }
+
+ // private members
+ private Hashtable bindings;
+ private Hashtable currentBindings;
+
+ private DefaultInputHandler(DefaultInputHandler copy)
+ {
+ bindings = currentBindings = copy.bindings;
+ }
+}
Added: xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/InputHandler.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/InputHandler.java?rev=594367&view=auto
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/InputHandler.java (added)
+++ xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/InputHandler.java Mon Nov 12 16:40:53 2007
@@ -0,0 +1,1070 @@
+/*
+ * InputHandler.java - Manages key bindings and executes actions
+ * Copyright (C) 1999 Slava Pestov
+ *
+ * You may use and modify this package for any purpose. Redistribution is
+ * permitted, in both source and binary form, provided that this notice
+ * remains intact in all source distributions of this package.
+ */
+package org.gjt.sp.jedit.textarea;
+
+import javax.swing.text.*;
+import javax.swing.JPopupMenu;
+import java.awt.event.*;
+import java.awt.Component;
+import java.util.*;
+
+/**
+ * An input handler converts the user's key strokes into concrete actions.
+ * It also takes care of macro recording and action repetition.<p>
+ *
+ * This class provides all the necessary support code for an input
+ * handler, but doesn't actually do any key binding logic. It is up
+ * to the implementations of this class to do so.
+ *
+ * @author Slava Pestov
+ * @version $Id: InputHandler.java,v 1.14 1999/12/13 03:40:30 sp Exp $
+ * @see org.gjt.sp.jedit.textarea.DefaultInputHandler
+ */
+public abstract class InputHandler extends KeyAdapter
+{
+ /**
+ * If this client property is set to Boolean.TRUE on the text area,
+ * the home/end keys will support 'smart' BRIEF-like behaviour
+ * (one press = start/end of line, two presses = start/end of
+ * viewscreen, three presses = start/end of document). By default,
+ * this property is not set.
+ */
+ public static final String SMART_HOME_END_PROPERTY = "InputHandler.homeEnd";
+
+ public static final ActionListener BACKSPACE = new backspace();
+ public static final ActionListener BACKSPACE_WORD = new backspace_word();
+ public static final ActionListener DELETE = new delete();
+ public static final ActionListener DELETE_WORD = new delete_word();
+ public static final ActionListener END = new end(false);
+ public static final ActionListener DOCUMENT_END = new document_end(false);
+ public static final ActionListener SELECT_END = new end(true);
+ public static final ActionListener SELECT_DOC_END = new document_end(true);
+ public static final ActionListener INSERT_BREAK = new insert_break();
+ public static final ActionListener INSERT_TAB = new insert_tab();
+ public static final ActionListener HOME = new home(false);
+ public static final ActionListener DOCUMENT_HOME = new document_home(false);
+ public static final ActionListener SELECT_HOME = new home(true);
+ public static final ActionListener SELECT_DOC_HOME = new document_home(true);
+ public static final ActionListener NEXT_CHAR = new next_char(false);
+ public static final ActionListener NEXT_LINE = new next_line(false);
+ public static final ActionListener NEXT_PAGE = new next_page(false);
+ public static final ActionListener NEXT_WORD = new next_word(false);
+ public static final ActionListener SELECT_NEXT_CHAR = new next_char(true);
+ public static final ActionListener SELECT_NEXT_LINE = new next_line(true);
+ public static final ActionListener SELECT_NEXT_PAGE = new next_page(true);
+ public static final ActionListener SELECT_NEXT_WORD = new next_word(true);
+ public static final ActionListener OVERWRITE = new overwrite();
+ public static final ActionListener PREV_CHAR = new prev_char(false);
+ public static final ActionListener PREV_LINE = new prev_line(false);
+ public static final ActionListener PREV_PAGE = new prev_page(false);
+ public static final ActionListener PREV_WORD = new prev_word(false);
+ public static final ActionListener SELECT_PREV_CHAR = new prev_char(true);
+ public static final ActionListener SELECT_PREV_LINE = new prev_line(true);
+ public static final ActionListener SELECT_PREV_PAGE = new prev_page(true);
+ public static final ActionListener SELECT_PREV_WORD = new prev_word(true);
+ public static final ActionListener REPEAT = new repeat();
+ public static final ActionListener TOGGLE_RECT = new toggle_rect();
+
+ // Default action
+ public static final ActionListener INSERT_CHAR = new insert_char();
+
+ private static Hashtable actions;
+
+ static
+ {
+ actions = new Hashtable();
+ actions.put("backspace",BACKSPACE);
+ actions.put("backspace-word",BACKSPACE_WORD);
+ actions.put("delete",DELETE);
+ actions.put("delete-word",DELETE_WORD);
+ actions.put("end",END);
+ actions.put("select-end",SELECT_END);
+ actions.put("document-end",DOCUMENT_END);
+ actions.put("select-doc-end",SELECT_DOC_END);
+ actions.put("insert-break",INSERT_BREAK);
+ actions.put("insert-tab",INSERT_TAB);
+ actions.put("home",HOME);
+ actions.put("select-home",SELECT_HOME);
+ actions.put("document-home",DOCUMENT_HOME);
+ actions.put("select-doc-home",SELECT_DOC_HOME);
+ actions.put("next-char",NEXT_CHAR);
+ actions.put("next-line",NEXT_LINE);
+ actions.put("next-page",NEXT_PAGE);
+ actions.put("next-word",NEXT_WORD);
+ actions.put("select-next-char",SELECT_NEXT_CHAR);
+ actions.put("select-next-line",SELECT_NEXT_LINE);
+ actions.put("select-next-page",SELECT_NEXT_PAGE);
+ actions.put("select-next-word",SELECT_NEXT_WORD);
+ actions.put("overwrite",OVERWRITE);
+ actions.put("prev-char",PREV_CHAR);
+ actions.put("prev-line",PREV_LINE);
+ actions.put("prev-page",PREV_PAGE);
+ actions.put("prev-word",PREV_WORD);
+ actions.put("select-prev-char",SELECT_PREV_CHAR);
+ actions.put("select-prev-line",SELECT_PREV_LINE);
+ actions.put("select-prev-page",SELECT_PREV_PAGE);
+ actions.put("select-prev-word",SELECT_PREV_WORD);
+ actions.put("repeat",REPEAT);
+ actions.put("toggle-rect",TOGGLE_RECT);
+ actions.put("insert-char",INSERT_CHAR);
+ }
+
+ /**
+ * Returns a named text area action.
+ * @param name The action name
+ */
+ public static ActionListener getAction(String name)
+ {
+ return (ActionListener)actions.get(name);
+ }
+
+ /**
+ * Returns the name of the specified text area action.
+ * @param listener The action
+ */
+ public static String getActionName(ActionListener listener)
+ {
+ Enumeration e = getActions();
+ while(e.hasMoreElements())
+ {
+ String name = (String)e.nextElement();
+ ActionListener _listener = getAction(name);
+ if(_listener == listener)
+ return name;
+ }
+ return null;
+ }
+
+ /**
+ * Returns an enumeration of all available actions.
+ */
+ public static Enumeration getActions()
+ {
+ return actions.keys();
+ }
+
+ /**
+ * Adds the default key bindings to this input handler.
+ * This should not be called in the constructor of this
+ * input handler, because applications might load the
+ * key bindings from a file, etc.
+ */
+ public abstract void addDefaultKeyBindings();
+
+ /**
+ * Adds a key binding to this input handler.
+ * @param keyBinding The key binding (the format of this is
+ * input-handler specific)
+ * @param action The action
+ */
+ public abstract void addKeyBinding(String keyBinding, ActionListener action);
+
+ /**
+ * Removes a key binding from this input handler.
+ * @param keyBinding The key binding
+ */
+ public abstract void removeKeyBinding(String keyBinding);
+
+ /**
+ * Removes all key bindings from this input handler.
+ */
+ public abstract void removeAllKeyBindings();
+
+ /**
+ * Grabs the next key typed event and invokes the specified
+ * action with the key as a the action command.
+ * @param action The action
+ */
+ public void grabNextKeyStroke(ActionListener listener)
+ {
+ grabAction = listener;
+ }
+
+ /**
+ * Returns if repeating is enabled. When repeating is enabled,
+ * actions will be executed multiple times. This is usually
+ * invoked with a special key stroke in the input handler.
+ */
+ public boolean isRepeatEnabled()
+ {
+ return repeat;
+ }
+
+ /**
+ * Enables repeating. When repeating is enabled, actions will be
+ * executed multiple times. Once repeating is enabled, the input
+ * handler should read a number from the keyboard.
+ */
+ public void setRepeatEnabled(boolean repeat)
+ {
+ this.repeat = repeat;
+ }
+
+ /**
+ * Returns the number of times the next action will be repeated.
+ */
+ public int getRepeatCount()
+ {
+ return (repeat ? Math.max(1,repeatCount) : 1);
+ }
+
+ /**
+ * Sets the number of times the next action will be repeated.
+ * @param repeatCount The repeat count
+ */
+ public void setRepeatCount(int repeatCount)
+ {
+ this.repeatCount = repeatCount;
+ }
+
+ /**
+ * Returns the macro recorder. If this is non-null, all executed
+ * actions should be forwarded to the recorder.
+ */
+ public InputHandler.MacroRecorder getMacroRecorder()
+ {
+ return recorder;
+ }
+
+ /**
+ * Sets the macro recorder. If this is non-null, all executed
+ * actions should be forwarded to the recorder.
+ * @param recorder The macro recorder
+ */
+ public void setMacroRecorder(InputHandler.MacroRecorder recorder)
+ {
+ this.recorder = recorder;
+ }
+
+ /**
+ * Returns a copy of this input handler that shares the same
+ * key bindings. Setting key bindings in the copy will also
+ * set them in the original.
+ */
+ public abstract InputHandler copy();
+
+ /**
+ * Executes the specified action, repeating and recording it as
+ * necessary.
+ * @param listener The action listener
+ * @param source The event source
+ * @param actionCommand The action command
+ */
+ public void executeAction(ActionListener listener, Object source,
+ String actionCommand)
+ {
+ // create event
+ ActionEvent evt = new ActionEvent(source,
+ ActionEvent.ACTION_PERFORMED,
+ actionCommand);
+
+ // don't do anything if the action is a wrapper
+ // (like EditAction.Wrapper)
+ if(listener instanceof Wrapper)
+ {
+ listener.actionPerformed(evt);
+ return;
+ }
+
+ // remember old values, in case action changes them
+ boolean _repeat = repeat;
+ int _repeatCount = getRepeatCount();
+
+ // execute the action
+ if(listener instanceof InputHandler.NonRepeatable)
+ listener.actionPerformed(evt);
+ else
+ {
+ for(int i = 0; i < Math.max(1,repeatCount); i++)
+ listener.actionPerformed(evt);
+ }
+
+ // do recording. Notice that we do no recording whatsoever
+ // for actions that grab keys
+ if(grabAction == null)
+ {
+ if(recorder != null)
+ {
+ if(!(listener instanceof InputHandler.NonRecordable))
+ {
+ if(_repeatCount != 1)
+ recorder.actionPerformed(REPEAT,String.valueOf(_repeatCount));
+
+ recorder.actionPerformed(listener,actionCommand);
+ }
+ }
+
+ // If repeat was true originally, clear it
+ // Otherwise it might have been set by the action, etc
+ if(_repeat)
+ {
+ repeat = false;
+ repeatCount = 0;
+ }
+ }
+ }
+
+ /**
+ * Returns the text area that fired the specified event.
+ * @param evt The event
+ */
+ public static JEditTextArea getTextArea(EventObject evt)
+ {
+ if(evt != null)
+ {
+ Object o = evt.getSource();
+ if(o instanceof Component)
+ {
+ // find the parent text area
+ Component c = (Component)o;
+ for(;;)
+ {
+ if(c instanceof JEditTextArea)
+ return (JEditTextArea)c;
+ else if(c == null)
+ break;
+ if(c instanceof JPopupMenu)
+ c = ((JPopupMenu)c)
+ .getInvoker();
+ else
+ c = c.getParent();
+ }
+ }
+ }
+
+ // this shouldn't happen
+ System.err.println("BUG: getTextArea() returning null");
+ System.err.println("Report this to Slava Pestov <sp...@gjt.org>");
+ return null;
+ }
+
+ // protected members
+
+ /**
+ * If a key is being grabbed, this method should be called with
+ * the appropriate key event. It executes the grab action with
+ * the typed character as the parameter.
+ */
+ protected void handleGrabAction(KeyEvent evt)
+ {
+ // Clear it *before* it is executed so that executeAction()
+ // resets the repeat count
+ ActionListener _grabAction = grabAction;
+ grabAction = null;
+ executeAction(_grabAction,evt.getSource(),
+ String.valueOf(evt.getKeyChar()));
+ }
+
+ // protected members
+ protected ActionListener grabAction;
+ protected boolean repeat;
+ protected int repeatCount;
+ protected InputHandler.MacroRecorder recorder;
+
+ /**
+ * If an action implements this interface, it should not be repeated.
+ * Instead, it will handle the repetition itself.
+ */
+ public interface NonRepeatable {}
+
+ /**
+ * If an action implements this interface, it should not be recorded
+ * by the macro recorder. Instead, it will do its own recording.
+ */
+ public interface NonRecordable {}
+
+ /**
+ * For use by EditAction.Wrapper only.
+ * @since jEdit 2.2final
+ */
+ public interface Wrapper {}
+
+ /**
+ * Macro recorder.
+ */
+ public interface MacroRecorder
+ {
+ void actionPerformed(ActionListener listener,
+ String actionCommand);
+ }
+
+ public static class backspace implements ActionListener
+ {
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+
+ if(!textArea.isEditable())
+ {
+ textArea.getToolkit().beep();
+ return;
+ }
+
+ if(textArea.getSelectionStart()
+ != textArea.getSelectionEnd())
+ {
+ textArea.setSelectedText("");
+ }
+ else
+ {
+ int caret = textArea.getCaretPosition();
+ if(caret == 0)
+ {
+ textArea.getToolkit().beep();
+ return;
+ }
+ try
+ {
+ textArea.getDocument().remove(caret - 1,1);
+ }
+ catch(BadLocationException bl)
+ {
+ bl.printStackTrace();
+ }
+ }
+ }
+ }
+
+ public static class backspace_word implements ActionListener
+ {
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ int start = textArea.getSelectionStart();
+ if(start != textArea.getSelectionEnd())
+ {
+ textArea.setSelectedText("");
+ }
+
+ int line = textArea.getCaretLine();
+ int lineStart = textArea.getLineStartOffset(line);
+ int caret = start - lineStart;
+
+ String lineText = textArea.getLineText(textArea
+ .getCaretLine());
+
+ if(caret == 0)
+ {
+ if(lineStart == 0)
+ {
+ textArea.getToolkit().beep();
+ return;
+ }
+ caret--;
+ }
+ else
+ {
+ String noWordSep = (String)textArea.getDocument().getProperty("noWordSep");
+ caret = TextUtilities.findWordStart(lineText,caret,noWordSep);
+ }
+
+ try
+ {
+ textArea.getDocument().remove(
+ caret + lineStart,
+ start - (caret + lineStart));
+ }
+ catch(BadLocationException bl)
+ {
+ bl.printStackTrace();
+ }
+ }
+ }
+
+ public static class delete implements ActionListener
+ {
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+
+ if(!textArea.isEditable())
+ {
+ textArea.getToolkit().beep();
+ return;
+ }
+
+ if(textArea.getSelectionStart()
+ != textArea.getSelectionEnd())
+ {
+ textArea.setSelectedText("");
+ }
+ else
+ {
+ int caret = textArea.getCaretPosition();
+ if(caret == textArea.getDocumentLength())
+ {
+ textArea.getToolkit().beep();
+ return;
+ }
+ try
+ {
+ textArea.getDocument().remove(caret,1);
+ }
+ catch(BadLocationException bl)
+ {
+ bl.printStackTrace();
+ }
+ }
+ }
+ }
+
+ public static class delete_word implements ActionListener
+ {
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ int start = textArea.getSelectionStart();
+ if(start != textArea.getSelectionEnd())
+ {
+ textArea.setSelectedText("");
+ }
+
+ int line = textArea.getCaretLine();
+ int lineStart = textArea.getLineStartOffset(line);
+ int caret = start - lineStart;
+
+ String lineText = textArea.getLineText(textArea
+ .getCaretLine());
+
+ if(caret == lineText.length())
+ {
+ if(lineStart + caret == textArea.getDocumentLength())
+ {
+ textArea.getToolkit().beep();
+ return;
+ }
+ caret++;
+ }
+ else
+ {
+ String noWordSep = (String)textArea.getDocument().getProperty("noWordSep");
+ caret = TextUtilities.findWordEnd(lineText,caret,noWordSep);
+ }
+
+ try
+ {
+ textArea.getDocument().remove(start,
+ (caret + lineStart) - start);
+ }
+ catch(BadLocationException bl)
+ {
+ bl.printStackTrace();
+ }
+ }
+ }
+
+ public static class end implements ActionListener
+ {
+ private boolean select;
+
+ public end(boolean select)
+ {
+ this.select = select;
+ }
+
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+
+ int caret = textArea.getCaretPosition();
+
+ int lastOfLine = textArea.getLineEndOffset(
+ textArea.getCaretLine()) - 1;
+ int lastVisibleLine = textArea.getFirstLine()
+ + textArea.getVisibleLines();
+ if(lastVisibleLine >= textArea.getLineCount())
+ {
+ lastVisibleLine = Math.min(textArea.getLineCount() - 1,
+ lastVisibleLine);
+ }
+ else
+ lastVisibleLine -= (textArea.getElectricScroll() + 1);
+
+ int lastVisible = textArea.getLineEndOffset(lastVisibleLine) - 1;
+ int lastDocument = textArea.getDocumentLength();
+
+ if(caret == lastDocument)
+ {
+ textArea.getToolkit().beep();
+ return;
+ }
+ else if(!Boolean.TRUE.equals(textArea.getClientProperty(
+ SMART_HOME_END_PROPERTY)))
+ caret = lastOfLine;
+ else if(caret == lastVisible)
+ caret = lastDocument;
+ else if(caret == lastOfLine)
+ caret = lastVisible;
+ else
+ caret = lastOfLine;
+
+ if(select)
+ textArea.select(textArea.getMarkPosition(),caret);
+ else
+ textArea.setCaretPosition(caret);
+ }
+ }
+
+ public static class document_end implements ActionListener
+ {
+ private boolean select;
+
+ public document_end(boolean select)
+ {
+ this.select = select;
+ }
+
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ if(select)
+ textArea.select(textArea.getMarkPosition(),
+ textArea.getDocumentLength());
+ else
+ textArea.setCaretPosition(textArea
+ .getDocumentLength());
+ }
+ }
+
+ public static class home implements ActionListener
+ {
+ private boolean select;
+
+ public home(boolean select)
+ {
+ this.select = select;
+ }
+
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+
+ int caret = textArea.getCaretPosition();
+
+ int firstLine = textArea.getFirstLine();
+
+ int firstOfLine = textArea.getLineStartOffset(
+ textArea.getCaretLine());
+ int firstVisibleLine = (firstLine == 0 ? 0 :
+ firstLine + textArea.getElectricScroll());
+ int firstVisible = textArea.getLineStartOffset(
+ firstVisibleLine);
+
+ if(caret == 0)
+ {
+ textArea.getToolkit().beep();
+ return;
+ }
+ else if(!Boolean.TRUE.equals(textArea.getClientProperty(
+ SMART_HOME_END_PROPERTY)))
+ caret = firstOfLine;
+ else if(caret == firstVisible)
+ caret = 0;
+ else if(caret == firstOfLine)
+ caret = firstVisible;
+ else
+ caret = firstOfLine;
+
+ if(select)
+ textArea.select(textArea.getMarkPosition(),caret);
+ else
+ textArea.setCaretPosition(caret);
+ }
+ }
+
+ public static class document_home implements ActionListener
+ {
+ private boolean select;
+
+ public document_home(boolean select)
+ {
+ this.select = select;
+ }
+
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ if(select)
+ textArea.select(textArea.getMarkPosition(),0);
+ else
+ textArea.setCaretPosition(0);
+ }
+ }
+
+ public static class insert_break implements ActionListener
+ {
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+
+ if(!textArea.isEditable())
+ {
+ textArea.getToolkit().beep();
+ return;
+ }
+
+ textArea.setSelectedText("\n");
+ }
+ }
+
+ public static class insert_tab implements ActionListener
+ {
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+
+ if(!textArea.isEditable())
+ {
+ textArea.getToolkit().beep();
+ return;
+ }
+
+ textArea.overwriteSetSelectedText("\t");
+ }
+ }
+
+ public static class next_char implements ActionListener
+ {
+ private boolean select;
+
+ public next_char(boolean select)
+ {
+ this.select = select;
+ }
+
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ int caret = textArea.getCaretPosition();
+ if(caret == textArea.getDocumentLength())
+ {
+ textArea.getToolkit().beep();
+ return;
+ }
+
+ if(select)
+ textArea.select(textArea.getMarkPosition(),
+ caret + 1);
+ else
+ textArea.setCaretPosition(caret + 1);
+ }
+ }
+
+ public static class next_line implements ActionListener
+ {
+ private boolean select;
+
+ public next_line(boolean select)
+ {
+ this.select = select;
+ }
+
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ int caret = textArea.getCaretPosition();
+ int line = textArea.getCaretLine();
+
+ if(line == textArea.getLineCount() - 1)
+ {
+ textArea.getToolkit().beep();
+ return;
+ }
+
+ int magic = textArea.getMagicCaretPosition();
+ if(magic == -1)
+ {
+ magic = textArea.offsetToX(line,
+ caret - textArea.getLineStartOffset(line));
+ }
+
+ caret = textArea.getLineStartOffset(line + 1)
+ + textArea.xToOffset(line + 1,magic);
+ if(select)
+ textArea.select(textArea.getMarkPosition(),caret);
+ else
+ textArea.setCaretPosition(caret);
+ textArea.setMagicCaretPosition(magic);
+ }
+ }
+
+ public static class next_page implements ActionListener
+ {
+ private boolean select;
+
+ public next_page(boolean select)
+ {
+ this.select = select;
+ }
+
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ int lineCount = textArea.getLineCount();
+ int firstLine = textArea.getFirstLine();
+ int visibleLines = textArea.getVisibleLines();
+ int line = textArea.getCaretLine();
+
+ firstLine += visibleLines;
+
+ if(firstLine + visibleLines >= lineCount - 1)
+ firstLine = lineCount - visibleLines;
+
+ textArea.setFirstLine(firstLine);
+
+ int caret = textArea.getLineStartOffset(
+ Math.min(textArea.getLineCount() - 1,
+ line + visibleLines));
+ if(select)
+ textArea.select(textArea.getMarkPosition(),caret);
+ else
+ textArea.setCaretPosition(caret);
+ }
+ }
+
+ public static class next_word implements ActionListener
+ {
+ private boolean select;
+
+ public next_word(boolean select)
+ {
+ this.select = select;
+ }
+
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ int caret = textArea.getCaretPosition();
+ int line = textArea.getCaretLine();
+ int lineStart = textArea.getLineStartOffset(line);
+ caret -= lineStart;
+
+ String lineText = textArea.getLineText(textArea
+ .getCaretLine());
+
+ if(caret == lineText.length())
+ {
+ if(lineStart + caret == textArea.getDocumentLength())
+ {
+ textArea.getToolkit().beep();
+ return;
+ }
+ caret++;
+ }
+ else
+ {
+ String noWordSep = (String)textArea.getDocument().getProperty("noWordSep");
+ caret = TextUtilities.findWordEnd(lineText,caret,noWordSep);
+ }
+
+ if(select)
+ textArea.select(textArea.getMarkPosition(),
+ lineStart + caret);
+ else
+ textArea.setCaretPosition(lineStart + caret);
+ }
+ }
+
+ public static class overwrite implements ActionListener
+ {
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ textArea.setOverwriteEnabled(
+ !textArea.isOverwriteEnabled());
+ }
+ }
+
+ public static class prev_char implements ActionListener
+ {
+ private boolean select;
+
+ public prev_char(boolean select)
+ {
+ this.select = select;
+ }
+
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ int caret = textArea.getCaretPosition();
+ if(caret == 0)
+ {
+ textArea.getToolkit().beep();
+ return;
+ }
+
+ if(select)
+ textArea.select(textArea.getMarkPosition(),
+ caret - 1);
+ else
+ textArea.setCaretPosition(caret - 1);
+ }
+ }
+
+ public static class prev_line implements ActionListener
+ {
+ private boolean select;
+
+ public prev_line(boolean select)
+ {
+ this.select = select;
+ }
+
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ int caret = textArea.getCaretPosition();
+ int line = textArea.getCaretLine();
+
+ if(line == 0)
+ {
+ textArea.getToolkit().beep();
+ return;
+ }
+
+ int magic = textArea.getMagicCaretPosition();
+ if(magic == -1)
+ {
+ magic = textArea.offsetToX(line,
+ caret - textArea.getLineStartOffset(line));
+ }
+
+ caret = textArea.getLineStartOffset(line - 1)
+ + textArea.xToOffset(line - 1,magic);
+ if(select)
+ textArea.select(textArea.getMarkPosition(),caret);
+ else
+ textArea.setCaretPosition(caret);
+ textArea.setMagicCaretPosition(magic);
+ }
+ }
+
+ public static class prev_page implements ActionListener
+ {
+ private boolean select;
+
+ public prev_page(boolean select)
+ {
+ this.select = select;
+ }
+
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ int firstLine = textArea.getFirstLine();
+ int visibleLines = textArea.getVisibleLines();
+ int line = textArea.getCaretLine();
+
+ if(firstLine < visibleLines)
+ firstLine = visibleLines;
+
+ textArea.setFirstLine(firstLine - visibleLines);
+
+ int caret = textArea.getLineStartOffset(
+ Math.max(0,line - visibleLines));
+ if(select)
+ textArea.select(textArea.getMarkPosition(),caret);
+ else
+ textArea.setCaretPosition(caret);
+ }
+ }
+
+ public static class prev_word implements ActionListener
+ {
+ private boolean select;
+
+ public prev_word(boolean select)
+ {
+ this.select = select;
+ }
+
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ int caret = textArea.getCaretPosition();
+ int line = textArea.getCaretLine();
+ int lineStart = textArea.getLineStartOffset(line);
+ caret -= lineStart;
+
+ String lineText = textArea.getLineText(textArea
+ .getCaretLine());
+
+ if(caret == 0)
+ {
+ if(lineStart == 0)
+ {
+ textArea.getToolkit().beep();
+ return;
+ }
+ caret--;
+ }
+ else
+ {
+ String noWordSep = (String)textArea.getDocument().getProperty("noWordSep");
+ caret = TextUtilities.findWordStart(lineText,caret,noWordSep);
+ }
+
+ if(select)
+ textArea.select(textArea.getMarkPosition(),
+ lineStart + caret);
+ else
+ textArea.setCaretPosition(lineStart + caret);
+ }
+ }
+
+ public static class repeat implements ActionListener,
+ InputHandler.NonRecordable
+ {
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ textArea.getInputHandler().setRepeatEnabled(true);
+ String actionCommand = evt.getActionCommand();
+ if(actionCommand != null)
+ {
+ textArea.getInputHandler().setRepeatCount(
+ Integer.parseInt(actionCommand));
+ }
+ }
+ }
+
+ public static class toggle_rect implements ActionListener
+ {
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ textArea.setSelectionRectangular(
+ !textArea.isSelectionRectangular());
+ }
+ }
+
+ public static class insert_char implements ActionListener,
+ InputHandler.NonRepeatable
+ {
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ String str = evt.getActionCommand();
+ int repeatCount = textArea.getInputHandler().getRepeatCount();
+
+ if(textArea.isEditable())
+ {
+ StringBuffer buf = new StringBuffer();
+ for(int i = 0; i < repeatCount; i++)
+ buf.append(str);
+ textArea.overwriteSetSelectedText(buf.toString());
+ }
+ else
+ {
+ textArea.getToolkit().beep();
+ }
+ }
+ }
+}