1 /* 2 * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.javafx.scene.web.skin; 27 28 import java.util.ResourceBundle; 29 30 import com.sun.javafx.application.PlatformImpl; 31 import com.sun.javafx.scene.traversal.Algorithm; 32 import com.sun.javafx.scene.traversal.Direction; 33 import com.sun.javafx.scene.traversal.ParentTraversalEngine; 34 import com.sun.javafx.scene.traversal.TraversalContext; 35 import javafx.geometry.Orientation; 36 import org.w3c.dom.html.HTMLDocument; 37 import org.w3c.dom.html.HTMLElement; 38 39 import javafx.application.ConditionalFeature; 40 import javafx.application.Platform; 41 import javafx.beans.value.ChangeListener; 42 import javafx.beans.value.ObservableValue; 43 import javafx.collections.FXCollections; 44 import javafx.collections.ObservableList; 45 import javafx.css.StyleableProperty; 46 import javafx.event.ActionEvent; 47 import javafx.event.EventHandler; 48 import javafx.geometry.Bounds; 49 import javafx.geometry.NodeOrientation; 50 import javafx.scene.Node; 51 import javafx.scene.control.Button; 52 import javafx.scene.control.ComboBox; 53 import javafx.scene.control.ListCell; 54 import javafx.scene.control.ListView; 55 import javafx.scene.control.Separator; 56 import javafx.scene.control.TextInputControl; 57 import javafx.scene.control.ToggleButton; 58 import javafx.scene.control.ToggleGroup; 59 import javafx.scene.control.ToolBar; 60 import javafx.scene.control.Tooltip; 61 import javafx.scene.image.Image; 62 import javafx.scene.image.ImageView; 63 import javafx.scene.input.KeyCode; 64 import javafx.scene.input.KeyEvent; 65 import javafx.scene.input.MouseEvent; 66 import javafx.scene.layout.ColumnConstraints; 67 import javafx.scene.layout.GridPane; 68 import javafx.scene.layout.Priority; 69 import javafx.scene.paint.Color; 70 import javafx.scene.text.Font; 71 import javafx.scene.web.HTMLEditor; 72 import javafx.scene.web.WebView; 73 import javafx.util.Callback; 74 75 import com.sun.javafx.scene.control.skin.ColorPickerSkin; 76 import com.sun.javafx.scene.control.skin.FXVK; 77 import com.sun.javafx.scene.web.behavior.HTMLEditorBehavior; 78 import com.sun.javafx.scene.traversal.TraversalEngine; 79 import com.sun.javafx.scene.traversal.TraverseListener; 80 //import com.sun.webkit.WebPage; 81 //import com.sun.webkit.event.WCFocusEvent; 82 //import com.sun.javafx.webkit.Accessor; 83 84 import java.security.AccessController; 85 import java.security.PrivilegedAction; 86 87 import java.util.HashMap; 88 import java.util.Locale; 89 import java.util.Map; 90 import javafx.scene.Scene; 91 import javafx.scene.control.*; 92 import javafx.scene.layout.*; 93 import com.sun.javafx.scene.control.skin.BehaviorSkinBase; 94 import javafx.collections.ListChangeListener; 95 96 import static javafx.geometry.NodeOrientation.*; 97 98 /** 99 * HTML editor skin. 100 */ 101 public class HTMLEditorSkin extends BehaviorSkinBase<HTMLEditor, HTMLEditorBehavior> implements TraverseListener { 102 private GridPane gridPane; 103 104 private ToolBar toolbar1; 105 private ToolBar toolbar2; 106 107 private Button cutButton; 108 private Button copyButton; 109 private Button pasteButton; 110 111 // private Button undoButton; 112 // private Button redoButton; 113 114 private Button insertHorizontalRuleButton; 115 116 private ToggleGroup alignmentToggleGroup; 117 private ToggleButton alignLeftButton; 118 private ToggleButton alignCenterButton; 119 private ToggleButton alignRightButton; 120 private ToggleButton alignJustifyButton; 121 122 private ToggleButton bulletsButton; 123 private ToggleButton numbersButton; 124 125 private Button indentButton; 126 private Button outdentButton; 127 128 private ComboBox<String> formatComboBox; 129 private Map<String, String> formatStyleMap; 130 private Map<String, String> styleFormatMap; 131 132 private ComboBox<String> fontFamilyComboBox; 133 134 private ComboBox<String> fontSizeComboBox; 135 private Map<String, String> fontSizeMap; 136 private Map<String, String> sizeFontMap; 137 138 private ToggleButton boldButton; 139 private ToggleButton italicButton; 140 private ToggleButton underlineButton; 141 private ToggleButton strikethroughButton; 142 143 private ColorPicker fgColorButton; 144 private ColorPicker bgColorButton; 145 146 private WebView webView; 147 // private WebPage webPage; 148 149 private static final String CUT_COMMAND = "cut"; 150 private static final String COPY_COMMAND = "copy"; 151 private static final String PASTE_COMMAND = "paste"; 152 153 private static final String UNDO_COMMAND = "undo"; 154 private static final String REDO_COMMAND = "redo"; 155 156 private static final String INSERT_HORIZONTAL_RULE_COMMAND = "inserthorizontalrule"; 157 158 private static final String ALIGN_LEFT_COMMAND = "justifyleft"; 159 private static final String ALIGN_CENTER_COMMAND = "justifycenter"; 160 private static final String ALIGN_RIGHT_COMMAND = "justifyright"; 161 private static final String ALIGN_JUSTIFY_COMMAND = "justifyfull"; 162 163 private static final String BULLETS_COMMAND = "insertUnorderedList"; 164 private static final String NUMBERS_COMMAND = "insertOrderedList"; 165 166 private static final String INDENT_COMMAND = "indent"; 167 private static final String OUTDENT_COMMAND = "outdent"; 168 169 private static final String FORMAT_COMMAND = "formatblock"; 170 private static final String FONT_FAMILY_COMMAND = "fontname"; 171 private static final String FONT_SIZE_COMMAND = "fontsize"; 172 173 private static final String BOLD_COMMAND = "bold"; 174 private static final String ITALIC_COMMAND = "italic"; 175 private static final String UNDERLINE_COMMAND = "underline"; 176 private static final String STRIKETHROUGH_COMMAND = "strikethrough"; 177 178 private static final String FOREGROUND_COLOR_COMMAND = "forecolor"; 179 private static final String BACKGROUND_COLOR_COMMAND = "backcolor"; 180 181 private static final Color DEFAULT_BG_COLOR = Color.WHITE; 182 private static final Color DEFAULT_FG_COLOR = Color.BLACK; 183 184 private static final String FORMAT_PARAGRAPH = "<p>"; 185 private static final String FORMAT_HEADING_1 = "<h1>"; 186 private static final String FORMAT_HEADING_2 = "<h2>"; 187 private static final String FORMAT_HEADING_3 = "<h3>"; 188 private static final String FORMAT_HEADING_4 = "<h4>"; 189 private static final String FORMAT_HEADING_5 = "<h5>"; 190 private static final String FORMAT_HEADING_6 = "<h6>"; 191 192 private static final String SIZE_XX_SMALL = "1"; 193 private static final String SIZE_X_SMALL = "2"; 194 private static final String SIZE_SMALL = "3"; 195 private static final String SIZE_MEDIUM = "4"; 196 private static final String SIZE_LARGE = "5"; 197 private static final String SIZE_X_LARGE = "6"; 198 private static final String SIZE_XX_LARGE = "7"; 199 200 private static final String INSERT_NEW_LINE_COMMAND = "insertnewline"; 201 private static final String INSERT_TAB_COMMAND = "inserttab"; 202 203 // As per RT-16330: default format -> bold/size mappings are as follows: 204 private static final String[][] DEFAULT_FORMAT_MAPPINGS = { 205 { FORMAT_PARAGRAPH, "", SIZE_SMALL }, 206 { FORMAT_HEADING_1, BOLD_COMMAND, SIZE_X_LARGE }, 207 { FORMAT_HEADING_2, BOLD_COMMAND, SIZE_LARGE }, 208 { FORMAT_HEADING_3, BOLD_COMMAND, SIZE_MEDIUM }, 209 { FORMAT_HEADING_4, BOLD_COMMAND, SIZE_SMALL }, 210 { FORMAT_HEADING_5, BOLD_COMMAND, SIZE_X_SMALL }, 211 { FORMAT_HEADING_6, BOLD_COMMAND, SIZE_XX_SMALL }, 212 }; 213 214 // As per RT-16379: default OS -> font mappings: 215 private static final String[] DEFAULT_WINDOWS_7_MAPPINGS = { 216 "Windows 7", "Segoe UI", "12px", "", "120" 217 }; 218 private static final String[][] DEFAULT_OS_MAPPINGS = { 219 // OS Font name size weight DPI 220 { "Windows XP", "Tahoma", "12px", "", "96" }, 221 { "Windows Vista", "Segoe UI", "12px", "", "96" }, 222 DEFAULT_WINDOWS_7_MAPPINGS, 223 { "Mac OS X", "Lucida Grande", "12px", "", "72" }, 224 { "Linux", "Lucida Sans", "12px", "", "96" }, 225 }; 226 private static final String DEFAULT_OS_FONT = getOSMappings()[1]; 227 228 private static final Label IOS_UNSUPPORTED_LABEL = 229 new Label("HTML Editor component is not supported on iOS platform"); 230 231 private static String[] getOSMappings() { 232 String os = System.getProperty("os.name"); 233 for (int i = 0; i < DEFAULT_OS_MAPPINGS.length; i++) { 234 if (os.equals(DEFAULT_OS_MAPPINGS[i][0])) { 235 return DEFAULT_OS_MAPPINGS[i]; 236 } 237 } 238 239 return DEFAULT_WINDOWS_7_MAPPINGS; 240 } 241 242 private ParentTraversalEngine engine; 243 244 private boolean resetToolbarState = false; 245 private String cachedHTMLText = "<html><body></body></html>"; 246 private ListChangeListener<Node> itemsListener = new ListChangeListener<Node>() { 247 @Override public void onChanged(ListChangeListener.Change<? extends Node> c) { 248 // while (c.next()) { 249 // if (c.getRemovedSize() > 0) { 250 // for (Node n : c.getList()) { 251 // if (n instanceof WebView) { 252 // // RT-28611 webView removed - set associated webPage to null 253 // webPage.dispose(); 254 // } 255 // } 256 // } 257 // } 258 } 259 }; 260 public HTMLEditorSkin(HTMLEditor htmlEditor) { 261 super(htmlEditor, new HTMLEditorBehavior(htmlEditor)); 262 263 getChildren().clear(); 264 265 gridPane = new GridPane(); 266 gridPane.getStyleClass().add("grid"); 267 getChildren().addAll(gridPane); 268 269 toolbar1 = new ToolBar(); 270 toolbar1.getStyleClass().add("top-toolbar"); 271 gridPane.add(toolbar1, 0, 0); 272 273 toolbar2 = new ToolBar(); 274 toolbar2.getStyleClass().add("bottom-toolbar"); 275 gridPane.add(toolbar2, 0, 1); 276 277 // populateToolbars(); 278 279 webView = new WebView(); 280 gridPane.add(/*webView*/IOS_UNSUPPORTED_LABEL, 0, 2); 281 282 ColumnConstraints column = new ColumnConstraints(); 283 column.setHgrow(Priority.ALWAYS); 284 gridPane.getColumnConstraints().add(column); 285 286 // webPage = Accessor.getPageFor(webView.getEngine()); 287 288 webView.addEventHandler(MouseEvent.ANY, new EventHandler<MouseEvent>() { 289 @Override public void handle(MouseEvent event) { 290 Platform.runLater(new Runnable() { 291 @Override public void run() { 292 updateToolbarState(true); 293 } 294 }); 295 } 296 }); 297 298 299 webView.addEventHandler(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() { 300 @Override public void handle(final KeyEvent event) { 301 applyTextFormatting(); 302 if (event.getCode() == KeyCode.CONTROL || event.getCode() == KeyCode.META) { 303 return; 304 } 305 if (event.getCode() == KeyCode.TAB && !event.isControlDown()) { 306 if (!event.isShiftDown()) { 307 /* 308 ** if we are in either Bullet or Numbers mode then the 309 ** TAB key tells us to indent again. 310 */ 311 if (getCommandState(BULLETS_COMMAND) || getCommandState(NUMBERS_COMMAND)) { 312 executeCommand(INDENT_COMMAND, null); 313 } 314 else { 315 executeCommand(INSERT_TAB_COMMAND, null); 316 } 317 } 318 else { 319 /* 320 ** if we are in either Bullet or Numbers mode then the 321 ** Shift-TAB key tells us to outdent. 322 */ 323 if (getCommandState(BULLETS_COMMAND) || getCommandState(NUMBERS_COMMAND)) { 324 executeCommand(OUTDENT_COMMAND, null); 325 } 326 } 327 return; 328 } 329 // Work around for bug that sends events from ColorPicker to this Scene 330 if ((fgColorButton != null && fgColorButton.isShowing()) || 331 (bgColorButton != null && bgColorButton.isShowing())) { 332 return; 333 } 334 Platform.runLater(new Runnable() { 335 @Override public void run() { 336 // if (webPage.getClientSelectedText().isEmpty()) { 337 // if (event.getCode() == KeyCode.UP || event.getCode() == KeyCode.DOWN || 338 // event.getCode() == KeyCode.LEFT || event.getCode() == KeyCode.RIGHT || 339 // event.getCode() == KeyCode.HOME || event.getCode() == KeyCode.END) { 340 // updateToolbarState(true); 341 // } else if (event.isControlDown() || event.isMetaDown()) { 342 // if (event.getCode() == KeyCode.B) { 343 // keyboardShortcuts(BOLD_COMMAND); 344 // } else if(event.getCode() == KeyCode.I) { 345 // keyboardShortcuts(ITALIC_COMMAND); 346 // } else if (event.getCode() == KeyCode.U) { 347 // keyboardShortcuts(UNDERLINE_COMMAND); 348 // } 349 // updateToolbarState(true); 350 // } else { 351 // resetToolbarState = event.getCode() == KeyCode.ENTER; 352 // if (resetToolbarState) { 353 // if (getCommandState(BOLD_COMMAND) != boldButton.selectedProperty().getValue()) { 354 // executeCommand(BOLD_COMMAND, boldButton.selectedProperty().getValue().toString()); 355 // } 356 // } 357 // updateToolbarState(false); 358 // } 359 // resetToolbarState = false; 360 // } 361 // else if (event.isShiftDown() && 362 // (event.getCode() == KeyCode.UP || event.getCode() == KeyCode.DOWN || 363 // event.getCode() == KeyCode.LEFT || event.getCode() == KeyCode.RIGHT)) { 364 // updateToolbarState(true); 365 // } 366 } 367 }); 368 } 369 }); 370 371 webView.addEventHandler(KeyEvent.KEY_RELEASED, new EventHandler<KeyEvent>() { 372 @Override public void handle(final KeyEvent event) { 373 if (event.getCode() == KeyCode.CONTROL || event.getCode() == KeyCode.META) { 374 return; 375 } 376 // Work around for bug that sends events from ColorPicker to this Scene 377 if ((fgColorButton != null && fgColorButton.isShowing()) || 378 (bgColorButton != null && bgColorButton.isShowing())) { 379 return; 380 } 381 Platform.runLater(new Runnable() { 382 @Override public void run() { 383 // if (webPage.getClientSelectedText().isEmpty()) { 384 // if (event.getCode() == KeyCode.UP || event.getCode() == KeyCode.DOWN || 385 // event.getCode() == KeyCode.LEFT || event.getCode() == KeyCode.RIGHT || 386 // event.getCode() == KeyCode.HOME || event.getCode() == KeyCode.END) { 387 // updateToolbarState(true); 388 // } else if (event.isControlDown() || event.isMetaDown()) { 389 // if (event.getCode() == KeyCode.B) { 390 // keyboardShortcuts(BOLD_COMMAND); 391 // } else if(event.getCode() == KeyCode.I) { 392 // keyboardShortcuts(ITALIC_COMMAND); 393 // } else if (event.getCode() == KeyCode.U) { 394 // keyboardShortcuts(UNDERLINE_COMMAND); 395 // } 396 // updateToolbarState(true); 397 // } else { 398 // resetToolbarState = event.getCode() == KeyCode.ENTER; 399 // if (!resetToolbarState) { 400 // updateToolbarState(false); 401 // } 402 // } 403 // resetToolbarState = false; 404 // } 405 } 406 }); 407 } 408 }); 409 410 getSkinnable().focusedProperty().addListener(new ChangeListener<Boolean>() { 411 @Override 412 public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, final Boolean newValue) { 413 Platform.runLater(new Runnable() { 414 @Override public void run() { 415 if (newValue) { 416 webView.requestFocus(); 417 } 418 } 419 }); 420 } 421 }); 422 423 webView.focusedProperty().addListener(new ChangeListener<Boolean>() { 424 @Override 425 public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, final Boolean newValue) { 426 if (newValue) { 427 // webPage.dispatchFocusEvent(new WCFocusEvent(WCFocusEvent.FOCUS_GAINED, WCFocusEvent.FORWARD)); 428 enableToolbar(true); 429 } else { 430 // webPage.dispatchFocusEvent(new WCFocusEvent(WCFocusEvent.FOCUS_LOST, WCFocusEvent.FORWARD)); 431 enableToolbar(false); 432 } 433 Platform.runLater(new Runnable() { 434 @Override public void run() { 435 updateToolbarState(true); 436 } 437 }); 438 439 if (PlatformImpl.isSupported(ConditionalFeature.VIRTUAL_KEYBOARD)) { 440 Platform.runLater(new Runnable() { 441 public void run() { 442 Scene scene = getSkinnable().getScene(); 443 if (newValue) { 444 FXVK.attach(webView); 445 } else if (scene == null || 446 scene.getWindow() == null || 447 !scene.getWindow().isFocused() || 448 !(scene.getFocusOwner() instanceof TextInputControl /*|| 449 getScene().getFocusOwner() instanceof WebView*/)) { 450 FXVK.detach(); 451 } 452 } 453 }); 454 } 455 } 456 }); 457 458 webView.getEngine().getLoadWorker().workDoneProperty().addListener(new ChangeListener<Number>() { 459 @Override 460 public void changed(ObservableValue<? extends Number> observable, final Number oldValue, final Number newValue) { 461 Platform.runLater(new Runnable() { 462 @Override public void run() { 463 webView.requestLayout(); 464 } 465 }); 466 467 double totalWork = webView.getEngine().getLoadWorker().getTotalWork(); 468 if (newValue.doubleValue() == totalWork) { 469 cachedHTMLText = null; 470 Platform.runLater(new Runnable() { 471 @Override public void run() { 472 setContentEditable(true); 473 updateToolbarState(true); 474 updateNodeOrientation(); 475 } 476 }); 477 } 478 } 479 }); 480 481 enableToolbar(true); 482 setHTMLText(cachedHTMLText); 483 484 engine = new ParentTraversalEngine(getSkinnable(), new Algorithm() { 485 @Override 486 public Node select(Node owner, Direction dir, TraversalContext context) { 487 return cutButton; 488 } 489 490 @Override 491 public Node selectFirst(TraversalContext context) { 492 return cutButton; 493 } 494 495 @Override 496 public Node selectLast(TraversalContext context) { 497 return cutButton; 498 } 499 }); 500 getSkinnable().setImpl_traversalEngine(engine); 501 webView.setFocusTraversable(true); 502 gridPane.getChildren().addListener(itemsListener); 503 } 504 505 public final String getHTMLText() { 506 // RT17203 setHTMLText is asynchronous. We use the cached version of 507 // the html text until the page finishes loading. 508 return cachedHTMLText != null ? cachedHTMLText : null;//webPage.getHtml(webPage.getMainFrame()); 509 } 510 511 public final void setHTMLText(String htmlText) { 512 cachedHTMLText = htmlText; 513 // webPage.load(webPage.getMainFrame(), htmlText, "text/html"); 514 515 Platform.runLater(new Runnable() { 516 @Override public void run() { 517 updateToolbarState(true); 518 } 519 }); 520 } 521 522 private ResourceBundle resources; 523 524 private void populateToolbars() { 525 resources = ResourceBundle.getBundle(HTMLEditorSkin.class.getName()); 526 527 // Toolbar 1 528 cutButton = addButton(toolbar1, resources.getString("cutIcon"), resources.getString("cut"), CUT_COMMAND, "html-editor-cut"); 529 copyButton = addButton(toolbar1, resources.getString("copyIcon"), resources.getString("copy"), COPY_COMMAND, "html-editor-copy"); 530 pasteButton = addButton(toolbar1, resources.getString("pasteIcon"), resources.getString("paste"), PASTE_COMMAND, "html-editor-paste"); 531 532 toolbar1.getItems().add(new Separator()); 533 534 // undoButton = addButton(toolbar1, "undoIcon", resources.getString("undo"), UNDO_COMMAND); 535 // redoButton = addButton(toolbar1, "redoIcon", resources.getString("redo"), REDO_COMMAND);// 536 // toolbar1.getItems().add(new Separator()); 537 538 alignmentToggleGroup = new ToggleGroup(); 539 alignLeftButton = addToggleButton(toolbar1, alignmentToggleGroup, 540 resources.getString("alignLeftIcon"), resources.getString("alignLeft"), ALIGN_LEFT_COMMAND, "html-editor-align-left"); 541 alignCenterButton = addToggleButton(toolbar1, alignmentToggleGroup, 542 resources.getString("alignCenterIcon"), resources.getString("alignCenter"), ALIGN_CENTER_COMMAND, "html-editor-align-center"); 543 alignRightButton = addToggleButton(toolbar1, alignmentToggleGroup, 544 resources.getString("alignRightIcon"), resources.getString("alignRight"), ALIGN_RIGHT_COMMAND, "html-editor-align-right"); 545 alignJustifyButton = addToggleButton(toolbar1, alignmentToggleGroup, 546 resources.getString("alignJustifyIcon"), resources.getString("alignJustify"), ALIGN_JUSTIFY_COMMAND, "html-editor-align-justify"); 547 548 toolbar1.getItems().add(new Separator()); 549 550 outdentButton = addButton(toolbar1, resources.getString("outdentIcon"), resources.getString("outdent"), OUTDENT_COMMAND, "html-editor-outdent"); 551 if (outdentButton.getGraphic() != null) outdentButton.getGraphic().setNodeOrientation(NodeOrientation.INHERIT); 552 indentButton = addButton(toolbar1, resources.getString("indentIcon"), resources.getString("indent"), INDENT_COMMAND, "html-editor-indent"); 553 if (indentButton.getGraphic() != null) indentButton.getGraphic().setNodeOrientation(NodeOrientation.INHERIT); 554 555 toolbar1.getItems().add(new Separator()); 556 557 ToggleGroup listStyleToggleGroup = new ToggleGroup(); 558 bulletsButton = addToggleButton(toolbar1, listStyleToggleGroup, 559 resources.getString("bulletsIcon"), resources.getString("bullets"), BULLETS_COMMAND, "html-editor-bullets"); 560 if (bulletsButton.getGraphic() != null) bulletsButton.getGraphic().setNodeOrientation(NodeOrientation.INHERIT); 561 numbersButton = addToggleButton(toolbar1, listStyleToggleGroup, 562 resources.getString("numbersIcon"), resources.getString("numbers"), NUMBERS_COMMAND, "html-editor-numbers"); 563 564 toolbar1.getItems().add(new Separator()); 565 566 //toolbar1.getItems().add(new Separator()); 567 568 // Toolbar 2 569 formatComboBox = new ComboBox<String>(); 570 formatComboBox.getStyleClass().add("font-menu-button"); 571 formatComboBox.setFocusTraversable(false); 572 formatComboBox.setMinWidth(Region.USE_PREF_SIZE); 573 toolbar2.getItems().add(formatComboBox); 574 575 formatStyleMap = new HashMap<String, String>(); 576 styleFormatMap = new HashMap<String, String>(); 577 578 createFormatMenuItem(FORMAT_PARAGRAPH, resources.getString("paragraph")); 579 Platform.runLater(new Runnable() { 580 @Override 581 public void run() { 582 formatComboBox.setValue(resources.getString("paragraph")); 583 } 584 }); 585 createFormatMenuItem(FORMAT_HEADING_1, resources.getString("heading1")); 586 createFormatMenuItem(FORMAT_HEADING_2, resources.getString("heading2")); 587 createFormatMenuItem(FORMAT_HEADING_3, resources.getString("heading3")); 588 createFormatMenuItem(FORMAT_HEADING_4, resources.getString("heading4")); 589 createFormatMenuItem(FORMAT_HEADING_5, resources.getString("heading5")); 590 createFormatMenuItem(FORMAT_HEADING_6, resources.getString("heading6")); 591 592 // formatComboBox.setCellFactory(new Callback<ListView<String>, ListCell<String>>() { 593 // @Override public ListCell<String> call(ListView<String> param) { 594 // final ListCell<String> cell = new ListCell<String>() { 595 // @Override public void updateItem(String item, boolean empty) { 596 // super.updateItem(item, empty); 597 // if (item != null) { 598 // setText(item); 599 // } 600 // } 601 // }; 602 // return cell; 603 // } 604 // }); 605 606 formatComboBox.setTooltip(new Tooltip(resources.getString("format"))); 607 608 formatComboBox.valueProperty().addListener(new ChangeListener<String>() { 609 @Override 610 public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) { 611 if (newValue == null) { 612 formatComboBox.setValue(null); 613 } else { 614 String formatValue = formatStyleMap.get(newValue); 615 executeCommand(FORMAT_COMMAND, formatValue); 616 updateToolbarState(false); 617 618 // RT-16330 match the new font format with the required weight and size 619 for (int i = 0; i < DEFAULT_FORMAT_MAPPINGS.length; i++) { 620 String[] mapping = DEFAULT_FORMAT_MAPPINGS[i]; 621 if (mapping[0].equalsIgnoreCase(formatValue)) { 622 executeCommand(FONT_SIZE_COMMAND, mapping[2]); 623 updateToolbarState(false); 624 break; 625 } 626 } 627 } 628 } 629 }); 630 631 fontFamilyComboBox = new ComboBox<String>(); 632 fontFamilyComboBox.getStyleClass().add("font-menu-button"); 633 fontFamilyComboBox.setMinWidth(FONT_FAMILY_MENUBUTTON_WIDTH); 634 fontFamilyComboBox.setPrefWidth(FONT_FAMILY_MENUBUTTON_WIDTH); 635 fontFamilyComboBox.setMaxWidth(FONT_FAMILY_MENUBUTTON_WIDTH); 636 fontFamilyComboBox.setFocusTraversable(false); 637 fontFamilyComboBox.setTooltip(new Tooltip(resources.getString("fontFamily"))); 638 toolbar2.getItems().add(fontFamilyComboBox); 639 640 fontFamilyComboBox.setCellFactory(new Callback<ListView<String>, ListCell<String>>() { 641 @Override public ListCell<String> call(ListView<String> param) { 642 final ListCell<String> cell = new ListCell<String>() { 643 @Override public void updateItem(String item, boolean empty) { 644 super.updateItem(item, empty); 645 if (item != null) { 646 setText(item); 647 setFont(new Font(item, 12)); 648 } 649 } 650 }; 651 cell.setMinWidth(FONT_FAMILY_MENU_WIDTH); 652 cell.setPrefWidth(FONT_FAMILY_MENU_WIDTH); 653 cell.setMaxWidth(FONT_FAMILY_MENU_WIDTH); 654 return cell; 655 } 656 }); 657 658 Platform.runLater(new Runnable() { 659 @Override public void run() { 660 final ObservableList<String> fonts = FXCollections.observableArrayList(Font.getFamilies()); 661 for (String fontFamily : fonts) { 662 if (DEFAULT_OS_FONT.equals(fontFamily)) { 663 fontFamilyComboBox.setValue(fontFamily); 664 } 665 fontFamilyComboBox.setItems(fonts); 666 } 667 } 668 }); 669 670 fontFamilyComboBox.valueProperty().addListener(new ChangeListener<String>() { 671 @Override 672 public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) { 673 executeCommand(FONT_FAMILY_COMMAND, newValue); 674 } 675 }); 676 677 fontSizeComboBox = new ComboBox<String>(); 678 fontSizeComboBox.getStyleClass().add("font-menu-button"); 679 fontSizeComboBox.setFocusTraversable(false); 680 toolbar2.getItems().add(fontSizeComboBox); 681 682 fontSizeMap = new HashMap<String, String>(); 683 sizeFontMap = new HashMap<String, String>(); 684 685 createFontSizeMenuItem(SIZE_XX_SMALL, resources.getString("extraExtraSmall")); 686 createFontSizeMenuItem(SIZE_X_SMALL, resources.getString("extraSmall")); 687 createFontSizeMenuItem(SIZE_SMALL, resources.getString("small")); 688 Platform.runLater(new Runnable() { 689 @Override 690 public void run() { 691 fontSizeComboBox.setValue(resources.getString("small")); 692 } 693 }); 694 createFontSizeMenuItem(SIZE_MEDIUM, resources.getString("medium")); 695 createFontSizeMenuItem(SIZE_LARGE, resources.getString("large")); 696 createFontSizeMenuItem(SIZE_X_LARGE, resources.getString("extraLarge")); 697 createFontSizeMenuItem(SIZE_XX_LARGE, resources.getString("extraExtraLarge")); 698 fontSizeComboBox.setTooltip(new Tooltip(resources.getString("fontSize"))); 699 700 fontSizeComboBox.setCellFactory(new Callback<ListView<String>, ListCell<String>>() { 701 @Override public ListCell<String> call(ListView<String> param) { 702 final ListCell<String> cell = new ListCell<String>() { 703 @Override public void updateItem(String item, boolean empty) { 704 super.updateItem(item, empty); 705 if (item != null) { 706 setText(item); 707 setFont(new Font((String)fontFamilyComboBox.getValue(), Double.valueOf(item.substring(0, item.indexOf(" "))))); 708 } 709 } 710 }; 711 return cell; 712 } 713 }); 714 715 716 fontSizeComboBox.valueProperty().addListener(new ChangeListener<String>() { 717 @Override 718 public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) { 719 Object fontSizeValue = getCommandValue(FONT_SIZE_COMMAND); 720 if (!newValue.equals(fontSizeValue)) { 721 executeCommand(FONT_SIZE_COMMAND, fontSizeMap.get(newValue)); 722 } 723 } 724 }); 725 726 toolbar2.getItems().add(new Separator()); 727 728 boldButton = addToggleButton(toolbar2, null, 729 resources.getString("boldIcon"), resources.getString("bold"), BOLD_COMMAND, "html-editor-bold"); 730 boldButton.setOnAction(new EventHandler<ActionEvent>() { 731 @Override 732 public void handle(ActionEvent event) { 733 // Only use the bold button for paragraphs. We don't 734 // want to turn bold off for headings. 735 736 if ("<p>".equals(formatStyleMap.get(formatComboBox.getValue()))) { 737 executeCommand(BOLD_COMMAND, boldButton.selectedProperty().getValue().toString()); 738 } 739 } 740 }); 741 italicButton = addToggleButton(toolbar2, null, 742 resources.getString("italicIcon"), resources.getString("italic"), ITALIC_COMMAND, "html-editor-italic"); 743 underlineButton = addToggleButton(toolbar2, null, 744 resources.getString("underlineIcon"), resources.getString("underline"), UNDERLINE_COMMAND, "html-editor-underline"); 745 strikethroughButton = addToggleButton(toolbar2, null, 746 resources.getString("strikethroughIcon"), resources.getString("strikethrough"), STRIKETHROUGH_COMMAND, "html-editor-strike"); 747 748 toolbar2.getItems().add(new Separator()); 749 750 insertHorizontalRuleButton = addButton(toolbar2, resources.getString("insertHorizontalRuleIcon"), 751 resources.getString("insertHorizontalRule"), INSERT_HORIZONTAL_RULE_COMMAND, "html-editor-hr"); 752 // We override setOnAction to insert a new line. This fixes RT-16453 753 insertHorizontalRuleButton.setOnAction(new EventHandler<ActionEvent>() { 754 @Override 755 public void handle(ActionEvent event) { 756 executeCommand(INSERT_NEW_LINE_COMMAND, null); 757 executeCommand(INSERT_HORIZONTAL_RULE_COMMAND, null); 758 updateToolbarState(false); 759 } 760 }); 761 762 fgColorButton = new ColorPicker(); 763 fgColorButton.getStyleClass().add("html-editor-foreground"); 764 fgColorButton.setFocusTraversable(false); 765 toolbar1.getItems().add(fgColorButton); 766 767 fgColorButton.applyCss(); 768 ColorPickerSkin fgColorPickerSkin = (ColorPickerSkin) fgColorButton.getSkin(); 769 String fgIcon = AccessController.doPrivileged(new PrivilegedAction<String>() { 770 @Override public String run() { 771 return HTMLEditorSkin.class.getResource(resources.getString("foregroundColorIcon")).toString(); 772 } 773 }); 774 ((StyleableProperty)fgColorPickerSkin.imageUrlProperty()).applyStyle(null,fgIcon); 775 776 fgColorButton.setValue(DEFAULT_FG_COLOR); 777 fgColorButton.setTooltip(new Tooltip(resources.getString("foregroundColor"))); 778 fgColorButton.setOnAction(new EventHandler<ActionEvent>() { 779 @Override public void handle(ActionEvent ev) { 780 Color newValue = fgColorButton.getValue(); 781 if (newValue != null) { 782 executeCommand(FOREGROUND_COLOR_COMMAND, colorValueToHex(newValue)); 783 fgColorButton.hide(); 784 } 785 } 786 }); 787 788 bgColorButton = new ColorPicker(); 789 bgColorButton.getStyleClass().add("html-editor-background"); 790 bgColorButton.setFocusTraversable(false); 791 toolbar1.getItems().add(bgColorButton); 792 793 bgColorButton.applyCss(); 794 ColorPickerSkin bgColorPickerSkin = (ColorPickerSkin) bgColorButton.getSkin(); 795 String bgIcon = AccessController.doPrivileged(new PrivilegedAction<String>() { 796 @Override public String run() { 797 return HTMLEditorSkin.class.getResource(resources.getString("backgroundColorIcon")).toString(); 798 } 799 }); 800 ((StyleableProperty)bgColorPickerSkin.imageUrlProperty()).applyStyle(null,bgIcon); 801 802 bgColorButton.setValue(DEFAULT_BG_COLOR); 803 bgColorButton.setTooltip(new Tooltip(resources.getString("backgroundColor"))); 804 805 bgColorButton.setOnAction(new EventHandler<ActionEvent>() { 806 @Override public void handle(ActionEvent ev) { 807 Color newValue = bgColorButton.getValue(); 808 if (newValue != null) { 809 executeCommand(BACKGROUND_COLOR_COMMAND, colorValueToHex(newValue)); 810 bgColorButton.hide(); 811 } 812 } 813 }); 814 } 815 816 private String colorValueToHex(Color c) { 817 return String.format((Locale)null, "#%02x%02x%02x", 818 Math.round(c.getRed() * 255), 819 Math.round(c.getGreen() * 255), 820 Math.round(c.getBlue() * 255)); 821 } 822 823 private Button addButton(ToolBar toolbar, final String iconName, String tooltipText, 824 final String command, final String styleClass) { 825 Button button = new Button(); 826 button.setFocusTraversable(false); 827 button.getStyleClass().add(styleClass); 828 toolbar.getItems().add(button); 829 830 Image icon = AccessController.doPrivileged(new PrivilegedAction<Image>() { 831 @Override public Image run() { 832 return new Image(HTMLEditorSkin.class.getResource(iconName).toString()); 833 } 834 }); 835 // button.setGraphic(new ImageView(icon)); 836 ((StyleableProperty)button.graphicProperty()).applyStyle(null,new ImageView(icon)); 837 button.setTooltip(new Tooltip(tooltipText)); 838 839 button.setOnAction(new EventHandler<ActionEvent>() { 840 @Override 841 public void handle(ActionEvent event) { 842 executeCommand(command, null); 843 updateToolbarState(false); 844 } 845 }); 846 847 return button; 848 } 849 850 private ToggleButton addToggleButton(ToolBar toolbar, ToggleGroup toggleGroup, 851 final String iconName, String tooltipText, final String command, final String styleClass) { 852 ToggleButton toggleButton = new ToggleButton(); 853 toggleButton.setUserData(command); 854 toggleButton.setFocusTraversable(false); 855 toggleButton.getStyleClass().add(styleClass); 856 toolbar.getItems().add(toggleButton); 857 if (toggleGroup != null) { 858 toggleButton.setToggleGroup(toggleGroup); 859 } 860 861 Image icon = AccessController.doPrivileged(new PrivilegedAction<Image>() { 862 @Override public Image run() { 863 return new Image(HTMLEditorSkin.class.getResource(iconName).toString()); 864 } 865 }); 866 ((StyleableProperty)toggleButton.graphicProperty()).applyStyle(null,new ImageView(icon)); 867 // toggleButton.setGraphic(new ImageView(icon)); 868 869 toggleButton.setTooltip(new Tooltip(tooltipText)); 870 871 if (!BOLD_COMMAND.equals(command)) { 872 toggleButton.selectedProperty().addListener(new ChangeListener<Boolean>() { 873 @Override 874 public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) { 875 if (getCommandState(command) != newValue.booleanValue()) { 876 executeCommand(command, null); 877 } 878 } 879 }); 880 } 881 return toggleButton; 882 } 883 884 private void createFormatMenuItem(String formatValue, String label) { 885 formatComboBox.getItems().add(label); 886 formatStyleMap.put(label, formatValue); 887 styleFormatMap.put(formatValue, label); 888 } 889 890 private void createFontSizeMenuItem(String fontSizeValue, String label) { 891 fontSizeComboBox.getItems().add(label); 892 fontSizeMap.put(label, fontSizeValue); 893 sizeFontMap.put(fontSizeValue, label); 894 } 895 896 private void updateNodeOrientation() { 897 NodeOrientation orientation = getSkinnable().getEffectiveNodeOrientation(); 898 899 // HTMLDocument htmlDocument = (HTMLDocument)webPage.getDocument(webPage.getMainFrame()); 900 // HTMLElement htmlDocumentElement = (HTMLElement)htmlDocument.getDocumentElement(); 901 // if (htmlDocumentElement.getAttribute("dir") == null) { 902 // htmlDocumentElement.setAttribute("dir", (orientation == RIGHT_TO_LEFT) ? "rtl" : "ltr"); 903 // } 904 905 if (orientation == RIGHT_TO_LEFT) { 906 try { 907 final String iconName = resources.getString("numbersIcon-rtl"); 908 Image icon = AccessController.doPrivileged(new PrivilegedAction<Image>() { 909 @Override public Image run() { 910 return new Image(HTMLEditorSkin.class.getResource(iconName).toString()); 911 } 912 }); 913 numbersButton.setGraphic(new ImageView(icon)); 914 } catch (java.util.MissingResourceException ex) { 915 // ignore 916 } 917 } 918 } 919 920 private void updateToolbarState(final boolean updateAlignment) { 921 if (!webView.isFocused()) { 922 return; 923 } 924 925 // These command aways return true. 926 copyButton.setDisable(!isCommandEnabled(CUT_COMMAND)); 927 cutButton.setDisable(!isCommandEnabled(COPY_COMMAND)); 928 pasteButton.setDisable(!isCommandEnabled(PASTE_COMMAND)); 929 930 // undoButton.setDisable(!isCommandEnabled(UNDO_COMMAND)); 931 // redoButton.setDisable(!isCommandEnabled(REDO_COMMAND)); 932 933 // undoButton.setDisable(!isCommandEnabled(FORMAT_COMMAND)); 934 // redoButton.setDisable(!isCommandEnabled(FORMAT_COMMAND)); 935 936 insertHorizontalRuleButton.setDisable(!isCommandEnabled(INSERT_HORIZONTAL_RULE_COMMAND)); 937 938 if (updateAlignment) { 939 alignLeftButton.setDisable(!isCommandEnabled(ALIGN_LEFT_COMMAND)); 940 alignLeftButton.setSelected(getCommandState(ALIGN_LEFT_COMMAND)); 941 alignCenterButton.setDisable(!isCommandEnabled(ALIGN_CENTER_COMMAND)); 942 alignCenterButton.setSelected(getCommandState(ALIGN_CENTER_COMMAND)); 943 alignRightButton.setDisable(!isCommandEnabled(ALIGN_RIGHT_COMMAND)); 944 alignRightButton.setSelected(getCommandState(ALIGN_RIGHT_COMMAND)); 945 alignJustifyButton.setDisable(!isCommandEnabled(ALIGN_JUSTIFY_COMMAND)); 946 alignJustifyButton.setSelected(getCommandState(ALIGN_JUSTIFY_COMMAND)); 947 } else { 948 if (alignmentToggleGroup.getSelectedToggle() != null) { 949 String command = alignmentToggleGroup.getSelectedToggle().getUserData().toString(); 950 if (isCommandEnabled(command) && !getCommandState(command) ) { 951 executeCommand(command, null); 952 } 953 } 954 } 955 956 if (alignmentToggleGroup.getSelectedToggle() == null) { 957 alignmentToggleGroup.selectToggle(alignLeftButton); 958 } 959 960 bulletsButton.setDisable(!isCommandEnabled(BULLETS_COMMAND)); 961 bulletsButton.setSelected(getCommandState(BULLETS_COMMAND)); 962 numbersButton.setDisable(!isCommandEnabled(NUMBERS_COMMAND)); 963 numbersButton.setSelected(getCommandState(NUMBERS_COMMAND)); 964 965 indentButton.setDisable(!isCommandEnabled(INDENT_COMMAND)); 966 outdentButton.setDisable(!isCommandEnabled(OUTDENT_COMMAND)); 967 968 formatComboBox.setDisable(!isCommandEnabled(FORMAT_COMMAND)); 969 970 971 String formatValue = getCommandValue(FORMAT_COMMAND); 972 if (formatValue != null) { 973 String htmlTag = "<" + formatValue + ">"; 974 String comboFormatValue = styleFormatMap.get(htmlTag); 975 String format = formatComboBox.getValue(); 976 977 // if the format value is then we assume that we're dealing with a paragraph, 978 // which seems to correspond with the HTML output we receive. 979 if ((resetToolbarState || htmlTag.equals("<>") || htmlTag.equalsIgnoreCase("<div>"))) { 980 formatComboBox.setValue(resources.getString("paragraph")); 981 } else if (format != null && ! format.equalsIgnoreCase(comboFormatValue)) { 982 formatComboBox.setValue(comboFormatValue); 983 } 984 } 985 986 fontFamilyComboBox.setDisable(!isCommandEnabled(FONT_FAMILY_COMMAND)); 987 final String fontFamilyValue = getCommandValue(FONT_FAMILY_COMMAND); 988 if (fontFamilyValue != null) { 989 String fontFamilyStr = fontFamilyValue; 990 991 // stripping out apostrophe characters, which are appended to either 992 // end of the font face name when the font face has one or more spaces. 993 if (fontFamilyStr.startsWith("'")) { 994 fontFamilyStr = fontFamilyStr.substring(1); 995 } 996 if (fontFamilyStr.endsWith("'")) { 997 fontFamilyStr = fontFamilyStr.substring(0,fontFamilyStr.length() - 1); 998 } 999 1000 Object selectedFont = fontFamilyComboBox.getValue(); 1001 if (selectedFont instanceof String) { 1002 if (!selectedFont.equals(fontFamilyStr)) { 1003 1004 ObservableList<String> fontFamilyItems = fontFamilyComboBox.getItems(); 1005 String selectedComboFont = null; 1006 for (String comboFontFamilyValue : fontFamilyItems) { 1007 1008 if (comboFontFamilyValue.equals(fontFamilyStr)) { 1009 selectedComboFont = comboFontFamilyValue; 1010 break; 1011 } 1012 // Note: By default, 'Dialog' is the font returned from webview. 1013 // For presidio, we're just mapping to an OS-specific font. 1014 if (comboFontFamilyValue.equals(DEFAULT_OS_FONT) && fontFamilyStr.equals("Dialog")) { 1015 selectedComboFont = comboFontFamilyValue; 1016 break; 1017 } 1018 } 1019 1020 if (selectedComboFont != null) { 1021 fontFamilyComboBox.setValue(selectedComboFont); 1022 } 1023 } 1024 } 1025 } 1026 1027 fontSizeComboBox.setDisable(!isCommandEnabled(FONT_SIZE_COMMAND)); 1028 String fontSizeValue = getCommandValue(FONT_SIZE_COMMAND); 1029 1030 if (resetToolbarState) { 1031 fontSizeComboBox.setValue(sizeFontMap.get(SIZE_SMALL)); 1032 } 1033 else { 1034 if (fontSizeValue != null) { 1035 if (!fontSizeComboBox.getValue().equals(sizeFontMap.get(fontSizeValue))) { 1036 fontSizeComboBox.setValue(sizeFontMap.get(fontSizeValue)); 1037 } 1038 } 1039 else { 1040 /* 1041 ** these is no font size set in webview, 1042 ** let's just use the default.... 1043 */ 1044 if (!fontSizeComboBox.getValue().equals(sizeFontMap.get(SIZE_SMALL))) { 1045 fontSizeComboBox.setValue(sizeFontMap.get(SIZE_SMALL)); 1046 } 1047 } 1048 } 1049 1050 boldButton.setDisable(!isCommandEnabled(BOLD_COMMAND)); 1051 if (formatValue != null) { 1052 if (!resetToolbarState && ("p".equals(formatValue) || "div".equals(formatValue))) { 1053 boldButton.setSelected(getCommandState(BOLD_COMMAND)); 1054 } 1055 } 1056 italicButton.setDisable(!isCommandEnabled(ITALIC_COMMAND)); 1057 italicButton.setSelected(getCommandState(ITALIC_COMMAND)); 1058 underlineButton.setDisable(!isCommandEnabled(UNDERLINE_COMMAND)); 1059 underlineButton.setSelected(getCommandState(UNDERLINE_COMMAND)); 1060 strikethroughButton.setDisable(!isCommandEnabled(STRIKETHROUGH_COMMAND)); 1061 strikethroughButton.setSelected(getCommandState(STRIKETHROUGH_COMMAND)); 1062 1063 fgColorButton.setDisable(!isCommandEnabled(FOREGROUND_COLOR_COMMAND)); 1064 String foregroundColorValue = getCommandValue(FOREGROUND_COLOR_COMMAND); 1065 if (foregroundColorValue != null) { 1066 Color c = Color.web(rgbToHex((String)foregroundColorValue)); 1067 fgColorButton.setValue(c); 1068 } 1069 1070 bgColorButton.setDisable(!isCommandEnabled(BACKGROUND_COLOR_COMMAND)); 1071 String backgroundColorValue = getCommandValue(BACKGROUND_COLOR_COMMAND); 1072 if (backgroundColorValue != null) { 1073 Color c = Color.web(rgbToHex((String)backgroundColorValue)); 1074 bgColorButton.setValue(c); 1075 } 1076 } 1077 1078 private void enableToolbar(final boolean enable) { 1079 Platform.runLater(new Runnable() { 1080 @Override public void run() { 1081 1082 // Make sure buttons have been created to avoid NPE 1083 if (copyButton == null) return; 1084 1085 /* 1086 ** if we're to enable, we still only enable 1087 ** the cut/copy/paste buttons that make sense 1088 */ 1089 if (enable) { 1090 copyButton.setDisable(!isCommandEnabled(COPY_COMMAND)); 1091 cutButton.setDisable(!isCommandEnabled(CUT_COMMAND)); 1092 pasteButton.setDisable(!isCommandEnabled(PASTE_COMMAND)); 1093 } 1094 else { 1095 copyButton.setDisable(true); 1096 cutButton.setDisable(true); 1097 pasteButton.setDisable(true); 1098 } 1099 1100 // undoButton.setDisable(!enable); 1101 // redoButton.setDisable(!enable); 1102 insertHorizontalRuleButton.setDisable(!enable); 1103 alignLeftButton.setDisable(!enable); 1104 alignCenterButton.setDisable(!enable); 1105 alignRightButton.setDisable(!enable); 1106 alignJustifyButton.setDisable(!enable); 1107 bulletsButton.setDisable(!enable); 1108 numbersButton.setDisable(!enable); 1109 indentButton.setDisable(!enable); 1110 outdentButton.setDisable(!enable); 1111 formatComboBox.setDisable(!enable); 1112 fontFamilyComboBox.setDisable(!enable); 1113 fontSizeComboBox.setDisable(!enable); 1114 boldButton.setDisable(!enable); 1115 italicButton.setDisable(!enable); 1116 underlineButton.setDisable(!enable); 1117 strikethroughButton.setDisable(!enable); 1118 fgColorButton.setDisable(!enable); 1119 bgColorButton.setDisable(!enable); 1120 } 1121 }); 1122 } 1123 1124 private boolean executeCommand(String command, String value) { 1125 return false; //webPage.executeCommand(command, value); 1126 } 1127 1128 private boolean isCommandEnabled(String command) { 1129 return false;// webPage.queryCommandEnabled(command); 1130 } 1131 1132 private void setContentEditable(boolean b) { 1133 // HTMLDocument htmlDocument = (HTMLDocument)webPage.getDocument(webPage.getMainFrame()); 1134 // HTMLElement htmlDocumentElement = (HTMLElement)htmlDocument.getDocumentElement(); 1135 // HTMLElement htmlBodyElement = (HTMLElement)htmlDocumentElement.getElementsByTagName("body").item(0); 1136 // htmlBodyElement.setAttribute("contenteditable", Boolean.toString(b)); 1137 } 1138 1139 private boolean getCommandState(String command) { 1140 return false;//webPage.queryCommandState(command); 1141 } 1142 1143 private String getCommandValue(String command) { 1144 return null;//webPage.queryCommandValue(command); 1145 } 1146 1147 private static String rgbToHex(String value) { 1148 if (value.startsWith("rgba")) { 1149 String[] components = value.substring(value.indexOf('(') + 1, value.lastIndexOf(')')).split(","); 1150 value = String.format("#%02X%02X%02X%02X", 1151 Integer.parseInt(components[0].trim()), 1152 Integer.parseInt(components[1].trim()), 1153 Integer.parseInt(components[2].trim()), 1154 Integer.parseInt(components[3].trim())); 1155 // The default background color for WebView, according to the HTML 1156 // standard is rgba=#00000000 (black). The canvas background is expected 1157 // to be white. 1158 if ("#00000000".equals(value)) { 1159 return "#FFFFFFFF"; 1160 } 1161 } else if (value.startsWith("rgb")) { 1162 String[] components = value.substring(value.indexOf('(') + 1, value.lastIndexOf(')')).split(","); 1163 value = String.format("#%02X%02X%02X", 1164 Integer.parseInt(components[0].trim()), 1165 Integer.parseInt(components[1].trim()), 1166 Integer.parseInt(components[2].trim())); 1167 } 1168 1169 return value; 1170 } 1171 1172 private void applyTextFormatting() { 1173 if (getCommandState(BULLETS_COMMAND) || getCommandState(NUMBERS_COMMAND)) { 1174 return; 1175 } 1176 1177 // if (webPage.getClientCommittedTextLength() == 0) { 1178 // String format = formatStyleMap.get(formatComboBox.getValue()); 1179 // String font = fontFamilyComboBox.getValue().toString(); 1180 // 1181 // executeCommand(FORMAT_COMMAND, format); 1182 // executeCommand(FONT_FAMILY_COMMAND, font); 1183 // } 1184 } 1185 1186 public void keyboardShortcuts(final String name) { 1187 if ("bold".equals(name)) { 1188 boldButton.fire(); 1189 } else if ("italic".equals(name)) { 1190 italicButton.setSelected(!italicButton.isSelected()); 1191 } else if ("underline".equals(name)) { 1192 underlineButton.setSelected(!underlineButton.isSelected()); 1193 } 1194 } 1195 1196 @Override 1197 public void onTraverse(Node node, Bounds bounds) { 1198 cutButton.requestFocus(); 1199 } 1200 1201 private boolean isFirstRun = true; 1202 1203 @Override 1204 protected void layoutChildren(final double x, final double y, 1205 final double w, final double h) { 1206 1207 if (isFirstRun) { 1208 populateToolbars(); 1209 isFirstRun = false; 1210 } 1211 super.layoutChildren(x,y,w,h); 1212 double toolbarWidth = Math.max(toolbar1.prefWidth(-1), toolbar2.prefWidth(-1)); 1213 toolbar1.setMinWidth(toolbarWidth); 1214 toolbar1.setPrefWidth(toolbarWidth); 1215 toolbar2.setMinWidth(toolbarWidth); 1216 toolbar2.setPrefWidth(toolbarWidth); 1217 } 1218 1219 private static final int FONT_FAMILY_MENUBUTTON_WIDTH = 150; 1220 private static final int FONT_FAMILY_MENU_WIDTH = 100; 1221 private static final int FONT_SIZE_MENUBUTTON_WIDTH = 80; 1222 1223 }