package gui; import static data.CorpusType.*; import static gui.GUIController.*; import static gui.Messages.*; import static util.Util.*; import java.io.File; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOCase; import org.apache.commons.io.filefilter.FileFilterUtils; import org.apache.commons.io.filefilter.TrueFileFilter; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import alg.XML_processing; import data.Corpus; import data.CorpusType; import data.Enums.solar.SolarFilters; import data.Tax; import javafx.collections.ObservableList; import javafx.concurrent.Task; import javafx.fxml.FXML; import javafx.scene.control.*; import javafx.scene.layout.Pane; import javafx.stage.DirectoryChooser; import javafx.stage.Stage; import javafx.application.HostServices; public class CorpusTab { public final static Logger logger = LogManager.getLogger(CorpusTab.class); public Pane setCorpusWrapperP; private Stage stage; @FXML private Button chooseCorpusLocationB; private File chosenCorpusLocation; @FXML private CheckBox readHeaderInfoChB; private boolean readHeaderInfo; @FXML private CheckBox gosUseOrthChB; private boolean gosUseOrth; @FXML private Button chooseResultsLocationB; @FXML private Label chooseCorpusL; private String chooseCorpusLabelContent; @FXML private Label chooseResultsL; private String chooseResultsLabelContent; @FXML private ProgressIndicator locationScanPI; @FXML private Hyperlink helpH; // *** shared *** private Corpus corpus; private CorpusType corpusType; // tabs - used to enable/disable private Tab stringLevelTabNew2; private Tab oneWordAnalysisTab; private Tab characterLevelTab; private Tab wordFormationTab; private Tab wordLevelTab; private Tab filterTab; private TabPane tabPane; private StringAnalysisTabNew2 satNew2Controller; private OneWordAnalysisTab oneWordTabController; private CharacterAnalysisTab catController; private FiltersForSolar ffsController; private WordFormationTab wfController; private WordLevelTab wlController; private HostServices hostService; public void initialize() { stage = new Stage(); // add listeners chooseCorpusLocationB.setOnAction(e -> chooseCorpusLocation()); chooseCorpusLocationB.setTooltip(new Tooltip(TOOLTIP_chooseCorpusLocationB)); helpH.setOnAction(e -> openHelpWebsite()); readHeaderInfoChB.selectedProperty().addListener((observable, oldValue, newValue) -> { readHeaderInfo = newValue; logger.info("read headers: ", readHeaderInfo); }); readHeaderInfoChB.setTooltip(new Tooltip(TOOLTIP_readHeaderInfoChB)); gosUseOrthChB.selectedProperty().addListener((observable, oldValue, newValue) -> { gosUseOrth = newValue; corpus.setGosOrthMode(gosUseOrth); wordFormationTab.setDisable(gosUseOrth); satNew2Controller.toggleMode(null); oneWordTabController.toggleMode(null); catController.toggleMode(null); logger.info("gosUseOrth: ", gosUseOrth); }); chooseResultsLocationB.setOnAction(e -> chooseResultsLocation(null)); // set labels and toggle visibility toggleGosChBVisibility(); chooseCorpusLabelContent = Messages.LABEL_CORPUS_LOCATION_NOT_SET; chooseCorpusL.setText(chooseCorpusLabelContent); chooseResultsLabelContent = Messages.LABEL_RESULTS_LOCATION_NOT_SET; chooseResultsL.setText(chooseResultsLabelContent); togglePiAndSetCorpusWrapper(false); } private void togglePiAndSetCorpusWrapper(boolean piIsActive) { locationScanPI.setVisible(piIsActive); setCorpusWrapperP.setLayoutX(piIsActive ? 100.0 : 10.0); } private void openHelpWebsite(){ hostService.showDocument(Messages.HELP_URL); } /** * In order for a directory to pass as a valid corpus location, following criteria has to be met: * *

* Additionally, if the user checks to read taxonomy/filters from the corpus files, that read * has to produce a non-empty list results list */ private void chooseCorpusLocation() { File selectedDirectory = directoryChooser(); if (selectedDirectory != null && ValidationUtil.isReadableDirectory(selectedDirectory)) { logger.info("selected corpus dir: ", selectedDirectory.getAbsolutePath()); // scan for xml files Collection corpusFiles = FileUtils.listFiles(selectedDirectory, FileFilterUtils.suffixFileFilter("xml", IOCase.INSENSITIVE), TrueFileFilter.INSTANCE); // make sure there are corpus files in selected directory or notify the user about it if (corpusFiles.size() == 0) { logger.info("alert: ", WARNING_CORPUS_NOT_FOUND); showAlert(Alert.AlertType.ERROR, WARNING_CORPUS_NOT_FOUND, null); } else { String chooseCorpusLabelContentTmp = detectCorpusType(corpusFiles, selectedDirectory.getAbsolutePath()); if (chooseCorpusLabelContentTmp == null) { logger.info("alert: ", WARNING_CORPUS_NOT_FOUND); showAlert(Alert.AlertType.ERROR, WARNING_CORPUS_NOT_FOUND, null); } else { initNewCorpus(selectedDirectory, corpusFiles); corpus.setChosenCorpusLocation(selectedDirectory); corpus.setDetectedCorpusFiles(corpusFiles); chooseCorpusLabelContent = chooseCorpusLabelContentTmp; logger.info("corpus dir: ", corpus.getChosenCorpusLocation().getAbsolutePath()); if (readHeaderInfo) { logger.info("reading header info..."); readHeaderInfo(); } else { setResults(); setCorpusForAnalysis(); } } } } } /** * If a user selects a valid corpus location, we define a new corpus (so none of the old data gets carried over) * * @param selectedDirectory * @param corpusFiles */ private void initNewCorpus(File selectedDirectory, Collection corpusFiles) { corpus = new Corpus(); corpus.setCorpusType(corpusType); corpus.setDetectedCorpusFiles(corpusFiles); corpus.setChosenCorpusLocation(selectedDirectory); chooseResultsLocation(selectedDirectory); } private void chooseResultsLocation(File dir) { // results location can be set either to default value (after selecting valid corpus location) - dir attribute // or to a dir picked via directoryChooser (when dir == null File selectedDirectory = dir == null ? directoryChooser() : dir; if (selectedDirectory != null) { String resultsLocationPath = selectedDirectory.getAbsolutePath().concat(File.separator); File chosenResultsLocationTmp = new File(resultsLocationPath); if (!ValidationUtil.isValidDirectory(chosenResultsLocationTmp)) { showAlert(Alert.AlertType.ERROR, WARNING_RESULTS_DIR_NOT_VALID); logger.info("alert: ", WARNING_RESULTS_DIR_NOT_VALID); } else { corpus.setChosenResultsLocation(chosenResultsLocationTmp); chooseResultsLabelContent = corpus.getChosenResultsLocation().getAbsolutePath(); chooseResultsL.setText(chooseResultsLabelContent); logger.info("results dir: " + chooseResultsLabelContent); } } } private void setResults() { // if everything is ok // check and enable checkbox if GOS toggleGosChBVisibility(); // set default results location String defaultResultsLocationPath = corpus.getChosenCorpusLocation().getAbsolutePath(); logger.info("setting default results location to: ", defaultResultsLocationPath); chooseCorpusL.setText(chooseCorpusLabelContent); } private void readHeaderInfo() { CorpusType corpusType = corpus.getCorpusType(); Collection corpusFiles = corpus.getDetectedCorpusFiles(); togglePiAndSetCorpusWrapper(true); chooseCorpusL.setText(LABEL_SCANNING_CORPUS); logger.info("reading header data for ", corpusType.toString()); if (corpusType == CorpusType.GIGAFIDA || corpusType == CorpusType.GOS || corpusType == CorpusType.CCKRES) { boolean corpusIsSplit = corpusFiles.size() > 1; final Task> task = new Task>() { @Override protected HashSet call() throws Exception { HashSet values = new HashSet<>(); long i = 0; if (!corpusIsSplit) { updateProgress(-1.0f, -1.0f); } for (File file : corpusFiles) { values.addAll((Collection) XML_processing.readXmlHeaderTaxonomyAndFilters(file.getAbsolutePath(), corpusIsSplit, corpusType)); i++; if (corpusIsSplit) { updateProgress(i, corpusFiles.size()); } } updateProgress(1.0f, 1.0f); return values; } }; locationScanPI.progressProperty().bind(task.progressProperty()); task.setOnSucceeded(e -> { ObservableList readTaxonomy = Tax.getTaxonomyForComboBox(corpusType, task.getValue()); if (ValidationUtil.isEmpty(readTaxonomy)) { // if no taxonomy found alert the user and keep other tabs disabled logger.info("No taxonomy found in headers."); GUIController.showAlert(Alert.AlertType.ERROR, WARNING_NO_TAXONOMY_FOUND); } else { // set taxonomy, update label corpus.setTaxonomy(readTaxonomy); corpus.setHeaderRead(true); chooseCorpusL.setText(chooseCorpusLabelContent); setResults(); setCorpusForAnalysis(); } togglePiAndSetCorpusWrapper(false); }); task.setOnCancelled(e -> togglePiAndSetCorpusWrapper(false)); task.setOnFailed(e -> togglePiAndSetCorpusWrapper(false)); final Thread thread = new Thread(task, "task"); thread.setDaemon(true); thread.start(); } else if (corpusType == CorpusType.SOLAR) { // many many fields boolean corpusIsSplit = corpusFiles.size() > 1; final Task>> task = new Task>>() { @Override protected HashMap> call() throws Exception { HashMap> values = new HashMap<>(); long i = 0; if (!corpusIsSplit) { updateProgress(-1.0f, -1.0f); } for (File file : corpusFiles) { HashMap> tmpvalues = (HashMap>) XML_processing.readXmlHeaderTaxonomyAndFilters(file.getAbsolutePath(), corpusIsSplit, corpusType); // update final results for (Map.Entry> entry : tmpvalues.entrySet()) { if (values.containsKey(entry.getKey())) { values.get(entry.getKey()).addAll(entry.getValue()); } else { values.put(entry.getKey(), entry.getValue()); } } i++; if (corpusIsSplit) { updateProgress(i, corpusFiles.size()); } } updateProgress(1.0f, 1.0f); return values; } }; locationScanPI.progressProperty().bind(task.progressProperty()); task.setOnSucceeded(e -> { HashMap> values = task.getValue(); if (ValidationUtil.isEmpty(values)) { // if no taxonomy found alert the user and keep other tabs disabled logger.info("No solar filters found in headers."); GUIController.showAlert(Alert.AlertType.ERROR, WARNING_NO_SOLAR_FILTERS_FOUND); } else { HashMap> filtersForComboBoxes = SolarFilters.getFiltersForComboBoxes(values); // set taxonomy, update label corpus.setSolarFiltersForXML(values); corpus.setSolarFilters(filtersForComboBoxes); corpus.setHeaderRead(true); chooseCorpusL.setText(chooseCorpusLabelContent); setResults(); setCorpusForAnalysis(); } togglePiAndSetCorpusWrapper(false); }); task.setOnCancelled(e -> togglePiAndSetCorpusWrapper(false)); task.setOnFailed(e -> togglePiAndSetCorpusWrapper(false)); final Thread thread = new Thread(task, "task"); thread.setDaemon(true); thread.start(); } } private void setCorpusForAnalysis() { if (corpus.validate()) { // new statistic, enable tabs... stringLevelTabNew2.setDisable(false); satNew2Controller.setCorpus(corpus); satNew2Controller.init(); oneWordAnalysisTab.setDisable(false); oneWordTabController.setCorpus(corpus); oneWordTabController.init(); characterLevelTab.setDisable(false); catController.setCorpus(corpus); catController.init(); //wordFormationTab.setDisable(false); wordLevelTab.setDisable(false); //wfController.setCorpus(corpus); //wfController.init(); wlController.setCorpus(corpus); wlController.init(); if (corpus.getCorpusType() == CorpusType.SOLAR) { filterTab.setDisable(false); tabPane.getTabs().add(1, filterTab); ffsController.setCorpus(corpus); ffsController.initFilters(); } else { filterTab.setDisable(true); tabPane.getTabs().removeAll(filterTab); } } else { GUIController.showAlert(Alert.AlertType.ERROR, corpus.getValidationErrorsToString()); } } private File directoryChooser() { DirectoryChooser directoryChooser = new DirectoryChooser(); // open in the folder where the jar is located if possible File workingDir = getWorkingDirectory(); if (workingDir != null) { directoryChooser.setInitialDirectory(workingDir); } return directoryChooser.showDialog(stage); } /** * Hides GOS related checkbox until needed. */ private void toggleGosChBVisibility() { gosUseOrthChB.setVisible(corpus != null && corpus.getCorpusType() != null && corpus.getCorpusType() == CorpusType.GOS); } private String detectCorpusType(Collection corpusFiles, String corpusLocation) { // check that we recognize this corpus // read first file only, maybe later do all, if toll on resources is acceptable File f = corpusFiles.iterator().next(); String title = XML_processing.readXMLHeaderTag(f.getAbsolutePath(), "title").toLowerCase(); String test = CCKRES.getNameLowerCase(); String debug = ""; // check if XML file's title contains any of recognized corpus titles corpusType = null; if (title.contains(SOLAR.getNameLowerCase())) { corpusType = SOLAR; } else if (title.contains(GIGAFIDA.getNameLowerCase())) { corpusType = GIGAFIDA; } else if (title.contains(CCKRES.getNameLowerCase())) { corpusType = CCKRES; } else if (title.contains(GOS.getNameLowerCase())) { corpusType = GOS; } if (corpusType == null) { return null; } else { corpus.setCorpusType(corpusType); StringBuilder sb = new StringBuilder(); sb.append(corpusLocation) .append("\n") .append(String.format(NOTIFICATION_FOUND_X_FILES, corpusFiles.size())) .append("\n") .append(String.format("Korpus: %s", corpusType.toString())); String result = sb.toString(); logger.debug(result); return result; } } public Corpus getCorpus() { return corpus; } public void setCorpus(Corpus corpus) { this.corpus = corpus; } public void setStringLevelTabNew2(Tab stringLevelTabNew2) { this.stringLevelTabNew2 = stringLevelTabNew2; } public void setOneWordAnalysisTab(Tab oneWordAnalysisTab) { this.oneWordAnalysisTab = oneWordAnalysisTab; } public void setCharacterLevelTab(Tab characterLevelTab) { this.characterLevelTab = characterLevelTab; } public void setWordLevelTab(Tab wordLevelTab) { this.wordLevelTab = wordLevelTab; } public void setFilterTab(Tab filterTab) { this.filterTab = filterTab; } public void setFfsController(FiltersForSolar ffsController) { this.ffsController = ffsController; } public void setTabPane(TabPane tabPane) { this.tabPane = tabPane; } public void setSatNew2Controller(StringAnalysisTabNew2 satNew2Controller) { this.satNew2Controller = satNew2Controller; } public void setOneWordTabController(OneWordAnalysisTab oneWordTabController) { this.oneWordTabController = oneWordTabController; } public void setCatController(CharacterAnalysisTab catController) { this.catController = catController; } /*public void setWfController(WordFormationTab wfController) { this.wfController = wfController; }*/ public void setWlController(WordLevelTab wlController) { this.wlController = wlController; } public void setWordFormationTab(Tab wordFormationTab) { this.wordFormationTab = wordFormationTab; } public void setHostServices(HostServices hostServices){ this.hostService = hostServices; } }