com.joliciel.talismane.terminology.viewer.TerminologyViewerController.java Source code

Java tutorial

Introduction

Here is the source code for com.joliciel.talismane.terminology.viewer.TerminologyViewerController.java

Source

/*
 * Copyright (c) 2011, 2012 Oracle and/or its affiliates.
 * All rights reserved. Use is subject to license terms.
 *
 * This file is available and licensed under the following license:
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  - Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  - Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the distribution.
 *  - Neither the name of Oracle nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package com.joliciel.talismane.terminology.viewer;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.Scanner;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.joliciel.talismane.terminology.Context;
import com.joliciel.talismane.terminology.Term;
import com.joliciel.talismane.terminology.TerminologyBase;
import com.joliciel.talismane.terminology.TerminologyService;
import com.joliciel.talismane.terminology.TerminologyServiceLocator;
import com.joliciel.talismane.utils.CSVFormatter;

import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.VBoxBuilder;
import javafx.scene.text.Text;
import javafx.stage.FileChooser;
import javafx.stage.Modality;
import javafx.stage.Stage;

public class TerminologyViewerController {
    private static final Log LOG = LogFactory.getLog(TerminologyViewerController.class);
    private static CSVFormatter CSV = new CSVFormatter();

    @FXML
    private TableView<Term> tblTerms;
    @FXML
    private TableView<Context> tblContexts;
    @FXML
    private TextField txtMinFrequency;
    @FXML
    private TextField txtSearch;
    @FXML
    private TextField txtTop;
    @FXML
    private Button btnReload;
    @FXML
    private CheckBox chkMarked;
    @FXML
    private CheckBox chkExpansions;
    @FXML
    private Label lblTermCount;

    TerminologyBase terminologyBase = null;
    Stage primaryStage = null;
    String editor = null;
    String arguments = null;
    String databaseURL = null;
    String databaseUsername = null;
    String databasePassword = null;
    String projectCode = null;
    String csvSeparator = ",";

    LinkedList<TermTableDefinition> termTableHistory = new LinkedList<TermTableDefinition>();
    int currentHistoryIndex = -1;

    @FXML
    protected void initialize() throws Exception {
        String currentDirPath = System.getProperty("user.dir");
        File confDir = new File(currentDirPath + "/conf/");
        confDir.mkdirs();
        File iniFile = new File(confDir, "talismane_terminology_viewer.ini");
        if (!iniFile.exists())
            iniFile.createNewFile();
        else {
            Scanner scanner = new Scanner(
                    new BufferedReader(new InputStreamReader(new FileInputStream(iniFile), "UTF-8")));

            while (scanner.hasNextLine()) {
                String line = scanner.nextLine();
                if (!line.startsWith("#")) {
                    int equalsPos = line.indexOf('=');
                    String parameter = line.substring(0, equalsPos);
                    String value = line.substring(equalsPos + 1);
                    if (parameter.equals("editor")) {
                        editor = value;
                    } else if (parameter.equals("arguments")) {
                        arguments = value;
                    } else if (parameter.equals("jdbc.url")) {
                        databaseURL = value;
                    } else if (parameter.equals("jdbc.username")) {
                        databaseUsername = value;
                    } else if (parameter.equals("jdbc.password")) {
                        databasePassword = value;
                    } else if (parameter.equals("project.code")) {
                        projectCode = value;
                    } else if (parameter.equals("csvSeparator")) {
                        csvSeparator = value;
                    }
                }
            }
            scanner.close();
        }
    }

    @FXML
    protected void handleMenuFileDatabaseAction(ActionEvent event) {
        TerminologyServiceLocator terminologyServiceLocator = TerminologyServiceLocator.getInstance();
        TerminologyService terminologyService = terminologyServiceLocator.getTerminologyService();
        Properties props = new Properties();
        props.put("jdbc.driverClassName", "org.postgresql.Driver");
        props.put("jdbc.url", databaseURL);
        props.put("jdbc.username", databaseUsername);
        props.put("jdbc.password", databasePassword);
        terminologyBase = terminologyService.getPostGresTerminologyBase(projectCode, props);
        this.onNewTermingologyBase();
    }

    private void onNewTermingologyBase() {
        int minFrequency = 5;
        try {
            minFrequency = Integer.parseInt(txtMinFrequency.getText());
        } catch (NumberFormatException nfe) {
            // do nothing
        }
        List<Term> terms = terminologyBase.getTermsByFrequency(minFrequency);

        tblTerms.setItems(FXCollections.observableArrayList(this.wrapTerms(terms)));
        this.pushTermTable();
        btnReload.setDisable(false);
    }

    private Collection<Term> wrapTerms(Collection<Term> terms) {
        List<Term> termWrappers = new ArrayList<Term>(terms.size());
        for (Term term : terms) {
            TermWrapper termWrapper = new TermWrapper(term);
            termWrappers.add(termWrapper);
        }
        return termWrappers;
    }

    @FXML
    protected void handleLimitButtonAction(ActionEvent event) {
        int maxCount = -1;
        String topStr = txtTop.getText();
        try {
            maxCount = Integer.parseInt(topStr);
        } catch (NumberFormatException e) {
            this.showAlert("Top must be a number.");
        }

        this.setSelectedTerm();
        ObservableList<Term> terms = tblTerms.getItems();

        List<Term> limitedTerms = new ArrayList<Term>(maxCount);
        int i = 0;
        for (Term term : terms) {
            if (i == maxCount)
                break;
            limitedTerms.add(term);
            i++;
        }
        tblTerms.setItems(FXCollections.observableArrayList(limitedTerms));
        this.pushTermTable();
    }

    @FXML
    protected void handleReloadButtonAction(ActionEvent event) {
        boolean haveCriteria = false;
        int minFrequency = -1;
        if (txtMinFrequency.getText().trim().length() > 0) {
            try {
                minFrequency = Integer.parseInt(txtMinFrequency.getText());
                haveCriteria = true;
            } catch (NumberFormatException nfe) {
                this.showAlert("Min Frequency must be a number.");
                return;
            }
        }

        String searchText = txtSearch.getText();

        boolean marked = chkMarked.isSelected();
        boolean markedExpansions = chkExpansions.isSelected();

        haveCriteria = minFrequency > 0 || searchText.length() > 0 || marked;

        if (haveCriteria) {
            this.setSelectedTerm();
            List<Term> terms = terminologyBase.getTerms(minFrequency, searchText, marked, markedExpansions);
            tblTerms.setItems(FXCollections.observableArrayList(this.wrapTerms(terms)));
            this.pushTermTable();
        } else {
            this.showAlert("No selection criteria entered.");
        }

    }

    @FXML
    protected void handleSearchButtonAction(ActionEvent event) {
        String searchText = txtSearch.getText();
        if (searchText.length() > 0) {
            this.setSelectedTerm();
            List<Term> terms = terminologyBase.getTermsByText(searchText);
            tblTerms.setItems(FXCollections.observableArrayList(this.wrapTerms(terms)));
            this.pushTermTable();
        } else {
            this.showAlert("Search text is too short.");
        }
    }

    @FXML
    protected void handleMarkedButtonAction(ActionEvent event) {
        this.setSelectedTerm();
        List<Term> terms = terminologyBase.getMarkedTerms();
        tblTerms.setItems(FXCollections.observableArrayList(this.wrapTerms(terms)));
        this.pushTermTable();
    }

    @FXML
    protected void handleHeadsButtonAction(ActionEvent event) {
        Term term = tblTerms.getSelectionModel().getSelectedItem();
        if (term != null) {
            this.setSelectedTerm();
            if (term instanceof TermWrapper) {
                term = ((TermWrapper) term).getWrappedTerm();
            }
            Set<Term> heads = terminologyBase.getHeads(term);
            tblTerms.setItems(FXCollections.observableArrayList(this.wrapTerms(heads)));
            this.pushTermTable();
        }
    }

    @FXML
    protected void handleExpansionsButtonAction(ActionEvent event) {
        this.doExpansions();
    }

    void doExpansions() {
        Term term = tblTerms.getSelectionModel().getSelectedItem();
        if (term != null) {
            this.setSelectedTerm();
            if (term instanceof TermWrapper) {
                term = ((TermWrapper) term).getWrappedTerm();
            }
            Set<Term> expansions = terminologyBase.getExpansions(term);
            tblTerms.setItems(FXCollections.observableArrayList(this.wrapTerms(expansions)));
            this.pushTermTable();
        }
    }

    @FXML
    protected void handleMarkButtonAction(ActionEvent event) {
        this.markTerm();
    }

    void markTerm() {
        Term term = tblTerms.getSelectionModel().getSelectedItem();
        if (term != null) {
            boolean marked = !term.isMarked();
            term.setMarked(marked);
            if (term instanceof TermWrapper) {
                terminologyBase.storeTerm(((TermWrapper) term).getWrappedTerm());
            } else {
                terminologyBase.storeTerm(term);
            }
        }
    }

    @FXML
    protected void handleExportButtonAction(ActionEvent event) {
        FileChooser fileChooser = new FileChooser();

        //Set extension filter
        FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("CSV (*.csv)", "*.csv");
        fileChooser.getExtensionFilters().add(extFilter);
        FileChooser.ExtensionFilter allFilter = new FileChooser.ExtensionFilter("All files (*)", "*");
        fileChooser.getExtensionFilters().add(allFilter);

        String currentDir = System.getProperty("user.dir");
        fileChooser.setInitialDirectory(new File(currentDir));

        //Show save file dialog
        File file = fileChooser.showSaveDialog(primaryStage);
        if (file != null) {
            try {
                CSV.setAddQuotesAlways(true);
                CSV.setCsvSeparator(csvSeparator);
                Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file)));
                ObservableList<Term> terms = tblTerms.getItems();
                writer.append(CSV.format("Term") + CSV.format("Frequency") + CSV.format("Expansions")
                        + CSV.format("Contexts") + "\n");
                for (Term term : terms) {
                    if (term instanceof TermWrapper) {
                        term = ((TermWrapper) term).getWrappedTerm();
                    }
                    writer.append(CSV.format(term.getText()));
                    writer.append(CSV.format(term.getFrequency()));
                    writer.append(CSV.format(term.getExpansionCount()));
                    StringBuilder sb = new StringBuilder();
                    for (Context context : terminologyBase.getContexts(term)) {
                        sb.append(context.getTextSegment() + "|");
                    }
                    writer.append(CSV.format(sb.toString()));
                    writer.append("\n");
                    writer.flush();
                }
                writer.close();
            } catch (IOException ioe) {
                throw new RuntimeException(ioe);
            }
        }

    }

    @FXML
    protected void tblTerms_OnMouseClicked(MouseEvent mouseEvent) {
        if (mouseEvent.getButton().equals(MouseButton.PRIMARY)) {
            this.refreshContexts();
        }
    }

    @FXML
    protected void tblTerms_OnKeyPressed(KeyEvent keyEvent) {
        if (keyEvent.isControlDown()) {
            //          LOG.debug("keyEvent.getCharacter(): " + keyEvent.getCharacter());
            //          LOG.debug("keyEvent.getCode().getName(): " + keyEvent.getCode().getName());
            if (keyEvent.getCode().getName().equals("C")) {
                final Clipboard clipboard = Clipboard.getSystemClipboard();
                final ClipboardContent content = new ClipboardContent();
                Term term = tblTerms.getSelectionModel().getSelectedItem();
                content.putString(term.getText());
                clipboard.setContent(content);
            }
        } else if (keyEvent.getCode().getName().equalsIgnoreCase("M")) {
            this.markTerm();
        } else if (keyEvent.getCode().getName().equalsIgnoreCase("E")) {
            this.doExpansions();
        } else if (keyEvent.getCode().getName().equalsIgnoreCase("B")) {
            this.doBack();
        } else if (keyEvent.getCode().getName().equalsIgnoreCase("F")) {
            this.doForward();
        }
    }

    @FXML
    protected void tblContexts_OnKeyPressed(KeyEvent keyEvent) {
        if (keyEvent.isControlDown()) {
            if (keyEvent.getCode().getName().equals("C")) {
                final Clipboard clipboard = Clipboard.getSystemClipboard();
                final ClipboardContent content = new ClipboardContent();
                Context context = tblContexts.getSelectionModel().getSelectedItem();
                content.putString(context.getTextSegment());
                clipboard.setContent(content);
            }
        }
    }

    @FXML
    protected void tblContexts_OnMouseClicked(MouseEvent mouseEvent) throws Exception {
        if (mouseEvent.getButton().equals(MouseButton.PRIMARY)) {
            if (mouseEvent.getClickCount() == 2) {
                if (editor != null && arguments != null) {
                    Context context = tblContexts.getSelectionModel().getSelectedItem();
                    if (context != null) {
                        String argumentString = arguments;
                        argumentString = argumentString.replace("%file", context.getFileName());
                        argumentString = argumentString.replace("%line", "" + context.getLineNumber());
                        argumentString = argumentString.replace("%column", "" + context.getColumnNumber());
                        String command = "\"" + editor + "\"" + argumentString;
                        LOG.debug(command);
                        Runtime.getRuntime().exec(command);
                    }
                }
            }
        }
    }

    public Stage getPrimaryStage() {
        return primaryStage;
    }

    public void setPrimaryStage(Stage primaryStage) {
        this.primaryStage = primaryStage;
    }

    private void showAlert(String text) {
        Stage dialogStage = new Stage();
        dialogStage.initModality(Modality.WINDOW_MODAL);
        dialogStage.setScene(new Scene(VBoxBuilder.create().children(new Text(text), new Button("Ok"))
                .alignment(Pos.CENTER).padding(new Insets(5)).build()));
        dialogStage.show();
    }

    @FXML
    protected void handleMenuSettingsPreferences(ActionEvent event) throws Exception {
        Stage preferencesStage = new Stage();
        preferencesStage.initModality(Modality.WINDOW_MODAL);
        FXMLLoader fxmlLoader = new FXMLLoader();
        Parent root = (Parent) fxmlLoader.load(getClass().getResource("preferences.fxml").openStream());

        PreferencesController controller = fxmlLoader.getController();
        controller.setPrimaryStage(preferencesStage);
        controller.setPrimaryController(this);

        preferencesStage.setTitle("Talismane Terminology Viewer Preferences");
        preferencesStage.setScene(new Scene(root, 400, 300));
        preferencesStage.show();
    }

    public String getEditor() {
        return editor;
    }

    public void setEditor(String editor) {
        this.editor = editor;
    }

    public String getArguments() {
        return arguments;
    }

    public void setArguments(String arguments) {
        this.arguments = arguments;
    }

    public String getDatabaseURL() {
        return databaseURL;
    }

    public void setDatabaseURL(String databaseURL) {
        this.databaseURL = databaseURL;
    }

    public String getDatabaseUsername() {
        return databaseUsername;
    }

    public void setDatabaseUsername(String databaseUsername) {
        this.databaseUsername = databaseUsername;
    }

    public String getDatabasePassword() {
        return databasePassword;
    }

    public void setDatabasePassword(String databasePassword) {
        this.databasePassword = databasePassword;
    }

    public String getProjectCode() {
        return projectCode;
    }

    public void setProjectCode(String projectCode) {
        this.projectCode = projectCode;
    }

    public String getCsvSeparator() {
        return csvSeparator;
    }

    public void setCsvSeparator(String csvSeparator) {
        this.csvSeparator = csvSeparator;
    }

    @FXML
    protected void handleBackButtonAction(ActionEvent event) {
        this.doBack();
    }

    void doBack() {
        if (currentHistoryIndex > 0) {
            this.setSelectedTerm();
            currentHistoryIndex--;
            TermTableDefinition def = termTableHistory.get(currentHistoryIndex);
            def.apply(tblTerms);
            lblTermCount.setText("" + tblTerms.getItems().size());
            this.refreshContexts();
        }
    }

    @FXML
    protected void handleForwardButtonAction(ActionEvent event) {
        this.doForward();
    }

    void doForward() {
        if (currentHistoryIndex < termTableHistory.size() - 1) {
            this.setSelectedTerm();
            currentHistoryIndex++;
            TermTableDefinition def = termTableHistory.get(currentHistoryIndex);
            def.apply(tblTerms);
            lblTermCount.setText("" + tblTerms.getItems().size());
            this.refreshContexts();
        }
    }

    @FXML
    protected void handleScrollButtonAction(ActionEvent event) {
        int selectedIndex = tblTerms.getSelectionModel().getSelectedIndex();
        tblTerms.scrollTo(selectedIndex);
        tblTerms.requestFocus();
    }

    void refreshContexts() {
        Term term = tblTerms.getSelectionModel().getSelectedItem();
        if (term != null) {
            if (term instanceof TermWrapper) {
                term = ((TermWrapper) term).getWrappedTerm();
            }
            List<Context> contexts = new ArrayList<Context>();
            if (term != null) {
                contexts = terminologyBase.getContexts(term);
            }
            tblContexts.setItems(FXCollections.observableArrayList(contexts));
        }
    }

    void pushTermTable() {
        lblTermCount.setText("" + tblTerms.getItems().size());
        for (int i = currentHistoryIndex + 1; i < termTableHistory.size(); i++) {
            termTableHistory.removeLast();
        }

        TermTableDefinition def = new TermTableDefinition(tblTerms);
        termTableHistory.addLast(def);
        if (termTableHistory.size() > 10)
            termTableHistory.removeFirst();
        currentHistoryIndex = termTableHistory.size() - 1;
    }

    void setSelectedTerm() {
        if (currentHistoryIndex >= 0 && currentHistoryIndex < termTableHistory.size()) {
            TermTableDefinition def = termTableHistory.get(currentHistoryIndex);
            def.update(tblTerms);
        }
        //      tblTerms.getSelectionModel().select(-1);
        //      tblTerms.scrollTo(0);
    }

    private static final class TermTableDefinition {
        private ObservableList<Term> terms;
        private int selectedIndex;

        public TermTableDefinition(TableView<Term> tblTerms) {
            this.terms = tblTerms.getItems();
            this.selectedIndex = tblTerms.getSelectionModel().getSelectedIndex();
        }

        public void update(TableView<Term> tblTerms) {
            this.selectedIndex = tblTerms.getSelectionModel().getSelectedIndex();
        }

        public void apply(final TableView<Term> tblTerms) {
            tblTerms.setItems(null);
            tblTerms.layout();
            tblTerms.setItems(terms);

            tblTerms.getSelectionModel().select(selectedIndex);

            tblTerms.requestFocus();
            tblTerms.layout();

            Platform.runLater(new Runnable() {
                @Override
                public void run() {
                    if (LOG.isTraceEnabled())
                        LOG.trace("Scrolling to " + selectedIndex);
                    tblTerms.scrollTo(selectedIndex);
                }
            });
        }

        @Override
        public String toString() {
            return "TermTableDef[" + terms.size() + "," + selectedIndex + "]";
        }

    }

}