| Author | DaveJarvis <email> |
|---|---|
| Date | 2021-01-02 15:01:21 GMT-0800 |
| Commit | c9dbef776822a58c1429bc5e86855053cfe52b0b |
| Parent | d8c47c0 |
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite; | ||
| import com.keenwrite.editors.TextDefinition; | ||
| import com.keenwrite.editors.TextEditor; | ||
| import com.keenwrite.editors.definition.DefinitionTreeItem; | ||
| import com.keenwrite.sigils.SigilOperator; | ||
| import static com.keenwrite.Constants.*; | ||
| -import static com.keenwrite.StatusBarNotifier.clue; | ||
| +import static com.keenwrite.StatusNotifier.clue; | ||
| /** |
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite; | ||
| import static com.keenwrite.ExportFormat.NONE; | ||
| import static com.keenwrite.Messages.get; | ||
| -import static com.keenwrite.StatusBarNotifier.clue; | ||
| +import static com.keenwrite.StatusNotifier.clue; | ||
| import static com.keenwrite.io.MediaType.*; | ||
| import static com.keenwrite.preferences.Workspace.*; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite; | ||
| final var menuBar = createMenuBar( actions ); | ||
| final var appPane = new BorderPane(); | ||
| - final var statusBar = StatusBarNotifier.getStatusBar(); | ||
| + final var statusBar = StatusNotifier.getStatusBar(); | ||
| final var caretListener = createCaretListener( mainPane ); | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| -package com.keenwrite; | ||
| - | ||
| -import com.keenwrite.service.events.Notifier; | ||
| -import org.controlsfx.control.StatusBar; | ||
| - | ||
| -import static com.keenwrite.Constants.STATUS_BAR_OK; | ||
| -import static com.keenwrite.Messages.get; | ||
| -import static javafx.application.Platform.runLater; | ||
| - | ||
| -/** | ||
| - * Responsible for passing notifications about exceptions (or other error | ||
| - * messages) through the application. Once the Event Bus is implemented, this | ||
| - * class can go away. | ||
| - */ | ||
| -public class StatusBarNotifier { | ||
| - private static final String OK = get( STATUS_BAR_OK, "OK" ); | ||
| - | ||
| - private static final Notifier sNotifier = Services.load( Notifier.class ); | ||
| - private static final StatusBar sStatusBar = new StatusBar(); | ||
| - | ||
| - /** | ||
| - * Resets the status bar to a default message. | ||
| - */ | ||
| - public static void clue() { | ||
| - // Don't burden the repaint thread if there's no status bar change. | ||
| - if( !OK.equals( sStatusBar.getText() ) ) { | ||
| - update( OK ); | ||
| - } | ||
| - } | ||
| - | ||
| - /** | ||
| - * Updates the status bar with a custom message. | ||
| - * | ||
| - * @param key The resource bundle key associated with a message (typically | ||
| - * to inform the user about an error). | ||
| - */ | ||
| - public static void clue( final String key ) { | ||
| - update( get( key ) ); | ||
| - } | ||
| - | ||
| - /** | ||
| - * Updates the status bar with a custom message. | ||
| - * | ||
| - * @param key The property key having a value to populate with arguments. | ||
| - * @param args The placeholder values to substitute into the key's value. | ||
| - */ | ||
| - public static void clue( final String key, final Object... args ) { | ||
| - update( get( key, args ) ); | ||
| - } | ||
| - | ||
| - /** | ||
| - * Called when an exception occurs that warrants the user's attention. | ||
| - * | ||
| - * @param t The exception with a message that the user should know about. | ||
| - */ | ||
| - public static void clue( final Throwable t ) { | ||
| - update( t.getMessage() ); | ||
| - } | ||
| - | ||
| - /** | ||
| - * Returns the global {@link Notifier} instance that can be used for opening | ||
| - * pop-up alert messages. | ||
| - * | ||
| - * @return The pop-up {@link Notifier} dispatcher. | ||
| - */ | ||
| - public static Notifier getNotifier() { | ||
| - return sNotifier; | ||
| - } | ||
| - | ||
| - public static StatusBar getStatusBar() { | ||
| - return sStatusBar; | ||
| - } | ||
| - | ||
| - /** | ||
| - * Updates the status bar to show the first line of the given message. | ||
| - * | ||
| - * @param message The message to show in the status bar. | ||
| - */ | ||
| - private static void update( final String message ) { | ||
| - runLater( | ||
| - () -> { | ||
| - final var s = message == null ? "" : message; | ||
| - final var i = s.indexOf( '\n' ); | ||
| - sStatusBar.setText( s.substring( 0, i > 0 ? i : s.length() ) ); | ||
| - } | ||
| - ); | ||
| - } | ||
| -} | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +package com.keenwrite; | ||
| + | ||
| +import com.keenwrite.service.events.Notifier; | ||
| +import com.keenwrite.ui.logging.LogView; | ||
| +import org.controlsfx.control.StatusBar; | ||
| + | ||
| +import static com.keenwrite.Constants.STATUS_BAR_OK; | ||
| +import static com.keenwrite.Messages.get; | ||
| +import static javafx.application.Platform.runLater; | ||
| + | ||
| +/** | ||
| + * Responsible for passing notifications about exceptions (or other error | ||
| + * messages) through the application. Once the Event Bus is implemented, this | ||
| + * class can go away. | ||
| + */ | ||
| +public class StatusNotifier { | ||
| + private static final String OK = get( STATUS_BAR_OK, "OK" ); | ||
| + | ||
| + private static final Notifier sNotifier = Services.load( Notifier.class ); | ||
| + private static final StatusBar sStatusBar = new StatusBar(); | ||
| + private static final LogView sLogView = new LogView(); | ||
| + | ||
| + /** | ||
| + * Resets the status bar to a default message. | ||
| + */ | ||
| + public static void clue() { | ||
| + // Don't burden the repaint thread if there's no status bar change. | ||
| + if( !OK.equals( sStatusBar.getText() ) ) { | ||
| + update( OK ); | ||
| + } | ||
| + } | ||
| + | ||
| + /** | ||
| + * Updates the status bar with a custom message. | ||
| + * | ||
| + * @param key The property key having a value to populate with arguments. | ||
| + * @param args The placeholder values to substitute into the key's value. | ||
| + */ | ||
| + public static void clue( final String key, final Object... args ) { | ||
| + final var message = get( key, args ); | ||
| + update( message ); | ||
| + sLogView.log( message ); | ||
| + } | ||
| + | ||
| + /** | ||
| + * Update the status bar with a pre-parsed message and exception. | ||
| + * | ||
| + * @param message The custom message to log. | ||
| + * @param t The exception that triggered the status update. | ||
| + */ | ||
| + public static void clue( final String message, final Throwable t ) { | ||
| + update( message ); | ||
| + sLogView.log( message, t ); | ||
| + } | ||
| + | ||
| + /** | ||
| + * Called when an exception occurs that warrants the user's attention. | ||
| + * | ||
| + * @param t The exception with a message that the user should know about. | ||
| + */ | ||
| + public static void clue( final Throwable t ) { | ||
| + update( t.getMessage() ); | ||
| + sLogView.log( t ); | ||
| + } | ||
| + | ||
| + /** | ||
| + * Returns the global {@link Notifier} instance that can be used for opening | ||
| + * pop-up alert messages. | ||
| + * | ||
| + * @return The pop-up {@link Notifier} dispatcher. | ||
| + */ | ||
| + public static Notifier getNotifier() { | ||
| + return sNotifier; | ||
| + } | ||
| + | ||
| + public static StatusBar getStatusBar() { | ||
| + return sStatusBar; | ||
| + } | ||
| + | ||
| + /** | ||
| + * Updates the status bar to show the first line of the given message. | ||
| + * | ||
| + * @param message The message to show in the status bar. | ||
| + */ | ||
| + private static void update( final String message ) { | ||
| + runLater( | ||
| + () -> { | ||
| + final var s = message == null ? "" : message; | ||
| + final var i = s.indexOf( '\n' ); | ||
| + sStatusBar.setText( s.substring( 0, i > 0 ? i : s.length() ) ); | ||
| + } | ||
| + ); | ||
| + } | ||
| + | ||
| + public static void viewIssues() { | ||
| + sLogView.view(); | ||
| + } | ||
| +} | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.editors; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.editors; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.editors; | ||
| import static com.keenwrite.Constants.DEFAULT_CHARSET; | ||
| -import static com.keenwrite.StatusBarNotifier.clue; | ||
| +import static com.keenwrite.StatusNotifier.clue; | ||
| import static java.nio.charset.Charset.forName; | ||
| import static java.nio.file.Files.readAllBytes; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.editors.definition; | ||
| import static com.keenwrite.Constants.DEFINITION_DEFAULT; | ||
| import static com.keenwrite.Messages.get; | ||
| -import static com.keenwrite.StatusBarNotifier.clue; | ||
| +import static com.keenwrite.StatusNotifier.clue; | ||
| import static java.lang.String.format; | ||
| import static java.util.regex.Pattern.compile; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.editors.definition; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.editors.definition; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.editors.definition; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.editors.definition; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.editors.definition; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.editors.definition; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.editors.definition; | ||
| -/* Copyright 2020 White Magic Software, Ltd. | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. | ||
| * | ||
| * All rights reserved. |
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.editors.definition.yaml; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.editors.definition.yaml; | ||
| -/* Copyright 2020 White Magic Software, Ltd. | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. | ||
| * | ||
| * All rights reserved. |
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.editors.markdown; | ||
| /* | ||
| - * Copyright 2020 White Magic Software, Ltd. | ||
| + * Copyright 2020-2021 White Magic Software, Ltd. | ||
| * | ||
| * All rights reserved. | ||
| public class LinkVisitor { | ||
| - private NodeVisitor visitor; | ||
| - private Link link; | ||
| - private final int offset; | ||
| + private NodeVisitor mVisitor; | ||
| + private Link mLink; | ||
| + private final int mOffset; | ||
| /** | ||
| * Creates a hyperlink given an offset into a paragraph and the Markdown AST | ||
| * link node. | ||
| * | ||
| * @param index Index into the paragraph that indicates the hyperlink to | ||
| * change. | ||
| */ | ||
| public LinkVisitor( final int index ) { | ||
| - this.offset = index; | ||
| + mOffset = index; | ||
| } | ||
| private synchronized NodeVisitor getVisitor() { | ||
| - if( this.visitor == null ) { | ||
| - this.visitor = createVisitor(); | ||
| + if( mVisitor == null ) { | ||
| + mVisitor = createVisitor(); | ||
| } | ||
| - return this.visitor; | ||
| + return mVisitor; | ||
| } | ||
| protected NodeVisitor createVisitor() { | ||
| return new NodeVisitor( | ||
| - new VisitHandler<>( Link.class, LinkVisitor.this::visit ) ); | ||
| + new VisitHandler<>( Link.class, LinkVisitor.this::visit ) ); | ||
| } | ||
| private Link getLink() { | ||
| - return this.link; | ||
| + return mLink; | ||
| } | ||
| private void setLink( final Link link ) { | ||
| - this.link = link; | ||
| + mLink = link; | ||
| } | ||
| public int getOffset() { | ||
| - return this.offset; | ||
| + return mOffset; | ||
| } | ||
| } | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.editors.markdown; | ||
| import static com.keenwrite.Constants.*; | ||
| import static com.keenwrite.Messages.get; | ||
| -import static com.keenwrite.StatusBarNotifier.clue; | ||
| +import static com.keenwrite.StatusNotifier.clue; | ||
| import static com.keenwrite.preferences.Workspace.*; | ||
| import static java.lang.Character.isWhitespace; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.exceptions; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.io; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.io; | ||
| import java.net.MalformedURLException; | ||
| import java.net.URI; | ||
| import java.net.URL; | ||
| import java.net.http.HttpClient; | ||
| import java.net.http.HttpRequest; | ||
| -import static com.keenwrite.StatusBarNotifier.clue; | ||
| +import static com.keenwrite.StatusNotifier.clue; | ||
| import static com.keenwrite.io.MediaType.UNDEFINED; | ||
| import static java.net.http.HttpClient.Redirect.NORMAL; |
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.io; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.io; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.predicates; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.preferences; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.preferences; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.preferences; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.preferences; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.preferences; | ||
| import static com.keenwrite.Constants.ICON_DIALOG; | ||
| -import static com.keenwrite.StatusBarNotifier.clue; | ||
| +import static com.keenwrite.StatusNotifier.clue; | ||
| import static java.lang.System.currentTimeMillis; | ||
| import static javafx.geometry.Pos.CENTER_LEFT; |
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.preferences; | ||
| import static com.keenwrite.Constants.*; | ||
| import static com.keenwrite.Launcher.getVersion; | ||
| -import static com.keenwrite.StatusBarNotifier.clue; | ||
| +import static com.keenwrite.StatusNotifier.clue; | ||
| import static com.keenwrite.preferences.Key.key; | ||
| import static java.util.Map.entry; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.preferences; | ||
| /* Copyright 2006 Patrick Wright | ||
| * Copyright 2007 Wisconsin Court System | ||
| - * Copyright 2020 White Magic Software, Ltd. | ||
| + * Copyright 2020-2021 White Magic Software, Ltd. | ||
| * | ||
| * This program is free software; you can redistribute it and/or |
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.preview; | ||
| import java.util.Map; | ||
| -import static com.keenwrite.StatusBarNotifier.clue; | ||
| +import static com.keenwrite.StatusNotifier.clue; | ||
| import static com.keenwrite.processors.text.TextReplacementFactory.replace; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.preview; | ||
| import java.net.URI; | ||
| -import static com.keenwrite.StatusBarNotifier.clue; | ||
| +import static com.keenwrite.StatusNotifier.clue; | ||
| import static com.keenwrite.util.ProtocolScheme.getProtocol; | ||
| import static java.awt.Desktop.Action.BROWSE; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.preview; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.preview; | ||
| import com.whitemagicsoftware.tex.*; | ||
| import com.whitemagicsoftware.tex.graphics.SvgDomGraphics2D; | ||
| import org.w3c.dom.Document; | ||
| import java.util.function.Supplier; | ||
| -import static com.keenwrite.StatusBarNotifier.clue; | ||
| +import static com.keenwrite.StatusNotifier.clue; | ||
| /** |
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.preview; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.preview; | ||
| import java.text.NumberFormat; | ||
| -import static com.keenwrite.StatusBarNotifier.clue; | ||
| +import static com.keenwrite.StatusNotifier.clue; | ||
| import static com.keenwrite.preview.RenderingSettings.RENDERING_HINTS; | ||
| import static java.awt.image.BufferedImage.TYPE_INT_RGB; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.preview; | ||
| import java.nio.file.Paths; | ||
| -import static com.keenwrite.StatusBarNotifier.clue; | ||
| +import static com.keenwrite.StatusNotifier.clue; | ||
| import static com.keenwrite.io.MediaType.*; | ||
| import static com.keenwrite.preview.MathRenderer.MATH_RENDERER; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.processors; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.processors; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.processors; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.processors; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.processors; | ||
| import static com.keenwrite.Constants.STATUS_PARSE_ERROR; | ||
| -import static com.keenwrite.StatusBarNotifier.clue; | ||
| +import static com.keenwrite.Messages.get; | ||
| +import static com.keenwrite.StatusNotifier.clue; | ||
| import static com.keenwrite.preferences.Workspace.*; | ||
| import static com.keenwrite.processors.text.TextReplacementFactory.replace; | ||
| return ENGINE.eval( r ).toString(); | ||
| } catch( final Exception ex ) { | ||
| - final var expr = r.substring( 0, min( r.length(), 30 ) ); | ||
| - clue( "Main.status.error.r", expr, ex.getMessage() ); | ||
| + final var expr = r.substring( 0, min( r.length(), 50 ) ); | ||
| + clue( get( "Main.status.error.r", expr, ex.getMessage() ), ex ); | ||
| return ""; | ||
| } | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.processors; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.processors; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.processors; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.processors; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.processors; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.processors; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.processors.markdown; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.processors.markdown.extensions; | ||
| import java.util.zip.Deflater; | ||
| -import static com.keenwrite.StatusBarNotifier.clue; | ||
| +import static com.keenwrite.StatusNotifier.clue; | ||
| import static com.keenwrite.processors.IdentityProcessor.IDENTITY; | ||
| import static com.vladsch.flexmark.html.HtmlRenderer.Builder; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.processors.markdown.extensions; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.processors.markdown.extensions; | ||
| import java.nio.file.Paths; | ||
| -import static com.keenwrite.StatusBarNotifier.clue; | ||
| +import static com.keenwrite.StatusNotifier.clue; | ||
| import static com.keenwrite.preferences.Workspace.KEY_IMAGES_DIR; | ||
| import static com.keenwrite.preferences.Workspace.KEY_IMAGES_ORDER; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.processors.markdown.extensions.caret; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.processors.markdown.extensions.r; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.processors.markdown.extensions.r; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.processors.markdown.extensions.tex; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.processors.markdown.extensions.tex; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.processors.markdown.extensions.tex; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.processors.markdown.extensions.tex; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.processors.text; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.processors.text; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.processors.text; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.processors.text; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.processors.text; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.search; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.service; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.service; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.service; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.service.events; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.service.events; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.service.events.impl; | ||
| import javafx.scene.Node; | ||
| import javafx.scene.control.ButtonBar; | ||
| import javafx.scene.control.DialogPane; | ||
| +import javafx.stage.Stage; | ||
| +import static com.keenwrite.Constants.ICON_DIALOG; | ||
| import static com.keenwrite.Constants.sSettings; | ||
| import static javafx.scene.control.ButtonBar.BUTTON_ORDER_WINDOWS; | ||
| /** | ||
| * Ensures a consistent button order for alert dialogs across platforms (because | ||
| * the default button order on Linux defies all logic). | ||
| */ | ||
| public class ButtonOrderPane extends DialogPane { | ||
| + public ButtonOrderPane() { | ||
| + ((Stage) getScene().getWindow()).getIcons().add( ICON_DIALOG ); | ||
| + } | ||
| @Override | ||
| protected Node createButtonBar() { | ||
| final var node = (ButtonBar) super.createButtonBar(); | ||
| node.setButtonOrder( getButtonOrder() ); | ||
| return node; | ||
| } | ||
| private String getButtonOrder() { | ||
| - return getSetting( "dialog.alert.button.order.windows", | ||
| - BUTTON_ORDER_WINDOWS ); | ||
| - } | ||
| - | ||
| - @SuppressWarnings("SameParameterValue") | ||
| - private String getSetting( final String key, final String defaultValue ) { | ||
| - return sSettings.getSetting( key, defaultValue ); | ||
| + return sSettings.getSetting( | ||
| + "dialog.alert.button.order.windows", BUTTON_ORDER_WINDOWS ); | ||
| } | ||
| } |
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.service.events.impl; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.service.events.impl; | ||
| import java.nio.file.Path; | ||
| +import static com.keenwrite.Constants.ICON_DIALOG_NODE; | ||
| import static com.keenwrite.Messages.get; | ||
| import static javafx.scene.control.Alert.AlertType.CONFIRMATION; | ||
| alert.setContentText( message.getContent() ); | ||
| alert.initOwner( parent ); | ||
| + alert.setGraphic( ICON_DIALOG_NODE ); | ||
| return alert; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.service.impl; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.service.impl; | ||
| import static com.keenwrite.Constants.APP_WATCHDOG_TIMEOUT; | ||
| -import static com.keenwrite.StatusBarNotifier.clue; | ||
| +import static com.keenwrite.StatusNotifier.clue; | ||
| import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.sigils; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.sigils; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.sigils; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.sigils; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.spelling.api; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.spelling.api; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. | ||
| * | ||
| * Redistribution and use in source and binary forms, with or without |
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.spelling.impl; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.spelling.impl; | ||
| import static com.keenwrite.Constants.LEXICONS_DIRECTORY; | ||
| -import static com.keenwrite.StatusBarNotifier.clue; | ||
| +import static com.keenwrite.StatusNotifier.clue; | ||
| import static io.gitlab.rxp90.jsymspell.SymSpell.Verbosity; | ||
| import static io.gitlab.rxp90.jsymspell.SymSpell.Verbosity.ALL; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.spelling.impl; | ||
| -/* Copyright 2020 White Magic Software, Ltd. | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. | ||
| * | ||
| * All rights reserved. |
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.ui.actions; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| -package com.keenwrite.ui.actions; | ||
| - | ||
| -import com.keenwrite.ExportFormat; | ||
| -import com.keenwrite.MainPane; | ||
| -import com.keenwrite.editors.TextDefinition; | ||
| -import com.keenwrite.editors.TextEditor; | ||
| -import com.keenwrite.editors.markdown.HyperlinkModel; | ||
| -import com.keenwrite.editors.markdown.LinkVisitor; | ||
| -import com.keenwrite.preferences.PreferencesController; | ||
| -import com.keenwrite.preferences.Workspace; | ||
| -import com.keenwrite.processors.markdown.MarkdownProcessor; | ||
| -import com.keenwrite.search.SearchModel; | ||
| -import com.keenwrite.ui.controls.SearchBar; | ||
| -import com.keenwrite.ui.dialogs.ImageDialog; | ||
| -import com.keenwrite.ui.dialogs.LinkDialog; | ||
| -import com.vladsch.flexmark.ast.Link; | ||
| -import javafx.scene.control.Alert; | ||
| -import javafx.scene.control.Dialog; | ||
| -import javafx.stage.Window; | ||
| -import javafx.stage.WindowEvent; | ||
| - | ||
| -import static com.keenwrite.Bootstrap.APP_TITLE; | ||
| -import static com.keenwrite.Constants.ICON_DIALOG_NODE; | ||
| -import static com.keenwrite.ExportFormat.*; | ||
| -import static com.keenwrite.Messages.get; | ||
| -import static com.keenwrite.StatusBarNotifier.clue; | ||
| -import static com.keenwrite.StatusBarNotifier.getStatusBar; | ||
| -import static com.keenwrite.preferences.Workspace.KEY_UI_RECENT_DIR; | ||
| -import static com.keenwrite.processors.ProcessorFactory.createProcessors; | ||
| -import static java.nio.file.Files.writeString; | ||
| -import static javafx.event.Event.fireEvent; | ||
| -import static javafx.scene.control.Alert.AlertType.INFORMATION; | ||
| -import static javafx.stage.WindowEvent.WINDOW_CLOSE_REQUEST; | ||
| - | ||
| -/** | ||
| - * Responsible for abstracting how functionality is mapped to the application. | ||
| - * This allows users to customize accelerator keys and will provide pluggable | ||
| - * functionality so that different text markup languages can change documents | ||
| - * using their respective syntax. | ||
| - */ | ||
| -@SuppressWarnings( "NonAsciiCharacters" ) | ||
| -public class ApplicationActions { | ||
| - private static final String STYLE_SEARCH = "search"; | ||
| - | ||
| - /** | ||
| - * When an action is executed, this is one of the recipients. | ||
| - */ | ||
| - private final MainPane mMainPane; | ||
| - | ||
| - /** | ||
| - * Tracks finding text in the active document. | ||
| - */ | ||
| - private final SearchModel mSearchModel; | ||
| - | ||
| - public ApplicationActions( final MainPane mainPane ) { | ||
| - mMainPane = mainPane; | ||
| - mSearchModel = new SearchModel(); | ||
| - mSearchModel.matchOffsetProperty().addListener( ( c, o, n ) -> { | ||
| - final var editor = getActiveTextEditor(); | ||
| - | ||
| - // Clear highlighted areas before adding highlighting to a new region. | ||
| - if( o != null ) { | ||
| - editor.unstylize( STYLE_SEARCH ); | ||
| - } | ||
| - | ||
| - if( n != null ) { | ||
| - editor.moveTo( n.getStart() ); | ||
| - editor.stylize( n, STYLE_SEARCH ); | ||
| - } | ||
| - } ); | ||
| - | ||
| - // When the active text editor changes, update the haystack. | ||
| - mMainPane.activeTextEditorProperty().addListener( | ||
| - ( c, o, n ) -> mSearchModel.search( getActiveTextEditor().getText() ) | ||
| - ); | ||
| - } | ||
| - | ||
| - public void file‿new() { | ||
| - getMainPane().newTextEditor(); | ||
| - } | ||
| - | ||
| - public void file‿open() { | ||
| - getMainPane().open( createFileChooser().openFiles() ); | ||
| - } | ||
| - | ||
| - public void file‿close() { | ||
| - getMainPane().close(); | ||
| - } | ||
| - | ||
| - public void file‿close_all() { | ||
| - getMainPane().closeAll(); | ||
| - } | ||
| - | ||
| - public void file‿save() { | ||
| - getMainPane().save(); | ||
| - } | ||
| - | ||
| - public void file‿save_as() { | ||
| - final var file = createFileChooser().saveAs(); | ||
| - file.ifPresent( ( f ) -> getMainPane().saveAs( f ) ); | ||
| - } | ||
| - | ||
| - public void file‿save_all() { | ||
| - getMainPane().saveAll(); | ||
| - } | ||
| - | ||
| - public void file‿export‿html_svg() { | ||
| - file‿export( HTML_TEX_SVG ); | ||
| - } | ||
| - | ||
| - public void file‿export‿html_tex() { | ||
| - file‿export( HTML_TEX_DELIMITED ); | ||
| - } | ||
| - | ||
| - public void file‿export‿markdown() { | ||
| - file‿export( MARKDOWN_PLAIN ); | ||
| - } | ||
| - | ||
| - private void file‿export( final ExportFormat format ) { | ||
| - final var main = getMainPane(); | ||
| - final var context = main.createProcessorContext(); | ||
| - final var chain = createProcessors( context ); | ||
| - final var editor = main.getActiveTextEditor(); | ||
| - final var doc = editor.getText(); | ||
| - final var export = chain.apply( doc ); | ||
| - final var filename = format.toExportFilename( editor.getPath() ); | ||
| - final var chooser = createFileChooser(); | ||
| - final var file = chooser.exportAs( filename ); | ||
| - | ||
| - file.ifPresent( ( f ) -> { | ||
| - try { | ||
| - writeString( f.toPath(), export ); | ||
| - final var m = get( "Main.status.export.success", f.toString() ); | ||
| - clue( m ); | ||
| - } catch( final Exception e ) { | ||
| - clue( e ); | ||
| - } | ||
| - } ); | ||
| - } | ||
| - | ||
| - public void file‿exit() { | ||
| - final var window = getWindow(); | ||
| - fireEvent( window, new WindowEvent( window, WINDOW_CLOSE_REQUEST ) ); | ||
| - } | ||
| - | ||
| - public void edit‿undo() { | ||
| - getActiveTextEditor().undo(); | ||
| - } | ||
| - | ||
| - public void edit‿redo() { | ||
| - getActiveTextEditor().redo(); | ||
| - } | ||
| - | ||
| - public void edit‿cut() { | ||
| - getActiveTextEditor().cut(); | ||
| - } | ||
| - | ||
| - public void edit‿copy() { | ||
| - getActiveTextEditor().copy(); | ||
| - } | ||
| - | ||
| - public void edit‿paste() { | ||
| - getActiveTextEditor().paste(); | ||
| - } | ||
| - | ||
| - public void edit‿select_all() { | ||
| - getActiveTextEditor().selectAll(); | ||
| - } | ||
| - | ||
| - public void edit‿find() { | ||
| - final var nodes = getStatusBar().getLeftItems(); | ||
| - | ||
| - if( nodes.isEmpty() ) { | ||
| - final var searchBar = new SearchBar(); | ||
| - | ||
| - searchBar.matchIndexProperty().bind( mSearchModel.matchIndexProperty() ); | ||
| - searchBar.matchCountProperty().bind( mSearchModel.matchCountProperty() ); | ||
| - | ||
| - searchBar.setOnCancelAction( ( event ) -> { | ||
| - final var editor = getActiveTextEditor(); | ||
| - nodes.remove( searchBar ); | ||
| - editor.unstylize( STYLE_SEARCH ); | ||
| - editor.getNode().requestFocus(); | ||
| - } ); | ||
| - | ||
| - searchBar.addInputListener( ( c, o, n ) -> { | ||
| - if( n != null && !n.isEmpty() ) { | ||
| - mSearchModel.search( n, getActiveTextEditor().getText() ); | ||
| - } | ||
| - } ); | ||
| - | ||
| - searchBar.setOnNextAction( ( event ) -> edit‿find_next() ); | ||
| - searchBar.setOnPrevAction( ( event ) -> edit‿find_prev() ); | ||
| - | ||
| - nodes.add( searchBar ); | ||
| - searchBar.requestFocus(); | ||
| - } | ||
| - else { | ||
| - nodes.clear(); | ||
| - } | ||
| - } | ||
| - | ||
| - public void edit‿find_next() { | ||
| - mSearchModel.advance(); | ||
| - } | ||
| - | ||
| - public void edit‿find_prev() { | ||
| - mSearchModel.retreat(); | ||
| - } | ||
| - | ||
| - public void edit‿preferences() { | ||
| - new PreferencesController( getWorkspace() ).show(); | ||
| - } | ||
| - | ||
| - public void format‿bold() { | ||
| - getActiveTextEditor().bold(); | ||
| - } | ||
| - | ||
| - public void format‿italic() { | ||
| - getActiveTextEditor().italic(); | ||
| - } | ||
| - | ||
| - public void format‿superscript() { | ||
| - getActiveTextEditor().superscript(); | ||
| - } | ||
| - | ||
| - public void format‿subscript() { | ||
| - getActiveTextEditor().subscript(); | ||
| - } | ||
| - | ||
| - public void format‿strikethrough() { | ||
| - getActiveTextEditor().strikethrough(); | ||
| - } | ||
| - | ||
| - public void insert‿blockquote() { | ||
| - getActiveTextEditor().blockquote(); | ||
| - } | ||
| - | ||
| - public void insert‿code() { | ||
| - getActiveTextEditor().code(); | ||
| - } | ||
| - | ||
| - public void insert‿fenced_code_block() { | ||
| - getActiveTextEditor().fencedCodeBlock(); | ||
| - } | ||
| - | ||
| - public void insert‿link() { | ||
| - insertObject( createLinkDialog() ); | ||
| - } | ||
| - | ||
| - public void insert‿image() { | ||
| - insertObject( createImageDialog() ); | ||
| - } | ||
| - | ||
| - private void insertObject( final Dialog<String> dialog ) { | ||
| - final var textArea = getActiveTextEditor().getTextArea(); | ||
| - dialog.showAndWait().ifPresent( textArea::replaceSelection ); | ||
| - } | ||
| - | ||
| - private Dialog<String> createLinkDialog() { | ||
| - return new LinkDialog( getWindow(), createHyperlinkModel() ); | ||
| - } | ||
| - | ||
| - private Dialog<String> createImageDialog() { | ||
| - final var path = getActiveTextEditor().getPath(); | ||
| - final var parentDir = path.getParent(); | ||
| - return new ImageDialog( getWindow(), parentDir ); | ||
| - } | ||
| - | ||
| - /** | ||
| - * Returns one of: selected text, word under cursor, or parsed hyperlink from | ||
| - * the Markdown AST. | ||
| - * | ||
| - * @return An instance containing the link URL and display text. | ||
| - */ | ||
| - private HyperlinkModel createHyperlinkModel() { | ||
| - final var context = getMainPane().createProcessorContext(); | ||
| - final var editor = getActiveTextEditor(); | ||
| - final var textArea = editor.getTextArea(); | ||
| - final var selectedText = textArea.getSelectedText(); | ||
| - | ||
| - // Convert current paragraph to Markdown nodes. | ||
| - final var mp = MarkdownProcessor.create( context ); | ||
| - final var p = textArea.getCurrentParagraph(); | ||
| - final var paragraph = textArea.getText( p ); | ||
| - final var node = mp.toNode( paragraph ); | ||
| - final var visitor = new LinkVisitor( textArea.getCaretColumn() ); | ||
| - final var link = visitor.process( node ); | ||
| - | ||
| - if( link != null ) { | ||
| - textArea.selectRange( p, link.getStartOffset(), p, link.getEndOffset() ); | ||
| - } | ||
| - | ||
| - return createHyperlinkModel( link, selectedText ); | ||
| - } | ||
| - | ||
| - private HyperlinkModel createHyperlinkModel( | ||
| - final Link link, final String selection ) { | ||
| - | ||
| - return link == null | ||
| - ? new HyperlinkModel( selection, "https://localhost" ) | ||
| - : new HyperlinkModel( link ); | ||
| - } | ||
| - | ||
| - public void insert‿heading_1() { | ||
| - insert‿heading( 1 ); | ||
| - } | ||
| - | ||
| - public void insert‿heading_2() { | ||
| - insert‿heading( 2 ); | ||
| - } | ||
| - | ||
| - public void insert‿heading_3() { | ||
| - insert‿heading( 3 ); | ||
| - } | ||
| - | ||
| - private void insert‿heading( final int level ) { | ||
| - getActiveTextEditor().heading( level ); | ||
| - } | ||
| - | ||
| - public void insert‿unordered_list() { | ||
| - getActiveTextEditor().unorderedList(); | ||
| - } | ||
| - | ||
| - public void insert‿ordered_list() { | ||
| - getActiveTextEditor().orderedList(); | ||
| - } | ||
| - | ||
| - public void insert‿horizontal_rule() { | ||
| - getActiveTextEditor().horizontalRule(); | ||
| - } | ||
| - | ||
| - public void definition‿create() { | ||
| - getActiveTextDefinition().createDefinition(); | ||
| - } | ||
| - | ||
| - public void definition‿rename() { | ||
| - getActiveTextDefinition().renameDefinition(); | ||
| - } | ||
| - | ||
| - public void definition‿delete() { | ||
| - getActiveTextDefinition().deleteDefinitions(); | ||
| - } | ||
| - | ||
| - public void definition‿autoinsert() { | ||
| - getMainPane().autoinsert(); | ||
| - } | ||
| - | ||
| - public void view‿refresh() { | ||
| - getMainPane().viewRefresh(); | ||
| - } | ||
| - | ||
| - public void view‿preview() { | ||
| - getMainPane().viewPreview(); | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +package com.keenwrite.ui.actions; | ||
| + | ||
| +import com.keenwrite.ExportFormat; | ||
| +import com.keenwrite.MainPane; | ||
| +import com.keenwrite.StatusNotifier; | ||
| +import com.keenwrite.editors.TextDefinition; | ||
| +import com.keenwrite.editors.TextEditor; | ||
| +import com.keenwrite.editors.markdown.HyperlinkModel; | ||
| +import com.keenwrite.editors.markdown.LinkVisitor; | ||
| +import com.keenwrite.preferences.PreferencesController; | ||
| +import com.keenwrite.preferences.Workspace; | ||
| +import com.keenwrite.processors.markdown.MarkdownProcessor; | ||
| +import com.keenwrite.search.SearchModel; | ||
| +import com.keenwrite.ui.controls.SearchBar; | ||
| +import com.keenwrite.ui.dialogs.ImageDialog; | ||
| +import com.keenwrite.ui.dialogs.LinkDialog; | ||
| +import com.vladsch.flexmark.ast.Link; | ||
| +import javafx.scene.control.Alert; | ||
| +import javafx.scene.control.Dialog; | ||
| +import javafx.stage.Window; | ||
| +import javafx.stage.WindowEvent; | ||
| + | ||
| +import static com.keenwrite.Bootstrap.APP_TITLE; | ||
| +import static com.keenwrite.Constants.ICON_DIALOG_NODE; | ||
| +import static com.keenwrite.ExportFormat.*; | ||
| +import static com.keenwrite.Messages.get; | ||
| +import static com.keenwrite.StatusNotifier.clue; | ||
| +import static com.keenwrite.StatusNotifier.getStatusBar; | ||
| +import static com.keenwrite.preferences.Workspace.KEY_UI_RECENT_DIR; | ||
| +import static com.keenwrite.processors.ProcessorFactory.createProcessors; | ||
| +import static java.nio.file.Files.writeString; | ||
| +import static javafx.event.Event.fireEvent; | ||
| +import static javafx.scene.control.Alert.AlertType.INFORMATION; | ||
| +import static javafx.stage.WindowEvent.WINDOW_CLOSE_REQUEST; | ||
| + | ||
| +/** | ||
| + * Responsible for abstracting how functionality is mapped to the application. | ||
| + * This allows users to customize accelerator keys and will provide pluggable | ||
| + * functionality so that different text markup languages can change documents | ||
| + * using their respective syntax. | ||
| + */ | ||
| +@SuppressWarnings( "NonAsciiCharacters" ) | ||
| +public class ApplicationActions { | ||
| + private static final String STYLE_SEARCH = "search"; | ||
| + | ||
| + /** | ||
| + * When an action is executed, this is one of the recipients. | ||
| + */ | ||
| + private final MainPane mMainPane; | ||
| + | ||
| + /** | ||
| + * Tracks finding text in the active document. | ||
| + */ | ||
| + private final SearchModel mSearchModel; | ||
| + | ||
| + public ApplicationActions( final MainPane mainPane ) { | ||
| + mMainPane = mainPane; | ||
| + mSearchModel = new SearchModel(); | ||
| + mSearchModel.matchOffsetProperty().addListener( ( c, o, n ) -> { | ||
| + final var editor = getActiveTextEditor(); | ||
| + | ||
| + // Clear highlighted areas before adding highlighting to a new region. | ||
| + if( o != null ) { | ||
| + editor.unstylize( STYLE_SEARCH ); | ||
| + } | ||
| + | ||
| + if( n != null ) { | ||
| + editor.moveTo( n.getStart() ); | ||
| + editor.stylize( n, STYLE_SEARCH ); | ||
| + } | ||
| + } ); | ||
| + | ||
| + // When the active text editor changes, update the haystack. | ||
| + mMainPane.activeTextEditorProperty().addListener( | ||
| + ( c, o, n ) -> mSearchModel.search( getActiveTextEditor().getText() ) | ||
| + ); | ||
| + } | ||
| + | ||
| + public void file‿new() { | ||
| + getMainPane().newTextEditor(); | ||
| + } | ||
| + | ||
| + public void file‿open() { | ||
| + getMainPane().open( createFileChooser().openFiles() ); | ||
| + } | ||
| + | ||
| + public void file‿close() { | ||
| + getMainPane().close(); | ||
| + } | ||
| + | ||
| + public void file‿close_all() { | ||
| + getMainPane().closeAll(); | ||
| + } | ||
| + | ||
| + public void file‿save() { | ||
| + getMainPane().save(); | ||
| + } | ||
| + | ||
| + public void file‿save_as() { | ||
| + final var file = createFileChooser().saveAs(); | ||
| + file.ifPresent( ( f ) -> getMainPane().saveAs( f ) ); | ||
| + } | ||
| + | ||
| + public void file‿save_all() { | ||
| + getMainPane().saveAll(); | ||
| + } | ||
| + | ||
| + public void file‿export‿html_svg() { | ||
| + file‿export( HTML_TEX_SVG ); | ||
| + } | ||
| + | ||
| + public void file‿export‿html_tex() { | ||
| + file‿export( HTML_TEX_DELIMITED ); | ||
| + } | ||
| + | ||
| + public void file‿export‿markdown() { | ||
| + file‿export( MARKDOWN_PLAIN ); | ||
| + } | ||
| + | ||
| + private void file‿export( final ExportFormat format ) { | ||
| + final var main = getMainPane(); | ||
| + final var context = main.createProcessorContext(); | ||
| + final var chain = createProcessors( context ); | ||
| + final var editor = main.getActiveTextEditor(); | ||
| + final var doc = editor.getText(); | ||
| + final var export = chain.apply( doc ); | ||
| + final var filename = format.toExportFilename( editor.getPath() ); | ||
| + final var chooser = createFileChooser(); | ||
| + final var file = chooser.exportAs( filename ); | ||
| + | ||
| + file.ifPresent( ( f ) -> { | ||
| + try { | ||
| + writeString( f.toPath(), export ); | ||
| + final var m = get( "Main.status.export.success", f.toString() ); | ||
| + clue( m ); | ||
| + } catch( final Exception ex ) { | ||
| + clue( ex ); | ||
| + } | ||
| + } ); | ||
| + } | ||
| + | ||
| + public void file‿exit() { | ||
| + final var window = getWindow(); | ||
| + fireEvent( window, new WindowEvent( window, WINDOW_CLOSE_REQUEST ) ); | ||
| + } | ||
| + | ||
| + public void edit‿undo() { | ||
| + getActiveTextEditor().undo(); | ||
| + } | ||
| + | ||
| + public void edit‿redo() { | ||
| + getActiveTextEditor().redo(); | ||
| + } | ||
| + | ||
| + public void edit‿cut() { | ||
| + getActiveTextEditor().cut(); | ||
| + } | ||
| + | ||
| + public void edit‿copy() { | ||
| + getActiveTextEditor().copy(); | ||
| + } | ||
| + | ||
| + public void edit‿paste() { | ||
| + getActiveTextEditor().paste(); | ||
| + } | ||
| + | ||
| + public void edit‿select_all() { | ||
| + getActiveTextEditor().selectAll(); | ||
| + } | ||
| + | ||
| + public void edit‿find() { | ||
| + final var nodes = getStatusBar().getLeftItems(); | ||
| + | ||
| + if( nodes.isEmpty() ) { | ||
| + final var searchBar = new SearchBar(); | ||
| + | ||
| + searchBar.matchIndexProperty().bind( mSearchModel.matchIndexProperty() ); | ||
| + searchBar.matchCountProperty().bind( mSearchModel.matchCountProperty() ); | ||
| + | ||
| + searchBar.setOnCancelAction( ( event ) -> { | ||
| + final var editor = getActiveTextEditor(); | ||
| + nodes.remove( searchBar ); | ||
| + editor.unstylize( STYLE_SEARCH ); | ||
| + editor.getNode().requestFocus(); | ||
| + } ); | ||
| + | ||
| + searchBar.addInputListener( ( c, o, n ) -> { | ||
| + if( n != null && !n.isEmpty() ) { | ||
| + mSearchModel.search( n, getActiveTextEditor().getText() ); | ||
| + } | ||
| + } ); | ||
| + | ||
| + searchBar.setOnNextAction( ( event ) -> edit‿find_next() ); | ||
| + searchBar.setOnPrevAction( ( event ) -> edit‿find_prev() ); | ||
| + | ||
| + nodes.add( searchBar ); | ||
| + searchBar.requestFocus(); | ||
| + } | ||
| + else { | ||
| + nodes.clear(); | ||
| + } | ||
| + } | ||
| + | ||
| + public void edit‿find_next() { | ||
| + mSearchModel.advance(); | ||
| + } | ||
| + | ||
| + public void edit‿find_prev() { | ||
| + mSearchModel.retreat(); | ||
| + } | ||
| + | ||
| + public void edit‿preferences() { | ||
| + new PreferencesController( getWorkspace() ).show(); | ||
| + } | ||
| + | ||
| + public void format‿bold() { | ||
| + getActiveTextEditor().bold(); | ||
| + } | ||
| + | ||
| + public void format‿italic() { | ||
| + getActiveTextEditor().italic(); | ||
| + } | ||
| + | ||
| + public void format‿superscript() { | ||
| + getActiveTextEditor().superscript(); | ||
| + } | ||
| + | ||
| + public void format‿subscript() { | ||
| + getActiveTextEditor().subscript(); | ||
| + } | ||
| + | ||
| + public void format‿strikethrough() { | ||
| + getActiveTextEditor().strikethrough(); | ||
| + } | ||
| + | ||
| + public void insert‿blockquote() { | ||
| + getActiveTextEditor().blockquote(); | ||
| + } | ||
| + | ||
| + public void insert‿code() { | ||
| + getActiveTextEditor().code(); | ||
| + } | ||
| + | ||
| + public void insert‿fenced_code_block() { | ||
| + getActiveTextEditor().fencedCodeBlock(); | ||
| + } | ||
| + | ||
| + public void insert‿link() { | ||
| + insertObject( createLinkDialog() ); | ||
| + } | ||
| + | ||
| + public void insert‿image() { | ||
| + insertObject( createImageDialog() ); | ||
| + } | ||
| + | ||
| + private void insertObject( final Dialog<String> dialog ) { | ||
| + final var textArea = getActiveTextEditor().getTextArea(); | ||
| + dialog.showAndWait().ifPresent( textArea::replaceSelection ); | ||
| + } | ||
| + | ||
| + private Dialog<String> createLinkDialog() { | ||
| + return new LinkDialog( getWindow(), createHyperlinkModel() ); | ||
| + } | ||
| + | ||
| + private Dialog<String> createImageDialog() { | ||
| + final var path = getActiveTextEditor().getPath(); | ||
| + final var parentDir = path.getParent(); | ||
| + return new ImageDialog( getWindow(), parentDir ); | ||
| + } | ||
| + | ||
| + /** | ||
| + * Returns one of: selected text, word under cursor, or parsed hyperlink from | ||
| + * the Markdown AST. | ||
| + * | ||
| + * @return An instance containing the link URL and display text. | ||
| + */ | ||
| + private HyperlinkModel createHyperlinkModel() { | ||
| + final var context = getMainPane().createProcessorContext(); | ||
| + final var editor = getActiveTextEditor(); | ||
| + final var textArea = editor.getTextArea(); | ||
| + final var selectedText = textArea.getSelectedText(); | ||
| + | ||
| + // Convert current paragraph to Markdown nodes. | ||
| + final var mp = MarkdownProcessor.create( context ); | ||
| + final var p = textArea.getCurrentParagraph(); | ||
| + final var paragraph = textArea.getText( p ); | ||
| + final var node = mp.toNode( paragraph ); | ||
| + final var visitor = new LinkVisitor( textArea.getCaretColumn() ); | ||
| + final var link = visitor.process( node ); | ||
| + | ||
| + if( link != null ) { | ||
| + textArea.selectRange( p, link.getStartOffset(), p, link.getEndOffset() ); | ||
| + } | ||
| + | ||
| + return createHyperlinkModel( link, selectedText ); | ||
| + } | ||
| + | ||
| + private HyperlinkModel createHyperlinkModel( | ||
| + final Link link, final String selection ) { | ||
| + | ||
| + return link == null | ||
| + ? new HyperlinkModel( selection, "https://localhost" ) | ||
| + : new HyperlinkModel( link ); | ||
| + } | ||
| + | ||
| + public void insert‿heading_1() { | ||
| + insert‿heading( 1 ); | ||
| + } | ||
| + | ||
| + public void insert‿heading_2() { | ||
| + insert‿heading( 2 ); | ||
| + } | ||
| + | ||
| + public void insert‿heading_3() { | ||
| + insert‿heading( 3 ); | ||
| + } | ||
| + | ||
| + private void insert‿heading( final int level ) { | ||
| + getActiveTextEditor().heading( level ); | ||
| + } | ||
| + | ||
| + public void insert‿unordered_list() { | ||
| + getActiveTextEditor().unorderedList(); | ||
| + } | ||
| + | ||
| + public void insert‿ordered_list() { | ||
| + getActiveTextEditor().orderedList(); | ||
| + } | ||
| + | ||
| + public void insert‿horizontal_rule() { | ||
| + getActiveTextEditor().horizontalRule(); | ||
| + } | ||
| + | ||
| + public void definition‿create() { | ||
| + getActiveTextDefinition().createDefinition(); | ||
| + } | ||
| + | ||
| + public void definition‿rename() { | ||
| + getActiveTextDefinition().renameDefinition(); | ||
| + } | ||
| + | ||
| + public void definition‿delete() { | ||
| + getActiveTextDefinition().deleteDefinitions(); | ||
| + } | ||
| + | ||
| + public void definition‿autoinsert() { | ||
| + getMainPane().autoinsert(); | ||
| + } | ||
| + | ||
| + public void view‿refresh() { | ||
| + getMainPane().viewRefresh(); | ||
| + } | ||
| + | ||
| + public void view‿preview() { | ||
| + getMainPane().viewPreview(); | ||
| + } | ||
| + | ||
| + public void view‿issues() { | ||
| + StatusNotifier.viewIssues(); | ||
| } | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.ui.actions; | ||
| addAction( "view.refresh", e -> actions.view‿refresh() ), | ||
| SEPARATOR_ACTION, | ||
| - addAction( "view.preview", e -> actions.view‿preview() ) | ||
| + addAction( "view.preview", e -> actions.view‿preview() ), | ||
| + addAction( "view.issues", e -> actions.view‿issues() ) | ||
| ), | ||
| createMenu( | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.ui.actions; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.ui.actions; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.ui.actions; | ||
| -/* Copyright 2020 White Magic Software, Ltd. | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. | ||
| * | ||
| * All rights reserved. |
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.ui.adapters; | ||
| import org.xhtmlrenderer.event.DocumentListener; | ||
| -import static com.keenwrite.StatusBarNotifier.clue; | ||
| +import static com.keenwrite.StatusNotifier.clue; | ||
| /** |
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.ui.adapters; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.ui.controls; | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +package com.keenwrite.ui.logging; | ||
| + | ||
| +import javafx.beans.property.SimpleStringProperty; | ||
| +import javafx.beans.property.StringProperty; | ||
| +import javafx.collections.ObservableList; | ||
| +import javafx.scene.control.Alert; | ||
| +import javafx.scene.control.TableColumn; | ||
| +import javafx.scene.control.TableView; | ||
| +import javafx.scene.input.ClipboardContent; | ||
| +import javafx.scene.input.KeyCodeCombination; | ||
| +import javafx.stage.Stage; | ||
| + | ||
| +import java.io.PrintWriter; | ||
| +import java.io.StringWriter; | ||
| +import java.time.LocalDateTime; | ||
| +import java.util.TreeSet; | ||
| + | ||
| +import static com.keenwrite.Constants.ICON_DIALOG; | ||
| +import static com.keenwrite.Messages.get; | ||
| +import static java.time.LocalDateTime.now; | ||
| +import static java.time.format.DateTimeFormatter.ofPattern; | ||
| +import static javafx.collections.FXCollections.observableArrayList; | ||
| +import static javafx.scene.control.Alert.AlertType.INFORMATION; | ||
| +import static javafx.scene.control.SelectionMode.MULTIPLE; | ||
| +import static javafx.scene.input.Clipboard.getSystemClipboard; | ||
| +import static javafx.scene.input.KeyCode.C; | ||
| +import static javafx.scene.input.KeyCode.INSERT; | ||
| +import static javafx.scene.input.KeyCombination.CONTROL_ANY; | ||
| +import static javafx.stage.Modality.NONE; | ||
| + | ||
| +/** | ||
| + * Responsible for logging application issues to {@link TableView} entries. | ||
| + */ | ||
| +public class LogView extends Alert { | ||
| + /** | ||
| + * Number of error messages to retain in the {@link TableView}, must be | ||
| + * greater than zero. | ||
| + */ | ||
| + private static final int CACHE_SIZE = 150; | ||
| + | ||
| + private final ObservableList<LogEntry> mEntries = observableArrayList(); | ||
| + private final TableView<LogEntry> mTable = new TableView<>( mEntries ); | ||
| + | ||
| + public LogView() { | ||
| + super( INFORMATION ); | ||
| + setTitle( get( "App.action.view.issues.text" ) ); | ||
| + initModality( NONE ); | ||
| + initTableView(); | ||
| + setResizable( true ); | ||
| + } | ||
| + | ||
| + /** | ||
| + * Brings the dialog to the foreground, showing it if needed. | ||
| + */ | ||
| + public void view() { | ||
| + super.show(); | ||
| + getStage().toFront(); | ||
| + } | ||
| + | ||
| + public void log( final String message ) { | ||
| + log( new LogEntry( message ) ); | ||
| + } | ||
| + | ||
| + public void log( final Throwable error ) { | ||
| + log( new LogEntry( error ) ); | ||
| + } | ||
| + | ||
| + public void log( final String message, final Throwable trace ) { | ||
| + log( new LogEntry( message, trace ) ); | ||
| + } | ||
| + | ||
| + private void log( final LogEntry logEntry ) { | ||
| + mEntries.add( logEntry ); | ||
| + | ||
| + while( mEntries.size() > CACHE_SIZE ) { | ||
| + mEntries.remove( 0 ); | ||
| + } | ||
| + | ||
| + mTable.scrollTo( logEntry ); | ||
| + } | ||
| + | ||
| + private void initTableView() { | ||
| + final var ctrlC = new KeyCodeCombination( C, CONTROL_ANY ); | ||
| + final var ctrlInsert = new KeyCodeCombination( INSERT, CONTROL_ANY ); | ||
| + | ||
| + final var colDate = new TableColumn<LogEntry, String>( "Date" ); | ||
| + final var colMessage = new TableColumn<LogEntry, String>( "Message" ); | ||
| + final var colTrace = new TableColumn<LogEntry, String>( "Trace" ); | ||
| + | ||
| + colDate.setCellValueFactory( log -> log.getValue().dateProperty() ); | ||
| + colMessage.setCellValueFactory( log -> log.getValue().messageProperty() ); | ||
| + colTrace.setCellValueFactory( log -> log.getValue().traceProperty() ); | ||
| + | ||
| + final var columns = mTable.getColumns(); | ||
| + columns.add( colDate ); | ||
| + columns.add( colMessage ); | ||
| + columns.add( colTrace ); | ||
| + | ||
| + mTable.setMaxWidth( Double.MAX_VALUE ); | ||
| + mTable.setPrefWidth( 1024 ); | ||
| + mTable.getSelectionModel().setSelectionMode( MULTIPLE); | ||
| + mTable.setOnKeyPressed( event -> { | ||
| + if( ctrlC.match( event ) || ctrlInsert.match( event ) ) { | ||
| + copyToClipboard( mTable ); | ||
| + } | ||
| + } ); | ||
| + | ||
| + final var pane = getDialogPane(); | ||
| + pane.setContent( mTable ); | ||
| + | ||
| + final var stage = getStage(); | ||
| + stage.getIcons().add( ICON_DIALOG ); | ||
| + } | ||
| + | ||
| + private Stage getStage() { | ||
| + return (Stage) getDialogPane().getScene().getWindow(); | ||
| + } | ||
| + | ||
| + private static final class LogEntry { | ||
| + private final StringProperty mDate; | ||
| + private final StringProperty mMessage; | ||
| + private final StringProperty mTrace; | ||
| + | ||
| + /** | ||
| + * Constructs a new {@link LogEntry} for the current time, and having | ||
| + * no associated stack trace. | ||
| + * | ||
| + * @param message The error message. | ||
| + */ | ||
| + public LogEntry( final String message ) { | ||
| + this( message, null ); | ||
| + } | ||
| + | ||
| + /** | ||
| + * Constructs a new {@link LogEntry} for the current time, and using | ||
| + * the given error's message. | ||
| + * | ||
| + * @param error The stack trace, must not be {@code null}. | ||
| + */ | ||
| + public LogEntry( final Throwable error ) { | ||
| + this( error.getMessage(), error ); | ||
| + } | ||
| + | ||
| + /** | ||
| + * Constructs a new {@link LogEntry} with the current date and time. | ||
| + * | ||
| + * @param message The error message. | ||
| + * @param trace The stack trace associated with the message, may be | ||
| + * {@code null}. | ||
| + */ | ||
| + public LogEntry( final String message, final Throwable trace ) { | ||
| + mDate = new SimpleStringProperty( toString( now() ) ); | ||
| + mMessage = new SimpleStringProperty( message ); | ||
| + mTrace = new SimpleStringProperty( toString( trace ) ); | ||
| + } | ||
| + | ||
| + private StringProperty messageProperty() {return mMessage;} | ||
| + | ||
| + private StringProperty dateProperty() { return mDate;} | ||
| + | ||
| + private StringProperty traceProperty() { return mTrace;} | ||
| + | ||
| + private String toString( final LocalDateTime date ) { | ||
| + return date.format( ofPattern( "d MMM u HH:mm:ss" ) ); | ||
| + } | ||
| + | ||
| + private String toString( final Throwable trace ) { | ||
| + try( final StringWriter sw = new StringWriter(); | ||
| + final PrintWriter pw = new PrintWriter( sw ) ) { | ||
| + if( trace != null ) { | ||
| + trace.printStackTrace( pw ); | ||
| + } | ||
| + return sw.toString(); | ||
| + } catch( final Exception ex ) { | ||
| + return ""; | ||
| + } | ||
| + } | ||
| + } | ||
| + | ||
| + public void copyToClipboard( final TableView<?> table ) { | ||
| + final var sb = new StringBuilder(); | ||
| + final var rows = new TreeSet<Integer>(); | ||
| + boolean firstRow = true; | ||
| + | ||
| + for( final var position : table.getSelectionModel().getSelectedCells() ) { | ||
| + rows.add( position.getRow() ); | ||
| + } | ||
| + | ||
| + for( final var row : rows ) { | ||
| + if( !firstRow ) { | ||
| + sb.append( '\n' ); | ||
| + } | ||
| + firstRow = false; | ||
| + boolean firstCol = true; | ||
| + for( final var column : table.getColumns() ) { | ||
| + if( !firstCol ) { | ||
| + sb.append( '\t' ); | ||
| + } | ||
| + firstCol = false; | ||
| + final var data = column.getCellData( row ); | ||
| + sb.append( data == null ? "" : data.toString() ); | ||
| + } | ||
| + } | ||
| + | ||
| + final var contents = new ClipboardContent(); | ||
| + contents.putString( sb.toString() ); | ||
| + getSystemClipboard().setContent( contents ); | ||
| + } | ||
| +} | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.util; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.util; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.util; | ||
| import static com.keenwrite.Constants.FONT_DIRECTORY; | ||
| -import static com.keenwrite.StatusBarNotifier.clue; | ||
| +import static com.keenwrite.StatusNotifier.clue; | ||
| import static com.keenwrite.util.ProtocolScheme.valueFrom; | ||
| import static com.keenwrite.util.ResourceWalker.GLOB_FONTS; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.util; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.util; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.util; | ||
| App.action.view.refresh.text=Refresh | ||
| +App.action.view.issues.description=Open document issues | ||
| +App.action.view.issues.accelerator=F6 | ||
| +App.action.view.issues.text=Issues | ||
| + | ||
| App.action.view.preview.description=Open document preview | ||
| App.action.view.preview.accelerator=F7 | ||
| App.action.view.preview.text=Preview | ||
| App.action.view.outline.description=Open document outline | ||
| App.action.view.outline.accelerator=F8 | ||
| App.action.view.outline.text=Outline | ||
| - | ||
| App.action.view.files.description=Open file system browser |
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.definition; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.io; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.processors.markdown; | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.r; | ||
| /* | ||
| - * Copyright 2020 White Magic Software, Ltd. | ||
| + * Copyright 2020-2021 White Magic Software, Ltd. | ||
| * | ||
| * All rights reserved. |
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */ | ||
| package com.keenwrite.util; | ||
| Delta | 841 lines added, 609 lines removed, 232-line increase |
|---|