2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com
.intellij
.ide
.actionMacro
;
18 import com
.intellij
.ide
.IdeBundle
;
19 import com
.intellij
.openapi
.actionSystem
.*;
20 import com
.intellij
.openapi
.editor
.Editor
;
21 import com
.intellij
.openapi
.editor
.actionSystem
.EditorActionManager
;
22 import com
.intellij
.openapi
.editor
.actionSystem
.TypedAction
;
23 import com
.intellij
.openapi
.ui
.playback
.commands
.KeyCodeTypeCommand
;
24 import com
.intellij
.openapi
.ui
.playback
.commands
.TypeCommand
;
25 import com
.intellij
.openapi
.util
.*;
26 import org
.jdom
.Element
;
27 import org
.jetbrains
.annotations
.NonNls
;
29 import java
.util
.ArrayList
;
30 import java
.util
.Arrays
;
31 import java
.util
.Iterator
;
32 import java
.util
.List
;
37 public class ActionMacro
implements JDOMExternalizable
{
38 private String myName
;
40 private final ArrayList
<ActionDescriptor
> myActions
= new ArrayList
<ActionDescriptor
>();
42 public static final String MACRO_ACTION_PREFIX
= "Macro.";
44 private static final String ATTRIBUTE_NAME
= "name";
46 private static final String ELEMENT_TYPING
= "typing";
49 private static final String ELEMENT_SHORTCUT
= "shortuct";
51 private static final String ATTRIBUTE_TEXT
= "text";
53 private static final String ATTRIBUTE_KEY_CODES
= "text-keycode";
55 private static final String ELEMENT_ACTION
= "action";
57 private static final String ATTRIBUTE_ID
= "id";
60 public ActionMacro() {
63 public ActionMacro(String name
) {
67 public String
getName() {
71 public void setName(String name
) {
75 public ActionDescriptor
[] getActions() {
76 return myActions
.toArray(new ActionDescriptor
[myActions
.size()]);
79 public void readExternal(Element macro
) throws InvalidDataException
{
80 setName(macro
.getAttributeValue(ATTRIBUTE_NAME
));
81 List actions
= macro
.getChildren();
82 for (Iterator iterator
= actions
.iterator(); iterator
.hasNext();) {
83 Element action
= (Element
)iterator
.next();
84 if (ELEMENT_TYPING
.equals(action
.getName())) {
85 Pair
<List
<Integer
>, List
<Integer
>> codes
= parseKeyCodes(action
.getAttributeValue(ATTRIBUTE_KEY_CODES
));
86 myActions
.add(new TypedDescriptor(action
.getAttributeValue(ATTRIBUTE_TEXT
), codes
.getFirst(), codes
.getSecond()));
88 else if (ELEMENT_ACTION
.equals(action
.getName())) {
89 myActions
.add(new IdActionDescriptor(action
.getAttributeValue(ATTRIBUTE_ID
)));
90 } else if (ELEMENT_SHORTCUT
.equals(action
.getName())) {
91 myActions
.add(new ShortcutActionDesciption(action
.getAttributeValue(ATTRIBUTE_TEXT
)));
96 private Pair
<List
<Integer
>, List
<Integer
>> parseKeyCodes(String keyCodesText
) {
97 return KeyCodeTypeCommand
.parseKeyCodes(keyCodesText
);
100 public String
unparseKeyCodes(Pair
<List
<Integer
>, List
<Integer
>> keyCodes
) {
101 return KeyCodeTypeCommand
.unparseKeyCodes(keyCodes
);
104 public void writeExternal(Element macro
) throws WriteExternalException
{
105 macro
.setAttribute(ATTRIBUTE_NAME
, myName
);
106 final ActionDescriptor
[] actions
= getActions();
107 for (int i
= 0; i
< actions
.length
; i
++) {
108 ActionDescriptor action
= actions
[i
];
109 Element actionNode
= null;
110 if (action
instanceof TypedDescriptor
) {
111 actionNode
= new Element(ELEMENT_TYPING
);
112 TypedDescriptor typedDescriptor
= (TypedDescriptor
)action
;
113 final String t
= typedDescriptor
.getText();
114 actionNode
.setAttribute(ATTRIBUTE_TEXT
, JDOMUtil
.escapeText(t
));
115 actionNode
.setAttribute(ATTRIBUTE_KEY_CODES
, unparseKeyCodes(new Pair
<List
<Integer
>, List
<Integer
>>(typedDescriptor
.getKeyCodes(), typedDescriptor
.getKeyModifiers())));
117 else if (action
instanceof IdActionDescriptor
) {
118 actionNode
= new Element(ELEMENT_ACTION
);
119 actionNode
.setAttribute(ATTRIBUTE_ID
, ((IdActionDescriptor
)action
).getActionId());
120 } else if (action
instanceof ShortcutActionDesciption
) {
121 actionNode
= new Element(ELEMENT_SHORTCUT
);
122 actionNode
.setAttribute(ATTRIBUTE_TEXT
, ((ShortcutActionDesciption
)action
).getText());
126 assert actionNode
!= null : action
;
128 macro
.addContent(actionNode
);
132 public String
toString() {
136 protected Object
clone() {
137 ActionMacro copy
= new ActionMacro(myName
);
138 for (int i
= 0; i
< myActions
.size(); i
++) {
139 ActionDescriptor action
= myActions
.get(i
);
140 copy
.myActions
.add((ActionDescriptor
)action
.clone());
146 public boolean equals(Object o
) {
147 if (this == o
) return true;
148 if (!(o
instanceof ActionMacro
)) return false;
150 final ActionMacro actionMacro
= (ActionMacro
)o
;
152 if (!myActions
.equals(actionMacro
.myActions
)) return false;
153 if (!myName
.equals(actionMacro
.myName
)) return false;
158 public int hashCode() {
160 result
= myName
.hashCode();
161 result
= 29 * result
+ myActions
.hashCode();
165 public void deleteAction(int idx
) {
166 myActions
.remove(idx
);
169 public void appendAction(String actionId
) {
170 myActions
.add(new IdActionDescriptor(actionId
));
173 public void appendShortuct(String text
) {
174 myActions
.add(new ShortcutActionDesciption(text
));
177 public void appendKeytyped(char c
, int keyCode
, int modifiers
) {
178 ActionDescriptor lastAction
= myActions
.size() > 0 ? myActions
.get(myActions
.size() - 1) : null;
179 if (lastAction
instanceof TypedDescriptor
) {
180 ((TypedDescriptor
)lastAction
).addChar(c
, keyCode
, modifiers
);
183 myActions
.add(new TypedDescriptor(c
, keyCode
, modifiers
));
187 public String
getActionId() {
188 return MACRO_ACTION_PREFIX
+ myName
;
191 public interface ActionDescriptor
{
194 void playBack(DataContext context
);
196 void generateTo(StringBuffer script
);
199 public static class TypedDescriptor
implements ActionDescriptor
{
201 private String myText
;
203 private List
<Integer
> myKeyCodes
= new ArrayList
<Integer
>();
204 private List
<Integer
> myModifiers
= new ArrayList
<Integer
>();
206 public TypedDescriptor(String text
, List
<Integer
> keyCodes
, List
<Integer
> modifiers
) {
208 myKeyCodes
.addAll(keyCodes
);
209 myModifiers
.addAll(modifiers
);
211 assert myKeyCodes
.size() == myModifiers
.size() : "codes=" + myKeyCodes
.toString() + " modifiers=" + myModifiers
.toString();
214 public TypedDescriptor(char c
, int keyCode
, int modifiers
) {
215 myText
= String
.valueOf(c
);
216 myKeyCodes
.add(keyCode
);
217 myModifiers
.add(modifiers
);
220 public void addChar(char c
, int keyCode
, int modifier
) {
222 myKeyCodes
.add(keyCode
);
223 myModifiers
.add(modifier
);
226 public String
getText() {
230 public Object
clone() {
231 return new TypedDescriptor(myText
, myKeyCodes
, myModifiers
);
234 public boolean equals(Object o
) {
235 if (this == o
) return true;
236 if (!(o
instanceof TypedDescriptor
)) return false;
237 return myText
.equals(((TypedDescriptor
)o
).myText
);
240 public int hashCode() {
241 return myText
.hashCode();
244 public void generateTo(StringBuffer script
) {
245 if (TypeCommand
.containsUnicode(myText
)) {
246 script
.append(KeyCodeTypeCommand
.PREFIX
).append(" ");
248 for (int i
= 0; i
< myKeyCodes
.size(); i
++) {
249 Integer each
= myKeyCodes
.get(i
);
250 script
.append(each
.toString());
251 script
.append(KeyCodeTypeCommand
.MODIFIER_DELIMITER
);
252 script
.append(myModifiers
.get(i
));
253 if (i
< myKeyCodes
.size() - 1) {
254 script
.append(KeyCodeTypeCommand
.CODE_DELIMITER
);
257 script
.append(" ").append(myText
).append("\n");
259 script
.append(myText
);
264 public String
toString() {
265 return IdeBundle
.message("action.descriptor.typing", myText
);
268 public void playBack(DataContext context
) {
269 Editor editor
= PlatformDataKeys
.EDITOR
.getData(context
);
270 final TypedAction typedAction
= EditorActionManager
.getInstance().getTypedAction();
271 char chars
[] = myText
.toCharArray();
272 for (int i
= 0; i
< chars
.length
; i
++) {
273 typedAction
.actionPerformed(editor
, chars
[i
], context
);
277 public List
<Integer
> getKeyCodes() {
281 public List
<Integer
> getKeyModifiers() {
286 public static class ShortcutActionDesciption
implements ActionDescriptor
{
288 private String myKeyStroke
;
290 public ShortcutActionDesciption(String stroke
) {
291 myKeyStroke
= stroke
;
294 public Object
clone() {
295 return new ShortcutActionDesciption(myKeyStroke
);
298 public void playBack(DataContext context
) {
301 public void generateTo(StringBuffer script
) {
302 script
.append("%[").append(myKeyStroke
).append("]\n");
305 public String
toString() {
306 return IdeBundle
.message("action.descriptor.keystroke", myKeyStroke
);
309 public String
getText() {
314 public static class IdActionDescriptor
implements ActionDescriptor
{
315 private final String actionId
;
317 public IdActionDescriptor(String id
) {
321 public String
getActionId() {
325 public String
toString() {
326 return IdeBundle
.message("action.descriptor.action", actionId
);
329 public Object
clone() {
330 return new IdActionDescriptor(actionId
);
333 public boolean equals(Object o
) {
334 if (this == o
) return true;
335 if (!(o
instanceof IdActionDescriptor
)) return false;
336 return actionId
.equals(((IdActionDescriptor
)o
).actionId
);
339 public int hashCode() {
340 return actionId
.hashCode();
343 public void playBack(DataContext context
) {
344 AnAction action
= ActionManager
.getInstance().getAction(getActionId());
345 if (action
== null) return;
346 Presentation presentation
= (Presentation
)action
.getTemplatePresentation().clone();
347 AnActionEvent event
= new AnActionEvent(null, context
, "MACRO_PLAYBACK", presentation
, ActionManager
.getInstance(), 0);
348 action
.beforeActionPerformedUpdate(event
);
349 if (!presentation
.isEnabled()) {
352 action
.actionPerformed(event
);
355 public void generateTo(StringBuffer script
) {
356 script
.append("%action ").append(getActionId()).append("\n");