edu.chl.proton.control.MarkdownTabController.java Source code

Java tutorial

Introduction

Here is the source code for edu.chl.proton.control.MarkdownTabController.java

Source

/*
 * Proton Text - A Markdown text editor
 * Copyright (C) 2017  Anton Levholm, Ludvig Ekman, Mickaela Sdergren
 * and Stina Werme
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package edu.chl.proton.control;

import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import com.sun.javafx.webkit.Accessor;
import com.sun.webkit.WebPage;
import edu.chl.proton.model.workspace.IDocumentHandler;
import edu.chl.proton.model.workspace.IFileHandler;
import edu.chl.proton.model.workspace.IStageHandler;
import edu.chl.proton.model.workspace.WorkspaceFactory;
import edu.chl.proton.view.popup.TextPrompt;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.web.HTMLEditor;
import javafx.scene.web.WebView;
import javafx.stage.FileChooser;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Observable;
import java.util.Observer;

/**
 * @author Anton Levholm
 * Created by antonlevholm on 2017-05-01.
 *
 * This class controls all functionality of open tabs (Markdown documents).
 */
public class MarkdownTabController {
    private static IFileHandler file;
    private static IDocumentHandler document;
    private IStageHandler stage;

    @FXML
    private HTMLEditor htmlEditor;
    @FXML
    private WebView webView;

    public void initialize() throws IOException {
        WorkspaceFactory factory = new WorkspaceFactory();
        Observable observable = factory.getWorkspace().getCurrentDocument();
        new UpdateView(observable);
        file = factory.getWorkspace();
        document = factory.getWorkspace();
        stage = factory.getWorkspace();
        hideHTMLEditorToolbars(htmlEditor);

        htmlEditor.setOnKeyReleased(new EventHandler<KeyEvent>() {
            @Override
            public void handle(KeyEvent event) {
                if (isValidEvent(event)) {
                    document.setText(htmlEditor.getHtmlText());
                }
            }

            private boolean isValidEvent(KeyEvent event) {
                return !isSelectAllEvent(event) && ((isPasteEvent(event)) || isCharacterKeyReleased(event));
            }

            private boolean isSelectAllEvent(KeyEvent event) {
                return event.isShortcutDown() && event.getCode() == KeyCode.A;
            }

            private boolean isPasteEvent(KeyEvent event) {
                return event.isShortcutDown() && event.getCode() == KeyCode.V;
            }

            private boolean isCharacterKeyReleased(KeyEvent event) {
                // Make custom changes here..
                switch (event.getCode()) {
                case ALT:
                case COMMAND:
                case CONTROL:
                case SHIFT:
                    return false;
                default:
                    return true;
                }
            }
        });
    }

    /**
     * Hides the default toolbar in HTMLEditor.
     * @param editor object to remove toolbar from.
     */
    // Found at http://stackoverflow.com/questions/10075841/how-to-hide-the-controls-of-htmleditor
    private static void hideHTMLEditorToolbars(final HTMLEditor editor) {
        editor.setVisible(false);
        Platform.runLater(() -> {
            Node[] nodes = editor.lookupAll(".tool-bar").toArray(new Node[0]);
            for (Node node : nodes) {
                node.setVisible(false);
                node.setManaged(false);
            }
            editor.setVisible(true);
        });
    }

    /**
     * Generates a PDF from the HTML String that getHTML() in IDocumentHandler returns.
     * @throws IOException if typecasting to WebView fails.
     * @throws DocumentException if the PDF cannot be created.
     */
    @FXML
    public void onClickGeneratePDF() throws IOException, DocumentException {
        String path = file.getCurrentDirectory().getPath() + "/untitled.pdf";
        String title = "Output filepath";
        TextPrompt prompt = new TextPrompt(stage.getStage(), title, path);
        if ((path = prompt.getResult()) != null) {
            com.itextpdf.text.Document doc = new com.itextpdf.text.Document();
            PdfWriter writer = PdfWriter.getInstance(doc, new FileOutputStream(path));
            writer.setInitialLeading(12);
            doc.open();
            XMLWorkerHelper.getInstance().parseXHtml(writer, doc,
                    new ByteArrayInputStream(document.getHTML().getBytes()));
            doc.close();
        }
    }

    /**
     * Creates text template for inserting of links
     * @throws IOException if typecasting to WebView fails.
     */
    @FXML
    public void onClickLinkButton() throws IOException {
        WebView webView = (WebView) htmlEditor.lookup("WebView");
        WebPage webPage = Accessor.getPageFor(webView.getEngine());
        webPage.executeCommand("insertText", "[text about link](http://url here)");
    }

    /**
     * Creates text template for inserting of headers.
     * @throws IOException if typecasting to WebView fails.
     */
    @FXML
    public void onClickHeadingButton() throws IOException {
        WebView webView = (WebView) htmlEditor.lookup("WebView");
        WebPage webPage = Accessor.getPageFor(webView.getEngine());
        webPage.executeCommand("insertText", "#");
    }

