1 /* 2 * Copyright 2008 Google Inc. 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.google.gwt.sample.showcase.client.content.text; 17 18 import com.google.gwt.core.client.GWT; 19 import com.google.gwt.event.dom.client.ChangeEvent; 20 import com.google.gwt.event.dom.client.ChangeHandler; 21 import com.google.gwt.event.dom.client.ClickEvent; 22 import com.google.gwt.event.dom.client.ClickHandler; 23 import com.google.gwt.event.dom.client.KeyUpEvent; 24 import com.google.gwt.event.dom.client.KeyUpHandler; 25 import com.google.gwt.i18n.client.Constants; 26 import com.google.gwt.resources.client.ClientBundle; 27 import com.google.gwt.resources.client.ImageResource; 28 import com.google.gwt.user.client.Window; 29 import com.google.gwt.user.client.ui.Composite; 30 import com.google.gwt.user.client.ui.HorizontalPanel; 31 import com.google.gwt.user.client.ui.Image; 32 import com.google.gwt.user.client.ui.ListBox; 33 import com.google.gwt.user.client.ui.PushButton; 34 import com.google.gwt.user.client.ui.RichTextArea; 35 import com.google.gwt.user.client.ui.ToggleButton; 36 import com.google.gwt.user.client.ui.VerticalPanel; 37 import com.google.gwt.user.client.ui.Widget; 38 39 /** 40 * A sample toolbar for use with {@link RichTextArea}. It provides a simple UI 41 * for all rich text formatting, dynamically displayed only for the available 42 * functionality. 43 */ 44 @SuppressWarnings("deprecation") 45 public class RichTextToolbar extends Composite { 46 47 /** 48 * This {@link ClientBundle} is used for all the button icons. Using a bundle 49 * allows all of these images to be packed into a single image, which saves a 50 * lot of HTTP requests, drastically improving startup time. 51 */ 52 public interface Images extends ClientBundle { 53 bold()54 ImageResource bold(); 55 createLink()56 ImageResource createLink(); 57 hr()58 ImageResource hr(); 59 indent()60 ImageResource indent(); 61 insertImage()62 ImageResource insertImage(); 63 italic()64 ImageResource italic(); 65 justifyCenter()66 ImageResource justifyCenter(); 67 justifyLeft()68 ImageResource justifyLeft(); 69 justifyRight()70 ImageResource justifyRight(); 71 ol()72 ImageResource ol(); 73 outdent()74 ImageResource outdent(); 75 removeFormat()76 ImageResource removeFormat(); 77 removeLink()78 ImageResource removeLink(); 79 strikeThrough()80 ImageResource strikeThrough(); 81 subscript()82 ImageResource subscript(); 83 superscript()84 ImageResource superscript(); 85 ul()86 ImageResource ul(); 87 underline()88 ImageResource underline(); 89 } 90 91 /** 92 * This {@link Constants} interface is used to make the toolbar's strings 93 * internationalizable. 94 */ 95 public interface Strings extends Constants { 96 black()97 String black(); 98 blue()99 String blue(); 100 bold()101 String bold(); 102 color()103 String color(); 104 createLink()105 String createLink(); 106 font()107 String font(); 108 green()109 String green(); 110 hr()111 String hr(); 112 indent()113 String indent(); 114 insertImage()115 String insertImage(); 116 italic()117 String italic(); 118 justifyCenter()119 String justifyCenter(); 120 justifyLeft()121 String justifyLeft(); 122 justifyRight()123 String justifyRight(); 124 large()125 String large(); 126 medium()127 String medium(); 128 normal()129 String normal(); 130 ol()131 String ol(); 132 outdent()133 String outdent(); 134 red()135 String red(); 136 removeFormat()137 String removeFormat(); 138 removeLink()139 String removeLink(); 140 size()141 String size(); 142 small()143 String small(); 144 strikeThrough()145 String strikeThrough(); 146 subscript()147 String subscript(); 148 superscript()149 String superscript(); 150 ul()151 String ul(); 152 underline()153 String underline(); 154 white()155 String white(); 156 xlarge()157 String xlarge(); 158 xsmall()159 String xsmall(); 160 xxlarge()161 String xxlarge(); 162 xxsmall()163 String xxsmall(); 164 yellow()165 String yellow(); 166 } 167 168 /** 169 * We use an inner EventHandler class to avoid exposing event methods on the 170 * RichTextToolbar itself. 171 */ 172 private class EventHandler implements ClickHandler, ChangeHandler, 173 KeyUpHandler { 174 onChange(ChangeEvent event)175 public void onChange(ChangeEvent event) { 176 Widget sender = (Widget) event.getSource(); 177 178 if (sender == backColors) { 179 basic.setBackColor(backColors.getValue(backColors.getSelectedIndex())); 180 backColors.setSelectedIndex(0); 181 } else if (sender == foreColors) { 182 basic.setForeColor(foreColors.getValue(foreColors.getSelectedIndex())); 183 foreColors.setSelectedIndex(0); 184 } else if (sender == fonts) { 185 basic.setFontName(fonts.getValue(fonts.getSelectedIndex())); 186 fonts.setSelectedIndex(0); 187 } else if (sender == fontSizes) { 188 basic.setFontSize(fontSizesConstants[fontSizes.getSelectedIndex() - 1]); 189 fontSizes.setSelectedIndex(0); 190 } 191 } 192 onClick(ClickEvent event)193 public void onClick(ClickEvent event) { 194 Widget sender = (Widget) event.getSource(); 195 196 if (sender == bold) { 197 basic.toggleBold(); 198 } else if (sender == italic) { 199 basic.toggleItalic(); 200 } else if (sender == underline) { 201 basic.toggleUnderline(); 202 } else if (sender == subscript) { 203 basic.toggleSubscript(); 204 } else if (sender == superscript) { 205 basic.toggleSuperscript(); 206 } else if (sender == strikethrough) { 207 extended.toggleStrikethrough(); 208 } else if (sender == indent) { 209 extended.rightIndent(); 210 } else if (sender == outdent) { 211 extended.leftIndent(); 212 } else if (sender == justifyLeft) { 213 basic.setJustification(RichTextArea.Justification.LEFT); 214 } else if (sender == justifyCenter) { 215 basic.setJustification(RichTextArea.Justification.CENTER); 216 } else if (sender == justifyRight) { 217 basic.setJustification(RichTextArea.Justification.RIGHT); 218 } else if (sender == insertImage) { 219 String url = Window.prompt("Enter an image URL:", "http://"); 220 if (url != null) { 221 extended.insertImage(url); 222 } 223 } else if (sender == createLink) { 224 String url = Window.prompt("Enter a link URL:", "http://"); 225 if (url != null) { 226 extended.createLink(url); 227 } 228 } else if (sender == removeLink) { 229 extended.removeLink(); 230 } else if (sender == hr) { 231 extended.insertHorizontalRule(); 232 } else if (sender == ol) { 233 extended.insertOrderedList(); 234 } else if (sender == ul) { 235 extended.insertUnorderedList(); 236 } else if (sender == removeFormat) { 237 extended.removeFormat(); 238 } else if (sender == richText) { 239 // We use the RichTextArea's onKeyUp event to update the toolbar status. 240 // This will catch any cases where the user moves the cursur using the 241 // keyboard, or uses one of the browser's built-in keyboard shortcuts. 242 updateStatus(); 243 } 244 } 245 onKeyUp(KeyUpEvent event)246 public void onKeyUp(KeyUpEvent event) { 247 Widget sender = (Widget) event.getSource(); 248 if (sender == richText) { 249 // We use the RichTextArea's onKeyUp event to update the toolbar status. 250 // This will catch any cases where the user moves the cursur using the 251 // keyboard, or uses one of the browser's built-in keyboard shortcuts. 252 updateStatus(); 253 } 254 } 255 } 256 257 private static final RichTextArea.FontSize[] fontSizesConstants = new RichTextArea.FontSize[] { 258 RichTextArea.FontSize.XX_SMALL, RichTextArea.FontSize.X_SMALL, 259 RichTextArea.FontSize.SMALL, RichTextArea.FontSize.MEDIUM, 260 RichTextArea.FontSize.LARGE, RichTextArea.FontSize.X_LARGE, 261 RichTextArea.FontSize.XX_LARGE}; 262 263 private Images images = (Images) GWT.create(Images.class); 264 private Strings strings = (Strings) GWT.create(Strings.class); 265 private EventHandler handler = new EventHandler(); 266 267 private RichTextArea richText; 268 private RichTextArea.BasicFormatter basic; 269 private RichTextArea.ExtendedFormatter extended; 270 271 private VerticalPanel outer = new VerticalPanel(); 272 private HorizontalPanel topPanel = new HorizontalPanel(); 273 private HorizontalPanel bottomPanel = new HorizontalPanel(); 274 private ToggleButton bold; 275 private ToggleButton italic; 276 private ToggleButton underline; 277 private ToggleButton subscript; 278 private ToggleButton superscript; 279 private ToggleButton strikethrough; 280 private PushButton indent; 281 private PushButton outdent; 282 private PushButton justifyLeft; 283 private PushButton justifyCenter; 284 private PushButton justifyRight; 285 private PushButton hr; 286 private PushButton ol; 287 private PushButton ul; 288 private PushButton insertImage; 289 private PushButton createLink; 290 private PushButton removeLink; 291 private PushButton removeFormat; 292 293 private ListBox backColors; 294 private ListBox foreColors; 295 private ListBox fonts; 296 private ListBox fontSizes; 297 298 /** 299 * Creates a new toolbar that drives the given rich text area. 300 * 301 * @param richText the rich text area to be controlled 302 */ RichTextToolbar(RichTextArea richText)303 public RichTextToolbar(RichTextArea richText) { 304 this.richText = richText; 305 this.basic = richText.getBasicFormatter(); 306 this.extended = richText.getExtendedFormatter(); 307 308 outer.add(topPanel); 309 outer.add(bottomPanel); 310 topPanel.setWidth("100%"); 311 bottomPanel.setWidth("100%"); 312 313 initWidget(outer); 314 setStyleName("gwt-RichTextToolbar"); 315 richText.addStyleName("hasRichTextToolbar"); 316 317 if (basic != null) { 318 topPanel.add(bold = createToggleButton(images.bold(), strings.bold())); 319 topPanel.add(italic = createToggleButton(images.italic(), 320 strings.italic())); 321 topPanel.add(underline = createToggleButton(images.underline(), 322 strings.underline())); 323 topPanel.add(subscript = createToggleButton(images.subscript(), 324 strings.subscript())); 325 topPanel.add(superscript = createToggleButton(images.superscript(), 326 strings.superscript())); 327 topPanel.add(justifyLeft = createPushButton(images.justifyLeft(), 328 strings.justifyLeft())); 329 topPanel.add(justifyCenter = createPushButton(images.justifyCenter(), 330 strings.justifyCenter())); 331 topPanel.add(justifyRight = createPushButton(images.justifyRight(), 332 strings.justifyRight())); 333 } 334 335 if (extended != null) { 336 topPanel.add(strikethrough = createToggleButton(images.strikeThrough(), 337 strings.strikeThrough())); 338 topPanel.add(indent = createPushButton(images.indent(), strings.indent())); 339 topPanel.add(outdent = createPushButton(images.outdent(), 340 strings.outdent())); 341 topPanel.add(hr = createPushButton(images.hr(), strings.hr())); 342 topPanel.add(ol = createPushButton(images.ol(), strings.ol())); 343 topPanel.add(ul = createPushButton(images.ul(), strings.ul())); 344 topPanel.add(insertImage = createPushButton(images.insertImage(), 345 strings.insertImage())); 346 topPanel.add(createLink = createPushButton(images.createLink(), 347 strings.createLink())); 348 topPanel.add(removeLink = createPushButton(images.removeLink(), 349 strings.removeLink())); 350 topPanel.add(removeFormat = createPushButton(images.removeFormat(), 351 strings.removeFormat())); 352 } 353 354 if (basic != null) { 355 bottomPanel.add(backColors = createColorList("Background")); 356 bottomPanel.add(foreColors = createColorList("Foreground")); 357 bottomPanel.add(fonts = createFontList()); 358 bottomPanel.add(fontSizes = createFontSizes()); 359 360 // We only use these handlers for updating status, so don't hook them up 361 // unless at least basic editing is supported. 362 richText.addKeyUpHandler(handler); 363 richText.addClickHandler(handler); 364 } 365 } 366 createColorList(String caption)367 private ListBox createColorList(String caption) { 368 ListBox lb = new ListBox(); 369 lb.addChangeHandler(handler); 370 lb.setVisibleItemCount(1); 371 372 lb.addItem(caption); 373 lb.addItem(strings.white(), "white"); 374 lb.addItem(strings.black(), "black"); 375 lb.addItem(strings.red(), "red"); 376 lb.addItem(strings.green(), "green"); 377 lb.addItem(strings.yellow(), "yellow"); 378 lb.addItem(strings.blue(), "blue"); 379 return lb; 380 } 381 createFontList()382 private ListBox createFontList() { 383 ListBox lb = new ListBox(); 384 lb.addChangeHandler(handler); 385 lb.setVisibleItemCount(1); 386 387 lb.addItem(strings.font(), ""); 388 lb.addItem(strings.normal(), ""); 389 lb.addItem("Times New Roman", "Times New Roman"); 390 lb.addItem("Arial", "Arial"); 391 lb.addItem("Courier New", "Courier New"); 392 lb.addItem("Georgia", "Georgia"); 393 lb.addItem("Trebuchet", "Trebuchet"); 394 lb.addItem("Verdana", "Verdana"); 395 return lb; 396 } 397 createFontSizes()398 private ListBox createFontSizes() { 399 ListBox lb = new ListBox(); 400 lb.addChangeHandler(handler); 401 lb.setVisibleItemCount(1); 402 403 lb.addItem(strings.size()); 404 lb.addItem(strings.xxsmall()); 405 lb.addItem(strings.xsmall()); 406 lb.addItem(strings.small()); 407 lb.addItem(strings.medium()); 408 lb.addItem(strings.large()); 409 lb.addItem(strings.xlarge()); 410 lb.addItem(strings.xxlarge()); 411 return lb; 412 } 413 createPushButton(ImageResource img, String tip)414 private PushButton createPushButton(ImageResource img, String tip) { 415 PushButton pb = new PushButton(new Image(img)); 416 pb.addClickHandler(handler); 417 pb.setTitle(tip); 418 return pb; 419 } 420 createToggleButton(ImageResource img, String tip)421 private ToggleButton createToggleButton(ImageResource img, String tip) { 422 ToggleButton tb = new ToggleButton(new Image(img)); 423 tb.addClickHandler(handler); 424 tb.setTitle(tip); 425 return tb; 426 } 427 428 /** 429 * Updates the status of all the stateful buttons. 430 */ updateStatus()431 private void updateStatus() { 432 if (basic != null) { 433 bold.setDown(basic.isBold()); 434 italic.setDown(basic.isItalic()); 435 underline.setDown(basic.isUnderlined()); 436 subscript.setDown(basic.isSubscript()); 437 superscript.setDown(basic.isSuperscript()); 438 } 439 440 if (extended != null) { 441 strikethrough.setDown(extended.isStrikethrough()); 442 } 443 } 444 } 445