KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > antlr > works > editor > EditorRules


1 /*
2
3 [The "BSD licence"]
4 Copyright (c) 2005 Jean Bovet
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the
15 documentation and/or other materials provided with the distribution.
16 3. The name of the author may not be used to endorse or promote products
17 derived from this software without specific prior written permission.
18
19 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 */

31
32 package org.antlr.works.editor;
33
34 import org.antlr.xjlib.appkit.swing.XJTree;
35 import org.antlr.xjlib.appkit.swing.XJTreeDelegate;
36 import org.antlr.xjlib.foundation.XJSystem;
37 import org.antlr.works.ate.swing.ATEKeyBindings;
38 import org.antlr.works.ate.syntax.generic.ATESyntaxLexer;
39 import org.antlr.works.ate.syntax.misc.ATEToken;
40 import org.antlr.works.components.grammar.CEditorGrammar;
41 import org.antlr.works.stats.StatisticsAW;
42 import org.antlr.works.syntax.GrammarSyntaxEngine;
43 import org.antlr.works.syntax.GrammarSyntaxLexer;
44 import org.antlr.works.syntax.element.ElementAction;
45 import org.antlr.works.syntax.element.ElementGroup;
46 import org.antlr.works.syntax.element.ElementReference;
47 import org.antlr.works.syntax.element.ElementRule;
48 import org.antlr.works.utils.IconManager;
49
50 import javax.swing.*;
51 import javax.swing.event.TreeSelectionEvent JavaDoc;
52 import javax.swing.event.TreeSelectionListener JavaDoc;
53 import javax.swing.text.BadLocationException JavaDoc;
54 import javax.swing.text.Document JavaDoc;
55 import javax.swing.tree.*;
56 import java.awt.*;
57 import java.awt.datatransfer.DataFlavor JavaDoc;
58 import java.awt.datatransfer.Transferable JavaDoc;
59 import java.awt.datatransfer.UnsupportedFlavorException JavaDoc;
60 import java.awt.dnd.DnDConstants JavaDoc;
61 import java.awt.dnd.DragSource JavaDoc;
62 import java.awt.event.ActionEvent JavaDoc;
63 import java.awt.event.KeyEvent JavaDoc;
64 import java.awt.event.MouseAdapter JavaDoc;
65 import java.awt.event.MouseEvent JavaDoc;
66 import java.io.IOException JavaDoc;
67 import java.util.*;
68 import java.util.List JavaDoc;
69
70 public class EditorRules implements XJTreeDelegate {
71
72     protected CEditorGrammar editor;
73
74     protected boolean programmaticallySelectingRule = false;
75     protected boolean selectNextRule = false;
76
77     protected XJTree rulesTree;
78     protected DefaultMutableTreeNode rulesTreeRootNode;
79     protected DefaultTreeModel rulesTreeModel;
80     protected List JavaDoc<String JavaDoc> rulesTreeExpandedNodes;
81     protected RuleTreeUserObject selectedObject;
82
83     protected boolean sort;
84
85     public EditorRules(CEditorGrammar editor, XJTree rulesTree) {
86         this.editor = editor;
87         this.rulesTree = rulesTree;
88
89         rulesTree.setDelegate(this);
90         rulesTree.setEnableDragAndDrop();
91
92         rulesTreeRootNode = new DefaultMutableTreeNode(new RuleTreeUserObject((ElementRule)null));
93         rulesTreeModel = new DefaultTreeModel(rulesTreeRootNode);
94         rulesTreeExpandedNodes = new ArrayList<String JavaDoc>();
95
96         rulesTree.setModel(rulesTreeModel);
97         rulesTree.addMouseListener(new RuleTreeMouseListener());
98         rulesTree.addTreeSelectionListener(new RuleTreeSelectionListener());
99
100         rulesTree.setRootVisible(false);
101         rulesTree.setShowsRootHandles(true);
102         rulesTree.setCellRenderer(new RulesTableRenderer());
103         rulesTree.setRowHeight(17);
104         rulesTree.getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
105     }
106
107     public void setKeyBindings(ATEKeyBindings keyBindings) {
108         keyBindings.addKeyBinding("RULE_MOVE_UP", KeyStroke.getKeyStroke(KeyEvent.VK_UP, Event.CTRL_MASK),
109                 new RuleMoveUpAction());
110         keyBindings.addKeyBinding("RULE_MOVE_DOWN", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, Event.CTRL_MASK),
111                 new RuleMoveDownAction());
112     }
113
114     public GrammarSyntaxEngine getParserEngine() {
115         return editor.getParserEngine();
116     }
117
118     public boolean isSorted() {
119         return sort;
120     }
121
122     public void setSorted(boolean flag) {
123         this.sort = flag;
124     }
125
126     public void toggleSorting() {
127         sort = !sort;
128         rebuildTree();
129     }
130
131     public void ignoreSelectedRules(boolean flag) {
132         for (ElementRule r : getSelectedRules()) {
133             r.ignored = flag;
134         }
135         rulesTree.repaint();
136         editor.rulesDidChange();
137     }
138
139     /**
140      * This method iterates over all rules and all blocks inside each rule to
141      * find a sequence of token equals to "$channel=HIDDEN" or "skip()".
142      */

