Source code: org/merlotxml/merlot/GD_XMLEditorDocUI.java
1 package org.merlotxml.merlot;
2
3 import java.io.*;
4 import java.awt.*;
5 import java.awt.datatransfer.*;
6 import java.awt.event.*;
7 import java.awt.print.*;
8 import java.util.*;
9 import java.beans.*;
10 import java.lang.reflect.*;
11
12 import org.w3c.dom.*;
13
14 import javax.swing.*;
15 import javax.swing.border.*;
16 import javax.swing.event.*;
17 import javax.swing.table.*;
18 import javax.swing.tree.*;
19
20 import com.sun.javax.swing.*;
21
22 import org.merlotxml.util.xml.*;
23 import matthew.awt.StrutLayout;
24 import org.merlotxml.awt.*;
25 import org.merlotxml.merlot.plugin.dtd.*;
26
27 import org.gendiapo.editor.*;
28 import org.gendiapo.editor.document.*;
29
30 import org.swing.*;
31
32 /**
33 *
34 * XML Document UI L&F code
35 *
36 * @version $Id: GD_XMLEditorDocUI.java,v 1.39 2002/10/29 15:22:02 flament Exp $
37 *
38 */
39 public class GD_XMLEditorDocUI extends XMLEditorDocUI
40 implements MerlotConstants, ChangeListener, StatusListener, GD_MerlotDOMNodeViewListener
41 {
42
43 JSplitPane _workspace;
44
45 // GD_MerlotDOMNodeViewer
46 Hashtable _views;
47
48 StateAction[] _actions;
49
50 MerlotDOMNode _wishNode;
51
52 AutoHideAttribute _autoHideAttribute;
53
54 public GD_XMLEditorDocUI(XMLEditorDoc doc)
55 {
56 super(doc);
57 }
58
59 protected void finalize() throws Throwable {
60 _autoHideAttribute.haltNow();
61 super.finalize();
62 }
63
64 /**
65 * return action define in dtd plugin for this document
66 */
67 public StateAction[] getActions() {
68 return _actions;
69 }
70
71 /**
72 * create all view and add them this
73 * @param root the root element in curent document
74 */
75 protected void setupViews(MerlotDOMNode root) {
76 // Creation des vues
77 GD_MerlotDOMNodeViewer styledView = new GD_StyledView(this, root);
78 GD_MerlotDOMNodeViewer treeView = new GD_TreeView(this, root);
79 GD_MerlotDOMNodeViewer attributeView = new GD_AttributeView(this, root);
80 GD_MerlotDOMNodeViewer toolbarView = new GD_ToolbarView(this, root);
81 _views.put("tree", treeView);
82 _views.put("attribute", attributeView);
83 _views.put("styled", styledView);
84 _views.put("toolbar", toolbarView);
85
86 _actions = ((GD_ToolbarView)toolbarView).getActions();
87 _table = ((GD_TreeView)treeView).getTreeTable();
88
89 // init _workspace : _scrollPane & _attributeView
90 _workspace = new JSplitPane(JSplitPane.VERTICAL_SPLIT, styledView.getPanel(), attributeView.getPanel());
91 // button to expand or colapse JSplitPane
92 _workspace.setOneTouchExpandable(true);
93 // Define in percent a height
94 _workspace.setDividerLocation (0.70);
95 _workspace.setResizeWeight (1.0);
96 _workspace.setPreferredSize(new Dimension(500,380));
97 // the minimum has to be set if the split pane is gonna move
98 _workspace.setMinimumSize(new Dimension(10,10));
99
100 // _splitPane
101 _splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, treeView.getPanel(), _workspace);
102 _splitPane.setOneTouchExpandable(true);
103 _splitPane.setResizeWeight(0.20);
104
105 this.setLayout(new BorderLayout());
106 this.add(_splitPane, BorderLayout.CENTER);
107 }
108
109 protected void setupAutoHideAttribute() {
110 GD_MerlotDOMNodeViewer view = (GD_MerlotDOMNodeViewer) _views.get("attribute");
111 JPanel panel = view.getPanel();
112 _autoHideAttribute = new AutoHideAttribute();
113 _autoHideAttribute.lock();
114 panel.addMouseListener(_autoHideAttribute);
115 panel.addMouseMotionListener(_autoHideAttribute);
116 Thread taha = new Thread(_autoHideAttribute, "AutoHideAttribute");
117 taha.start();
118 }
119
120 protected class AutoHideAttribute implements MouseListener, MouseMotionListener, Runnable {
121
122 boolean firstUnlock = true;
123 boolean lock = false;
124 boolean hide = false;
125 boolean inside = false;
126 boolean haltNow = false;
127 long lastMove = 0;
128 int normalLocation = 0;
129
130 public void mouseClicked(java.awt.event.MouseEvent mouseEvent) {
131 }
132
133 public void mouseEntered(java.awt.event.MouseEvent mouseEvent) {
134 inside = true;
135 showAttributes();
136 }
137
138 public void mouseExited(java.awt.event.MouseEvent mouseEvent) {
139 Component c = mouseEvent.getComponent();
140 Rectangle rect = c.getBounds();
141 int x = mouseEvent.getX();
142 int y = mouseEvent.getY();
143 if ((x<1) || (y<1) || (x >= rect.width-1) || (y >= rect.height-1)) {
144 inside = false;
145 }
146 }
147
148 public void mousePressed(java.awt.event.MouseEvent mouseEvent) {
149 }
150
151 public void mouseReleased(java.awt.event.MouseEvent mouseEvent) {
152 }
153
154 public void mouseDragged(java.awt.event.MouseEvent mouseEvent) {
155 }
156
157 public void mouseMoved(java.awt.event.MouseEvent mouseEvent) {
158 lock = false;
159 inside = true;
160 lastMove = System.currentTimeMillis();
161 }
162
163 public void run() {
164 while (!haltNow) {
165 // wait 1 sec
166 try {
167 Thread.sleep(1000);
168 } catch (Exception e) {
169 haltNow = true;
170 }
171 // test if no move since 5 sec
172 /*
173 long now = System.currentTimeMillis();
174 if ((now-lastMove) > 5000) {
175 inside = false;
176 }*/
177 // hide panel if not inside
178 if (!inside) {
179 hideAttributes();
180 }
181 }
182 }
183
184 public void haltNow() {
185 haltNow = true;
186 }
187
188 protected synchronized void showAttributes() {
189 if (hide) {
190 _workspace.setDividerLocation(normalLocation);
191 hide = false;
192 }
193 }
194
195 protected synchronized void hideAttributes() {
196 if ((!lock) && (!hide)) {
197 if (firstUnlock) {
198 firstUnlock = false;
199 JInfoTip.show(_workspace, Component.CENTER_ALIGNMENT, Component.BOTTOM_ALIGNMENT, MerlotResource.getString(UI,"message.hideattribute"));
200 }
201 normalLocation = _workspace.getDividerLocation();
202 _workspace.setDividerLocation(0.99);
203 _workspace.setDividerSize(5);
204 hide = true;
205 }
206 }
207
208 protected synchronized void lock() {
209 lock = true;
210 }
211
212 }
213
214 protected void showAttributes() {
215 _autoHideAttribute.lock();
216 _autoHideAttribute.showAttributes();
217 }
218
219 protected void hideAttributes() {
220 _autoHideAttribute.hideAttributes();
221 }
222
223
224 /**
225 * This panel looks a little like Windows Explorer. It has a treetable at the left,
226 * a JSplitPane slider in the middle, and then an editing workspace at the right.
227 */
228 protected void setupPanel()
229 {
230 /*
231 * init les deux composants avec dim minimum
232 * obligatoire pour le JSplitPane
233 * pour répartir, utiliser setDividerLocation et setResizeWeight
234 */
235
236 // -- Vues
237 _views = new Hashtable();
238
239 _XMLmodel = _doc.getTreeTableModel();
240 MerlotDOMDocument root = _XMLmodel.getDocument();
241 MerlotDOMNode[] children = root.getChildNodes();
242 MerlotDOMNode visualroot = children[1];
243 setupViews(visualroot);
244 setupAutoHideAttribute();
245
246 // Ajout de this comme listener des MerlotDOMNodeViewer
247 for (Enumeration e = _views.elements() ; e.hasMoreElements() ;) {
248 GD_MerlotDOMNodeViewer mdnv = (GD_MerlotDOMNodeViewer) (e.nextElement());
249 mdnv.addMerlotDOMNodeViewListener(this);
250 }
251
252 // -- StatusPanel
253 _statusPanel = new JPanel();
254 PercentLayout statusLay = new PercentLayout(PercentLayout.HORIZONTAL, 5);
255 // statusLay.DEBUG = true;
256
257 _statusPanel.setLayout(statusLay);
258
259 _status1 = new JLabel();
260
261 _status2 = new JLabel();
262 _status2.setPreferredSize(new Dimension(100,20));
263
264 _status3 = new JLabel();
265 _statusPanel.add(_status1,new PercentLayout.Constraints(60,PercentLayout.BOTH));
266 _statusPanel.add(_status2,new PercentLayout.Constraints(10,PercentLayout.BOTH));
267 _statusPanel.add(_status3,new PercentLayout.Constraints(30,PercentLayout.BOTH));
268 }
269
270 // --
271 public GD_XMLEditorDoc getXMLEditorDoc() {
272 return (GD_XMLEditorDoc) _doc;
273 }
274
275 /**
276 * Get JEditorPane of styled view
277 */
278 public JEditorPane getEditorPane() {
279 GD_StyledView styledView = (GD_StyledView) _views.get("styled");
280 return styledView.getEditorPane();
281 }
282
283 public Printable getPrintable() {
284 return (Printable) getEditorPane();
285 }
286
287 /**
288 * Update styled view from MerlotDOMDocument
289 */
290 public void updateStyledView() {
291 GD_StyledView styledView = (GD_StyledView) _views.get("styled");
292 styledView.updateStyledView();
293 }
294
295 /**
296 * Save the current node from view
297 */
298 public boolean sync() {
299 boolean allSync = true;
300 for (Enumeration e = _views.elements() ; e.hasMoreElements() ;) {
301 GD_MerlotDOMNodeViewListener mdnv = (GD_MerlotDOMNodeViewListener) (e.nextElement());
302 if (!mdnv.beforeSelect(null,null)) {
303 allSync = false;
304 }
305 }
306 return allSync;
307 }
308
309 /**
310 * Propagate beforeSelect to all view expect from "view"
311 * @param view the view which want to change node
312 * @param newNode the node selected in view
313 */
314 public boolean beforeSelect(GD_MerlotDOMNodeViewer view, MerlotDOMNode newNode) {
315 // Make Selection for all view expect for "view"
316 boolean ok = true;
317 for (Enumeration e = _views.elements() ; e.hasMoreElements() ;) {
318 GD_MerlotDOMNodeViewListener mdnv = (GD_MerlotDOMNodeViewListener) (e.nextElement());
319 if (mdnv != view) {
320 if (!mdnv.beforeSelect(view,newNode)) {
321 ok = false;
322 }
323 }
324 }
325 return ok;
326 }
327
328 /**
329 * Select the node than the current node in "view"
330 * @param view the view of reference
331 */
332 public void selected(GD_MerlotDOMNodeViewer view) {
333 MerlotDOMNode node = view.getNode();
334
335 // Supprime this des listener pour chaque vue
336 for (Enumeration e = _views.elements() ; e.hasMoreElements() ;) {
337 GD_MerlotDOMNodeViewer mdnv = (GD_MerlotDOMNodeViewer) (e.nextElement());
338 mdnv.removeMerlotDOMNodeViewListener(this);
339 }
340
341 // Selection pour toutes les autres vue que view
342 for (Enumeration e = _views.elements() ; e.hasMoreElements() ;) {
343 GD_MerlotDOMNodeViewer mdnv = (GD_MerlotDOMNodeViewer) (e.nextElement());
344 if (mdnv != view) {
345 mdnv.select(node);
346 }
347 }
348
349 // Remet this comme listener pour chaque vue
350 for (Enumeration e = _views.elements() ; e.hasMoreElements() ;) {
351 GD_MerlotDOMNodeViewer mdnv = (GD_MerlotDOMNodeViewer) (e.nextElement());
352 mdnv.addMerlotDOMNodeViewListener(this);
353 }
354
355 updateNodeMenu(XMLEditorFrame.getSharedInstance()._nodeMenu);
356 }
357
358 /**
359 * return the node that GD_XMLEditorDoc want to show
360 */
361 private MerlotDOMNode getWishNode() {
362 return _wishNode;
363 }
364
365 /**
366 * call from GD_XMLEditorDoc
367 * @param node the node that GD_XMLEditorDoc want to edit
368 * @param brandSpankinNew not used
369 */
370 public void editNode(MerlotDOMNode node, boolean brandSpankinNew) {
371 _wishNode = node;
372 }
373
374 /**
375 * override default to do nothing
376 */
377 public void selectNode(MerlotDOMNode node) {
378 //editNode(node, false);
379 }
380
381 /**
382 * select a node
383 * in fact select a node in first view then all view are synchronize
384 * @param node the node to select
385 */
386 public void syncSelectNode(MerlotDOMNode node) {
387 Enumeration e = _views.elements();
388 GD_MerlotDOMNodeViewer first = (GD_MerlotDOMNodeViewer) e.nextElement();
389 first.select(node);
390 }
391
392 class AsyncSelect implements Runnable {
393
394 MerlotDOMNode _node;
395
396 public AsyncSelect(MerlotDOMNode node) {
397 _node = node;
398 }
399
400 public void run() {
401 syncSelectNode(_node);
402 }
403 }
404
405 /**
406 * call syncSelectNode with SwingUtilities.invokeLater
407 */
408 public void asyncSelectNode(MerlotDOMNode node) {
409 SwingUtilities.invokeLater(new AsyncSelect(node));
410 }
411
412 /**
413 * override default to do nothing
414 */
415 public void refreshNode(MerlotDOMNode node, boolean cancelOnly) {
416 //editNode(node, false);
417 }
418
419 /**
420 * override default to do nothing
421 */
422 public void showNode(MerlotDOMNode node) {
423 //editNode(node, false);
424
425 }
426
427 /**
428 * call from GD_XMLEditorDoc to select another node when the deleted one
429 * @param node the node that was deleted
430 */
431 public void deleteNode(MerlotDOMNode node) {
432 MerlotDOMNode select = node.getPreviousSibling();
433
434 while (select==null?false:((select instanceof MerlotDOMText)?(!((MerlotDOMText) select).isVisible()):false)) {
435 select = select.getPreviousSibling();
436 }
437
438 if (select == null) {
439 select = node.getParentNode();
440 }
441
442 if (node != null) {
443 asyncSelectNode(select);
444 }
445 }
446
447 /**
448 * return the current select node (use the first view)
449 */
450 public MerlotDOMNode getSelectedNode() {
451 GD_MerlotDOMNodeViewer v = (GD_MerlotDOMNodeViewer) _views.elements().nextElement();
452 return v.getNode();
453 }
454
455 /**
456 * return all nodes selected (for compatibilty : only one can selected)
457 */
458 public MerlotDOMNode[] getSelectedNodes() {
459 MerlotDOMNode[] nodes = new MerlotDOMNode[1];
460 nodes[0] = getSelectedNode();
461 return nodes;
462 }
463
464 /**
465 * return context menu for "node"
466 * @param node the node of reference to get the context menu
467 */
468 protected java.util.List getNodeMenuItems(MerlotDOMNode node)
469 {
470 ArrayList result = new ArrayList();
471 XMLEditorActions actions = XMLEditorActions.getSharedInstance();
472 Object[] path = _XMLmodel.getTreePathForNode(node);
473
474 result.add(getNodeAddMenu(node,AFTER));
475 result.add(getNodeAddMenu(node,INTO));
476
477 result.add(MerlotUtils.createActionMenuItem(_doc._deleteNodeAction));
478
479 _doc._deleteNodeAction.setEnabled(path.length > 2); // BUG01136
480 _doc._cutNodeAction.setEnabled(path.length > 2);
481 result.add(new Object()); // separator
482
483 result.add(MerlotUtils.createActionMenuItem(_doc._cutNodeAction));
484 result.add(MerlotUtils.createActionMenuItem(_doc._copyNodeAction));
485 result.add(createTreePasteMenu());
486
487 enablePasteItems(node);
488
489 try {
490 MerlotDOMEditor editor = node.getEditor();
491
492 JMenuItem[] menu_additions = editor.getMenuItems(node);
493 if (menu_additions != null && menu_additions.length > 0) {
494 result.add(new Object()); // separator
495
496 for (int i = 0; i < menu_additions.length; i++) {
497 result.add(menu_additions[i]);
498 }
499
500 }
501 }
502 catch (Throwable t) {
503 MerlotDebug.exception(t);
504 }
505 return result;
506
507 }
508
509 protected void addItemsToMenu(java.util.List menuItems, MenuElement menu)
510 {
511 Iterator iter = menuItems.iterator();
512 while (iter.hasNext()) {
513 Object o = iter.next();
514 if (menu instanceof JMenu) {
515 if (o instanceof JMenuItem) {
516 ((JMenu)menu).add((JMenuItem)o);
517 }
518 else {
519 ((JMenu)menu).addSeparator();
520 }
521 }
522 else if (menu instanceof JPopupMenu) {
523 if (o instanceof JMenuItem) {
524 ((JPopupMenu)menu).add((JMenuItem)o);
525 }
526 else {
527 ((JPopupMenu)menu).addSeparator();
528 }
529 }
530
531 }
532
533
534 }
535
536
537 /**
538 * Creates the add-> menu popup for right-click actions on a particular node.
539 *
540 * @param node the node this is acting on.
541 * @param where what the add is for.. INTO, BEFORE, AFTER the context node
542 * @return a menu containing elements that can be added to a node. If the INTO param is
543 * passed, this also adds the add after and before submenus.
544 */
545
546 protected JMenu getNodeAddMenu(MerlotDOMNode node, int where)
547 {
548 MerlotDOMNode parent = node.getParentNode();
549 MerlotDOMEditor editor = null;
550 MerlotDOMNode contextNode = null;
551 int contextLocation = -1;
552
553 String wherestr;
554
555 JMenu menu;
556 switch (where) {
557 case INTO:
558 default:
559 menu = new GD_JMoreMenu(MerlotResource.getString(UI,"node.popup.add.child"));
560 editor = node.getEditor();
561 contextNode = node;
562 parent = node;
563 wherestr = "INTO";
564
565 break;
566 case BEFORE:
567 menu = new GD_JMoreMenu(MerlotResource.getString(UI,"node.popup.add.before"));
568 if (parent != null) {
569 editor = parent.getEditor();
570 contextNode = parent;
571 contextLocation = parent.getChildIndex(node);
572 }
573 wherestr = "BEFORE";
574 break;
575 case AFTER:
576 menu = new GD_JMoreMenu(MerlotResource.getString(UI,"node.popup.add.after"));
577 if (parent != null) {
578 editor = parent.getEditor();
579 contextNode = parent;
580 contextLocation = parent.getChildIndex(node) + 1;
581 }
582 wherestr = "AFTER";
583 break;
584 }
585
586 if (contextNode == null) {
587 menu.setEnabled(false);
588 return menu;
589 }
590
591 // get list of possible sub-elements for the node here
592 Enumeration elements;
593
594
595 if (contextLocation < 0) {
596 elements = contextNode.getAppendableElements();
597 }
598 else {
599 elements = contextNode.getInsertableElements(contextLocation);
600 }
601
602 if (elements != null) {
603 // Make list of visible element in menu
604 TreeSet list = new TreeSet();
605 while (elements.hasMoreElements()) {
606 DTDElement el = (DTDElement) elements.nextElement();
607 if (!suppressToUser(editor, parent, el)) {
608 list.add(el);
609 }
610 }
611
612 // Find group
613 Collection items = organizeDTDElement(node, list);
614
615 // Create menu
616 ActionListener listener = new NodeAddActionListener(parent,node,where);
617 StringBuffer shortcuts = new StringBuffer();
618 boolean addShortCut = (where == AFTER);
619
620 Iterator it = items.iterator();
621 while (it.hasNext()) {
622 Object o = it.next();
623 if (o instanceof String) {
624 String s = (String) o;
625 menu.add(new JTextSeparator(s));
626 } else if (o instanceof DTDElement) {
627 DTDElement el = (DTDElement) o;
628
629 JMenuItem item = DTDElementToJMenuItem(editor, node, el, addShortCut, shortcuts);
630 item.addActionListener(listener);
631 item.setActionCommand(el.getName());
632 menu.add(item);
633 }
634 }
635 }
636
637 //menu.addSeparator();
638 //JMenuItem addSpecial = getNodeAddSpecialMenu(node);
639 //menu.insertStatic(addSpecial);
640 if (menu.getItemCount() == 0) {
641 menu.setEnabled(false);
642 }
643 return menu;
644
645 }
646
647 /** Get list of DTDElement and organize it with groups define in plugin
648 * @param elements collection of DTDElement
649 * @return collection of (DTDElement and String), String represents header of groups
650 */
651 public Collection organizeDTDElement(MerlotDOMNode node, Collection elements) {
652 // Get groups(key=group name, value=list of element name)
653 HashMap groups;
654 java.util.List groupsOrder;
655 Collection result = new ArrayList();
656
657 DTDPluginConfig dpc = node.getDTDPluginConfig();
658 if (!(dpc instanceof GD_DTDPluginConfig)) {
659 result = elements;
660 } else {
661 groups = ((GD_DTDPluginConfig) dpc).getGroups();
662 groupsOrder = ((GD_DTDPluginConfig) dpc).getGroupsOrder();
663
664 if (groupsOrder.isEmpty()) {
665 result = elements;
666 } else {
667 // To help to find DTDElement
668 HashMap nameToDTDElement = new HashMap();
669 Iterator elementsIterator = elements.iterator();
670 while (elementsIterator.hasNext()) {
671 DTDElement dtdelement = (DTDElement) elementsIterator.next();
672 nameToDTDElement.put(dtdelement.getName(), dtdelement);
673 }
674
675 // Fill result : process each group
676 Iterator i = groupsOrder.iterator();
677 while (i.hasNext()) {
678 // for one group
679 String groupName = (String) i.next();
680 java.util.List groupElements = (java.util.List) groups.get(groupName);
681
682 // add DTDElement of elements
683 Collection elementsInGroup = new ArrayList();
684 Iterator ei = groupElements.iterator();
685 while (ei.hasNext()) {
686 String element = (String) ei.next();
687 DTDElement dtdElement = (DTDElement) nameToDTDElement.get(element);
688 if (dtdElement != null) {
689 elements.remove(dtdElement);
690 elementsInGroup.add(dtdElement);
691 }
692 }
693
694 // if there is elements in this group add them to the result
695 if (!elementsInGroup.isEmpty()) {
696 result.add(groupName);
697 result.addAll(elementsInGroup);
698 }
699 }
700
701 // Add no name group
702 if (!elements.isEmpty()) {
703 Collection tmp = new ArrayList();
704 tmp.addAll(elements);
705 tmp.addAll(result);
706 result = tmp;
707 }
708 }
709 }
710 return result;
711 }
712
713 protected boolean suppressToUser(MerlotDOMEditor editor, MerlotDOMNode node, DTDElement el) {
714 boolean suppressItems = XMLEditorSettings.getSharedInstance().getSuppressAddMenuItems();
715 if (!suppressItems) {
716 return false;
717 } else {
718 DTDCacheEntry dtdentry = _doc.getDTDCacheEntry();
719 DTDPluginConfig pluginConfig = null;
720
721 if (dtdentry instanceof PluginDTDCacheEntry) {
722 pluginConfig = ((PluginDTDCacheEntry)dtdentry).getPluginConfig();
723 }
724 MerlotDOMEditor e = null;
725 try {
726 e = MerlotEditorFactory.getInstance().getEditor(el.getName(),pluginConfig);
727 }
728 catch (InstantiationException ex) {}
729 catch (IllegalAccessException ex) {}
730
731 if (e == null) {
732 return false;
733 } else {
734 boolean editorSuppress;
735 boolean eSuppress;
736 if (editor instanceof GenDiapoEditor) {
737 editorSuppress = ((GenDiapoEditor) editor).suppressAddType(node, el);
738 } else {
739 editorSuppress = editor.suppressAddType(el);
740 }
741 if (e instanceof GenDiapoEditor) {
742 eSuppress = ((GenDiapoEditor) e).suppressAddType(node, el);
743 } else {
744 eSuppress = e.suppressAddType(el);
745 }
746 return (editorSuppress || eSuppress);
747 }
748 }
749 }
750
751 protected JMenuItem DTDElementToJMenuItem(MerlotDOMEditor editor, MerlotDOMNode node, DTDElement el, boolean addShortCut, StringBuffer shortcuts) {
752 // icon
753 Icon icon = null;
754 DTDPluginConfig config = _doc.getDTDPluginConfig();
755 if (config != null) {
756 icon = config.getIconFor(el.getName(), DTDPluginConfig.ICON_SIZE_SMALL);
757 }
758
759 // text
760 String menuText;
761 if (editor instanceof GenDiapoEditor) {
762 menuText = ((GenDiapoEditor) editor).getUserName(node, el);
763 } else {
764 menuText = el.getName();
765 }
766
767 // jmenuitem
768 JMenuItem item = new JMenuItem(menuText,icon);
769
770 // Add shortcut if necessary
771 if (addShortCut) {
772
773 // possible char for a shortcut
774 String keys = el.getName().toUpperCase()+"123456789";
775
776 // delete unwanted character
777 char[] charKeys = keys.toCharArray();
778 keys = "";
779 int i = 0;
780 while (i<charKeys.length) {
781 char c = charKeys[i++];
782 if ((c>='A' && c<='Z') || (c>='0' && c<='9')) {
783 keys += c;
784 }
785 }
786
787 // try to find short cut
788 i=0;
789 String shortcutsStr = shortcuts.toString();
790 while ((i<keys.length()) && (shortcutsStr.indexOf(keys.charAt(i))) != -1) {
791 i++;
792 }
793
794 // if we found a shortcut add it
795 if (i<keys.length()) {
796 char key = keys.charAt(i);
797 shortcuts.append(key);
798 item.setAccelerator(KeyStroke.getKeyStroke(key, java.awt.event.InputEvent.ALT_MASK));
799 }
800 }
801
802 return item;
803 }
804
805 protected void doPopup(MouseEvent e)
806 {
807 // La source doit provenir d'un Component representant un GD_MerlotDOMNodeViewer
808
809 JPopupMenu menu = null;
810
811 Object o = e.getSource();
812
813 // La source dans etre un composant
814 if (!(o instanceof Component)) {
815 return;
816 }
817
818 // Trouve le 1er JPanel parent
819 Component c = (Component) o;
820 int x,y;
821 while ((!(c instanceof JPanel)) || (c == null)) {
822 c = c.getParent();
823 // translate source point
824 e.translatePoint((int)c.getX(), (int)c.getY());
825 if (c instanceof JScrollPane) {
826 Point p = ((JScrollPane)c).getViewport().getViewPosition();
827 e.translatePoint((int)-p.getX(), (int)-p.getY());
828 }
829 }
830
831 Point pt = e.getPoint();
832
833 if (c == null) {
834 return;
835 }
836 JPanel panel = (JPanel) c;
837
838 // Recupere la vue associee
839 GD_MerlotDOMNodeViewer viewer = (GD_MerlotDOMNodeViewer) panel.getClientProperty(GD_MerlotDOMNodeViewer.VIEWER);
840
841 // Recupere le noeud associe
842 MerlotDOMNode node = viewer.getNode();
843
844 // Creation du menu
845 if (node != null) {
846 menu = getNodePopupMenu(node);
847 }
848
849 // Placement du menu
850 if (menu != null) {
851 //XXX make sure menu is all the way on the screen
852 menu.pack();
853 Dimension menusize = menu.getPreferredSize();
854 MerlotDebug.msg("menusize = ["+menusize.width+", "+menusize.height+"] pt.x = "+pt.x+" pt.y = "+pt.y);
855
856 Point screenpoint = (Point)pt.clone();
857
858 javax.swing.SwingUtilities.convertPointToScreen(screenpoint,panel);
859 Dimension screensize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
860
861 Point endpoint = new Point();
862 endpoint.x = screenpoint.x + menusize.width;
863 endpoint.y = screenpoint.y + menusize.height;
864
865 if (screenpoint.x < 0) {
866 screenpoint.x = 0;
867 }
868 if (screenpoint.y < 0) {
869 screenpoint.y = 0;
870 }
871 if (endpoint.x > (int)screensize.getWidth()) {
872 screenpoint.x = (int)screensize.getWidth() - menusize.width;
873 }
874 if (endpoint.y > (int)screensize.getHeight()) {
875 // Add 30 points for a possible Windows Taskbar
876 // (i.e. - programmer couldn't figure out how to ask the system
877 // if it was auto-hidden.) - empirically determined value
878 // if anybody has a better idea.....
879 screenpoint.y = (int)screensize.getHeight() - menusize.height - 30;
880 }
881
882 Point componentpoint = (Point)screenpoint.clone();
883 javax.swing.SwingUtilities.convertPointFromScreen(componentpoint,panel);
884 pt = componentpoint;
885 menu.show(panel,pt.x,pt.y);
886 }
887
888 // MerlotDebug.msg("node = "+node+ " real node class = " +node.getRealNode().getClass());
889
890 }
891
892 // --
893 public Transferable getTransferable()
894 {
895 GD_TreeView treeView = (GD_TreeView) _views.get("tree");
896 return treeView.getTransferable();
897 }
898
899 public int getSelectedRow()
900 {
901 GD_TreeView treeView = (GD_TreeView) _views.get("tree");
902 return treeView.getSelectedRow();
903 }
904
905 // --
906 public void stateChanged(ChangeEvent evt)
907 {
908 MerlotDebug.msg("stateChanged. MouseChagnedTab = "+_mouseChangedTab);
909
910 /*=$**/
911 //aucun composant sélectionné
912 //Component c = _workspace.getSelectedComponent();
913 Component c = null;
914 /*=$**/
915
916 if (c != null && _mouseChangedTab) {
917 // find the component in the hashtable
918 Object o = _openEditors.get(c);
919 if (o instanceof MerlotDOMNode) {
920 // hilight the path to this node in the tree
921 Object[] path = _XMLmodel.getTreePathForNode((MerlotDOMNode)o);
922 _table.getTree().setSelectionPath(new TreePath(path));
923 }
924 }
925 }
926
927
928
929 protected class NodeAddActionListener implements ActionListener /*XMLEditorDocUI.NodeAddActionListener*/ {
930
931 MerlotDOMNode _parent, _sibling;
932 int _action = INTO;
933
934 public NodeAddActionListener (MerlotDOMNode parent) {
935 _parent = parent;
936 }
937
938 public NodeAddActionListener (MerlotDOMNode parent, MerlotDOMNode sibling, int action) {
939 _parent = parent;
940 _sibling = sibling;
941 _action = action;
942 }
943
944 public void actionPerformed(ActionEvent evt) {
945 if (sync()) {
946
947 Object source = evt.getSource();
948 if (source instanceof JMenuItem) {
949 String s = evt.getActionCommand();
950 MerlotDebug.msg("Add: "+s);
951 // create an element
952 // update of wishNode
953 _doc.addNewNode(_parent, s, _sibling, _action);
954 // select wishNode
955 asyncSelectNode(getWishNode());
956 }
957 }
958 }
959
960 }
961
962 boolean isThereElement(MerlotDOMNode[] nodes) {
963 for(int i=0; i<nodes.length; i++) {
964 if (nodes[i] instanceof MerlotDOMElement) {
965 return true;
966 }
967 }
968 return false;
969 }
970
971 public void statusChanged(StatusEvent evt) {
972 }
973
974 public Transferable getTransferable(MerlotDOMNode node) {
975 Transferable t;
976
977 Object[] pathToChild = _XMLmodel.getTreePathForNode(node);
978 TreePath pToChild = new TreePath(pathToChild);
979 TreePath[] treePaths = new TreePath[1];
980 treePaths[0] = pToChild;
981
982 t = _XMLmodel.getTransferable(treePaths);
983 return t;
984 }
985
986 public Transferable getTransferableOfChilds(MerlotDOMNode node) {
987 Transferable t;
988 MerlotDOMNode[] children = node.getChildNodes();
989 TreePath[] treePaths = new TreePath[children.length];
990
991 for (int i=0; i<children.length; i++) {
992 Object[] pathToChild = _XMLmodel.getTreePathForNode(children[i]);
993 treePaths[i] = new TreePath(pathToChild);
994 }
995
996 t = _XMLmodel.getTransferable(treePaths);
997 return t;
998 }
999
1000 public void updateNodeMenu(JMenu menu)
1001 {
1002 MerlotDOMNode node = getSelectedNode();
1003 java.util.List nodeMenu = getNodeMenuItems(node);
1004 ((GD_XMLEditorFrame) XMLEditorFrame.getSharedInstance()).setupEditMenu(menu, nodeMenu);
1005 }
1006
1007
1008}