Skip to content

Commit

Permalink
Extract About tab controller (#475)
Browse files Browse the repository at this point in the history
- extract AboutView controller and FMXL
- refactor AboutViewController to make better use of Optional and Stream
- add Google Guava library to dependencies

Closes #456.
  • Loading branch information
skaldarnar authored Nov 15, 2019
1 parent 0986204 commit a48d817
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 86 deletions.
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ dependencies {

compile group: 'com.google.code.gson', name: 'gson', version: '2.8.5'
compile group: 'ch.qos.logback', name: 'logback-classic', version: '1.1.2'

implementation("com.google.guava:guava:28.1-jre")

// For Web API
// TODO: extract swagger dependencies into swagger.gradle
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package org.terasology.launcher.gui.javafx;

import com.github.rjeschke.txtmark.Configuration;
import com.github.rjeschke.txtmark.Processor;
import com.google.common.io.Files;
import javafx.fxml.FXML;
import javafx.scene.control.Accordion;
import javafx.scene.control.TitledPane;
import javafx.scene.layout.AnchorPane;
import javafx.scene.web.WebView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.terasology.launcher.util.BundleUtils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;

/**
* Controller for the <b>About</b> section in the tab view.
*
* Presents static content which is compiled from Markdown and HTML documents.
*/
public class AboutViewController {

private static final Logger logger = LoggerFactory.getLogger(AboutViewController.class);

/** Bundle key for the resources related to this view. */
private static final String ABOUT = "about";

private static final Charset UTF_8 = Charset.forName("UTF-8");

@FXML
private Accordion aboutInfoAccordion;

@FXML
public void initialize() {
update();
}

/**
* Update/reload the <b>About</b> view.
*
* This will reload and parse the files to display again!
*/
public void update() {
aboutInfoAccordion.getPanes().clear();

Stream.of("README.md", "CHANGELOG.md", "CONTRIBUTING.md", "LICENSE")
.map(filename -> BundleUtils.getFXMLUrl(ABOUT, filename))
.filter(Objects::nonNull)
.map(this::getPaneFor)
.filter(Optional::isPresent)
.map(Optional::get)
.forEach(aboutInfoAccordion.getPanes()::add);

if (!aboutInfoAccordion.getPanes().isEmpty()) {
aboutInfoAccordion.setExpandedPane(aboutInfoAccordion.getPanes().get(0));
}
}

private Optional<TitledPane> getPaneFor(URL url) {
return getViewFor(url)
.map(view -> {
view.getStylesheets().add(BundleUtils.getFXMLUrl("css_webview").toExternalForm());
view.setContextMenuEnabled(false);
return view;
})
.map(view -> {
final AnchorPane pane = new AnchorPane();
AnchorPane.setBottomAnchor(view, 0.0);
AnchorPane.setTopAnchor(view, 0.0);
pane.getChildren().add(view);
return pane;
})
.map(contentPane -> {
String fname = Files.getNameWithoutExtension(url.getFile());
final TitledPane titledPane = new TitledPane(fname, contentPane);
titledPane.setAnimated(false);
return titledPane;
});
}

private Optional<WebView> getViewFor(URL url) {
switch (Files.getFileExtension(url.getFile().toLowerCase())) {
case "md":
case "markdown":
return renderMarkdown(url);
case "htm":
case "html":
return renderHtml(url);
default:
return renderUnknown(url);
}

}

private Optional<WebView> renderMarkdown(URL url) {
WebView view = null;
try (InputStream input = url.openStream()) {
view = new WebView();
String content = new StringBuilder()
.append("<body style='padding-left:24px;'>\n")
.append(Processor.process(input, Configuration.DEFAULT))
.append("</body>")
.toString();
view.getEngine().loadContent(content, "text/html");
} catch (IOException e) {
logger.warn("Could not render markdown file: {}", url);
}
return Optional.ofNullable(view);
}

private Optional<WebView> renderHtml(URL url) {
final WebView view = new WebView();
view.getEngine().load(url.toExternalForm());
return Optional.of(view);
}

private Optional<WebView> renderUnknown(URL url) {
WebView view = null;
try (Reader isr = new InputStreamReader(url.openStream(), UTF_8);
BufferedReader br = new BufferedReader(isr)) {

view = new WebView();
StringBuilder content = new StringBuilder();
String line = br.readLine();

while (line != null) {
content.append(line);
content.append(System.lineSeparator());
line = br.readLine();
}
view.getEngine().loadContent(content.toString(), "text/plain");
} catch (IOException e) {
logger.warn("Could not render file: {}", url);
}
return Optional.ofNullable(view);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

package org.terasology.launcher.gui.javafx;

import com.github.rjeschke.txtmark.Configuration;
import com.github.rjeschke.txtmark.Processor;
import javafx.animation.ScaleTransition;
import javafx.animation.Transition;
import javafx.application.HostServices;
Expand All @@ -30,20 +28,17 @@
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Accordion;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.TabPane;
import javafx.scene.control.TitledPane;
import javafx.scene.control.Tooltip;
import javafx.scene.effect.BlendMode;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.web.WebView;
import javafx.stage.Modality;
import javafx.stage.Stage;
Expand All @@ -63,26 +58,17 @@
import org.terasology.launcher.util.ProgressListener;
import org.terasology.launcher.version.TerasologyLauncherVersionInfo;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.MalformedURLException;
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.util.List;
import java.util.Objects;
import java.util.ResourceBundle;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Stream;

public class ApplicationController {

private static final Logger logger = LoggerFactory.getLogger(ApplicationController.class);
private static final String ABOUT = "about";

private static final long MB = 1024L * 1024;
private static final long MINIMUM_FREE_SPACE = 200 * MB;
Expand Down Expand Up @@ -196,7 +182,7 @@ public void onDone(Runnable cleanupCallback) {
@FXML
private Label versionInfo;
@FXML
private Accordion aboutInfoAccordion;
private AboutViewController aboutViewController;
@FXML
private Button settingsButton;
@FXML
Expand Down Expand Up @@ -635,7 +621,7 @@ private void updateGui() {
updateLabels();
updateTooltipTexts();
updateChangeLog();
updateAboutTab();
aboutViewController.update();
}

private void updateLabels() {
Expand Down Expand Up @@ -743,70 +729,6 @@ private void updateChangeLog() {
changelogView.getEngine().setUserStyleSheetLocation(BundleUtils.getFXMLUrl("css_webview").toExternalForm());
}

private void updateAboutTab() {
aboutInfoAccordion.getPanes().clear();
Charset cs = Charset.forName("UTF-8");

Stream.of("README.md", "CHANGELOG.md", "CONTRIBUTING.md", "LICENSE")
.map(filename -> BundleUtils.getFXMLUrl(ABOUT, filename))
.filter(Objects::nonNull)
.forEach(url -> {
try {
int fnameIdx = url.getFile().lastIndexOf('/');
int extIdx = url.getFile().lastIndexOf('.');
String fname = url.getFile().substring(fnameIdx + 1);
String ext = extIdx < 0 ? "" : url.getFile().substring(extIdx + 1).toLowerCase();

final WebView view = new WebView();
StringBuilder sb = new StringBuilder();

if (ext.equals("md") || ext.equals("markdown")) {
try (InputStream input = url.openStream()) {
sb.append("<body style='padding-left:24px;'>\n");
sb.append(Processor.process(input, Configuration.DEFAULT));
sb.append("</body>");
view.getEngine().loadContent(sb.toString(), "text/html");
}
} else if (ext.equals("htm") || ext.equals("html")) {
view.getEngine().load(url.toExternalForm());
} else {
try (Reader isr = new InputStreamReader(url.openStream(), cs);
BufferedReader br = new BufferedReader(isr)) {
String line = br.readLine();

while (line != null) {
sb.append(line);
sb.append(System.lineSeparator());
line = br.readLine();
}
view.getEngine().loadContent(sb.toString(), "text/plain");
}
}

view.getStylesheets().add(BundleUtils.getFXMLUrl("css_webview").toExternalForm());
view.setContextMenuEnabled(false);

final AnchorPane pane = new AnchorPane();
AnchorPane.setBottomAnchor(view, 0.0);
AnchorPane.setTopAnchor(view, 0.0);
pane.getChildren().add(view);

final TitledPane titledPane = new TitledPane(fname, pane);
titledPane.setAnimated(false);

aboutInfoAccordion.getPanes().add(titledPane);
} catch (MalformedURLException e) {
logger.warn("Could not load info file -- {}", url);
} catch (IOException e) {
logger.warn("Failed to parse markdown file {}", url, e);
}
});

if (!aboutInfoAccordion.getPanes().isEmpty()) {
aboutInfoAccordion.setExpandedPane(aboutInfoAccordion.getPanes().get(0));
}
}

private String getGameInfoText(TerasologyGameVersion gameVersion) {
// logger.debug("Display game version: {} {}", gameVersion, gameVersion.getGameVersionInfo());
//
Expand Down
12 changes: 12 additions & 0 deletions src/main/resources/org/terasology/launcher/views/about-view.fxml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.control.Accordion?>
<AnchorPane fx:controller="org.terasology.launcher.gui.javafx.AboutViewController"
xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2"
minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
<children>
<Accordion fx:id="aboutInfoAccordion"
prefHeight="336.0" prefWidth="800.0"
AnchorPane.bottomAnchor="8.0" AnchorPane.leftAnchor="8.0" AnchorPane.rightAnchor="8.0"
AnchorPane.topAnchor="8.0"/>
</children>
</AnchorPane>
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

<?import javafx.collections.FXCollections?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Accordion?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.Label?>
Expand Down Expand Up @@ -165,11 +164,7 @@
</Tab>
<Tab fx:id="aboutTab" closable="false" text="About">
<content>
<AnchorPane id="Content" minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
<children>
<Accordion fx:id="aboutInfoAccordion" prefHeight="336.0" prefWidth="800.0" AnchorPane.bottomAnchor="8.0" AnchorPane.leftAnchor="8.0" AnchorPane.rightAnchor="8.0" AnchorPane.topAnchor="8.0" />
</children>
</AnchorPane>
<fx:include fx:id="aboutView" source="about-view.fxml"/>
</content>
</Tab>
<Tab closable="false" text="Logging">
Expand Down

0 comments on commit a48d817

Please sign in to comment.