Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/keenwrite.git

Prevent JavaFX logging to stderr. Add character offset to status bar. Revised how editing of TreeView works. Prevent R eval error from generating output; instead, erroneous R statement is inlined and status bar updated with offset of parser error. Removed slight code duplication.

Authordjarvis <email>
Date2017-01-04 20:44:53 GMT-0800
Commit3a9d0bf7719671e4706c7877baa54353773ac665
Parent7f39434
Delta215 lines added, 21 lines removed, 194-line increase
src/main/resources/com/scrivenvar/messages.properties
# ########################################################################
-Main.statusbar.line=Line {0} of {1}
+Main.statusbar.text.offset=offset
+Main.statusbar.line=Line {0} of {1}, ${Main.statusbar.text.offset} {2}
Main.statusbar.state.default=OK
+Main.statusbar.parse.error={0} (near ${Main.statusbar.text.offset} {1})
+
+# ########################################################################
+#
+# Definition Pane and its Tree View
+#
+# ########################################################################
+
+Definition.menu.add=Add
+Definition.menu.remove=Delete
# ########################################################################
src/main/java/com/scrivenvar/processors/InlineRProcessor.java
package com.scrivenvar.processors;
+import static com.scrivenvar.Constants.STATUS_PARSE_ERROR;
+import static com.scrivenvar.Messages.get;
+import com.scrivenvar.Services;
import static com.scrivenvar.decorators.RVariableDecorator.PREFIX;
import static com.scrivenvar.decorators.RVariableDecorator.SUFFIX;
import static com.scrivenvar.processors.text.TextReplacementFactory.replace;
+import com.scrivenvar.service.events.Notifier;
import static java.lang.Math.min;
import java.nio.file.Path;
private ScriptEngine engine;
+
+ private final Notifier notifier = Services.load( Notifier.class );
/**
/**
* @see https://github.com/DaveJarvis/scrivenvar/issues/30
- * @param workingDirectory
+ * @param workingDirectory
*/
private void init( final Path workingDirectory ) {
// In Windows, path characters must be changed from escape chars.
- eval( replace( ""
- + "assign( 'anchor', as.Date( '$date.anchor$', format='%Y-%m-%d' ), envir = .GlobalEnv );"
- + "setwd( '" + workingDirectory.toString().replace( '\\', '/' ) + "' );"
- + "source( '../bin/pluralize.R' );"
- + "source( '../bin/common.R' )", getDefinitions() ) );
+ try {
+ eval( replace( ""
+ + "assign( 'anchor', as.Date( '$date.anchor$', format='%Y-%m-%d' ), envir = .GlobalEnv );"
+ + "setwd( '" + workingDirectory.toString().replace( '\\', '/' ) + "' );"
+ + "source( '../bin/pluralize.R' );"
+ + "source( '../bin/common.R' )", getDefinitions() ) );
+ } catch( final Exception e ) {
+ throw new RuntimeException( e );
+ }
}
// Pass the R statement into the R engine for evaluation.
- final Object result = eval( r );
+ try {
+ final Object result = eval( r );
- // Append the string representation of the result into the text.
- sb.append( result );
+ // Append the string representation of the result into the text.
+ sb.append( result );
+ } catch( final Exception e ) {
+ // If the string couldn't be parsed using R, append the statement
+ // that failed to parse, instead of its evaluated value.
+ sb.append( PREFIX ).append( r ).append( SUFFIX );
+
+ // Tell the user that there was a problem.
+ getNotifier().notify( get( STATUS_PARSE_ERROR,
+ e.getMessage(), currIndex )
+ );
+ }
// Retain the R statement's ending position in the text.
prevIndex = currIndex + 1;
-
}
else {
* @return The object resulting from the evaluation.
*/
- private Object eval( final String r ) {
- try {
- return getScriptEngine().eval( r );
- } catch( final ScriptException ex ) {
- throw new IllegalArgumentException( ex );
- }
+ private Object eval( final String r ) throws ScriptException {
+ return getScriptEngine().eval( r );
}
private synchronized ScriptEngine getScriptEngine() {
if( this.engine == null ) {
this.engine = (new ScriptEngineManager()).getEngineByName( "Renjin" );
}
return this.engine;
+ }
+
+ private Notifier getNotifier() {
+ return this.notifier;
}
}
src/main/java/com/scrivenvar/definition/EmptyDefinitionSource.java
}
- @Override
- public TreeView<String> asTreeView() {
- return new TreeView<>();
- }
@Override
public Map<String, String> getResolvedMap() {
return new HashMap<>();
+ }
+
+ @Override
+ protected TreeView<String> createTreeView() {
+ return new TreeView<>();
}
}
src/main/java/com/scrivenvar/definition/TextFieldTreeCell.java
+/*
+ * Copyright 2016 White Magic Software, Ltd.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.scrivenvar.definition;
+
+import static com.scrivenvar.Messages.get;
+import javafx.event.ActionEvent;
+import javafx.scene.control.ContextMenu;
+import javafx.scene.control.MenuItem;
+import javafx.scene.control.TextField;
+import javafx.scene.control.TreeCell;
+import javafx.scene.control.TreeItem;
+import static javafx.scene.input.KeyCode.ENTER;
+import static javafx.scene.input.KeyCode.ESCAPE;
+import javafx.scene.input.KeyEvent;
+
+/**
+ * Provides behaviour of adding, removing, and editing tree view items.
+ *
+ * @author White Magic Software, Ltd.
+ */
+public class TextFieldTreeCell extends TreeCell<String> {
+
+ private TextField textField;
+ private final ContextMenu editMenu = new ContextMenu();
+
+ public TextFieldTreeCell() {
+ initEditMenu();
+ }
+
+ private void initEditMenu() {
+ final MenuItem addItem = createMenuItem( "Definition.menu.add" );
+ final MenuItem removeItem = createMenuItem( "Definition.menu.remove" );
+
+ addItem.setOnAction( (ActionEvent e) -> {
+ final VariableTreeItem<String> treeItem = new VariableTreeItem<>( "Undefined" );
+ getTreeItem().getChildren().add( treeItem );
+ } );
+
+ removeItem.setOnAction( (ActionEvent e) -> {
+ final TreeItem c = getTreeItem();
+ boolean remove = c.getParent().getChildren().remove( c );
+ System.out.println( "Remove" );
+ } );
+
+ getEditMenu().getItems().add( addItem );
+ getEditMenu().getItems().add( removeItem );
+ }
+
+ private ContextMenu getEditMenu() {
+ return this.editMenu;
+ }
+
+ private MenuItem createMenuItem( String label ) {
+ return new MenuItem( get( label ) );
+ }
+
+ @Override
+ public void startEdit() {
+ if( getTreeItem().isLeaf() ) {
+ super.startEdit();
+
+ final TextField inputField = getTextField();
+
+ setText( null );
+ setGraphic( inputField );
+ inputField.selectAll();
+ inputField.requestFocus();
+ }
+ }
+
+ @Override
+ public void cancelEdit() {
+ super.cancelEdit();
+
+ setText( (String)getItem() );
+ setGraphic( getTreeItem().getGraphic() );
+ }
+
+ @Override
+ public void updateItem( String item, boolean empty ) {
+ super.updateItem( item, empty );
+
+ if( empty ) {
+ setText( null );
+ setGraphic( null );
+ }
+ else if( isEditing() ) {
+ TextField tf = getTextField();
+ tf.setText( getItemValue() );
+
+ setText( null );
+ setGraphic( tf );
+ }
+ else {
+ setText( getItemValue() );
+ setGraphic( getTreeItem().getGraphic() );
+
+ if( !getTreeItem().isLeaf() && getTreeItem().getParent() != null ) {
+ setContextMenu( getEditMenu() );
+ }
+ }
+ }
+
+ private TextField createTextField() {
+ final TextField tf = new TextField( getItemValue() );
+
+ tf.setOnKeyReleased( (KeyEvent t) -> {
+ switch( t.getCode() ) {
+ case ENTER:
+ commitEdit( tf.getText() );
+ break;
+ case ESCAPE:
+ cancelEdit();
+ break;
+ }
+ } );
+
+ return tf;
+ }
+
+ /**
+ * Returns the item's text value.
+ *
+ * @return A non-null String, possibly empty.
+ */
+ private String getItemValue() {
+ return getItem() == null ? "" : getItem();
+ }
+
+ private TextField getTextField() {
+ if( this.textField == null ) {
+ this.textField = createTextField();
+ }
+
+ return this.textField;
+ }
+}