Dave Jarvis' Repositories

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

New name. Added recursively dereferencing resource bundle messages.

Authordjarvis <email>
Date2016-10-18 17:32:08 GMT-0700
Commitdf6f3192992ff6b9756faed65251c225e1bccc5e
Parentac6bf49
src/main/java/org/markdownwriterfx/Messages.java
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-
package org.markdownwriterfx;
import java.text.MessageFormat;
import java.util.ResourceBundle;
+import java.util.Stack;
/**
- * @author Karl Tauber
+ * Recursively resolves message properties. Property values can refer
+ * to other properties using a <code>${var}</code> syntax.
+ *
+ * @author Karl Tauber, Dave Jarvis
*/
-public class Messages
-{
- private static final String BUNDLE_NAME = "org.markdownwriterfx.messages";
- private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle(BUNDLE_NAME);
+public class Messages {
- private Messages() {
- }
+ private static final String BUNDLE_NAME = "org.markdownwriterfx.messages";
+ private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle( BUNDLE_NAME );
- public static String get(String key) {
-// try {
- return RESOURCE_BUNDLE.getString(key);
-// } catch (MissingResourceException e) {
-// return '!' + key + '!';
-// }
- }
+ private Messages() {
+ }
- public static String get(String key, Object... args) {
- return MessageFormat.format(get(key), args);
- }
+ /**
+ * Return the value of a resource bundle value after having resolved any
+ * references to other bundle variables.
+ *
+ * @param props The bundle containing resolvable properties.
+ * @param s The value for a key to resolve.
+ *
+ * @return The value of the key with all references recursively dereferenced.
+ */
+ private static String resolve( ResourceBundle props, String s ) {
+ StringBuilder sb = new StringBuilder( 256 );
+ Stack<StringBuilder> stack = new Stack<>();
+ int len = s.length();
+
+ for( int i = 0; i < len; i++ ) {
+ char c = s.charAt( i );
+
+ switch( c ) {
+ case '$': {
+ if( i + 1 < len && s.charAt( i + 1 ) == '{' ) {
+ stack.push( sb );
+ sb = new StringBuilder( 256 );
+ i++;
+ }
+ break;
+ }
+
+ case '}': {
+ if( stack.isEmpty() ) {
+ throw new IllegalArgumentException( "unexpected '}'" );
+ }
+
+ String name = sb.toString();
+
+ sb = stack.pop();
+ sb.append( props.getString( name ) );
+ break;
+ }
+
+ default: {
+ sb.append( c );
+ break;
+ }
+ }
+ }
+
+ if( !stack.isEmpty() ) {
+ throw new IllegalArgumentException( "missing '}'" );
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Returns the value for a key from the message bundle.
+ *
+ * @param key Retrieve the value for this key.
+ *
+ * @return The value for the key.
+ */
+ public static String get( String key ) {
+ return resolve( RESOURCE_BUNDLE, RESOURCE_BUNDLE.getString( key ) );
+ }
+
+ /**
+ * Returns the value for a key from the message bundle with the arguments
+ * replacing <code>{#}</code> placeholders.
+ *
+ * @param key Retrieve the value for this key.
+ * @param args The values to substitute for placeholders.
+ *
+ * @return The value for the key.
+ */
+ public static String get( String key, Object... args ) {
+ return MessageFormat.format( get( key ), args );
+ }
}
src/main/java/org/markdownwriterfx/Scrivano.java
-/*
- * Copyright (c) 2015 Karl Tauber <karl at jformdesigner dot com>
- * 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 org.markdownwriterfx;
-
-import javafx.application.Application;
-import javafx.scene.Scene;
-import javafx.scene.image.Image;
-import javafx.stage.Stage;
-import org.markdownwriterfx.service.Options;
-import org.markdownwriterfx.service.Settings;
-import org.markdownwriterfx.util.StageState;
-
-/**
- * Markdown Writer FX application.
- *
- * @author Karl Tauber
- */
-public final class Scrivano extends Application {
-
- private static Application app;
-
- private MainWindow mainWindow;
- private StageState stageState;
- private final Settings settings = Services.load( Settings.class );
- private final Options options = Services.load( Options.class );
-
- public static void main( String[] args ) {
- launch( args );
- }
-
- /**
- * Application entry point.
- *
- * @param stage The primary application stage.
- *
- * @throws Exception Could not read configuration file.
- */
- @Override
- public void start( Stage stage ) throws Exception {
- initApplication();
- initWindow();
- initState( stage );
- initStage( stage );
-
- stage.show();
- }
-
- private void initApplication() {
- app = this;
- }
-
- private Settings getSettings() {
- return this.settings;
- }
-
- private Options getOptions() {
- return this.options;
- }
-
- private String getApplicationTitle() {
- return getSettings().getSetting( "application.title", "Scrivano" );
- }
-
- private void initWindow() {
- setWindow( new MainWindow() );
- }
-
- private void initState( Stage stage ) {
- stageState = new StageState( stage, getOptions().getState() );
- }
-
- private void initStage( Stage stage ) {
- stage.getIcons().addAll(
- new Image( "org/markdownwriterfx/markdownwriterfx16.png" ),
- new Image( "org/markdownwriterfx/markdownwriterfx32.png" ),
- new Image( "org/markdownwriterfx/markdownwriterfx128.png" ),
- new Image( "org/markdownwriterfx/markdownwriterfx256.png" ),
- new Image( "org/markdownwriterfx/markdownwriterfx512.png" ) );
- stage.setTitle( getApplicationTitle() );
- stage.setScene( getScene() );
- }
-
- private Scene getScene() {
- return getMainWindow().getScene();
- }
-
- protected MainWindow getMainWindow() {
- return this.mainWindow;
- }
-
- private void setWindow( MainWindow mainWindow ) {
- this.mainWindow = mainWindow;
- }
-
- private StageState getStageState() {
- return this.stageState;
- }
-
- private void setStageState( StageState stageState ) {
- this.stageState = stageState;
- }
-
- private static Application getApplication() {
- return app;
- }
-
- public static void showDocument( String uri ) {
- getApplication().getHostServices().showDocument( uri );
- }
-}
src/main/java/org/markdownwriterfx/Scrivendor.java
+/*
+ * Copyright (c) 2015 Karl Tauber <karl at jformdesigner dot com>
+ * 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 org.markdownwriterfx;
+
+import javafx.application.Application;
+import javafx.scene.Scene;
+import javafx.scene.image.Image;
+import javafx.stage.Stage;
+import org.markdownwriterfx.service.Options;
+import org.markdownwriterfx.service.Settings;
+import org.markdownwriterfx.util.StageState;
+
+/**
+ * Based on the Markdown Writer FX application.
+ *
+ * @author Karl Tauber and White Magic Software, Ltd.
+ */
+public final class Scrivendor extends Application {
+
+ private static Application app;
+
+ private MainWindow mainWindow;
+ private StageState stageState;
+ private final Settings settings = Services.load( Settings.class );
+ private final Options options = Services.load( Options.class );
+
+ public static void main( String[] args ) {
+ launch( args );
+ }
+
+ /**
+ * Application entry point.
+ *
+ * @param stage The primary application stage.
+ *
+ * @throws Exception Could not read configuration file.
+ */
+ @Override
+ public void start( Stage stage ) throws Exception {
+ initApplication();
+ initWindow();
+ initState( stage );
+ initStage( stage );
+
+ stage.show();
+ }
+
+ private void initApplication() {
+ app = this;
+ }
+
+ private Settings getSettings() {
+ return this.settings;
+ }
+
+ private Options getOptions() {
+ return this.options;
+ }
+
+ private String getApplicationTitle() {
+ return Messages.get( "Application.title" );
+ }
+
+ private void initWindow() {
+ setWindow( new MainWindow() );
+ }
+
+ private void initState( Stage stage ) {
+ stageState = new StageState( stage, getOptions().getState() );
+ }
+
+ private void initStage( Stage stage ) {
+ stage.getIcons().addAll(
+ new Image( "org/markdownwriterfx/markdownwriterfx16.png" ),
+ new Image( "org/markdownwriterfx/markdownwriterfx32.png" ),
+ new Image( "org/markdownwriterfx/markdownwriterfx128.png" ),
+ new Image( "org/markdownwriterfx/markdownwriterfx256.png" ),
+ new Image( "org/markdownwriterfx/markdownwriterfx512.png" ) );
+ stage.setTitle( getApplicationTitle() );
+ stage.setScene( getScene() );
+ }
+
+ private Scene getScene() {
+ return getMainWindow().getScene();
+ }
+
+ protected MainWindow getMainWindow() {
+ return this.mainWindow;
+ }
+
+ private void setWindow( MainWindow mainWindow ) {
+ this.mainWindow = mainWindow;
+ }
+
+ private StageState getStageState() {
+ return this.stageState;
+ }
+
+ private void setStageState( StageState stageState ) {
+ this.stageState = stageState;
+ }
+
+ private static Application getApplication() {
+ return app;
+ }
+
+ public static void showDocument( String uri ) {
+ getApplication().getHostServices().showDocument( uri );
+ }
+}
src/main/java/org/markdownwriterfx/controls/WebHyperlink.java
import javafx.beans.property.StringProperty;
import javafx.scene.control.Hyperlink;
-import org.markdownwriterfx.Scrivano;
+import org.markdownwriterfx.Scrivendor;
/**
@Override
public void fire() {
- Scrivano.showDocument(getUri());
+ Scrivendor.showDocument(getUri());
}
src/main/resources/org/markdownwriterfx/messages.properties
#
+#---- Application ----
+
+# The application title should exist only once in the entire code base.
+# All other references should either refer to this value via the Messages
+# class, or indirectly using ${Application.title}.
+Application.title=Scrivendor
+
#---- MainWindow ----
MainWindow.helpMenu=_Help
-MainWindow.helpAboutAction=About Scrivano
+MainWindow.helpAboutAction=About ${Application.title}
MainWindow.about.title=_About
-MainWindow.about.headerText=Scrivano
-MainWindow.about.contentText=Copyright (c) 2016 White Magic Software, Ltd.
+MainWindow.about.headerText=${Application.title}
+MainWindow.about.contentText=Copyright 2016 White Magic Software, Ltd.
#---- FileEditor ----
src/main/resources/org/markdownwriterfx/settings.properties
-application.title=Scrivano
-
# Comma-separated list of markdown filename extensions.
application.extensions.markdown=*.Rmd,*.md,*.txt,*.markdown
Delta232 lines added, 159 lines removed, 73-line increase