package nl.tudelft.lifetiles.annotation.controller; import java.net.URL; import java.util.List; import java.util.ResourceBundle; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.collections.transformation.FilteredList; import javafx.fxml.FXML; import javafx.scene.control.ListCell; import javafx.scene.control.ListView; import javafx.scene.control.TextField; import javafx.scene.layout.VBox; import nl.tudelft.lifetiles.annotation.model.AbstractBookmark; import nl.tudelft.lifetiles.core.controller.AbstractController; import nl.tudelft.lifetiles.core.util.Message; /** * Controller for the Bookmark sidebar. * @author Albert Smit * */ public class BookmarkController extends AbstractController { /** * The wrapper element for the control. */ @FXML private VBox wrapper; /** * A listView to show all annotations. */ @FXML private ListView<AbstractBookmark> bookmarkList; /** * the searchbox to search through all annotations. */ @FXML private TextField searchBox; /** * The list of all bookmarks. */ private ObservableList<AbstractBookmark> listItems; /** * The filtered list that will wrap the listItems. * do not add items directly to this list, instead add them to listItems. */ private FilteredList<AbstractBookmark> filteredItems; /** * {@inheritDoc} */ @Override public final void initialize(final URL location, final ResourceBundle resources) { setVisibility(false); // wrap the observable list in a filtered list so we can search it later listItems = FXCollections.observableArrayList(); filteredItems = new FilteredList<AbstractBookmark>(listItems); bookmarkList.setItems(filteredItems); /* * create a new Cell factory so we can use a different method * to create the text of each cell, * and assign an event handler for mouse clicks. */ bookmarkList.setCellFactory(param -> { // cell needs to be an inner class to use shout in its onMouseClick method final ListCell<AbstractBookmark> cell = new ListCell<AbstractBookmark>() { /** * the ListCell, creates the correct text and adds the right eventhandler. */ public void updateItem(final AbstractBookmark item, final boolean empty) { super.updateItem(item, empty); if (item != null) { setText(item.toCellString()); setOnMouseClicked(event -> { if (event.getClickCount() == 2) { shout(Message.GOTO, "" , Long.valueOf(item.getUnifiedPosition())); } }); } } }; return cell; }); initListeners(); } /** * Initialize the shout listeners. */ // java doesn't let us typecheck generics so the casts are unchecked // checkstyle doesn't like assert without parentheses with generics @SuppressWarnings({"checkstyle:genericwhitespace", "unchecked"}) private void initListeners() { listen(Message.BOOKMARKS, (sender, subject, args) -> setVisibility(true) ); listen(Message.LOADED, (sender, subject, args) -> { if ("known mutations".equals(subject) || "annotations".equals(subject)) { assert args[0] instanceof List<?>; List<AbstractBookmark> bookmarks = (List<AbstractBookmark>) args[0]; listItems.addAll(bookmarks); } }); } /** * closes the bookmark sidebar. */ @FXML // PMD/findbugs do not work well with javafx. The method IS used. @SuppressWarnings("PMD.UnusedPrivateMethod") @SuppressFBWarnings("UPM_UNCALLED_PRIVATE_METHOD") private void closeAction() { setVisibility(false); } /** * updates the filtering predicate. * uses a simple contains check on the text of the listItem. */ @FXML // PMD/findbugs do not work well with javafx. The method IS used. @SuppressWarnings("PMD.UnusedPrivateMethod") @SuppressFBWarnings("UPM_UNCALLED_PRIVATE_METHOD") private void searchAction() { filteredItems.setPredicate(annotation -> { if (searchBox.textProperty().get().isEmpty()) { return true; } return annotation.toCellString().contains(searchBox.getCharacters()); }); } /** * makes the sidebar (in)visible. * @param flag a boolean indicating intended visibility. */ private void setVisibility(final boolean flag) { wrapper.visibleProperty().set(flag); } }