You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

VRichTextToolbar.java 16KB

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