View Javadoc

1   package sk.uniba.euromath.editor.xmlEditor.tools;
2   
3   import java.util.Collections;
4   
5   import org.eclipse.core.runtime.IStatus;
6   import org.eclipse.gef.DragTracker;
7   import org.eclipse.gef.EditPart;
8   import org.eclipse.gef.EditPartViewer;
9   import org.eclipse.gef.EditPartViewer.Conditional;
10  import org.eclipse.gef.tools.TargetingTool;
11  import org.eclipse.swt.events.KeyEvent;
12  import org.w3c.dom.DOMException;
13  import org.w3c.dom.Node;
14  
15  import sk.baka.ikslibs.interval.DOMInterval;
16  import sk.baka.ikslibs.interval.DOMIntervalSet;
17  import sk.baka.ikslibs.ptr.DomPointer;
18  import sk.baka.ikslibs.ptr.DomPointerFactory;
19  import sk.uniba.euromath.EuroMath;
20  import sk.uniba.euromath.document.XMLAccess;
21  import sk.uniba.euromath.editor.xmlEditor.IXMLEditPart;
22  import sk.uniba.euromath.editor.xmlEditor.XMLEditDomain;
23  import sk.uniba.euromath.editor.xmlEditor.viewers.IXMLGraphicalViewer;
24  
25  /***
26   * Drag tracker handling drags interpreting them as selections. Local selection
27   * is created translating start-point end-point to DOMPointers making
28   * DOMInterval. Depending on input is local selection combined with viewer's
29   * selection. <br>
30   * Start(end) point translation is always to DOMPinters pointing between nodes,
31   * not into.
32   * 
33   * @author Martin Kollar 23.09.2005
34   */
35  public class XMLStructureDragTracker extends TargetingTool implements
36                  DragTracker {
37  
38          /***
39           * Holds selection of graphical viewer displayed before this drag
40           * started.
41           */
42          private DOMIntervalSet globalSelectionPriorDrag;
43  
44          /***
45           * Source editpart;
46           */
47          private IXMLEditPart sourceEditPart;
48  
49          /***
50           * Constructs new XMLDragTracker with the given XMLEditPart
51           * 
52           * @param sourceEditPart
53           *                source editPart where selection starts
54           */
55          public XMLStructureDragTracker(IXMLEditPart sourceEditPart) {
56                  super();
57                  this.sourceEditPart = sourceEditPart;
58          }
59  
60          /***
61           * Retreives selection from viewer, before drag started.
62           */
63          @Override
64          public void setViewer(EditPartViewer viewer) {
65                  super.setViewer(viewer);
66                  if (this.globalSelectionPriorDrag == null) {
67                          this.globalSelectionPriorDrag = getXMLGraphicalViewer()
68                                          .getDOMSelection();
69                  }
70          }
71  
72          @Override
73          protected boolean handleDragStarted() {
74                  return stateTransition(STATE_DRAG, STATE_DRAG_IN_PROGRESS);
75          }
76  
77          @Override
78          protected boolean handleDrag() {
79                  updateTargetUnderMouse();
80                  return true;
81          }
82  
83          @Override
84          protected boolean handleDragInProgress() {
85                  if (isInState(STATE_DRAG_IN_PROGRESS
86                  /* | STATE_ACCESSIBLE_DRAG_IN_PROGRESS */)) {
87                  }
88                  return true;
89          }
90  
91          @Override
92          protected boolean handleExitingEditPart() {
93                  getXMLGraphicalViewer().setSelection(computeGlobalSelection());
94                  return true;
95          }
96  
97          @Override
98          protected boolean handleEnteredEditPart() {
99                  getXMLGraphicalViewer().setSelection(computeGlobalSelection());
100                 return true;
101         }
102 
103         @Override
104         protected boolean handleButtonDown(int button) {
105                 updateTargetUnderMouse();
106                 // selecting is controlled by left mouse button drags
107                 if (button != 1) {
108                         // TODO Studva
109                         setState(STATE_INVALID);
110                         return false;
111                 }
112 
113                 stateTransition(STATE_INITIAL, STATE_DRAG);
114                 return true;
115         }
116 
117         /***
118          * Computes local selection corresponding to drag.
119          * 
120          * @return selection made by this drag
121          */
122         protected DOMIntervalSet computeLocalSelection() {
123                 if (!(getSourceEditPart() instanceof IXMLEditPart)
124                                 || (((IXMLEditPart) getSourceEditPart())
125                                                 .getID() == null)) {
126                         return new DOMIntervalSet();
127                 }
128                 if (!(getTargetEditPart() instanceof IXMLEditPart)
129                                 || (((IXMLEditPart) getTargetEditPart())
130                                                 .getID() == null)) {
131                         return new DOMIntervalSet();
132                 }
133 
134                 Node node1 = null;
135                 Node node2 = null;
136                 try {
137                         node1 = getXMLAccess().getIDManager().getNode(
138                                         ((IXMLEditPart) getSourceEditPart())
139                                                         .getID()).item(0);
140                         node2 = getXMLAccess().getIDManager().getNode(
141                                         ((IXMLEditPart) getTargetEditPart())
142                                                         .getID()).item(0);
143                 } catch (DOMException e) {
144                         EuroMath.log(IStatus.ERROR, 0,
145                                         "Invalid state of Euromath.", e);
146                         return new DOMIntervalSet();
147                 }
148 
149                 // compare pointers to find they ordering
150                 int nodeCompare = node1.compareDocumentPosition(node2);
151 
152                 if ((nodeCompare & (Node.DOCUMENT_POSITION_CONTAINS | Node.DOCUMENT_POSITION_CONTAINED_BY)) != 0) {
153                         // in this case, use only node of target editpart -
154                         // node2
155                         // point before node
156                         DomPointer startPointer = DomPointerFactory
157                                         .create(node2);
158                         // point after node
159                         DomPointer endPointer = DomPointerFactory.create(node2
160                                         .getParentNode(), node2
161                                         .getNextSibling());
162                         return new DOMIntervalSet(new DOMInterval(startPointer,
163                                         endPointer));
164                 }
165 
166                 if (node1.equals(node2)
167                                 || ((nodeCompare & Node.DOCUMENT_POSITION_FOLLOWING) != 0)) {
168                         // nodes are same = select the node, or node1 is before
169                         // node2
170                         // point before node
171                         DomPointer startPointer = DomPointerFactory
172                                         .create(node1);
173                         // point after node
174                         DomPointer endPointer = DomPointerFactory.create(node2
175                                         .getParentNode(), node2
176                                         .getNextSibling());
177                         return new DOMIntervalSet(new DOMInterval(startPointer,
178                                         endPointer));
179                 }
180 
181                 if ((nodeCompare & Node.DOCUMENT_POSITION_PRECEDING) != 0) {
182                         // node2 is before node1
183                         // point before node
184                         DomPointer startPointer = DomPointerFactory
185                                         .create(node2);
186                         // point after node
187                         DomPointer endPointer = DomPointerFactory.create(node1
188                                         .getParentNode(), node1
189                                         .getNextSibling());
190                         return new DOMIntervalSet(new DOMInterval(startPointer,
191                                         endPointer));
192                 }
193                 // illegal state because nodes aren't ordered correctly
194                 throw new IllegalStateException();
195         }
196 
197         /***
198          * If in the drag state, the tool selects the source edit part. If the
199          * edit part was already selected, {@link #performDirectEdit()} is
200          * called. If the edit part is newly selected and not completely
201          * visible, {@link EditPartViewer#reveal(EditPart)} is called to show
202          * the selected edit part.
203          * 
204          * @see org.eclipse.gef.tools.AbstractTool#handleButtonUp(int)
205          */
206         protected boolean handleButtonUp(int button) {
207                 if (isInState(STATE_DRAG | STATE_DRAG_IN_PROGRESS)) {
208                         finishDrag();
209                         setState(STATE_TERMINAL);
210                         return true;
211                 }
212 
213                 setState(STATE_TERMINAL);
214                 return true;
215         }
216 
217         /***
218          * Computes actual selection to set to viewer. Pressed ctrl and shift
219          * keys influence how selection is computed. The user needs 3 styles of
220          * selecting: simple interval (nothing pressed), union interval with
221          * current selection(shift pressed) and xor interval with current
222          * selection(ctrl pressed).
223          * 
224          * @return global selection uctual to current state of drag, returned by
225          *         copy
226          */
227         protected DOMIntervalSet computeGlobalSelection() {
228                 DOMIntervalSet localSelection = computeLocalSelection();
229 
230                 // ctrl not pressed, shift not pressed
231                 if ((!getCurrentInput().isControlKeyDown())
232                                 && (!getCurrentInput().isShiftKeyDown())) {
233                         return localSelection;
234                 }
235                 // ctrl pressed
236                 if (getCurrentInput().isControlKeyDown()
237                                 && !getCurrentInput().isShiftKeyDown()) {
238                         // XOR
239                         return localSelection
240                                         .invert(this.globalSelectionPriorDrag);
241                 }
242                 // shift pressed
243                 if (getCurrentInput().isShiftKeyDown()
244                                 && !getCurrentInput().isControlKeyDown()) {
245                         // union
246                         DOMIntervalSet result = new DOMIntervalSet(
247                                         localSelection);
248                         result.union(this.globalSelectionPriorDrag, null);
249                         return result;
250                 }
251                 // keys are illegaly pressed, don't change viewer's selection
252                 return this.globalSelectionPriorDrag;
253         }
254 
255         protected XMLAccess getXMLAccess() {
256                 return ((XMLEditDomain) getDomain()).getXMLEditor()
257                                 .getXMLAccess();
258         }
259 
260         protected IXMLGraphicalViewer getXMLGraphicalViewer() {
261                 return (IXMLGraphicalViewer) getCurrentViewer();
262         }
263 
264         @Override
265         protected String getCommandName() {
266                 return "XML Structure Drag Tracker.";//$NON-NLS-1$
267         }
268 
269         protected EditPart getSourceEditPart() {
270                 return this.sourceEditPart;
271         }
272 
273         /***
274          * Simpler implementation than super, as target is directly taken
275          * editpart at mouse cursor location, which must be XMLEditPart with not
276          * null element id. In case when drag started at location where editpart
277          * hasn't id (source edit part hasn't id), source editpart is set to
278          * target, if not yet.
279          */
280         protected boolean updateTargetUnderMouse() {
281                 if (!isTargetLocked()) {
282                         EditPart editPart = getCurrentViewer()
283                                         .findObjectAtExcluding(getLocation(),
284                                                         Collections.EMPTY_SET,
285                                                         new Conditional() {
286                                                                 public boolean evaluate(
287                                                                                 EditPart editpart) {
288                                                                         return XMLStructureDragTracker.this
289                                                                                         .evaluate(editpart);
290                                                                 }
291                                                         });
292                         boolean changed = getTargetEditPart() != editPart;
293                         setTargetEditPart(editPart);
294                         // if needed correct source editpart
295                         if (!evaluate(getSourceEditPart()))
296                                 this.sourceEditPart = (IXMLEditPart)editPart;
297                         return changed;
298                 }
299                 return false;
300         }
301 
302         /***
303          * Test editpart, if is acceptable as end point of selection under
304          * mouse.
305          * 
306          * @param editpart
307          *                to test for potential target - end point of selection
308          * @return true if is suitable for end point of selection
309          */
310         protected boolean evaluate(EditPart editpart) {
311                 return (editpart instanceof IXMLEditPart)
312                                 && (((IXMLEditPart) editpart).getID() != null)
313                                 && (((IXMLEditPart) editpart).getID().indexOf(
314                                                 ';') < 0);
315         }
316 
317         /***
318          * Is called at termination of drag to perfom and finish selection and
319          * drag related tasks.
320          */
321         protected void finishDrag() {
322                 getXMLGraphicalViewer().setSelection(computeGlobalSelection());
323         }
324 
325         @Override
326         protected boolean handleKeyDown(KeyEvent e) {
327                 finishDrag();
328                 setState(STATE_TERMINAL);
329                 return true;
330         }
331 
332         @Override
333         protected boolean handleKeyUp(KeyEvent e) {
334                 finishDrag();
335                 setState(STATE_TERMINAL);
336                 return true;
337         }
338 }