001/* TextAction.java --
002   Copyright (C) 2002, 2004 Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package javax.swing.text;
040
041import java.awt.Component;
042import java.awt.KeyboardFocusManager;
043import java.awt.Point;
044import java.awt.event.ActionEvent;
045import java.util.HashMap;
046import java.util.Iterator;
047
048import javax.swing.AbstractAction;
049import javax.swing.Action;
050
051/**
052 * TextAction
053 * @author Andrew Selkirk
054 */
055public abstract class TextAction extends AbstractAction
056{
057  /**
058   * Constructor TextAction
059   * @param name TODO
060   */
061  public TextAction(String name)
062  {
063    super(name);
064  }
065
066  /**
067   * Returns the <code>JTextComponent</code> object associated with the given
068   * <code>ActionEvent</code>. If the source of the event is not a
069   * <code>JTextComponent</code> the currently focused text component is returned.
070   *
071   * @param event the action event
072   *
073   * @return the <code>JTextComponent</code>
074   */
075  protected final JTextComponent getTextComponent(ActionEvent event)
076  {
077    JTextComponent target = null;
078    if (event != null)
079      {
080        Object source = event.getSource();
081        if (source instanceof JTextComponent)
082          target = (JTextComponent) source;
083      }
084    if (target == null)
085      target = getFocusedComponent();
086    return target;
087  }
088
089  /**
090   * Creates a new array of <code>Action</code> containing both given arrays.
091   *
092   * @param list1 the first action array
093   * @param list2 the second action array
094   *
095   * @return the augmented array of actions
096   */
097  public static final Action[] augmentList(Action[] list1, Action[] list2)
098  {
099    HashMap<Object,Action> actions = new HashMap<Object,Action>();
100
101    for (int i = 0; i < list1.length; ++i)
102      {
103        Action a = list1[i];
104        Object name = a.getValue(Action.NAME);
105        actions.put(name != null ? name : "", a);
106      }
107
108    for (int i = 0; i < list2.length; ++i)
109      {
110        Action a = list2[i];
111        Object name = a.getValue(Action.NAME);
112        actions.put(name != null ? name : "", a);
113      }
114    Action[] augmented = new Action[actions.size()];
115
116    int i = 0;
117    for (Iterator<Action> it = actions.values().iterator(); it.hasNext(); i++)
118      augmented[i] = it.next();
119    return augmented;
120
121  }
122
123  /**
124   * Returns the current focused <code>JTextComponent</code> object.
125   *
126   * @return the <code>JTextComponent</code>
127   */
128  protected final JTextComponent getFocusedComponent()
129  {
130    KeyboardFocusManager kfm =
131      KeyboardFocusManager.getCurrentKeyboardFocusManager();
132    Component focused = kfm.getPermanentFocusOwner();
133    JTextComponent textComp = null;
134    if (focused instanceof JTextComponent)
135      textComp = (JTextComponent) focused;
136    return textComp;
137  }
138
139  /** Abstract helper class which implements everything needed for an
140   * Action implementation in <code>DefaultEditorKit</code> which
141   * does horizontal movement (and selection).
142   */
143  abstract static class HorizontalMovementAction extends TextAction
144  {
145    int dir;
146
147    HorizontalMovementAction(String name, int direction)
148    {
149      super(name);
150      dir = direction;
151    }
152
153    public void actionPerformed(ActionEvent event)
154    {
155      JTextComponent t = getTextComponent(event);
156      try
157      {
158        if (t != null)
159          {
160            int offs
161              = Utilities.getNextVisualPositionFrom(t,
162                                                    t.getCaretPosition(),
163                                                    dir);
164
165            Caret c = t.getCaret();
166
167            actionPerformedImpl(c, offs);
168
169            c.setMagicCaretPosition(t.modelToView(offs).getLocation());
170          }
171      }
172    catch(BadLocationException ble)
173      {
174        throw
175          (InternalError) new InternalError("Illegal offset").initCause(ble);
176      }
177
178    }
179
180    protected abstract void actionPerformedImpl(Caret c, int offs)
181      throws BadLocationException;
182  }
183
184  /** Abstract helper class which implements everything needed for an
185   * Action implementation in <code>DefaultEditorKit</code> which
186   * does vertical movement (and selection).
187   */
188  abstract static class VerticalMovementAction extends TextAction
189  {
190    int dir;
191
192    VerticalMovementAction(String name, int direction)
193    {
194      super(name);
195      dir = direction;
196    }
197
198    public void actionPerformed(ActionEvent event)
199    {
200      JTextComponent t = getTextComponent(event);
201      try
202        {
203          if (t != null)
204            {
205              Caret c = t.getCaret();
206              // The magic caret position may be null when the caret
207              // has not moved yet.
208              Point mcp = c.getMagicCaretPosition();
209
210              int pos;
211              if (mcp != null)
212                {
213                  mcp.y = t.modelToView(c.getDot()).y;
214                  pos = t.viewToModel(mcp);
215                }
216              else
217                pos = c.getDot();
218
219              pos = Utilities.getNextVisualPositionFrom(t,
220                                                        t.getCaretPosition(),
221                                                        dir);
222
223              if (pos > -1)
224                actionPerformedImpl(c, pos);
225            }
226        }
227      catch(BadLocationException ble)
228      {
229        throw
230          (InternalError) new InternalError("Illegal offset").initCause(ble);
231      }
232    }
233
234    protected abstract void actionPerformedImpl(Caret c, int offs)
235    throws BadLocationException;
236
237  }
238
239
240}