I'm trying to implement a custom widget by reusing an existing
JavaScript library (http://www.jswitch.com/scripts/show/1) a kind of
stackpanel with a fading effect.
The idea is to host any widget as a subMenu.
When I create any GWT hosted widget (let's say a TextBox) that contain
bound events (click, change, ...) in this way :
TextBox tb = new TextBox();
tb.addClickListener(....)
AddSubMenu("mainMenu","subMenu",tb)
My Textbox listeners are never called. Obviously, I understand why.
Because when we deal with AppendChild elements, GWT doesn't
necessarily know that this Widget is a child widget in the whole
widget hierarchy and onBrowserEvent() could only fire sunk events on
the host widget (in this case, xpmenu).
The question is : how can I create a kind of composite widget where I
could reuse an initial DOM layout (see the xpmenu DOM at the end) and
fire events to all my child components. I don't want to deal with
Composite/Panel and so on because they rely on a kind of user's layout
(flow, vertical, etc...) for which I don't have the hands on.
I know it is possible because Tree widget works this way.
Tell me if I'm not clear ....
Sam
--------------------------------------
My code looks like the following :
package com.mycompany.project.client;
import java.util.HashMap;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.*;
public class XPMenu extends Widget implements SourcesClickEvents,
SourcesChangeEvents, SourcesKeyboardEvents {
java.util.HashMap menuEntries = new HashMap();
private ClickListenerCollection clickListeners;
private FocusListenerCollection focusListeners;
private KeyboardListenerCollection keyboardListeners;
private MouseListenerCollection mouseListeners;
public XPMenu() {
setElement(DOM.createDiv());
setStyleName(getElement(), "navbar",true);
Element scriptJS = DOM.createElement("script");
DOM.setAttribute(scriptJS, "type", "text/javascript");
DOM.setAttribute(scriptJS, "src", "xpmenuv21.js");
DOM.appendChild(getElement(), scriptJS);
DOM.setEventListener(getElement(), this);
sinkEvents(Event.MOUSEEVENTS | Event.ONCLICK | Event.KEYEVENTS);
}
public void addMenu(String name) {
Element mainDiv = DOM.createDiv();
setStyleName(mainDiv, "mainDiv",true);
DOM.insertChild(getElement(),
mainDiv,DOM.getChildCount(getElement())) ;
Element topItem = DOM.createDiv();
DOM.setAttribute(topItem, "id", name);
setStyleName(topItem, "topItem",true);
DOM.appendChild(mainDiv, topItem);
DOM.setInnerText(topItem, name);
Element dropMenu = DOM.createDiv();
setStyleName(dropMenu, "dropMenu",true);
DOM.appendChild(mainDiv, dropMenu);
Element subMenu = DOM.createDiv();
DOM.setAttribute(subMenu, "Style", "display:inline;");
setStyleName(subMenu, "subMenu",true);
DOM.appendChild(dropMenu, subMenu);
menuEntries.put(name,subMenu);
}
public void addSubMenu(String menu, String submenu, Widget w) {
Element subMenu = (Element) menuEntries.get(menu);
// menu doesn't exist
if (subMenu==null) return ;
Element subItem = DOM.createDiv();
DOM.appendChild(subMenu, subItem);
setStyleName(subItem, "subItem",true);
// by default, xpmenu hosts only href links
// DOM.setInnerHTML(subItem, "<a href=#>" + submenu +"</a>");
// but I want to host any widget
DOM.appendChild(subItem,w.getElement());
}
public void onBrowserEvent(Event event) {
switch (DOM.eventGetType(event)) {
case Event.ONCLICK:
if (clickListeners != null) {
clickListeners.fireClick(this);
}
break;
case Event.ONMOUSEDOWN:
case Event.ONMOUSEUP:
case Event.ONMOUSEMOVE:
case Event.ONMOUSEOVER:
case Event.ONMOUSEOUT:
if (mouseListeners != null) {
mouseListeners.fireMouseEvent(this, event);
}
break;
case Event.ONBLUR:
case Event.ONKEYDOWN:
case Event.ONKEYUP:
case Event.ONKEYPRESS:
if (keyboardListeners != null) {
keyboardListeners.fireKeyboardEvent(this, event);
}
break;
}
}
// Listeners
public void addClickListener(ClickListener listener) {
if (clickListeners == null) {
clickListeners = new ClickListenerCollection();
}
clickListeners.add(listener);
}
public void addFocusListener(FocusListener listener) {
if (focusListeners == null) {
focusListeners = new FocusListenerCollection();
}
focusListeners.add(listener);
}
public void addKeyboardListener(KeyboardListener listener) {
if (keyboardListeners == null) {
keyboardListeners = new KeyboardListenerCollection();
}
keyboardListeners.add(listener);
}
public void addMouseListener(MouseListener listener) {
if (mouseListeners == null) {
mouseListeners = new MouseListenerCollection();
}
mouseListeners.add(listener);
}
public void removeClickListener(ClickListener listener) {
// TODO Auto-generated method stub
}
public void addChangeListener(ChangeListener listener) {
// TODO Auto-generated method stub
}
public void removeChangeListener(ChangeListener listener) {
// TODO Auto-generated method stub
}
public void removeKeyboardListener(KeyboardListener listener) {
// TODO Auto-generated method stub
}
}
----------------------------------------------------------
The DOM I want to mimic :
<!-- *********************************Start
Menu****************************** -->
<div class="mainDiv" >
<div class="topItem" >Demo Menu 1</div>
<div class="dropMenu" ><!-- -->
<div class="subMenu" style="display:inline;">
<div class="subItem"><a href="#">Configuration</a></div>
<div class="subItem"><a href="#">Tool Box</a></div>
<div class="subItem"><a href="#">Contact Us</a></div>
<div class="subItem"><a href="#">Sub Menu 4</a></div>
<div class="subItem"><a href="#">Sub Menu 5</a></div>
</div>
</div>
</div>
<!-- *********************************End
Menu****************************** -->
<br>
<!-- *********************************Start
Menu****************************** -->
<div class="mainDiv" >
<div class="topItem" >Demo Menu 2</div>
<div class="dropMenu" ><!-- -->
<div class="subMenu" style="display:none;">
<div class="subItem"><a href="#">Configuration</a></div>
<div class="subItem"><a href="#">Sub Menu 2</a></div>
<div class="subItem"><a href="#">Sub Menu 3</a></div>
<div class="subItem"><a href="#">Sub Menu 4</a></div>
</div>
</div>
</div>
<!-- *********************************End
Menu****************************** -->
<script type="text/javascript" src="xpmenuv21.js"></script>
</div>
XPMenu.onBrowserEvent(Event event) {
// Event handling for the host widget
switch (event) (......)
// child widget propagation
for (int i=0;i<widgets.size();i++) ((Widget)
widgets.get(i)).onBrowserEvent(event);