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 15KB

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