001package gwt.material.design.client.ui; 002 003/* 004 * #%L 005 * GwtMaterial 006 * %% 007 * Copyright (C) 2015 GwtMaterialDesign 008 * %% 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 * #L% 021 */ 022 023import java.util.Iterator; 024import java.util.NoSuchElementException; 025 026import com.google.gwt.dom.client.Element; 027import com.google.gwt.event.logical.shared.AttachEvent; 028import com.google.gwt.event.shared.HandlerRegistration; 029import com.google.gwt.user.client.ui.HasOneWidget; 030import com.google.gwt.user.client.ui.HasText; 031import com.google.gwt.user.client.ui.HasWidgets; 032import com.google.gwt.user.client.ui.IsWidget; 033import com.google.gwt.user.client.ui.Widget; 034import gwt.material.design.client.constants.Position; 035import gwt.material.design.client.base.HasId; 036import gwt.material.design.client.base.HasPosition; 037 038/** 039 * Basic implementation for the Material Design tooltip. 040 * <h3>UiBinder Example</h3> 041 * <pre> 042 *{@code<m:MaterialTooltip text="..."> 043 * ... 044 * </b:MaterialTooltip> 045 *} 046 * </pre> 047 * @author kevzlou7979 048 * @author Ben Dol 049 */ 050public class MaterialTooltip implements IsWidget, HasWidgets, HasOneWidget, HasId, HasText, HasPosition { 051 052 private String text; 053 private Position position = Position.TOP; 054 private int delayMs = 0; 055 056 private Widget widget; 057 private String id; 058 059 private HandlerRegistration attachHandler; 060 061 /** 062 * Creates the empty Tooltip 063 */ 064 public MaterialTooltip() { 065 } 066 067 /** 068 * Creates the tooltip around this widget 069 * 070 * @param w widget for the tooltip 071 */ 072 public MaterialTooltip(final Widget w) { 073 setWidget(w); 074 } 075 076 /** 077 * Creates the tooltip around this widget with given title 078 * 079 * @param w widget for the tooltip 080 * @param text text for the tooltip 081 */ 082 public MaterialTooltip(final Widget w, final String text) { 083 setWidget(w); 084 setText(text); 085 } 086 087 /** 088 * {@inheritDoc} 089 */ 090 @Override 091 public void setWidget(final Widget w) { 092 // Validate 093 if (w == widget) { 094 return; 095 } 096 097 if(attachHandler != null) { 098 attachHandler.removeHandler(); 099 attachHandler = null; 100 } 101 102 // Detach new child 103 if (w != null) { 104 w.removeFromParent(); 105 } 106 107 // Remove old child 108 if (widget != null) { 109 remove(widget); 110 } 111 112 // Logical attach, but don't physical attach; done by jquery. 113 widget = w; 114 if (widget == null) { 115 return; 116 } 117 118 if(!widget.isAttached()) { 119 // When we attach it, configure the tooltip 120 attachHandler = widget.addAttachHandler(new AttachEvent.Handler() { 121 @Override 122 public void onAttachOrDetach(final AttachEvent event) { 123 reconfigure(); 124 } 125 }); 126 } else { 127 reconfigure(); 128 } 129 } 130 131 /** 132 * {@inheritDoc} 133 */ 134 @Override 135 public void add(final Widget child) { 136 if (getWidget() != null) { 137 throw new IllegalStateException("Can only contain one child widget"); 138 } 139 setWidget(child); 140 } 141 142 /** 143 * {@inheritDoc} 144 */ 145 @Override 146 public void setWidget(final IsWidget w) { 147 setWidget(w.asWidget()); 148 } 149 150 /** 151 * {@inheritDoc} 152 */ 153 @Override 154 public Widget getWidget() { 155 return widget; 156 } 157 158 /** 159 * {@inheritDoc} 160 */ 161 @Override 162 public void setId(final String id) { 163 this.id = id; 164 if (widget != null) { 165 widget.getElement().setId(id); 166 } 167 } 168 169 /** 170 * {@inheritDoc} 171 */ 172 @Override 173 public String getId() { 174 return (widget == null) ? id : widget.getElement().getId(); 175 } 176 177 /** 178 * {@inheritDoc} 179 */ 180 @Override 181 public void setPosition(final Position position) { 182 this.position = position; 183 184 widget.getElement().setAttribute("data-position", position.getCssName()); 185 } 186 187 /** 188 * {@inheritDoc} 189 */ 190 @Override 191 public Position getPosition() { 192 return position; 193 } 194 195 public void setDelayMs(final int delayMs) { 196 this.delayMs = delayMs; 197 198 widget.getElement().setAttribute("data-delay", String.valueOf(delayMs)); 199 } 200 201 public int getDelayMs() { 202 return delayMs; 203 } 204 205 /** 206 * Gets the tooltip's display string 207 * 208 * @return String tooltip display string 209 */ 210 @Override 211 public String getText() { 212 return text; 213 } 214 215 /** 216 * Sets the tooltip's display string 217 * 218 * @param text String display string 219 */ 220 @Override 221 public void setText(final String text) { 222 this.text = text; 223 224 widget.getElement().setAttribute("data-tooltip", text); 225 } 226 227 /** 228 * Reconfigures the tooltip, must be called when altering 229 * any tooltip after it has already been shown. 230 */ 231 public void reconfigure() { 232 remove(); 233 configure(); 234 } 235 236 protected void configure() { 237 configure(widget.getElement(), text, position.getCssName(), delayMs); 238 } 239 240 /** 241 * Force the Tooltip to be destroyed 242 */ 243 public void remove() { 244 if(widget != null) { 245 command(widget.getElement(), "remove"); 246 } 247 } 248 249 /** 250 * {@inheritDoc} 251 */ 252 @Override 253 public void clear() { 254 widget = null; 255 } 256 257 /** 258 * {@inheritDoc} 259 */ 260 @Override 261 public Iterator<Widget> iterator() { 262 // Simple iterator for the widget 263 return new Iterator<Widget>() { 264 boolean hasElement = widget != null; 265 Widget returned = null; 266 267 @Override 268 public boolean hasNext() { 269 return hasElement; 270 } 271 272 @Override 273 public Widget next() { 274 if (!hasElement || (widget == null)) { 275 throw new NoSuchElementException(); 276 } 277 hasElement = false; 278 return (returned = widget); 279 } 280 281 @Override 282 public void remove() { 283 if (returned != null) { 284 MaterialTooltip.this.remove(returned); 285 } 286 } 287 }; 288 } 289 290 /** 291 * {@inheritDoc} 292 */ 293 @Override 294 public boolean remove(final Widget w) { 295 // Validate. 296 if (widget != w) { 297 return false; 298 } 299 300 // Logical detach. 301 clear(); 302 return true; 303 } 304 305 /** 306 * {@inheritDoc} 307 */ 308 @Override 309 public Widget asWidget() { 310 return widget; 311 } 312 313 /** 314 * {@inheritDoc} 315 */ 316 @Override 317 public String toString() { 318 return asWidget().toString(); 319 } 320 321 protected native void configure(Element e, String tooltip, String position, int delay) /*-{ 322 $wnd.jQuery(e).tooltip({ 323 tooltip: tooltip, 324 position: position, 325 delay: delay 326 }); 327 }-*/; 328 329 protected native void command(final Element e, final String command) /*-{ 330 $wnd.jQuery(e).tooltip(command); 331 }-*/; 332}