Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Highlight groups that match any/all of the entries selected in the main table. #2515

Merged
merged 4 commits into from
Feb 6, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `#
- Add tab which shows the MathSciNet review website if the `MRNumber` field is present.
- Partly switched to new UI technology (JavaFX).
- Redesigned group panel.
- Number of matched entries is always shown.
- The background color of the hit counter signals whether the group contains all/any of the entries selected in the main table.
- Redesigned about dialog.
- Redesigned key bindings dialog.
- Redesigned journal abbreviations dialog.
Expand Down
783 changes: 363 additions & 420 deletions src/main/java/net/sf/jabref/gui/BasePanel.java

Large diffs are not rendered by default.

1,025 changes: 472 additions & 553 deletions src/main/java/net/sf/jabref/gui/JabRefFrame.java

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions src/main/java/net/sf/jabref/gui/StateManager.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package net.sf.jabref.gui;

import java.util.List;
import java.util.Optional;

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.groups.GroupTreeNode;

/**
Expand All @@ -20,6 +24,7 @@ public class StateManager {

private final ObjectProperty<Optional<BibDatabaseContext>> activeDatabase = new SimpleObjectProperty<>(Optional.empty());
private final ObjectProperty<Optional<GroupTreeNode>> activeGroup = new SimpleObjectProperty<>(Optional.empty());
private final ObservableList<BibEntry> selectedEntries = FXCollections.observableArrayList();

public ObjectProperty<Optional<BibDatabaseContext>> activeDatabaseProperty() {
return activeDatabase;
Expand All @@ -28,4 +33,13 @@ public ObjectProperty<Optional<BibDatabaseContext>> activeDatabaseProperty() {
public ObjectProperty<Optional<GroupTreeNode>> activeGroupProperty() {
return activeGroup;
}

public ObservableList<BibEntry> getSelectedEntries() {
return FXCollections.unmodifiableObservableList(selectedEntries);
}

public void setSelectedEntries(List<BibEntry> newSelectedEntries) {
selectedEntries.clear();
selectedEntries.addAll(newSelectedEntries);
}
}
3 changes: 0 additions & 3 deletions src/main/java/net/sf/jabref/gui/actions/Actions.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,6 @@ public class Actions {
public static final String GLOBAL_SEARCH = "globalSearch";
public static final String SELECT_ALL = "selectAll";
public static final String SEND_AS_EMAIL = "sendAsEmail";
public static final String TOGGLE_HIGHLIGHTS_GROUPS_MATCHING_ALL = "toggleHighlightGroupsMatchingAll";
public static final String TOGGLE_HIGHLIGHTS_GROUPS_MATCHING_ANY = "toggleHighlightGroupsMatchingAny";
public static final String TOGGLE_HIGHLIGHTS_GROUPS_MATCHING_DISABLE = "toggleHighlightGroupsMatchingDisable";
public static final String TOGGLE_GROUPS = "toggleGroups";
public static final String TOGGLE_PREVIEW = "togglePreview";
public static final String UNABBREVIATE = "unabbreviate";
Expand Down
28 changes: 22 additions & 6 deletions src/main/java/net/sf/jabref/gui/groups/GroupNodeViewModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@

import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.collections.ObservableList;

import net.sf.jabref.gui.StateManager;
import net.sf.jabref.gui.util.BindingsHelper;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.event.EntryEvent;
Expand All @@ -28,31 +31,44 @@ public class GroupNodeViewModel {
private final GroupTreeNode groupNode;
private final SimpleIntegerProperty hits;
private final SimpleBooleanProperty hasChildren;
private final BooleanBinding anySelectedEntriesMatched;
private final BooleanBinding allSelectedEntriesMatched;

public GroupNodeViewModel(BibDatabaseContext databaseContext, GroupTreeNode groupNode) {
public GroupNodeViewModel(BibDatabaseContext databaseContext, StateManager stateManager, GroupTreeNode groupNode) {
this.databaseContext = Objects.requireNonNull(databaseContext);
this.groupNode = Objects.requireNonNull(groupNode);

name = groupNode.getName();
isRoot = groupNode.isRoot();
iconCode = "";
children = EasyBind.map(groupNode.getChildren(), child -> new GroupNodeViewModel(databaseContext, child));
children = EasyBind.map(groupNode.getChildren(), child -> new GroupNodeViewModel(databaseContext, stateManager, child));
hasChildren = new SimpleBooleanProperty();
hasChildren.bind(Bindings.isNotEmpty(children));
hits = new SimpleIntegerProperty(0);
calculateNumberOfMatches();

// Register listener
databaseContext.getDatabase().registerListener(this);

ObservableList<Boolean> selectedEntriesMatchStatus = EasyBind.map(stateManager.getSelectedEntries(), groupNode::matches);
anySelectedEntriesMatched = BindingsHelper.any(selectedEntriesMatchStatus, matched -> matched);
allSelectedEntriesMatched = BindingsHelper.all(selectedEntriesMatchStatus, matched -> matched);
}

public GroupNodeViewModel(BibDatabaseContext databaseContext, StateManager stateManager, AbstractGroup group) {
this(databaseContext, stateManager, new GroupTreeNode(group));
}

static GroupNodeViewModel getAllEntriesGroup(BibDatabaseContext newDatabase, StateManager stateManager) {
return new GroupNodeViewModel(newDatabase, stateManager, new AllEntriesGroup(Localization.lang("All entries")));
}

public GroupNodeViewModel(BibDatabaseContext databaseContext, AbstractGroup group) {
this(databaseContext, new GroupTreeNode(group));
public BooleanBinding anySelectedEntriesMatchedProperty() {
return anySelectedEntriesMatched;
}

static GroupNodeViewModel getAllEntriesGroup(BibDatabaseContext newDatabase) {
return new GroupNodeViewModel(newDatabase, new AllEntriesGroup(Localization.lang("All entries")));
public BooleanBinding allSelectedEntriesMatchedProperty() {
return allSelectedEntriesMatched;
}

public SimpleBooleanProperty hasChildrenProperty() {
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/net/sf/jabref/gui/groups/GroupTree.css
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@
-fx-background-radius: 10px;
}

.numberColumn > .hits:any-selected {
-fx-background-color: #c6c44f;
}

.numberColumn > .hits:all-selected {
-fx-background-color: #4dc64f;
}

.disclosureNodeColumn {
-fx-alignment: top-right;
-fx-font-size: 12px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import net.sf.jabref.gui.AbstractController;
import net.sf.jabref.gui.DialogService;
import net.sf.jabref.gui.StateManager;
import net.sf.jabref.gui.util.BindingsHelper;
import net.sf.jabref.gui.util.RecursiveTreeItem;
import net.sf.jabref.gui.util.ViewModelTreeTableCellFactory;
import net.sf.jabref.logic.l10n.Localization;
Expand Down Expand Up @@ -59,10 +60,14 @@ public void initialize() {
);

// Number of hits
PseudoClass anySelected = PseudoClass.getPseudoClass("any-selected");
PseudoClass allSelected = PseudoClass.getPseudoClass("all-selected");
numberColumn.setCellFactory(new ViewModelTreeTableCellFactory<GroupNodeViewModel, GroupNodeViewModel>()
.withGraphic(viewModel -> {
final StackPane node = new StackPane();
node.getStyleClass().setAll("hits");
BindingsHelper.includePseudoClassWhen(node, anySelected, viewModel.anySelectedEntriesMatchedProperty());
BindingsHelper.includePseudoClassWhen(node, allSelected, viewModel.allSelectedEntriesMatchedProperty());
Text text = new Text();
text.textProperty().bind(viewModel.getHits().asString());
text.getStyleClass().setAll("text");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ private void onActiveDatabaseChanged(Optional<BibDatabaseContext> newDatabase) {
GroupNodeViewModel newRoot = newDatabase
.map(BibDatabaseContext::getMetaData)
.flatMap(MetaData::getGroups)
.map(root -> new GroupNodeViewModel(newDatabase.get(), root))
.orElse(GroupNodeViewModel.getAllEntriesGroup(newDatabase.get()));
.map(root -> new GroupNodeViewModel(newDatabase.get(), stateManager, root))
.orElse(GroupNodeViewModel.getAllEntriesGroup(newDatabase.get(), stateManager));
rootGroup.setValue(newRoot);
}
}
Expand Down
47 changes: 47 additions & 0 deletions src/main/java/net/sf/jabref/gui/util/BindingsHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package net.sf.jabref.gui.util;

import java.util.function.Predicate;

import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.BooleanPropertyBase;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.css.PseudoClass;
import javafx.scene.Node;

/**
* Helper methods for javafx binding.
* Some methods are taken from https://bugs.openjdk.java.net/browse/JDK-8134679
*/
public class BindingsHelper {
public static <T> BooleanBinding any(ObservableList<T> source, Predicate<T> predicate) {
return Bindings.createBooleanBinding(() -> source.stream().anyMatch(predicate), source);
}

public static <T> BooleanBinding all(ObservableList<T> source, Predicate<T> predicate) {
// Stream.allMatch() (in contrast to Stream.anyMatch() returns 'true' for empty streams, so this has to be checked explicitly.
return Bindings.createBooleanBinding(() -> !source.isEmpty() && source.stream().allMatch(predicate), source);
}

public static void includePseudoClassWhen(Node node, PseudoClass pseudoClass, ObservableValue<? extends Boolean> condition) {
BooleanProperty pseudoClassState = new BooleanPropertyBase(false) {
@Override
protected void invalidated() {
node.pseudoClassStateChanged(pseudoClass, get());
}

@Override
public Object getBean() {
return node;
}

@Override
public String getName() {
return pseudoClass.getPseudoClassName();
}
};
pseudoClassState.bind(condition);
}
}
8 changes: 8 additions & 0 deletions src/main/java/net/sf/jabref/model/groups/GroupTreeNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -216,4 +216,12 @@ public int calculateNumberOfMatches(List<BibEntry> entries) {
public int calculateNumberOfMatches(BibDatabase database) {
return calculateNumberOfMatches(database.getEntries());
}

/**
* Returns whether this group matches the specified {@link BibEntry} while taking the hierarchical information
* into account.
*/
public boolean matches(BibEntry entry) {
return getSearchMatcher().isMatch(entry);
}
}

This file was deleted.

Loading