143
144     public void findTokensToIgnore(boolean reset) {
145         List JavaDoc<ElementRule> rules = getRules();
146         if(rules == null || rules.isEmpty())
147             return;
148
149         findTokensToIgnore(rules, reset);
150
151         rulesTree.repaint();
152     }
153
154     public static void findTokensToIgnore(List JavaDoc<ElementRule> rules, boolean reset) {
155         for (ElementRule rule : rules) {
156             if(reset)
157                 rule.ignored = false;
158
159             List JavaDoc<ElementAction> actions = rule.getActions();
160             if (actions == null || actions.isEmpty())
161                 continue;
162
163             for (ElementAction action : actions) {
164                 List JavaDoc<ATEToken> tokens = action.getTokens();
165                 for (int t = 0; t < tokens.size(); t++) {
166                     ATEToken token = tokens.get(t);
167                     /* the 'channel' token can be either an ID or a reference if a rule in the grammar has the name
168                    'channel' */

169                     if ((token.type == ATESyntaxLexer.TOKEN_ID || token.type == GrammarSyntaxLexer.TOKEN_REFERENCE)
170                             && token.getAttribute().equals("channel") && t + 3 < tokens.size())
171                     {
172                         ATEToken t1 = tokens.get(t + 1);
173                         ATEToken t2 = tokens.get(t + 2);
174                         if (t1.type != ATESyntaxLexer.TOKEN_CHAR || !t1.getAttribute().equals("="))
175                             continue;
176
177                         if (t2.type != ATESyntaxLexer.TOKEN_ID || !t2.getAttribute().equals("HIDDEN"))
178                             continue;
179
180                         rule.ignored = true;
181                         break;
182                     }
183                     if (token.type == GrammarSyntaxLexer.TOKEN_ID && token.getAttribute().equals("skip")) {
184                         // Take skip() into account only if it is the only token in the block
185
if (tokens.size() == 5 && t == 1) {
186                             rule.ignored = true;
187                             break;
188                         }
189                     }
190                 }
191             }
192         }
193     }
194
195     public boolean getFirstSelectedRuleIgnoredFlag() {
196         List JavaDoc<ElementRule> selectedRules = getSelectedRules();
197         if(selectedRules == null || selectedRules.isEmpty())
198             return false;
199         else
200             return (selectedRules.get(0)).ignored;
201     }
202
203     public class RuleMoveUpAction extends AbstractAction {
204         public void actionPerformed(ActionEvent JavaDoc event) {
205             ElementRule sourceRule = getEnclosingRuleAtPosition(editor.getCaretPosition());
206             int previousRuleIndex = getParserEngine().getRules().indexOf(sourceRule)-1;
207             if(previousRuleIndex>=0) {
208                 ElementRule targetRule = getParserEngine().getRuleAtIndex(previousRuleIndex);
209                 moveRule(sourceRule, targetRule, true);
210             }
211         }
212     }
213
214     public class RuleMoveDownAction extends AbstractAction {
215         public void actionPerformed(ActionEvent JavaDoc event) {
216             ElementRule targetRule = getEnclosingRuleAtPosition(editor.getCaretPosition());
217             int nextRuleIndex = getParserEngine().getRules().indexOf(targetRule)+1;
218             ElementRule sourceRule = getParserEngine().getRuleAtIndex(nextRuleIndex);
219             if(sourceRule != null) {
220                 moveRule(sourceRule, targetRule, true);
221                 selectNextRule = true;
222             }
223         }
224     }
225
226     public void refreshRules() {
227         saveExpandedNodes();
228         rulesTreeModel.reload();
229         restoreExpandedNodes();
230
231         // Select again the row (otherwise, the selection is lost)
232
selectRuleInTreeAtPosition(editor.getCaretPosition());
233     }
234
235     public ElementGroup getSelectedGroup() {
236         DefaultMutableTreeNode node = (DefaultMutableTreeNode)rulesTree.getSelectionPath().getLastPathComponent();
237         RuleTreeUserObject n = (RuleTreeUserObject)node.getUserObject();
238         if(n.group != null)
239             return n.group;
240         else
241             return null;
242     }
243
244     public ElementGroup findOpenGroupClosestToLocation(int location) {
245         // Look backward into the list of groups
246
List JavaDoc<ElementGroup> groups = getParserEngine().getGroups();
247         if(groups == null || groups.isEmpty())
248             return null;
249
250         ElementGroup previous = null;
251         for (ElementGroup group : groups) {
252             if (!group.openGroup)
253                 continue;
254
255             ATEToken t = group.token;
256             if (t.getStartIndex() > location)
257                 break;
258
259             previous = group;
260         }
261         return previous;
262     }
263
264     public ElementGroup findClosingGroupForGroup(ElementGroup group) {
265         List JavaDoc<ElementGroup> groups = getParserEngine().getGroups();
266         if(groups == null || groups.isEmpty())
267             return null;
268
269         int index = groups.indexOf(group)+1;
270         if(index == -1)
271             return null;
272
273         int open = 0;
274         while(index < groups.size()) {
275             ElementGroup g = groups.get(index);
276             if(g.openGroup)
277                 open++;
278             else if(open == 0)
279                 return g;
280             else
281                 open--;
282             index++;
283         }
284         return null;
285     }
286
287     public List JavaDoc<ElementRule> getRules() {
288         return getParserEngine().getRules();
289     }
290
291     public List JavaDoc<ElementRule> getSortedRules() {
292         return getSortedRules(getRules());
293     }
294
295     public List JavaDoc<ElementRule> getSortedRules(List JavaDoc<ElementRule> rules) {
296         if(rules == null)
297             return null;
298
299         List JavaDoc<ElementRule> sortedRules = new ArrayList<ElementRule>(rules);
300         Collections.sort(sortedRules);
301         if(!sortedRules.isEmpty()) {
302             ElementRule firstRule = sortedRules.get(0);
303             if(firstRule.lexer) {
304                 for(int index=0; index<sortedRules.size(); index++) {
305                     ElementRule rule = sortedRules.get(0);
306                     if(!rule.lexer)
307                         break;
308
309                     sortedRules.add(rule);
310                     sortedRules.remove(0);
311                 }
312             }
313         }
314         return sortedRules;
315     }
316
317     public List JavaDoc<ElementRule> getSelectedRules() {
318         List JavaDoc<ElementRule> rules = new ArrayList<ElementRule>(); // GrammarSyntaxRule objects
319
for (Object JavaDoc o1 : rulesTree.getSelectedNodes()) {
320             DefaultMutableTreeNode node = (DefaultMutableTreeNode) o1;
321             RuleTreeUserObject o = (RuleTreeUserObject) node.getUserObject();
322             if (o.rule != null)
323                 rules.add(o.rule);
324         }
325         return rules;
326     }
327
328     public ElementRule getLastRule() {
329         List JavaDoc<ElementRule> rules = getParserEngine().getRules();
330         if(rules != null && !rules.isEmpty())
331             return rules.get(rules.size()-1);
332         else
333             return null;
334     }
335
336     public ElementRule getLastParserRule() {
337         List JavaDoc<ElementRule> rules = getParserEngine().getRules();
338         for(int index = rules.size()-1; index>0; index--) {
339             ElementRule rule = rules.get(index);
340             if(!rule.lexer)
341                 return rule;
342         }
343         return null;
344     }
345
346     public ElementRule getLastLexerRule() {
347         List JavaDoc<ElementRule> rules = getParserEngine().getRules();
348         for(int index = rules.size()-1; index>0; index--) {
349             ElementRule rule = rules.get(index);
350             if(rule.lexer)
351                 return rule;
352         }
353         return null;
354     }
355
356     public ElementRule getRuleWithName(String JavaDoc name) {
357         List JavaDoc<ElementRule> rules = getParserEngine().getRules();
358         for (ElementRule r : rules) {
359             if (r.name.equals(name))
360                 return r;
361         }
362         return null;
363     }
364
365     public List JavaDoc<String JavaDoc> getRulesStartingWith(String JavaDoc match) {
366         List JavaDoc<String JavaDoc> matches = new ArrayList<String JavaDoc>();
367         if(getParserEngine().getRules() == null)
368             return matches;
369
370         List JavaDoc<ElementRule> rules = getParserEngine().getRules();
371         for (ElementRule r : rules) {
372             String JavaDoc rname = r.name.toLowerCase();
373             if (rname.startsWith(match) && !matches.contains(r.name))
374                 matches.add(r.name);
375         }
376         return matches;
377     }
378
379     public List JavaDoc<ElementReference> getReferencesInRule(ElementRule rule) {
380         if(getParserEngine().getRules() == null)
381             return null;
382
383         List JavaDoc<ElementReference> refs = new ArrayList<ElementReference>();
384         for (ElementReference r : getParserEngine().getReferences()) {
385             if (r.rule == rule)
386                 refs.add(r);
387         }
388         return refs;
389     }
390
391     public ElementRule getEnclosingRuleAtPosition(int pos) {
392         if(getParserEngine().getRules() == null)
393             return null;
394
395         for (ElementRule r : getParserEngine().getRules()) {
396             if (r.containsIndex(pos))
397                 return r;
398         }
399         return null;
400     }
401
402     public ElementRule selectRuleInTreeAtPosition(int pos) {
403         if(programmaticallySelectingRule || getParserEngine().getRules() == null)
404             return null;
405
406         programmaticallySelectingRule = true;
407         ElementRule rule = getEnclosingRuleAtPosition(pos);
408         selectRuleInTree(rule);
409         programmaticallySelectingRule = false;
410         return rule;
411     }
412
413     public ElementRule selectRuleNameInTree(String JavaDoc name) {
414         if(programmaticallySelectingRule || getParserEngine().getRules() == null)
415             return null;
416
417         ElementRule rule = null;
418         programmaticallySelectingRule = true;
419         for (ElementRule r : getParserEngine().getRules()) {
420             if (r.name.equals(name)) {
421                 selectRuleInTree(r);
422                 rule = r;
423                 break;
424             }
425         }
426         programmaticallySelectingRule = false;
427         return rule;
428     }
429
430     public ElementRule getRuleAtIndex(int index) {
431         if(getParserEngine().getRules() == null)
432             return null;
433
434         for (ElementRule r : getParserEngine().getRules()) {
435             if (index >= r.getStartIndex() && index <= r.getEndIndex())
436                 return r;
437         }
438         return null;
439     }
440
441     public boolean isRuleAtIndex(int index) {
442         return getRuleAtIndex(index) != null;
443     }
444
445     public void selectNextRule() {
446         ElementRule rule = getEnclosingRuleAtPosition(editor.getCaretPosition());
447         int index = getParserEngine().getRules().indexOf(rule)+1;
448         rule = getParserEngine().getRuleAtIndex(index);
449         if(rule != null) {
450             editor.setCaretPosition(rule.getStartIndex());
451             editor.rulesCaretPositionDidChange();
452         }
453     }
454
455     public void selectRuleInTree(ElementRule rule) {
456         if(rule == null)
457             return;
458
459         Enumeration enumeration = rulesTreeRootNode.depthFirstEnumeration();
460         while(enumeration.hasMoreElements()) {
461             DefaultMutableTreeNode node = (DefaultMutableTreeNode)enumeration.nextElement();
462             RuleTreeUserObject n = (RuleTreeUserObject)node.getUserObject();
463             if(n != null && n.rule == rule) {
464                 TreePath path = new TreePath(node.getPath());
465                 rulesTree.setSelectionPath(path);
466                 rulesTree.scrollPathToVisible(path);
467                 break;
468             }
469         }
470     }
471
472     public void goToRule(ElementRule rule) {
473         editor.setCaretPosition(rule.start.getStartIndex());
474     }
475
476     public void rebuildTree() {
477         saveExpandedNodes();
478         rememberSelectedTreeItem();
479
480         rulesTreeRootNode.removeAllChildren();
481
482         List JavaDoc<ElementRule> rules = getParserEngine().getRules();
483         List JavaDoc<ElementGroup> groups = getParserEngine().getGroups();
484         if(rules == null || groups == null)
485             return;
486
487         if(groups.isEmpty()) {
488             buildTree(rulesTreeRootNode, rules, 0, rules.size()-1);
489         } else {
490             Stack<DefaultMutableTreeNode> parentStack = new Stack<DefaultMutableTreeNode>();
491             parentStack.add(rulesTreeRootNode);
492
493             int ruleIndex = 0;
494             for (ElementGroup group : groups) {
495                 DefaultMutableTreeNode parentNode = parentStack.peek();
496                 if (group.ruleIndex >= 0) {
497                     buildTree(parentNode, rules, ruleIndex, group.ruleIndex);
498                     ruleIndex = group.ruleIndex + 1;
499                 }
500
501                 if (group.openGroup) {
502                     DefaultMutableTreeNode node = new DefaultMutableTreeNode(new RuleTreeUserObject(group));
503                     parentNode.add(node);
504                     parentStack.push(node);
505                 } else {
506                     if (parentStack.size() > 1)
507                         parentStack.pop();
508                 }
509             }
510
511             if(ruleIndex < rules.size()) {
512                 DefaultMutableTreeNode parentNode = parentStack.peek();
513                 buildTree(parentNode, rules, ruleIndex, rules.size()-1);
514             }
515         }
516
517         rulesTreeModel.reload();
518
519         restoreSelectedTreeItem();
520         restoreExpandedNodes();
521     }
522
523     public void rememberSelectedTreeItem() {
524         DefaultMutableTreeNode node = rulesTree.getSelectedNode();
525         selectedObject = null;
526         if(node != null)
527             selectedObject = (RuleTreeUserObject)node.getUserObject();
528     }
529
530     public void restoreSelectedTreeItem() {
531         if(selectedObject == null)
532             return;
533
534         DefaultMutableTreeNode node = findNodeWithRuleName(selectedObject.rule.name);
535         if(node == null)
536             return;
537
538         programmaticallySelectingRule = true;
539         TreePath path = new TreePath(node.getPath());
540         rulesTree.setSelectionPath(path);
541         rulesTree.scrollPathToVisible(path);
542         programmaticallySelectingRule = false;
543     }
544
545     public void saveExpandedNodes() {
546         rulesTreeExpandedNodes.clear();
547         Enumeration e = rulesTreeRootNode.depthFirstEnumeration();
548         while(e.hasMoreElements()) {
549             DefaultMutableTreeNode node = (DefaultMutableTreeNode)e.nextElement();
550             if(!node.isLeaf() && !node.isRoot() && rulesTree.isExpanded(new TreePath(node.getPath()))) {
551                 RuleTreeUserObject n = (RuleTreeUserObject)node.getUserObject();
552                 rulesTreeExpandedNodes.add(n.group.name);
553             }
554         }
555     }
556
557     public void restoreExpandedNodes() {
558         for (String JavaDoc groupName : rulesTreeExpandedNodes) {
559             DefaultMutableTreeNode node = findNodeWithGroupName(groupName);
560             if (node != null)
561                 rulesTree.expandPath(new TreePath(node.getPath()));
562         }
563     }
564
565     public DefaultMutableTreeNode findNodeWithGroupName(String JavaDoc groupName) {
566         Enumeration e = rulesTreeRootNode.depthFirstEnumeration();
567         while(e.hasMoreElements()) {
568             DefaultMutableTreeNode node = (DefaultMutableTreeNode)e.nextElement();
569             RuleTreeUserObject n = (RuleTreeUserObject)node.getUserObject();
570             if(n.group != null && n.group.name.equalsIgnoreCase(groupName))
571                 return node;
572         }
573         return null;
574     }
575
576     public DefaultMutableTreeNode findNodeWithRuleName(String JavaDoc ruleName) {
577         Enumeration e = rulesTreeRootNode.depthFirstEnumeration();
578         while(e.hasMoreElements()) {
579             DefaultMutableTreeNode node = (DefaultMutableTreeNode)e.nextElement();
580             RuleTreeUserObject n = (RuleTreeUserObject)node.getUserObject();
581             if(n.rule != null && n.rule.name.equalsIgnoreCase(ruleName))
582                 return node;
583         }
584         return null;
585     }
586
587     protected void buildTree(DefaultMutableTreeNode parentNode, List JavaDoc<ElementRule> rules, int from, int to) {
588         // Sort the list of subrules
589
List JavaDoc<ElementRule> subrules = rules.subList(from, to+1);
590         if(sort && !subrules.isEmpty()) {
591             subrules = getSortedRules(subrules);
592             Collections.sort(subrules);
593             ElementRule firstRule = subrules.get(0);
594             if(firstRule.lexer) {
595                 for(int index=0; index<subrules.size(); index++) {
596                     ElementRule rule = subrules.get(0);
597                     if(!rule.lexer)
598                         break;
599
600                     subrules.add(rule);
601                     subrules.remove(0);
602                 }
603             }
604         }
605
606         for (ElementRule rule : subrules) {
607             parentNode.add(new DefaultMutableTreeNode(new RuleTreeUserObject(rule)));
608         }
609     }
610
611     public void parserDidParse() {
612         rebuildTree();
613         if(selectNextRule) {
614             // Can be set by RuleMoveDown() class when a rule is moved down. Selection has to occurs here
615
// after rules have been parsed. We use this flag to select the next rule instead of the current one.
616
selectNextRule = false;
617             selectNextRule();
618         } else
619             selectRuleInTreeAtPosition(editor.getCaretPosition());
620     }
621
622     public boolean moveRule(ElementRule sourceRule, ElementRule targetRule, boolean dropAbove) {
623         if(sourceRule == null || targetRule == null)
624             return false;
625
626         String JavaDoc sourceRuleText = editor.getText().substring(sourceRule.getStartIndex(), sourceRule.getEndIndex()+1);
627
628         try {
629             Document JavaDoc doc = editor.getTextPane().getDocument();
630
631             int removeStartIndex = sourceRule.getStartIndex();
632             int targetInsertionIndex = dropAbove ? targetRule.getStartIndex() : targetRule.getEndIndex();
633
634             // should move at the line after the rule (a comment can be located
635
// after the end of the rule but still on the same line)
636

637             // Remove one more character to remove the end of line of the rule
638
int removeLength = sourceRule.getLength()+1;
639             if(removeStartIndex+removeLength > doc.getLength())
640                 removeLength--;
641
642             if(sourceRule.getStartIndex()>targetRule.getStartIndex()) {
643                 doc.remove(removeStartIndex, removeLength);
644                 doc.insertString(targetInsertionIndex, "\n"+sourceRuleText, null);
645                 editor.setCaretPosition(targetInsertionIndex);
646             } else {
647                 doc.insertString(targetInsertionIndex, "\n"+sourceRuleText, null);
648                 doc.remove(removeStartIndex, removeLength);
649                 editor.setCaretPosition(targetInsertionIndex-removeLength);
650             }
651             return true;
652         } catch (BadLocationException JavaDoc e) {
653             editor.console.print(e);
654             return false;
655         }
656     }
657
658     public void selectRuleFromUserAction() {
659         // Do not select the rule if the selection changes
660
// was triggered programmatically instead than by the user
661
if(programmaticallySelectingRule)
662             return;
663
664         /** Select a rule only if there is one selected row
665          */

666         if(rulesTree.getSelectionCount() != 1)
667             return;
668
669         TreePath selPath[] = rulesTree.getSelectionPaths();
670         if(selPath == null)
671             return;
672
673         List JavaDoc<ElementRule> selRules = new ArrayList<ElementRule>();
674         for (TreePath aSelPath : selPath) {
675             DefaultMutableTreeNode node = (DefaultMutableTreeNode) aSelPath.getLastPathComponent();
676             RuleTreeUserObject n = (RuleTreeUserObject) node.getUserObject();
677             if (n.rule != null)
678                 selRules.add(n.rule);
679         }
680
681         if(!selRules.isEmpty()) {
682             goToRule(selRules.get(0));
683             // Request focus because it was lost when moving the caret in the document
684
rulesTree.requestFocusInWindow();
685         }
686     }
687
688     public Cursor xjTreeDragSourceDefaultCursor(XJTree tree) {
689         return DragSource.DefaultMoveDrop;
690     }
691
692     public int xjTreeDragAndDropConstants(XJTree tree) {
693         return DnDConstants.ACTION_MOVE;
694     }
695
696     public boolean xjTreeDrop(XJTree tree, Object JavaDoc sourceObject, Object JavaDoc targetObject, int dropLocation) {
697         StatisticsAW.shared().recordEvent(StatisticsAW.EVENT_DROP_RULE);
698
699         ElementRule sourceRule = ((EditorRules.RuleTreeUserObject) sourceObject).rule;
700         ElementRule targetRule = ((EditorRules.RuleTreeUserObject) targetObject).rule;
701
702         return moveRule(sourceRule, targetRule, dropLocation == XJTree.DROP_ABOVE);
703     }
704
705     public static final Color HIGHLIGHTED_COLOR = new Color(0, 0.5f, 1, 0.4f);
706
707     public static class RulesTableRenderer extends DefaultTreeCellRenderer {
708
709         public Component getTreeCellRendererComponent(
710                 JTree tree,
711                 Object JavaDoc value,
712                 boolean sel,
713                 boolean expanded,
714                 boolean leaf,
715                 int row,
716                 boolean hasFocus)
717         {
718             Component r = super.getTreeCellRendererComponent(
719                     tree, value, sel,
720                     expanded, leaf, row,
721                     hasFocus);
722
723             // FIX AW-5
724
if(XJSystem.isWindows()) {
725                 setBackgroundSelectionColor(HIGHLIGHTED_COLOR);
726             }
727
728             setIcon(null);
729             setToolTipText("");
730
731             DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
732             RuleTreeUserObject n = (RuleTreeUserObject)node.getUserObject();
733             if(n.rule != null) {
734                 if(n.rule.lexer)
735                     setIcon(IconManager.shared().getIconLexer());
736                 else
737                     setIcon(IconManager.shared().getIconParser());
738             }
739
740             setFont(getFont().deriveFont(Font.PLAIN));
741             setForeground(Color.black);
742
743             if(n.rule != null) {
744                 if(n.rule.hasErrors()) {
745                     setForeground(Color.red);
746                     setToolTipText(n.rule.getErrorMessageHTML());
747                 }
748                 if(n.rule.ignored)
749                     setFont(getFont().deriveFont(Font.ITALIC));
750             }
751
752             return r;
753         }
754     }
755
756     public class RuleTreeSelectionListener implements TreeSelectionListener JavaDoc {
757         public void valueChanged(TreeSelectionEvent JavaDoc e) {
758             selectRuleFromUserAction();
759         }
760     }
761
762     public class RuleTreeMouseListener extends MouseAdapter JavaDoc {
763
764         public void mousePressed(MouseEvent JavaDoc e) {
765             selectRuleFromUserAction();
766             checkForPopupTrigger(e);
767         }
768
769         public void mouseReleased(MouseEvent JavaDoc e) {
770             checkForPopupTrigger(e);
771         }
772
773         public void checkForPopupTrigger(MouseEvent JavaDoc e) {
774             if(e.isPopupTrigger()) {
775                 rulesTree.modifySelectionIfNecessary(e);
776
777                 List JavaDoc<Object JavaDoc> selectedObjects = new ArrayList<Object JavaDoc>(); // RuleTreeUserObject objects
778
for (Object JavaDoc o : rulesTree.getSelectedNodes()) {
779                     DefaultMutableTreeNode node = (DefaultMutableTreeNode) o;
780                     selectedObjects.add(node.getUserObject());
781                 }
782                 JPopupMenu menu = editor.rulesGetContextualMenu(selectedObjects);
783                 if(menu != null)
784                     menu.show(e.getComponent(), e.getX(), e.getY());
785             }
786         }
787
788     }
789
790     public static class RuleTreeUserObject implements Transferable JavaDoc {
791
792         public ElementRule rule;
793         public ElementGroup group;
794
795         public RuleTreeUserObject(ElementRule rule) {
796             this.rule = rule;
797         }
798
799         public RuleTreeUserObject(ElementGroup group) {
800             this.group = group;
801         }
802
803         public String JavaDoc toString() {
804             if(group != null)
805                 return group.name;
806             else if(rule != null)
807                 return rule.name;
808             else
809                 return "";
810         }
811
812         public DataFlavor JavaDoc[] getTransferDataFlavors() {
813             return new DataFlavor JavaDoc[0];
814         }
815
816         public boolean isDataFlavorSupported(DataFlavor JavaDoc flavor) {
817             return false;
818         }
819
820         public Object JavaDoc getTransferData(DataFlavor JavaDoc flavor) throws UnsupportedFlavorException JavaDoc, IOException JavaDoc {
821             return null;
822         }
823     }
824
825 }
826
Popular Tags