1
2
3
4
5
6
7
8 package com.extjs.gxt.ui.client.fx;
9
10 import com.extjs.gxt.ui.client.Style;
11 import com.extjs.gxt.ui.client.core.El;
12 import com.extjs.gxt.ui.client.core.XDOM;
13 import com.extjs.gxt.ui.client.event.BaseObservable;
14 import com.extjs.gxt.ui.client.event.ComponentEvent;
15 import com.extjs.gxt.ui.client.event.DragEvent;
16 import com.extjs.gxt.ui.client.event.DragListener;
17 import com.extjs.gxt.ui.client.event.Events;
18 import com.extjs.gxt.ui.client.event.Listener;
19 import com.extjs.gxt.ui.client.event.PreviewEvent;
20 import com.extjs.gxt.ui.client.util.BaseEventPreview;
21 import com.extjs.gxt.ui.client.util.Rectangle;
22 import com.extjs.gxt.ui.client.widget.Component;
23 import com.extjs.gxt.ui.client.widget.Shim;
24 import com.google.gwt.event.dom.client.KeyCodes;
25 import com.google.gwt.user.client.Command;
26 import com.google.gwt.user.client.DOM;
27 import com.google.gwt.user.client.DeferredCommand;
28 import com.google.gwt.user.client.Element;
29 import com.google.gwt.user.client.Event;
30 import com.google.gwt.user.client.Window;
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78 @SuppressWarnings("deprecation")
79 public class Draggable extends BaseObservable {
80
81 protected int conX, conY, conWidth, conHeight;
82 protected int dragStartX, dragStartY;
83 protected int lastX, lastY;
84 protected El proxyEl;
85 protected Rectangle startBounds;
86
87 private int clientWidth, clientHeight;
88 private boolean constrainClient = true;
89 private boolean constrainHorizontal;
90 private boolean constrainVertical;
91 private Component container;
92 private DragEvent dragEvent;
93 private boolean dragging;
94 private Component dragWidget;
95 private boolean enabled = true;
96 private Component handle;
97 private Listener<ComponentEvent> listener;
98 private boolean moveAfterProxyDrag = true;
99 private BaseEventPreview preview;
100 private String proxyStyle = "x-drag-proxy";
101 private boolean sizeProxyToSource = true;
102 private int startDragDistance = 2;
103 private Element startElement;
104
105 private boolean updateZIndex = true;
106 private boolean useProxy = true;
107 private int xLeft = Style.DEFAULT, xRight = Style.DEFAULT;
108 private int xTop = Style.DEFAULT, xBottom = Style.DEFAULT;
109
110
111
112
113
114
115 public Draggable(Component dragComponent) {
116 this(dragComponent, dragComponent);
117 }
118
119
120
121
122
123
124
125 public Draggable(final Component dragComponent, final Component handle) {
126 listener = new Listener<ComponentEvent>() {
127 public void handleEvent(ComponentEvent ce) {
128 onMouseDown(ce);
129 }
130 };
131 this.dragWidget = dragComponent;
132 this.handle = handle;
133
134 handle.addListener(Events.OnMouseDown, listener);
135
136 preview = new BaseEventPreview() {
137
138 @Override
139 public boolean onPreview(PreviewEvent event) {
140 event.preventDefault();
141 switch (event.getEventTypeInt()) {
142 case Event.ONKEYDOWN:
143 if (dragging && event.getKeyCode() == KeyCodes.KEY_ESCAPE) {
144 cancelDrag();
145 }
146 break;
147 case Event.ONMOUSEMOVE:
148 onMouseMove(event.getEvent());
149 break;
150 case Event.ONMOUSEUP:
151 stopDrag(event.getEvent());
152 break;
153 }
154 return true;
155 }
156
157 };
158 preview.setAutoHide(false);
159
160 handle.sinkEvents(Event.ONMOUSEDOWN);
161 }
162
163
164
165
166
167
168 public void addDragListener(DragListener listener) {
169 addListener(Events.DragStart, listener);
170 addListener(Events.DragMove, listener);
171 addListener(Events.DragCancel, listener);
172 addListener(Events.DragEnd, listener);
173 }
174
175
176
177
178 public void cancelDrag() {
179 preview.remove();
180 if (dragging) {
181 dragging = false;
182 if (isUseProxy()) {
183 proxyEl.disableTextSelection(false);
184 proxyEl.setVisibility(false);
185 proxyEl.remove();
186 } else {
187 dragWidget.el().setPagePosition(startBounds.x, startBounds.y);
188 }
189 DragEvent de = new DragEvent(this);
190 de.setStartElement(startElement);
191 fireEvent(Events.DragCancel, de);
192 afterDrag();
193 }
194 startElement = null;
195 }
196
197
198
199
200
201
202 public Component getContainer() {
203 return container;
204 }
205
206
207
208
209
210
211 public Component getDragHandle() {
212 return handle;
213 }
214
215
216
217
218
219
220 public Component getDragWidget() {
221 return dragWidget;
222 }
223
224
225
226
227
228
229 public String getProxyStyle() {
230 return proxyStyle;
231 }
232
233
234
235
236
237
238 public int getStartDragDistance() {
239 return startDragDistance;
240 }
241
242
243
244
245
246
247 public boolean isConstrainClient() {
248 return constrainClient;
249 }
250
251
252
253
254
255
256 public boolean isConstrainHorizontal() {
257 return constrainHorizontal;
258 }
259
260
261
262
263
264
265 public boolean isConstrainVertical() {
266 return constrainVertical;
267 }
268
269
270
271
272
273
274 public boolean isDragging() {
275 return dragging;
276 }
277
278
279
280
281
282
283 public boolean isEnabled() {
284 return enabled;
285 }
286
287
288
289
290
291
292 public boolean isMoveAfterProxyDrag() {
293 return moveAfterProxyDrag;
294 }
295
296
297
298
299
300
301 public boolean isSizeProxyToSource() {
302 return sizeProxyToSource;
303 }
304
305
306
307
308
309
310 public boolean isUpdateZIndex() {
311 return updateZIndex;
312 }
313
314
315
316
317
318
319 public boolean isUseProxy() {
320 return useProxy;
321 }
322
323
324
325
326 public void release() {
327 cancelDrag();
328 handle.removeListener(Events.OnMouseDown, listener);
329 }
330
331
332
333
334
335
336 public void removeDragListener(DragListener listener) {
337 if (hasListeners()) {
338 removeListener(Events.DragStart, listener);
339 removeListener(Events.DragMove, listener);
340 removeListener(Events.DragCancel, listener);
341 removeListener(Events.DragEnd, listener);
342 }
343 }
344
345
346
347
348
349
350 public void setConstrainClient(boolean constrainClient) {
351 this.constrainClient = constrainClient;
352 }
353
354
355
356
357
358
359 public void setConstrainHorizontal(boolean constrainHorizontal) {
360 this.constrainHorizontal = constrainHorizontal;
361 }
362
363
364
365
366
367
368 public void setConstrainVertical(boolean constrainVertical) {
369 this.constrainVertical = constrainVertical;
370 }
371
372
373
374
375
376
377 public void setContainer(Component container) {
378 this.container = container;
379 }
380
381
382
383
384
385
386
387 public void setEnabled(boolean enabled) {
388 this.enabled = enabled;
389 }
390
391
392
393
394
395
396 public void setMoveAfterProxyDrag(boolean moveAfterProxyDrag) {
397 this.moveAfterProxyDrag = moveAfterProxyDrag;
398 }
399
400
401
402
403
404
405 public void setProxy(El element) {
406 proxyEl = element;
407 }
408
409
410
411
412
413
414 public void setProxyStyle(String proxyStyle) {
415 this.proxyStyle = proxyStyle;
416 }
417
418
419
420
421
422
423
424 public void setSizeProxyToSource(boolean sizeProxyToSource) {
425 this.sizeProxyToSource = sizeProxyToSource;
426 }
427
428
429
430
431
432
433
434 public void setStartDragDistance(int startDragDistance) {
435 this.startDragDistance = startDragDistance;
436 }
437
438
439
440
441
442
443
444
445 public void setUpdateZIndex(boolean updateZIndex) {
446 this.updateZIndex = updateZIndex;
447 }
448
449
450
451
452
453
454 public void setUseProxy(boolean useProxy) {
455 this.useProxy = useProxy;
456 }
457
458
459
460
461
462
463
464 public void setXConstraint(int left, int right) {
465 xLeft = left;
466 xRight = right;
467 }
468
469
470
471
472
473
474
475 public void setYConstraint(int top, int bottom) {
476 xTop = top;
477 xBottom = bottom;
478 }
479
480 protected void afterDrag() {
481 XDOM.getBodyEl().removeStyleName("x-unselectable");
482 XDOM.getBodyEl().removeStyleName("x-dd-cursor");
483 Shim.get().uncover();
484 }
485
486 protected El createProxy() {
487 proxyEl = new El(DOM.createDiv());
488 proxyEl.setVisibility(false);
489 proxyEl.dom.setClassName(getProxyStyle());
490 proxyEl.disableTextSelection(true);
491 return proxyEl;
492 }
493
494 protected void onMouseDown(ComponentEvent ce) {
495 if (!enabled || ce.getEvent().getButton() != Event.BUTTON_LEFT) {
496 return;
497 }
498 Element target = ce.getTarget();
499 String s = DOM.getElementProperty(target, "className");
500 if (s != null && s.indexOf("x-nodrag") != -1) {
501 return;
502 }
503
504
505 if ((!"input".equalsIgnoreCase(ce.getTarget().getTagName()) && !"textarea".equalsIgnoreCase(ce.getTarget().getTagName()))
506 || ce.getTarget().getPropertyBoolean("disabled")) {
507 ce.preventDefault();
508 }
509
510 startBounds = dragWidget.el().getBounds();
511
512 startElement = ce.getTarget();
513
514 dragStartX = ce.getClientX();
515 dragStartY = ce.getClientY();
516
517 preview.add();
518
519 clientWidth = Window.getClientWidth() + XDOM.getBodyScrollLeft();
520 clientHeight = Window.getClientHeight() + XDOM.getBodyScrollTop();
521
522 if (container != null) {
523 conX = container.getAbsoluteLeft();
524 conY = container.getAbsoluteTop();
525 conWidth = container.getOffsetWidth();
526 conHeight = container.getOffsetHeight();
527 }
528
529 if (startDragDistance == 0) {
530 startDrag(ce.getEvent());
531 }
532
533 }
534
535 protected void onMouseMove(Event event) {
536 Element elem = event.getEventTarget().cast();
537
538
539 if (hasAttribute(elem, "class")) {
540
541
542 String cls = El.getClassName(((Element) event.getEventTarget().cast()));
543
544 if (cls != null && cls.contains("x-insert")) {
545 return;
546 }
547 }
548
549 int x = DOM.eventGetClientX(event);
550 int y = DOM.eventGetClientY(event);
551
552 if (!dragging && (Math.abs(dragStartX - x) > startDragDistance || Math.abs(dragStartY - y) > startDragDistance)) {
553 startDrag(event);
554 }
555
556 if (dragging) {
557 int left = constrainHorizontal ? startBounds.x : startBounds.x + (x - dragStartX);
558 int top = constrainVertical ? startBounds.y : startBounds.y + (y - dragStartY);
559
560 if (constrainClient) {
561 if (!constrainHorizontal) {
562 int width = startBounds.width;
563 left = Math.max(left, 0);
564 left = Math.max(0, Math.min(clientWidth - width, left));
565 }
566 if (!constrainVertical) {
567 top = Math.max(top, 0);
568 int height = startBounds.height;
569 if (Math.min(clientHeight - height, top) > 0) {
570 top = Math.max(2, Math.min(clientHeight - height, top));
571 }
572 }
573 }
574
575 if (container != null) {
576 int width = startBounds.width;
577 int height = startBounds.height;
578 if (!constrainHorizontal) {
579 left = Math.max(left, conX);
580 left = Math.min(conX + conWidth - width, left);
581 }
582 if (!constrainVertical) {
583 top = Math.min(conY + conHeight - height, top);
584 top = Math.max(top, conY);
585 }
586 }
587 if (!constrainHorizontal) {
588 if (xLeft != Style.DEFAULT) {
589 left = Math.max(startBounds.x - xLeft, left);
590 }
591 if (xRight != Style.DEFAULT) {
592 left = Math.min(startBounds.x + xRight, left);
593 }
594 }
595
596 if (!constrainVertical) {
597 if (xTop != Style.DEFAULT) {
598 top = Math.max(startBounds.y - xTop, top);
599 }
600 if (xBottom != Style.DEFAULT) {
601 top = Math.min(startBounds.y + xBottom, top);
602 }
603 }
604
605 lastX = left;
606 lastY = top;
607
608 dragEvent.setSource(this);
609 dragEvent.setStartElement(startElement);
610 dragEvent.setComponent(dragWidget);
611 dragEvent.setEvent(event);
612 dragEvent.setCancelled(false);
613 dragEvent.setX(lastX);
614 dragEvent.setY(lastY);
615 fireEvent(Events.DragMove, dragEvent);
616
617 if (dragEvent.isCancelled()) {
618 cancelDrag();
619 return;
620 }
621
622 int tl = dragEvent.getX() != lastX ? dragEvent.getX() : lastX;
623 int tt = dragEvent.getY() != lastY ? dragEvent.getY() : lastY;
624 if (useProxy) {
625 proxyEl.setPagePosition(tl, tt);
626 } else {
627 dragWidget.el().setPagePosition(tl, tt);
628 }
629 }
630
631 }
632
633 protected void startDrag(Event event) {
634 DragEvent de = new DragEvent(this);
635 de.setComponent(dragWidget);
636 de.setEvent(event);
637 de.setX(startBounds.x);
638 de.setY(startBounds.y);
639 de.setStartElement(startElement);
640
641 if (fireEvent(Events.DragStart, de)) {
642 dragging = true;
643 XDOM.getBodyEl().addStyleName("x-unselectable");
644 XDOM.getBodyEl().addStyleName("x-dd-cursor");
645 dragWidget.el().makePositionable();
646
647 event.preventDefault();
648 Shim.get().cover(true);
649
650 lastX = startBounds.x;
651 lastY = startBounds.y;
652
653 if (dragEvent == null) {
654 dragEvent = new DragEvent(this);
655 }
656
657 if (useProxy) {
658 if (proxyEl == null) {
659 createProxy();
660 }
661 if (container == null) {
662 XDOM.getBody().appendChild(proxyEl.dom);
663 } else {
664 container.el().appendChild(proxyEl.dom);
665 }
666 proxyEl.setVisibility(true);
667 proxyEl.setZIndex(XDOM.getTopZIndex());
668 proxyEl.makePositionable(true);
669
670 if (sizeProxyToSource) {
671 proxyEl.setBounds(startBounds);
672 } else {
673 proxyEl.setXY(startBounds.x, startBounds.y);
674 }
675
676
677 if (de.getHeight() > 0 && de.getWidth() > 0) {
678 proxyEl.setSize(de.getWidth(), de.getHeight(), true);
679 } else if (de.getHeight() > 0) {
680 proxyEl.setHeight(de.getHeight(), true);
681 } else if (de.getWidth() > 0) {
682 proxyEl.setWidth(de.getWidth(), true);
683 }
684 } else if (updateZIndex) {
685 dragWidget.setZIndex(XDOM.getTopZIndex());
686 }
687 } else {
688 cancelDrag();
689 }
690 }
691
692 protected void stopDrag(Event event) {
693 preview.remove();
694 if (dragging) {
695 dragging = false;
696 if (isUseProxy()) {
697 if (isMoveAfterProxyDrag()) {
698 Rectangle rect = proxyEl.getBounds();
699 dragWidget.el().setPagePosition(rect.x, rect.y);
700 }
701 proxyEl.setVisibility(false);
702 proxyEl.disableTextSelection(false);
703 DeferredCommand.addCommand(new Command() {
704 public void execute() {
705 if (proxyEl != null) {
706 proxyEl.remove();
707 }
708 }
709 });
710 }
711 DragEvent de = new DragEvent(this);
712 de.setStartElement(startElement);
713 de.setComponent(dragWidget);
714 de.setEvent(event);
715 de.setX(lastX);
716 de.setY(lastY);
717 fireEvent(Events.DragEnd, de);
718 afterDrag();
719 }
720 startElement = null;
721 }
722
723 private native boolean hasAttribute(Element elem, String name)
724
725 ;
726
727 }