application.ui.library.SearchController Maven / Gradle / Ivy
package application.ui.library;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathExpressionException;
import org.daisy.braille.utils.pef.PEFBook;
import org.daisy.braille.utils.pef.PEFBookLoader;
import org.daisy.braille.utils.pef.PEFSearchIndex;
import org.daisy.dotify.common.io.FileIO;
import org.xml.sax.SAXException;
import application.common.Settings;
import application.l10n.Messages;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.VBox;
import javafx.stage.DirectoryChooser;
import javafx.stage.Window;
/**
* Provides a controller for the search view.
* @author Joel Håkansson
*
*/
public class SearchController extends VBox {
private static final Logger logger = Logger.getLogger(SearchController.class.getCanonicalName());
@FXML private Button expandButton;
@FXML private Button folderButton;
@FXML private TextField searchFor;
@FXML private Label currentFolder;
@FXML private ListView listView;
@FXML private ProgressBar searchProgress;
BookScanner bookScanner;
ExecutorService exeService;
/**
* Creates a new search view controller.
*/
public SearchController() {
try {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Search.fxml"), Messages.getBundle());
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
fxmlLoader.load();
} catch (IOException e) {
logger.log(Level.WARNING, "Failed to load view", e);
}
configureFolderLabel(Settings.getSettings().getLibraryPath().getAbsolutePath());
exeService = Executors.newWorkStealingPool();
startScanning();
}
private void startScanning() {
if (bookScanner!=null) {
bookScanner.cancel();
}
bookScanner = new BookScanner();
searchProgress.progressProperty().bind(bookScanner.progressProperty());
bookScanner.setOnSucceeded(ev -> {
if (!"".equals(searchFor.getText())) {
searchChanged();
}
});
exeService.submit(bookScanner);
}
/**
* Updates the list of results.
*/
@FXML void searchChanged() {
Platform.runLater(()-> {
PEFSearchIndex index = bookScanner.getValue();
if (index!=null) {
listView.getItems().clear();
String search = searchFor.getText();
for (PEFBook p : index.containsAll(search)) {
listView.getItems().add(new PefBookAdapter(p));
}
}
});
}
/**
* Opens a directory chooser dialog. If a directory is selected,
* the results are updated.
*/
@FXML void showOpenFolder() {
Window stage = folderButton.getScene().getWindow();
DirectoryChooser chooser = new DirectoryChooser();
chooser.setTitle(Messages.TITLE_SET_SEARCH_FOLDER.localize());
chooser.setInitialDirectory(Settings.getSettings().getLibraryPath());
File selected = chooser.showDialog(stage);
if (selected!=null) {
Settings.getSettings().setLibraryPath(selected.getAbsolutePath());
configureFolderLabel(Settings.getSettings().getLibraryPath().getAbsolutePath());
startScanning();
}
}
/**
* Gets the selected result, or null if no result is selected.
* @return returns the selected result, or null
*/
public PefBookAdapter getSelectedItem() {
return listView.getSelectionModel().getSelectedItem();
}
/**
* Performs an action when a book is selected to be opened.
*
* @param action the action to perform
*/
public void setOnOpen(Consumer action) {
listView.setOnMouseClicked(ev -> {
if (ev.getClickCount() == 2) {
PefBookAdapter book = getSelectedItem();
if (book != null) {
action.accept(book);
ev.consume();
}
}
});
listView.setOnKeyReleased(ev -> {
if (ev.getCode() == KeyCode.ENTER) {
PefBookAdapter book = getSelectedItem();
if (book != null) {
action.accept(book);
ev.consume();
}
}
;
});
}
private void configureFolderLabel(String text) {
currentFolder.setText(text);
currentFolder.setTooltip(new Tooltip(text));
}
private class BookScanner extends Task {
@Override
protected PEFSearchIndex call() throws Exception {
PEFSearchIndex search = new PEFSearchIndex(1);
PEFBookLoader loader = new PEFBookLoader();
Collection files = FileIO.listFilesRecursive(Settings.getSettings().getLibraryPath(), ".pef");
int i = 0;
updateProgress(i, files.size());
for (File f : files) {
if (isCancelled()) {
break;
}
try {
PEFBook book = loader.load(f);
if (book!=null) {
search.add(book);
}
} catch (XPathExpressionException | ParserConfigurationException | SAXException | IOException e) {
//e.printStackTrace();
}
i++;
updateProgress(i, files.size());
}
return search;
}
}
}