Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/keenwrite.git
src/main/java/com/keenwrite/MainPane.java
clue();
- // Processing the text will update the status bar.
+ // Processing the text may update the status bar.
process( getActiveTextEditor() );
}
src/main/java/com/keenwrite/io/HttpFacade.java
import java.util.zip.GZIPInputStream;
-import static com.keenwrite.events.StatusEvent.clue;
import static java.lang.System.getProperty;
import static java.lang.System.setProperty;
* @return The server response.
*/
- public static Response httpGet( final URL url ) throws IOException {
- return new Response( url );
+ public static Response httpGet( final URL url ) throws Exception {
+ return new Response(url);
}
/**
* Convenience method to send an HTTP GET request to a server.
*
* @param uri The remote resource to fetch.
* @return The server response.
* @see #httpGet(URL)
*/
- public static Response httpGet( final URI uri ) throws IOException {
- clue( "Main.status.image.request.init" );
+ public static Response httpGet( final URI uri ) throws Exception {
return httpGet( uri.toURL() );
}
* @see #httpGet(URL)
*/
- public static Response httpGet( final String url ) throws IOException {
+ public static Response httpGet( final String url ) throws Exception {
return httpGet( new URL( url ) );
}
private Response( final URL url ) throws IOException {
assert url != null;
+
+ //clue( "Main.status.image.request.init" );
final var connection = url.openConnection();
mConn.setRequestProperty( "connection", "close" );
mConn.connect();
- clue( "Main.status.image.request.fetch", url.getHost() );
+ //clue( "Main.status.image.request.fetch", url.getHost() );
final var code = mConn.getResponseCode();
}
- clue( "Main.status.image.request.success", mediaType );
+ //clue( "Main.status.image.request.success", mediaType );
return mediaType;
}
src/main/java/com/keenwrite/preview/HtmlPreview.java
import com.keenwrite.preferences.LocaleProperty;
import com.keenwrite.preferences.Workspace;
-import javafx.application.Platform;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.StringProperty;
import java.util.Locale;
-import static com.keenwrite.constants.Constants.*;
import static com.keenwrite.Messages.get;
+import static com.keenwrite.constants.Constants.*;
import static com.keenwrite.events.Bus.register;
import static com.keenwrite.events.ScrollLockEvent.fireScrollLockEvent;
import static com.keenwrite.events.StatusEvent.clue;
import static com.keenwrite.preferences.WorkspaceKeys.*;
import static com.keenwrite.ui.fonts.IconFactory.getIconFont;
import static java.awt.BorderLayout.*;
import static java.lang.Math.max;
import static java.lang.String.format;
import static java.lang.Thread.sleep;
-import static javafx.application.Platform.runLater;
import static javafx.scene.CacheHint.SPEED;
import static javax.swing.SwingUtilities.invokeLater;
private String mHead = "";
- private boolean mLocked;
+ private volatile boolean mLocked;
private final JButton mScrollLockButton = new JButton();
}
- final Runnable scrollToBox = () -> {
+ invokeLater( () -> {
int iter = 0;
Box box = null;
scrollTo( box );
- };
-
- if( Platform.isFxApplicationThread() ) {
- scrollToBox.run();
- }
- else {
- runLater( scrollToBox );
- }
+ } );
}
private void scrollTo( final Box box ) {
if( box != null ) {
- scrollTo( createPoint( box ) );
- }
- }
-
- private void scrollTo( final Point point ) {
- invokeLater( () -> {
- mView.scrollTo( point );
+ mView.scrollTo( createPoint( box ) );
getScrollPane().repaint();
- } );
+ }
}
src/main/java/com/keenwrite/processors/PdfProcessor.java
import com.keenwrite.typesetting.Typesetter;
+import javafx.concurrent.Task;
+
+import java.nio.file.Path;
+import java.util.concurrent.ExecutorService;
import static com.keenwrite.Bootstrap.APP_TITLE_LOWERCASE;
import static com.keenwrite.Messages.get;
import static com.keenwrite.events.StatusEvent.clue;
import static com.keenwrite.io.MediaType.TEXT_XML;
import static java.nio.file.Files.writeString;
+import static java.util.concurrent.Executors.newFixedThreadPool;
/**
* Responsible for using a typesetting engine to convert an XHTML document
* into a PDF file.
*/
public final class PdfProcessor extends ExecutorProcessor<String> {
+ private static final ExecutorService sExecutor = newFixedThreadPool( 5 );
private final ProcessorContext mContext;
*/
public String apply( final String xhtml ) {
- try {
- clue( get( "Main.status.typeset.create" ) );
- final var sTypesetter = new Typesetter( mContext.getWorkspace() );
- final var document = TEXT_XML.createTemporaryFile( APP_TITLE_LOWERCASE );
- final var pathOutput = mContext.getExportPath();
+ final var exporter = new Exporter( xhtml );
+ exporter.setOnRunning( e -> clue( get( "Main.status.typeset.create" ) ) );
+ exporter.setOnSucceeded( e -> {
clue( get( "Main.status.typeset.export" ) );
- final var pathInput = writeString( document, xhtml );
- sTypesetter.typeset( pathInput, pathOutput );
- } catch( final Exception ex ) {
- clue( ex );
- }
+
+ final var pathOutput = mContext.getExportPath();
+ final var pathInput = exporter.getValue();
+ final var typesetter = new Typesetter( mContext.getWorkspace() );
+
+ try {
+ typesetter.typeset( pathInput, pathOutput );
+ } catch( final Exception ex ) {
+ clue( ex );
+ }
+ } );
+
+ sExecutor.execute( exporter );
// Do not continue processing (the document was typeset into a binary).
return null;
+ }
+
+ /**
+ * Responsible for exporting the active document to a file. That file is
+ * then read and typeset by a third-party application.
+ */
+ private static class Exporter extends Task<Path> {
+ private final String mXhtml;
+
+ private Exporter( final String xhtml ) {
+ mXhtml = xhtml;
+ }
+
+ @Override
+ protected Path call() throws Exception {
+ final var document = TEXT_XML.createTemporaryFile( APP_TITLE_LOWERCASE );
+ return writeString( document, mXhtml );
+ }
}
}
src/main/java/com/keenwrite/processors/XhtmlProcessor.java
package com.keenwrite.processors;
-import com.keenwrite.io.HttpFacade;
import com.keenwrite.preferences.Workspace;
import static com.keenwrite.Bootstrap.APP_TITLE_LOWERCASE;
import static com.keenwrite.events.StatusEvent.clue;
+import static com.keenwrite.io.HttpFacade.httpGet;
import static com.keenwrite.preferences.WorkspaceKeys.KEY_IMAGES_DIR;
import static com.keenwrite.preferences.WorkspaceKeys.KEY_IMAGES_ORDER;
assert context != null;
-
mContext = context;
}
// Download remote resources into temporary files.
if( protocol.isRemote() ) {
- final var response = HttpFacade.httpGet( src);
+ final var response = httpGet( src);
final var mediaType = response.getMediaType();
src/main/java/com/keenwrite/typesetting/Typesetter.java
import com.keenwrite.preferences.Key;
import com.keenwrite.preferences.Workspace;
+import javafx.concurrent.Task;
-import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutorService;
+import java.util.concurrent.TimeoutException;
-import static com.keenwrite.constants.Constants.DEFAULT_DIRECTORY;
import static com.keenwrite.Messages.get;
+import static com.keenwrite.constants.Constants.DEFAULT_DIRECTORY;
import static com.keenwrite.events.StatusEvent.clue;
import static com.keenwrite.preferences.WorkspaceKeys.KEY_TYPESET_CONTEXT_ENV;
import static com.keenwrite.preferences.WorkspaceKeys.KEY_TYPESET_CONTEXT_PATH;
+import static java.lang.Long.MAX_VALUE;
import static java.lang.String.format;
import static java.lang.System.currentTimeMillis;
import static java.util.concurrent.Executors.newFixedThreadPool;
import static java.util.concurrent.TimeUnit.*;
/**
- * Represents the executable responsible for typesetting text. This will
+ * Responsible for invoking an executable to typeset text. This will
* construct suitable command-line arguments to invoke the typesetting engine.
*/
public class Typesetter {
- private static final File TYPESETTER = new File( "context" );
-
- private static final ExecutorService sService = newFixedThreadPool( 5 );
+ private static final File TYPESETTER = new File( "mtxrun" );
private final Workspace mWorkspace;
*/
public void typeset( final Path input, final Path output )
- throws IOException {
+ throws Exception {
if( TYPESETTER.canRun() ) {
- sService.submit( new TypesetTask( input, output ) );
+ final var executor = newFixedThreadPool( 5 );
+ final var task = new TypesetTask( input, output );
+ final var elapsed = currentTimeMillis();
+
+ task.setOnRunning(
+ e -> clue( get(
+ "Main.status.typeset.began", output
+ ) )
+ );
+
+ task.setOnSucceeded(
+ e -> clue( get(
+ "Main.status.typeset.ended.success", output, since( elapsed )
+ ) )
+ );
+
+ task.setOnFailed(
+ e -> clue( get(
+ "Main.status.typeset.ended.failure",
+ output, since( elapsed ), task.getValue()
+ ) )
+ );
+
+ executor.execute( task );
+ executor.shutdown();
+ if( !executor.awaitTermination( MAX_VALUE, NANOSECONDS ) ) {
+ throw new TimeoutException();
+ }
}
}
/**
* Launches a task to typeset a document.
*/
- public class TypesetTask implements Callable<Integer> {
+ private class TypesetTask extends Task<Integer> {
private final List<String> mArgs = new ArrayList<>();
/**
* Working directory must be set because ConTeXt cannot write the
* result to an arbitrary location.
*/
private final Path mDirectory;
-
- /**
- * Fully qualified destination file name.
- */
- private final Path mOutput;
public TypesetTask( final Path input, final Path output ) {
final var filename = output.getFileName();
final var parentDir = output.getParent();
mDirectory = (parentDir == null ? DEFAULT_DIRECTORY : parentDir);
- mOutput = output;
final var paths = getProperty( KEY_TYPESET_CONTEXT_PATH );
final var envs = getProperty( KEY_TYPESET_CONTEXT_ENV );
mArgs.add( TYPESETTER.getName() );
+ mArgs.add( "--autogenerate" );
+ mArgs.add( "--script" );
+ mArgs.add( "mtx-context" );
mArgs.add( "--batchmode" );
mArgs.add( "--purgeall" );
@Override
public Integer call() throws Exception {
- final var elapsed = currentTimeMillis();
- final var output = mOutput.toString();
- clue( get( "Main.status.typeset.began", output ) );
-
final var builder = new ProcessBuilder( mArgs );
builder.directory( mDirectory.toFile() );
- // TODO: Create luatex-cache directory in system temporary directory.
-// final var env = builder.environment();
-// env.put( "TEXMFCACHE", System.getProperty( "java.io.tmpdir" ) );
+ final var env = builder.environment();
+ env.put( "TEXMFCACHE", System.getProperty( "java.io.tmpdir" ) );
+ //final var process = builder.inheritIO().start();
final var process = builder.start();
process.waitFor();
-
- final var code = process.exitValue();
- final var time = asElapsed( currentTimeMillis() - elapsed );
- clue(
- code == 0
- ? get( "Main.status.typeset.ended.success", output, time )
- : get( "Main.status.typeset.ended.failure", output, time, code )
- );
-
- return code;
+ final int exit = process.exitValue();
+ process.destroy();
+ return exit;
}
}
private String getProperty( final Key key ) {
return mWorkspace.stringProperty( key ).get();
+ }
+
+ /**
+ * Calculates the time that has elapsed from the current time to the
+ * given moment in time.
+ *
+ * @param start The starting time, which really should be before the
+ * current time.
+ * @return A human-readable formatted time.
+ * @see #asElapsed(long)
+ */
+ private static String since( final long start ) {
+ return asElapsed( currentTimeMillis() - start );
}
src/main/java/com/keenwrite/ui/controls/EventedStatusBar.java
import static com.keenwrite.events.Bus.register;
+import static javafx.application.Platform.isFxApplicationThread;
import static javafx.application.Platform.runLater;
// Don't burden the repaint thread if there's no status bar change.
if( !getText().equals( message ) ) {
- runLater(
- () -> {
- final var s = message == null ? "" : message;
- final var i = s.indexOf( '\n' );
- setText( s.substring( 0, i > 0 ? i : s.length() ) );
- }
- );
+ final var s = message == null ? "" : message;
+ final var i = s.indexOf( '\n' );
+
+ final Runnable update =
+ () -> setText( s.substring( 0, i > 0 ? i : s.length() ) );
+
+ if( isFxApplicationThread() ) {
+ update.run();
+ }
+ else {
+ runLater( update );
+ }
}
}

Address flaky Swing threading, change cache directory

Author DaveJarvis <email>
Date 2021-04-06 16:34:51 GMT-0700
Commit 69b4fccaecaf80c748504edbe4094aec8dd489d1
Parent b34b0ef
Delta 128 lines added, 84 lines removed, 44-line increase