Sunday, January 23, 2011

GWT DialogBox with close widget inside the header

I was looking in internet for dialog box which allows me to put widget inside the header but most of the examples I found were not really very helpful. I collect the experience in Internet and create my own widget. It is not really the best approach but works very well for now.

1 /*
2 * Copyright 2010
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
6 * the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
14 * the License.
15 */
16 package com.mvp.client.ui.widget;
17
18 import com.google.gwt.core.client.GWT;
19 import com.google.gwt.dom.client.EventTarget;
20 import com.google.gwt.dom.client.NativeEvent;
21 import com.google.gwt.safehtml.shared.SafeHtml;
22 import com.google.gwt.user.client.Element;
23 import com.google.gwt.user.client.Event;
24 import com.google.gwt.user.client.ui.DialogBox;
25 import com.google.gwt.user.client.ui.HTML;
26 import com.google.gwt.user.client.ui.HasHorizontalAlignment;
27 import com.google.gwt.user.client.ui.HorizontalPanel;
28 import com.google.gwt.user.client.ui.Widget;
29
30 /**
31 * Extended DialogBox widget with close button inside the pop-up header
32 *
33 * @author L.Pelov
34 */
35 public class DialogBoxExt extends DialogBox {
36
37 private HorizontalPanel captionPanel = new HorizontalPanel();
38
39 // widget which will be use to close the dialog box
40 private Widget closeWidget = null;
41
42 /**
43 * You have to provide a widget here. If click on the widget the dialog box
44 * will be closed.
45 *
46 * @param closeDialogBox
47 */
48 public DialogBoxExt(Widget closeDialogBox) {
49 super();
50
51 closeWidget = closeDialogBox;
52
53 // empty header could case a problem!
54 setHTML(" ");
55 }
56
57 @Override
58 public void setHTML(String html) {
59 if (closeWidget != null) {
60 setCaption(html, closeWidget);
61 } else {
62 super.setHTML(html);
63 }
64 }
65
66 @Override
67 public void setHTML(SafeHtml html) {
68 if (closeWidget != null) {
69 setCaption(html.asString(), closeWidget);
70 } else {
71 super.setHTML(html);
72 }
73 }
74
75 /**
76 * Makes a new caption and replace the old one.
77 *
78 * @param txt
79 * @param w
80 */
81 private void setCaption(String txt, Widget w) {
82 captionPanel.setWidth("100%");
83 captionPanel.add(new HTML(txt));
84 captionPanel.add(w);
85 captionPanel.setCellHorizontalAlignment(w,
86 HasHorizontalAlignment.ALIGN_RIGHT);
87 // make sure that only when you click on this icon the widget will be
88 // closed!, don't make the field too width
89 captionPanel.setCellWidth(w, "1%");
90 captionPanel.addStyleName("Caption");
91
92 // Get the cell element that holds the caption
93 Element td = getCellElement(0, 1);
94
95 // Remove the old caption
96 td.setInnerHTML("");
97
98 // append our horizontal panel
99 td.appendChild(captionPanel.getElement());
100 }
101
102 /**
103 * Close handler, which will hide the dialog box
104 */
105 private class DialogBoxCloseHandler {
106 public void onClick(Event event) {
107 hide();
108 }
109 }
110
111 /**
112 * Function checks if the browser event is was inside the caption region
113 *
114 * @param event
115 * browser event
116 * @return true if event inside the caption panel (DialogBox header)
117 */
118 protected boolean isCaptionControlEvent(NativeEvent event) {
119 // return isWidgetEvent(event, captionPanel.getWidget(1));
120 return isWidgetEvent(event, closeWidget);
121 }
122
123 /**
124 * Overrides the browser event from the DialogBox
125 */
126 @Override
127 public void onBrowserEvent(Event event) {
128 if (isCaptionControlEvent(event)) {
129
130 switch (event.getTypeInt()) {
131 case Event.ONMOUSEUP:
132 case Event.ONCLICK:
133 new DialogBoxCloseHandler().onClick(event);
134 break;
135 case Event.ONMOUSEOVER:
136 break;
137 case Event.ONMOUSEOUT:
138 break;
139 }
140
141 return;
142 }
143
144 // go to the DialogBox browser event
145 super.onBrowserEvent(event);
146 }
147
148 /**
149 * Function checks if event was inside a given widget
150 *
151 * @param event
152 * - current event
153 * @param w
154 * - widget to prove if event was inside
155 * @return - true if event inside the given widget
156 */
157 protected boolean isWidgetEvent(NativeEvent event, Widget w) {
158 EventTarget target = event.getEventTarget();
159
160 if (Element.is(target)) {
161 boolean t = w.getElement().isOrHasChild(Element.as(target));
162 GWT.log("isWidgetEvent:" + w + ':' + target + ':' + t);
163 return t;
164 }
165 return false;
166 }
167
168 }
169

You can checkout the code from here.


Let’s see the code in details. I am overriding directly the DialogBox widget, I don’t really want to change the original code. Everything inside works very well, I just add a new functionality to the existing one.


The new constructor takes now a widget element. This element could be any GWT widget. You can use a picture or just a html text. Inside the constructor I call the function setHTML once to make sure that the header is not empty. Empty header could cause some problems, when you try to catch the events.The function setHTML is overridden. If the widget which should represent a closing element inside the header is not available, then everything works like before. You can use this overridden class in your code without to worry of already implemented functionality.


The next step will be to replace the caption header from the original DialogBox with our widget. This is done in the function setCaption. Basically what the function does, it generates caption which is now a HorizontalPanel widget, then remove the original caption widget and then appends new child element instead which is our already generated header. The following line code: captionPanel.setCellWidth(w, "1%"); guaranties that the icon or the text you use to close the dialog box is not too bright.


The next part is to override the onBrowserEvent function. Basically what we have to do here is to check if there is onClick event inside the browser and if the click was made on our close widget element. If so then hide the panel, otherwise just go to the native dialog box event handling.


cheers

No comments:

Post a Comment