Problem/Issue
I need to be able to drag objects (widgets or other non widget
objects) from one window to another within the same application
without facing text selection problems. For instance if I have a
dialog box containing a list of fields that I want included on a
spreadsheet grid, I would want to be able to highlight those fields on
the list in the dialog and drop them on a grid in another window.
Another scenario is if I have a list of people in a grid. The
application uses tree control based folders for navigation. The grid
only shows people in a specific folder. To drag people (rows in a
grid) from one folder to another, you highlight the rows and start
dragging them and drop on a different folder (a node in the tree
control). So the drag and drop is occurring from a grid to a tree
control.
Now the problem is that in GWT, when you start dragging, the browser
highlights (does text selection) all windows affected by the mouse
move event by default. The idea is to prevent the ugly default text
selection at the application level as soon as drag event is fired.
For that I propose using an event preview class that is an extension
of a container widget like a GWT’s SimplePanel. The class must
implement an event preview to catch all events of interest and prevent
their default behavior before they reach their targets, which are
children of this preview container.This preview class will be used as
the main container of all widgets in you application thus:
Panel p; .. //add panel to previewer
MainEventPreviewer previewer = new MainEventPreviewer (p);
//add previewer to the page
RootPanel.get().add(previewer);
The Panel “p” will be the container of all subsequent widgets used in
the application.
This setup guarantees that the event preview in the previewer class
will always be on top of of the preview stack as long as there is no
DialogBox or PopupPanel displayed. As you will see in the event
preview code below, when dragging starts, in the ONMOUSEDOWN and
ONMOUSEMOVE events, the event preview panel disables default behavior
before any child widgets have received those events . That way, no
default text selection occurs.
When the mouse is released (ONMOUSEUP event), the preview class causes
the default state to be restored once again.
Note that it doesn’t matter which widget(s) are doing the drag and
drop as long as those widgets are child widgets within the containment
hierarchy with MainEventPreviewer class as their parent. The drag and
drop and text selection behavior will be neatly controlled.
[CODE]
public class MainEventPreviewer extends SimplePanel implements
EventPreview {
private DragTimer m_DragTimer;
private boolean ib_lbutton_down = false, ib_dragging = false;
public MainEventPreviewer(Panel panel) {
setWidget(panel);
m_DragTimer = new DragTimer();
DOM.addEventPreview(this);
}
/**
* Preview all browser events before they are passed on to their
respective widgets here. As long as there is no PopupPanel or
DialogBox currently showing, this
* preview code will be at the top of the browser stack and hence
helps avoid things like default text selection when DRAGGING or doing
SHIFT-CLICK to highlight multiple objects
* on a list control for instance.
*
* @param event Browser event to be previewed
* @return TRUE if the event must be propagated or FALSE to block
event
*
*/
public boolean onEventPreview(Event event) {
int type = DOM.eventGetType(event);
switch (type) {
case Event.ONKEYDOWN:
case Event.ONKEYUP:
case Event.ONKEYPRESS:
if (DOM.eventGetShiftKey(event) || DOM.eventGetCtrlKey
(event)) {
DOM.eventPreventDefault(event);
}
break;
case Event.ONMOUSEUP:
ib_lbutton_down = false;
ib_dragging = false;
m_DragTimer.cancel();
JSNIUtils.setTextSelectionEnabled(true);//for Chrome
and Safari browsers use the JSNI method
break;
case Event.ONCONTEXTMENU:
DOM.eventPreventDefault(event);
DOM.eventCancelBubble(event, true);
return false;//donmt allow to bubble break;
case Event.ONMOUSEDOWN:
if (DOM.eventGetButton(event) == Event.BUTTON_LEFT) {
ib_lbutton_down = true;
m_DragTimer.startTimer();
if (DOM.eventGetShiftKey(event) ||
DOM.eventGetCtrlKey(event)) {
DOM.eventPreventDefault
(event);
}
}
break;
case Event.ONMOUSEMOVE:
if (ib_lbutton_down || (ib_dragging ||
m_DragTimer.isRealDrag()) || DOM.eventGetShiftKey(event)) {
DOM.eventPreventDefault(event);
//for Chrome and Safari do not respect
eventPreventdefault so we have used a JSNI method here
//to prevent text selection and default dragging
JSNIUtils.setTextSelectionEnabled(false);
if (!ib_dragging && m_DragTimer.isRealDrag()) {
ib_dragging = true;
m_DragTimer.cancel();
}
}
break;
}
//DO allow the event to fire.
return true;
}
}
[/CODE]
The drag timer helps in distinguishing false drag events from real
ones. The code is below.
[CODE]
/**
*
* @author Melody
*/
public class DragTimer extends Timer {
private int ii_dragtimer_count = 0;
public DragTimer() {
}
public void run() {
ii_dragtimer_count += 1;
}
public void cancel() {
super.cancel();
ii_dragtimer_count = 0;
}
public void startTimer() {
scheduleRepeating(10);
}
public boolean isRealDrag() {
return ii_dragtimer_count >= 1;
}
}
[/CODE]
I did have to use JSNI to affect text selection events in Safari and
Chrome (Webkit based browsers). This is because these browser ignore
the DOM.eventPrevntDefault() method used to cancel default behavior in
GWT. Here is the code I used.
[CODE]
/**
* Needed for Chrome and Safari browsers.
*
* Remember to call this function with ab_enable = TRUE to clear
when the widget on which it is called is unattached. This avoids
* memory leaks
*
* @param ab_enable If true then the ondrag and onselectstart
events will be nullified, else they will be made to
* return false so that default browser selection
does not occur during dragging.
*/
public native static void setTextSelectionEnabled(boolean
ab_enable)/*-{
if (!ab_enable) {
$doc.onselectstart = function () { return false; };
$doc.ondrag = function () { return false; };
} else {
$doc.onselectstart = null;
$doc.ondrag = null;
}
}-*/;
[/CODE]
This is working for me and my drag and drop works just fine. I can
drag rows from a FlexTable based grid and drop them on the tree
control and all the accompanying visuals.
Hope this helps someone. I welcome any improvements and/or critiques.
Melody
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Google Web Toolkit" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/Google-Web-Toolkit?hl=en
-~----------~----~----~----~------~----~------~--~---