private void updateOpenRevealMenuItems() { // Get the file name part of the suffix String suffix = new PrefixedValue(getValue()).getSuffix(); String fileName = null; if (!suffix.isEmpty()) { String[] urlParts = suffix.split("\\/"); fileName = urlParts[urlParts.length - 1]; // On windows, we may have "\" separators. urlParts = fileName.split("\\\\"); fileName = urlParts[urlParts.length - 1]; } if (fileName != null) { openMi.setVisible(true); revealMi.setVisible(true); openMi.setText(I18N.getString("inspector.list.open", fileName)); if (EditorPlatform.IS_MAC) { revealMi.setText(I18N.getString("inspector.list.reveal.finder", fileName)); } else { revealMi.setText(I18N.getString("inspector.list.reveal.explorer", fileName)); } } else { openMi.setVisible(false); revealMi.setVisible(false); } }
// Method to please FindBugs private void initialize(String url) { setValue(url); EventHandler<ActionEvent> onActionListener = new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { // System.out.println("StylesheetItem : onActionListener"); if (getValue().equals(currentValue)) { // no change return; } if (stylesheetTf.getText().isEmpty()) { remove(null); } // System.out.println("StyleEditorItem : COMMIT"); editor.commit(StylesheetItem.this); if (event != null && event.getSource() instanceof TextField) { ((TextField) event.getSource()).selectAll(); } updateButtons(); updateOpenRevealMenuItems(); currentValue = getValue(); } }; ChangeListener<String> textPropertyChange = new ChangeListener<String>() { @Override public void changed( ObservableValue<? extends String> ov, String prevText, String newText) { if (prevText.isEmpty() || newText.isEmpty()) { // Text changed FROM empty value, or TO empty value: buttons status change updateButtons(); updateOpenRevealMenuItems(); } } }; stylesheetTf.textProperty().addListener(textPropertyChange); updateButtons(); setTextEditorBehavior(stylesheetTf, onActionListener); // Initialize menu items text removeMi.setText(I18N.getString("inspector.list.remove")); moveUpMi.setText(I18N.getString("inspector.list.moveup")); moveDownMi.setText(I18N.getString("inspector.list.movedown")); }
@FXML void chooseStylesheet(ActionEvent event) { String[] extensions = {"*.css"}; // NOI18N FileChooser fileChooser = new FileChooser(); fileChooser.setTitle(I18N.getString("inspector.select.css.title")); fileChooser .getExtensionFilters() .add( new FileChooser.ExtensionFilter( I18N.getString("inspector.select.css.filter"), Arrays.asList(extensions))); File file = fileChooser.showOpenDialog(root.getScene().getWindow()); if ((file == null)) { return; } URL url; try { url = file.toURI().toURL(); } catch (MalformedURLException ex) { throw new RuntimeException("Invalid URL", ex); // NOI18N } if (alreadyUsed(url.toExternalForm())) { System.err.println( I18N.getString("inspector.stylesheet.alreadyexist", url)); // should go to message panel return; } switchToItemList(); // Add editor item String urlStr; if (fxmlFileLocation != null) { // If the document exists, make the type as document relative by default. urlStr = PrefixedValue.makePrefixedValue(url, fxmlFileLocation).toString(); switchType(Type.DOCUMENT_RELATIVE_PATH); } else { urlStr = url.toExternalForm(); switchType(Type.PLAIN_STRING); } addItem(new StylesheetItem(this, urlStr)); // Workaround for RT-34863: Reload of an updated css file has no effect. // This reset the whole CSS from top. Would need to be moved on the FXOM side. Deprecation.reapplyCSS(root.getScene()); userUpdateValueProperty(getValue()); }
private void updateContentGroup() { /* * fxomRoot */ final String statusMessageText, statusStyleClass; contentGroup.getChildren().clear(); if (fxomDocument == null) { statusMessageText = "FXOMDocument is null"; // NOI18N statusStyleClass = "stage-prompt"; // NOI18N } else if (fxomDocument.getFxomRoot() == null) { statusMessageText = I18N.getString("content.label.status.invitation"); statusStyleClass = "stage-prompt"; // NOI18N } else { final Object userSceneGraph = fxomDocument.getSceneGraphRoot(); if (userSceneGraph instanceof Node) { final Node rootNode = (Node) userSceneGraph; assert rootNode.getParent() == null; contentGroup.getChildren().add(rootNode); layoutContent(true /* applyCSS */); if (layoutException == null) { statusMessageText = ""; // NOI18N statusStyleClass = "stage-prompt-default"; // NOI18N } else { contentGroup.getChildren().clear(); statusMessageText = I18N.getString("content.label.status.cannot.display"); statusStyleClass = "stage-prompt"; // NOI18N } } else { statusMessageText = I18N.getString("content.label.status.cannot.display"); statusStyleClass = "stage-prompt"; // NOI18N } } backgroundPane.setText(statusMessageText); backgroundPane.getStyleClass().clear(); backgroundPane.getStyleClass().add(statusStyleClass); // If layoutException != null, then this layout call is required // so that backgroundPane updates its message... Strange... backgroundPane.layout(); adjustWorkspace(); }
private void open(EditorItem source) { String urlStr = getUrl(source); if (urlStr == null) { return; } try { EditorPlatform.open(urlStr); } catch (IOException ex) { System.err.println( I18N.getString( "inspector.stylesheet.cannotopen", urlStr + " : " + ex)); // should go to message panel } }
private void reveal(EditorItem source) { String urlStr = getUrl(source); if (urlStr == null) { return; } try { File file = URLUtils.getFile(urlStr); if (file == null) { // urlStr is not a file URL return; } EditorPlatform.revealInFileBrowser(file); } catch (URISyntaxException | IOException ex) { System.err.println( I18N.getString( "inspector.stylesheet.cannotreveal", urlStr + " : " + ex)); // should go to message panel } }
private void initialize(boolean multiLineSupported) { this.multiLineSupported = multiLineSupported; valueListener = event -> { userUpdateValueProperty(getValue()); textNode.selectAll(); }; setTextEditorBehavior(this, textNode, valueListener); getMenu().getItems().add(i18nMenuItem); getMenu().getItems().add(multilineMenuItem); i18nMenuItem.setOnAction( e -> { if (!i18nMode) { setValue( new PrefixedValue( PrefixedValue.Type.RESOURCE_KEY, I18N.getString("inspector.i18n.dummykey")) .toString()); } else { setValue(""); // NOI18N } I18nStringEditor.this.getCommitListener().handle(null); updateMenuItems(); }); multilineMenuItem.setOnAction( e -> { if (!multiLineMode) { switchToTextArea(); } else { switchToTextField(); } multiLineMode = !multiLineMode; updateMenuItems(); }); }
@Override protected String makeDescription() { return I18N.getString("label.action.edit.add.context.menu"); }
/** * Editor of the 'stylesheet' property. It may contain several stylesheets (css) files, that are * handled by an inline class (StylesheetItem). */ public class StylesheetEditor extends InlineListEditor { private final StackPane root = new StackPane(); private final Parent rootInitialBt; private final MenuItem documentRelativeMenuItem = new MenuItem(I18N.getString("inspector.resource.documentrelative")); private final MenuItem classPathRelativeMenuItem = new MenuItem(I18N.getString("inspector.resource.classpathrelative")); private final MenuItem absoluteMenuItem = new MenuItem(I18N.getString("inspector.resource.absolute")); private Type type; private URL fxmlFileLocation; @SuppressWarnings("LeakingThisInConstructor") public StylesheetEditor( IMetadata metadata, ValuePropertyMetadata propMeta, Set<Class<?>> selectedClasses, URL fxmlFileLocation) { super(metadata, propMeta, selectedClasses); this.fxmlFileLocation = fxmlFileLocation; setLayoutFormat(PropertyEditor.LayoutFormat.DOUBLE_LINE); // Add initial button rootInitialBt = EditorUtils.loadFxml("StylesheetEditorInitialBt.fxml", this); // NOI18N root.getChildren().add(rootInitialBt); // Set the initial value to empty list (instead of null) valueProperty().setValue(FXCollections.observableArrayList()); documentRelativeMenuItem.setOnAction( new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent e) { switchType(Type.DOCUMENT_RELATIVE_PATH); } }); classPathRelativeMenuItem.setOnAction( new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent e) { switchType(Type.CLASSLOADER_RELATIVE_PATH); } }); absoluteMenuItem.setOnAction( new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent e) { switchType(Type.PLAIN_STRING); } }); getMenu() .getItems() .addAll(documentRelativeMenuItem, classPathRelativeMenuItem, absoluteMenuItem); } @Override public Node getValueEditor() { return super.handleGenericModes(root); } @Override public Object getValue() { List<String> value = FXCollections.observableArrayList(); // Group all the item values in a list for (EditorItem stylesheetItem : getEditorItems()) { String itemValue = stylesheetItem.getValue(); if (itemValue.isEmpty()) { continue; } value.add(itemValue); } if (value.isEmpty()) { // no stylesheet return super.getPropertyMeta().getDefaultValueObject(); } else { type = getType(value); return value; } } @SuppressWarnings("unchecked") @Override public void setValue(Object value) { if (value == null) { reset(); return; } assert value instanceof List; if (((List) value).isEmpty()) { reset(); return; } // Warning : value is the editing list. // We do not want to set the valueProperty() to editing list setValueGeneric(value); if (isSetValueDone()) { return; } type = getType((List<String>) value); updateMenuItems(); Iterator<EditorItem> itemsIter = new ArrayList<>(getEditorItems()).iterator(); for (String item : (List<String>) value) { item = item.trim(); if (item.isEmpty()) { continue; } EditorItem editorItem; if (itemsIter.hasNext()) { // re-use the current items first editorItem = itemsIter.next(); } else { // additional items required editorItem = addItem(new StylesheetItem(this, item)); } editorItem.setValue(item); } // Empty the remaining items, if needed while (itemsIter.hasNext()) { EditorItem editorItem = itemsIter.next(); removeItem(editorItem); } switchToItemList(); } public void reset( ValuePropertyMetadata propMeta, Set<Class<?>> selectedClasses, URL fxmlFileLocation) { super.reset(propMeta, selectedClasses, true); this.fxmlFileLocation = fxmlFileLocation; switchToInitialButton(); } @Override protected void reset() { super.reset(true); switchToInitialButton(); } @Override public void requestFocus() { EditorItem firstItem = getEditorItems().get(0); assert firstItem instanceof StylesheetItem; ((StylesheetItem) firstItem).requestFocus(); } @Override public void remove(EditorItem source) { super.remove(source, true); if (super.getEditorItems().isEmpty()) { // Switch to initial button switchToInitialButton(); } } private void open(EditorItem source) { String urlStr = getUrl(source); if (urlStr == null) { return; } try { EditorPlatform.open(urlStr); } catch (IOException ex) { System.err.println( I18N.getString( "inspector.stylesheet.cannotopen", urlStr + " : " + ex)); // should go to message panel } } private void reveal(EditorItem source) { String urlStr = getUrl(source); if (urlStr == null) { return; } try { File file = URLUtils.getFile(urlStr); if (file == null) { // urlStr is not a file URL return; } EditorPlatform.revealInFileBrowser(file); } catch (URISyntaxException | IOException ex) { System.err.println( I18N.getString( "inspector.stylesheet.cannotreveal", urlStr + " : " + ex)); // should go to message panel } } private String getUrl(EditorItem source) { URL url = EditorUtils.getUrl(source.getValue(), fxmlFileLocation); if (url == null) { return null; } String urlStr = url.toExternalForm(); return urlStr; } @FXML void chooseStylesheet(ActionEvent event) { String[] extensions = {"*.css"}; // NOI18N FileChooser fileChooser = new FileChooser(); fileChooser.setTitle(I18N.getString("inspector.select.css.title")); fileChooser .getExtensionFilters() .add( new FileChooser.ExtensionFilter( I18N.getString("inspector.select.css.filter"), Arrays.asList(extensions))); File file = fileChooser.showOpenDialog(root.getScene().getWindow()); if ((file == null)) { return; } URL url; try { url = file.toURI().toURL(); } catch (MalformedURLException ex) { throw new RuntimeException("Invalid URL", ex); // NOI18N } if (alreadyUsed(url.toExternalForm())) { System.err.println( I18N.getString("inspector.stylesheet.alreadyexist", url)); // should go to message panel return; } switchToItemList(); // Add editor item String urlStr; if (fxmlFileLocation != null) { // If the document exists, make the type as document relative by default. urlStr = PrefixedValue.makePrefixedValue(url, fxmlFileLocation).toString(); switchType(Type.DOCUMENT_RELATIVE_PATH); } else { urlStr = url.toExternalForm(); switchType(Type.PLAIN_STRING); } addItem(new StylesheetItem(this, urlStr)); // Workaround for RT-34863: Reload of an updated css file has no effect. // This reset the whole CSS from top. Would need to be moved on the FXOM side. Deprecation.reapplyCSS(root.getScene()); userUpdateValueProperty(getValue()); } @FXML void buttonTyped(KeyEvent event) { if (event.getCode() == KeyCode.ENTER) { chooseStylesheet(null); } } private void switchToItemList() { // Replace initial button by the item list (vbox) if (root.getChildren().contains(rootInitialBt)) { root.getChildren().remove(rootInitialBt); root.getChildren().add(super.getValueEditor()); } } private void switchToInitialButton() { // Replace the item list (vbox) by initial button root.getChildren().clear(); root.getChildren().add(rootInitialBt); } private boolean alreadyUsed(String url) { for (EditorItem item : super.getEditorItems()) { if (item.getValue().equals(url)) { return true; } } return false; } private void switchType(Type type) { this.type = type; updateMenuItems(); for (EditorItem editorItem : getEditorItems()) { assert editorItem instanceof StylesheetItem; StylesheetItem stylesheetItem = (StylesheetItem) editorItem; URL url = EditorUtils.getUrl(stylesheetItem.getValue(), fxmlFileLocation); String value = null; if ((url == null) || (type == Type.CLASSLOADER_RELATIVE_PATH)) { // In this case we empty the text field (i.e. suffix) content value = new PrefixedValue(type, "").toString(); // NOI18N } else if (type == Type.PLAIN_STRING) { value = url.toExternalForm(); } else if (type == Type.DOCUMENT_RELATIVE_PATH) { value = PrefixedValue.makePrefixedValue(url, fxmlFileLocation).toString(); } stylesheetItem.setValue(value); commit(stylesheetItem); } } private Type getType(List<String> styleSheets) { Type commonType = null; for (String styleSheet : styleSheets) { if (commonType == null) { commonType = getType(styleSheet); } else { if (commonType != getType(styleSheet)) { // mix of different types: set all to document relative commonType = Type.DOCUMENT_RELATIVE_PATH; break; } } } return commonType; } private static Type getType(String styleSheet) { return (new PrefixedValue(styleSheet)).getType(); } private void updateMenuItems() { documentRelativeMenuItem.setDisable(false); classPathRelativeMenuItem.setDisable(false); absoluteMenuItem.setDisable(false); if (fxmlFileLocation == null) { documentRelativeMenuItem.setDisable(true); } if (type == Type.DOCUMENT_RELATIVE_PATH) { documentRelativeMenuItem.setDisable(true); } else if (type == Type.CLASSLOADER_RELATIVE_PATH) { classPathRelativeMenuItem.setDisable(true); } else if (type == Type.PLAIN_STRING) { absoluteMenuItem.setDisable(true); } } /** * ************************************************************************** * * <p>StyleClass item : styleClass text fields, and +/action buttons. * * <p>************************************************************************** */ private class StylesheetItem implements EditorItem { @FXML private Button plusBt; @FXML private MenuItem removeMi; @FXML private MenuItem moveUpMi; @FXML private MenuItem moveDownMi; @FXML private MenuItem openMi; @FXML private MenuItem revealMi; @FXML private Label prefixLb; @FXML private TextField stylesheetTf; private final Pane root; private String currentValue; private final EditorItemDelegate editor; private Type itemType = Type.PLAIN_STRING; @SuppressWarnings("LeakingThisInConstructor") public StylesheetItem(EditorItemDelegate editor, String url) { // System.out.println("New StylesheetItem."); this.editor = editor; Parent parentRoot = EditorUtils.loadFxml("StylesheetEditorItem.fxml", this); assert parentRoot instanceof Pane; root = (Pane) parentRoot; initialize(url); } // Method to please FindBugs private void initialize(String url) { setValue(url); EventHandler<ActionEvent> onActionListener = new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { // System.out.println("StylesheetItem : onActionListener"); if (getValue().equals(currentValue)) { // no change return; } if (stylesheetTf.getText().isEmpty()) { remove(null); } // System.out.println("StyleEditorItem : COMMIT"); editor.commit(StylesheetItem.this); if (event != null && event.getSource() instanceof TextField) { ((TextField) event.getSource()).selectAll(); } updateButtons(); updateOpenRevealMenuItems(); currentValue = getValue(); } }; ChangeListener<String> textPropertyChange = new ChangeListener<String>() { @Override public void changed( ObservableValue<? extends String> ov, String prevText, String newText) { if (prevText.isEmpty() || newText.isEmpty()) { // Text changed FROM empty value, or TO empty value: buttons status change updateButtons(); updateOpenRevealMenuItems(); } } }; stylesheetTf.textProperty().addListener(textPropertyChange); updateButtons(); setTextEditorBehavior(stylesheetTf, onActionListener); // Initialize menu items text removeMi.setText(I18N.getString("inspector.list.remove")); moveUpMi.setText(I18N.getString("inspector.list.moveup")); moveDownMi.setText(I18N.getString("inspector.list.movedown")); } @Override public final Node getNode() { return root; } @Override public String getValue() { String suffix; if (stylesheetTf.getText().isEmpty()) { return ""; // NOI18N } else { suffix = stylesheetTf.getText().trim(); } return (new PrefixedValue(itemType, suffix)).toString(); } @Override public void setValue(String styleSheet) { PrefixedValue prefixedValue = new PrefixedValue(styleSheet); itemType = prefixedValue.getType(); handlePrefix(itemType); if (prefixedValue.getSuffix() != null) { stylesheetTf.setText(prefixedValue.getSuffix().trim()); } else { // may happen if wrong style sheet stylesheetTf.setText(""); // NOI18N } updateButtons(); updateOpenRevealMenuItems(); currentValue = getValue(); } @Override public void reset() { stylesheetTf.setText(""); // NOI18N stylesheetTf.setPromptText(null); } @Override public void setValueAsIndeterminate() { handleIndeterminate(stylesheetTf); } protected void requestFocus() { EditorUtils.doNextFrame( new Runnable() { @Override public void run() { stylesheetTf.requestFocus(); } }); } @Override public MenuItem getMoveUpMenuItem() { return moveUpMi; } @Override public MenuItem getMoveDownMenuItem() { return moveDownMi; } @Override public MenuItem getRemoveMenuItem() { return removeMi; } @Override public Button getPlusButton() { return plusBt; } @FXML void chooseStylesheet(ActionEvent event) { ((StylesheetEditor) editor).chooseStylesheet(event); } @FXML void remove(ActionEvent event) { editor.remove(this); } @FXML void up(ActionEvent event) { editor.up(this); } @FXML void down(ActionEvent event) { editor.down(this); } @FXML void open(ActionEvent event) { ((StylesheetEditor) editor).open(this); } @FXML void reveal(ActionEvent event) { ((StylesheetEditor) editor).reveal(this); } @FXML void plusBtTyped(KeyEvent event) { if (event.getCode() == KeyCode.ENTER) { chooseStylesheet(null); } } private void updateOpenRevealMenuItems() { // Get the file name part of the suffix String suffix = new PrefixedValue(getValue()).getSuffix(); String fileName = null; if (!suffix.isEmpty()) { String[] urlParts = suffix.split("\\/"); fileName = urlParts[urlParts.length - 1]; // On windows, we may have "\" separators. urlParts = fileName.split("\\\\"); fileName = urlParts[urlParts.length - 1]; } if (fileName != null) { openMi.setVisible(true); revealMi.setVisible(true); openMi.setText(I18N.getString("inspector.list.open", fileName)); if (EditorPlatform.IS_MAC) { revealMi.setText(I18N.getString("inspector.list.reveal.finder", fileName)); } else { revealMi.setText(I18N.getString("inspector.list.reveal.explorer", fileName)); } } else { openMi.setVisible(false); revealMi.setVisible(false); } } private void updateButtons() { if (stylesheetTf.getText().isEmpty()) { // if no content, disable plus plusBt.setDisable(true); removeMi.setDisable(false); } else { // enable plus and minus plusBt.setDisable(false); removeMi.setDisable(false); } } protected void disablePlusButton(boolean disable) { plusBt.setDisable(disable); } protected void disableRemove(boolean disable) { removeMi.setDisable(disable); } protected void handlePrefix(Type type) { this.itemType = type; if (type == Type.DOCUMENT_RELATIVE_PATH) { setPrefix(FXMLLoader.RELATIVE_PATH_PREFIX); } else if (type == Type.CLASSLOADER_RELATIVE_PATH) { setPrefix(FXMLLoader.RELATIVE_PATH_PREFIX + "/"); // NOI18N } else { // absolute removeLabel(); } } private void setPrefix(String str) { if (!prefixLb.isVisible()) { prefixLb.setVisible(true); prefixLb.setManaged(true); } prefixLb.setText(str); } private void removeLabel() { prefixLb.setVisible(false); prefixLb.setManaged(false); } } }
/** String editor with I18n + multi-line handling. */ public class I18nStringEditor extends PropertyEditor { private static final String PERCENT_STR = "%"; // NOI18N private TextInputControl textNode = new TextField(); private HBox i18nHBox = null; private EventHandler<ActionEvent> valueListener; private final MenuItem i18nMenuItem = new MenuItem(); private final String I18N_ON = I18N.getString("inspector.i18n.on"); private final String I18N_OFF = I18N.getString("inspector.i18n.off"); private final MenuItem multilineMenuItem = new MenuItem(); private final String MULTI_LINE = I18N.getString("inspector.i18n.multiline"); private final String SINGLE_LINE = I18N.getString("inspector.i18n.singleline"); private boolean multiLineSupported = false; // Specific states private boolean i18nMode = false; private boolean multiLineMode = false; public I18nStringEditor( ValuePropertyMetadata propMeta, Set<Class<?>> selectedClasses, boolean multiLineSupported) { super(propMeta, selectedClasses); initialize(multiLineSupported); } private void initialize(boolean multiLineSupported) { this.multiLineSupported = multiLineSupported; valueListener = event -> { userUpdateValueProperty(getValue()); textNode.selectAll(); }; setTextEditorBehavior(this, textNode, valueListener); getMenu().getItems().add(i18nMenuItem); getMenu().getItems().add(multilineMenuItem); i18nMenuItem.setOnAction( e -> { if (!i18nMode) { setValue( new PrefixedValue( PrefixedValue.Type.RESOURCE_KEY, I18N.getString("inspector.i18n.dummykey")) .toString()); } else { setValue(""); // NOI18N } I18nStringEditor.this.getCommitListener().handle(null); updateMenuItems(); }); multilineMenuItem.setOnAction( e -> { if (!multiLineMode) { switchToTextArea(); } else { switchToTextField(); } multiLineMode = !multiLineMode; updateMenuItems(); }); } @Override public Object getValue() { String val = textNode.getText(); if (i18nMode) { val = new PrefixedValue(PrefixedValue.Type.RESOURCE_KEY, val).toString(); } else { val = EditorUtils.getPlainString(val); } return val; } @Override public void setValue(Object value) { setValueGeneric(value); if (isSetValueDone()) { return; } if (value == null) { textNode.setText(null); return; } assert value instanceof String; String val = (String) value; PrefixedValue prefixedValue = new PrefixedValue(val); String suffix = prefixedValue.getSuffix(); // Handle i18n if (prefixedValue.isResourceKey()) { if (!i18nMode) { wrapInHBox(); i18nMode = true; } } else if (i18nMode) { // no percent + i18nMode unwrapHBox(); i18nMode = false; } // Handle multi-line if (containsLineFeed(prefixedValue.toString())) { if (i18nMode) { // multi-line + i18n ==> set as i18n only multiLineMode = false; switchToTextField(); } else { if (!multiLineMode) { multiLineMode = true; switchToTextArea(); } } } else { // no line feed if (multiLineMode) { multiLineMode = false; switchToTextField(); } } if (i18nMode) { textNode.setText(suffix); } else { // We may have other special characters (@, $, ...) to display in the text field textNode.setText(prefixedValue.toString()); } updateMenuItems(); } public void reset( ValuePropertyMetadata propMeta, Set<Class<?>> selectedClasses, boolean multiLineSupported) { super.reset(propMeta, selectedClasses); this.multiLineSupported = multiLineSupported; textNode.setPromptText(null); } @Override public Node getValueEditor() { Node valueEditor; if (i18nMode) { valueEditor = i18nHBox; } else { valueEditor = textNode; } return super.handleGenericModes(valueEditor); } @Override protected void valueIsIndeterminate() { handleIndeterminate(textNode); } protected void switchToTextArea() { if (textNode instanceof TextArea) { return; } // Move the node from TextField to TextArea TextArea textArea = new TextArea(textNode.getText()); setTextEditorBehavior(this, textArea, valueListener); textArea.setPrefRowCount(5); setLayoutFormat(LayoutFormat.SIMPLE_LINE_TOP); if (textNode.getParent() != null) { // textNode is already in scene graph EditorUtils.replaceNode(textNode, textArea, getLayoutFormat()); } textNode = textArea; } protected void switchToTextField() { if (textNode instanceof TextField) { return; } // Move the node from TextArea to TextField. // The current text is compacted to a single line. String val = textNode.getText().replace("\n", ""); // NOI18N TextField textField = new TextField(val); setTextEditorBehavior(this, textField, valueListener); setLayoutFormat(LayoutFormat.SIMPLE_LINE_CENTERED); if (textNode.getParent() != null) { // textNode is already in scene graph EditorUtils.replaceNode(textNode, textField, getLayoutFormat()); } textNode = textField; } private void wrapInHBox() { i18nHBox = new HBox(); i18nHBox.setAlignment(Pos.CENTER); EditorUtils.replaceNode(textNode, i18nHBox, null); Label percentLabel = new Label(PERCENT_STR); percentLabel.getStyleClass().add("symbol-prefix"); // NOI18N i18nHBox.getChildren().addAll(percentLabel, textNode); HBox.setHgrow(percentLabel, Priority.NEVER); // we have to set a small pref width for the text node else it will // revert to it's API set pref width which is too wide textNode.setPrefWidth(30.0); HBox.setHgrow(textNode, Priority.ALWAYS); } private void unwrapHBox() { i18nHBox.getChildren().remove(textNode); EditorUtils.replaceNode(i18nHBox, textNode, null); } private static boolean containsLineFeed(String str) { return str.contains("\n"); // NOI18N } @Override public void requestFocus() { EditorUtils.doNextFrame(() -> textNode.requestFocus()); } private void updateMenuItems() { if (i18nMode) { i18nMenuItem.setText(I18N_OFF); multilineMenuItem.setDisable(true); } else { i18nMenuItem.setText(I18N_ON); multilineMenuItem.setDisable(false); } if (multiLineMode) { multilineMenuItem.setText(SINGLE_LINE); i18nMenuItem.setDisable(true); } else { multilineMenuItem.setText(MULTI_LINE); i18nMenuItem.setDisable(false); } if (!multiLineSupported) { multilineMenuItem.setDisable(true); } } }