    /**
     * Creates text template for inserting of bold text.
     * @throws IOException if typecasting to WebView fails.
     */
    @FXML
    public void onClickBoldButton() throws IOException {
        WebView webView = (WebView) htmlEditor.lookup("WebView");
        WebPage webPage = Accessor.getPageFor(webView.getEngine());
        webPage.executeCommand("insertText", "****");
    }

    /**
     * Creates text template for inserting of italic text.
     * @throws IOException if typecasting to WebView fails.
     */
    @FXML
    public void onClickItalicButton() throws IOException {
        WebView webView = (WebView) htmlEditor.lookup("WebView");
        WebPage webPage = Accessor.getPageFor(webView.getEngine());
        webPage.executeCommand("insertText", "**");
    }

    /**
     * Creates text template for inserting of quote text.
     * @throws IOException if typecasting to WebView fails.
     */
    @FXML
    public void onClickQuoteButton() throws IOException {
        WebView webView = (WebView) htmlEditor.lookup("WebView");
        WebPage webPage = Accessor.getPageFor(webView.getEngine());
        webPage.executeCommand("insertText", "\n> ");
    }

    /**
     * Inserts image from file directory with help from user through file choosing,
     * or if image from web: creates text template.
     * @throws IOException if typecasting to WebView fails.
     */
    @FXML
    public void onClickImageButton() throws IOException {
        Alert alert = new Alert(Alert.AlertType.CONFIRMATION, "Is the image in your file system?", ButtonType.YES,
                ButtonType.NO);
        alert.showAndWait();

        if (alert.getResult() == ButtonType.NO) {
            WebView webView = (WebView) htmlEditor.lookup("WebView");
            WebPage webPage = Accessor.getPageFor(webView.getEngine());
            webPage.executeCommand("insertText", "![text about image](Image URL)");
        } else {
            FileChooser fileChooser = new FileChooser();
            fileChooser.setTitle("Choose image");
            File file = fileChooser.showOpenDialog(stage.getStage());
            if (file != null && file.isFile()) {
                if (isImage(file.getPath())) {
                    WebView webView = (WebView) htmlEditor.lookup("WebView");
                    WebPage webPage = Accessor.getPageFor(webView.getEngine());
                    webPage.executeCommand("insertText", "![text about image](" + file.toURI() + ")");
                } else {
                    Alert alert2 = new Alert(Alert.AlertType.ERROR, "File choosen is not an image.");
                    alert2.showAndWait();
                }
            }
        }
    }

    /**
     * Creates text template for inserting of code text
     * @throws IOException if typecasting to WebView fails.
     */
    @FXML
    public void onClickCodeButton() throws IOException {
        WebView webView = (WebView) htmlEditor.lookup("WebView");
        WebPage webPage = Accessor.getPageFor(webView.getEngine());
        webPage.executeCommand("insertText", "``````");
    }

    /**
     * Creates text template for inserting of ordered listing
     * @throws IOException if typecasting to WebView fails.
     */
    @FXML
    public void onClickOrderedListButton() throws IOException {
        WebView webView = (WebView) htmlEditor.lookup("WebView");
        WebPage webPage = Accessor.getPageFor(webView.getEngine());
        webPage.executeCommand("insertText", "\n1.   ");
    }

    /**
     * Creates text template for inserting of unordered listing
     * @throws IOException if typecasting to WebView fails.
     */
    @FXML
    public void onClickUnorderedListButton() throws IOException {
        WebView webView = (WebView) htmlEditor.lookup("WebView");
        WebPage webPage = Accessor.getPageFor(webView.getEngine());
        webPage.executeCommand("insertText", "\n*     ");
    }

    /**
     * Creates markdown text for horizontal line
     * @throws IOException if typecasting to WebView fails.
     */
    @FXML
    public void onClickHorizontalLineButton() throws IOException {
        WebView webView = (WebView) htmlEditor.lookup("WebView");
        WebPage webPage = Accessor.getPageFor(webView.getEngine());
        webPage.executeCommand("insertText", "\n*****\n");
    }

    /**
     * Class used for observing changes in the corresponding tab in the model.
     */
    public class UpdateView implements Observer {
        Observable observable;

        UpdateView(Observable observable) {
            this.observable = observable;
            observable.addObserver(this);
        }

        @Override
        public void update(Observable o, Object arg) {
            if (MainController.fileIsOpened()) {
                String text = document.getText();
                htmlEditor.setHtmlText(text);
                MainController.fileHasOpened();
            }
            String html = document.getHTML();
            webView.getEngine().loadContent(html);
        }
    }

    /**
     * Method for checking file type.
     * @param string containing the file path.
     * @return true if the file is an accepted image file.
     */
    private boolean isImage(String string) {
        if (string.substring(string.length() - 4).equals(".pdf")
                || string.substring(string.length() - 4).equals(".gif")
                || string.substring(string.length() - 4).equals(".png")
                || string.substring(string.length() - 4).equals(".jpg")
                || string.substring(string.length() - 5).equals(".jpeg")
                || string.substring(string.length() - 4).equals(".tif")
                || string.substring(string.length() - 4).equals(".bmp")) {
            return true;
        }
        return false;
    }

}