diff --git a/src/main/java/org/jabref/gui/IconTheme.java b/src/main/java/org/jabref/gui/IconTheme.java index 1771f288664..ed6d8132d09 100644 --- a/src/main/java/org/jabref/gui/IconTheme.java +++ b/src/main/java/org/jabref/gui/IconTheme.java @@ -32,24 +32,21 @@ public class IconTheme { - public static Font FONT; - public static Font FONT_16; - public static javafx.scene.text.Font FX_FONT; - /* Colors */ // JabRef's default colors public static final Color DEFAULT_COLOR = JabRefPreferences.getInstance().getColor(JabRefPreferences.ICON_ENABLED_COLOR); public static final Color DEFAULT_DISABLED_COLOR = JabRefPreferences.getInstance().getColor(JabRefPreferences.ICON_DISABLED_COLOR); + private static final String DEFAULT_ICON_PATH = "/images/external/red.png"; + private static final Log LOGGER = LogFactory.getLog(IconTheme.class); + private static final Map KEY_TO_ICON = readIconThemeFile( + IconTheme.class.getResource("/images/Icons.properties"), "/images/external/"); + public static Font FONT; // Christmas edition //public static final Color DEFAULT_COLOR = new Color(0x155115); //public static final Color DEFAULT_DISABLED_COLOR = new Color(0x990000); - - private static final Map KEY_TO_ICON = readIconThemeFile( - IconTheme.class.getResource("/images/Icons.properties"), "/images/external/"); - private static final String DEFAULT_ICON_PATH = "/images/external/red.png"; - - private static final Log LOGGER = LogFactory.getLog(IconTheme.class); + public static Font FONT_16; + public static javafx.scene.text.Font FX_FONT; static { try (InputStream stream = FontBasedIcon.class.getResourceAsStream("/fonts/materialdesignicons-webfont.ttf")) { @@ -63,6 +60,90 @@ public class IconTheme { } } + public static javafx.scene.paint.Color getDefaultColor() { + return javafx.scene.paint.Color.rgb(DEFAULT_COLOR.getRed(), DEFAULT_COLOR.getGreen(), DEFAULT_COLOR.getBlue(), DEFAULT_COLOR.getAlpha() / 255.0); + } + + /** + * Constructs an ImageIcon for the image representing the given function, in the resource + * file listing images. + * + * @param name The name of the icon, such as "open", "save", "saveAs" etc. + * @return The ImageIcon for the function. + */ + public static ImageIcon getImage(String name) { + return new ImageIcon(getIconUrl(name)); + } + + public static Image getJabRefImageFX() { + return getImageFX("jabrefIcon48"); + } + + /** + * Constructs an {@link Image} for the image representing the given function, in the resource + * file listing images. + * + * @param name The name of the icon, such as "open", "save", "saveAs" etc. + * @return The {@link Image} for the function. + */ + public static Image getImageFX(String name) { + return new Image(getIconUrl(name).toString()); + } + + /** + * Looks up the URL for the image representing the given function, in the resource + * file listing images. + * + * @param name The name of the icon, such as "open", "save", "saveAs" etc. + * @return The URL to the actual image to use. + */ + public static URL getIconUrl(String name) { + String key = Objects.requireNonNull(name, "icon name"); + if (!KEY_TO_ICON.containsKey(key)) { + LOGGER.warn("Could not find icon url by name " + name + ", so falling back on default icon " + + DEFAULT_ICON_PATH); + } + String path = KEY_TO_ICON.getOrDefault(key, DEFAULT_ICON_PATH); + return Objects.requireNonNull(IconTheme.class.getResource(path), "Path must not be null for key " + key); + } + + /** + * Read a typical java property url into a Map. Currently doesn't support escaping + * of the '=' character - it simply looks for the first '=' to determine where the key ends. + * Both the key and the value is trimmed for whitespace at the ends. + * + * @param url The URL to read information from. + * @param prefix A String to prefix to all values read. Can represent e.g. the directory where icon files are to be + * found. + * @return A Map containing all key-value pairs found. + */ + // FIXME: prefix can be removed?! + private static Map readIconThemeFile(URL url, String prefix) { + Objects.requireNonNull(url, "url"); + Objects.requireNonNull(prefix, "prefix"); + + Map result = new HashMap<>(); + + try (BufferedReader in = new BufferedReader( + new InputStreamReader(url.openStream(), StandardCharsets.ISO_8859_1))) { + String line; + while ((line = in.readLine()) != null) { + if (!line.contains("=")) { + continue; + } + + int index = line.indexOf('='); + String key = line.substring(0, index).trim(); + String value = prefix + line.substring(index + 1).trim(); + result.put(key, value); + } + } catch (IOException e) { + LOGGER.warn("Unable to read default icon theme.", e); + } + return result; + } + + public enum JabRefIcon { ADD("\uf416") /*css: mdi-plus-box*/, @@ -165,6 +246,8 @@ public enum JabRefIcon { BLOG("\uf46b"), /* css: rss */ GLOBAL_SEARCH("\uF1E7"), /* css: earth */ DATE_PICKER("\uF0ED;"), /* css: calendar */ + DEFAULT_GROUP_ICON("\uF316"), /* css: label-outline */ + ALL_ENTRIES_GROUP_ICON("\uF1B8"), /* css: database */ // STILL MISSING: GROUP_REGULAR("\uF4E6", Color.RED); @@ -259,85 +342,4 @@ public FontBasedIcon createWithNewColor(Color newColor) { } } - - - /** - * Constructs an ImageIcon for the image representing the given function, in the resource - * file listing images. - * - * @param name The name of the icon, such as "open", "save", "saveAs" etc. - * @return The ImageIcon for the function. - */ - public static ImageIcon getImage(String name) { - return new ImageIcon(getIconUrl(name)); - } - - public static Image getJabRefImageFX() { - return getImageFX("jabrefIcon48"); - } - - /** - * Constructs an {@link Image} for the image representing the given function, in the resource - * file listing images. - * - * @param name The name of the icon, such as "open", "save", "saveAs" etc. - * @return The {@link Image} for the function. - */ - public static Image getImageFX(String name) { - return new Image(getIconUrl(name).toString()); - } - - - /** - * Looks up the URL for the image representing the given function, in the resource - * file listing images. - * - * @param name The name of the icon, such as "open", "save", "saveAs" etc. - * @return The URL to the actual image to use. - */ - public static URL getIconUrl(String name) { - String key = Objects.requireNonNull(name, "icon name"); - if (!KEY_TO_ICON.containsKey(key)) { - LOGGER.warn("Could not find icon url by name " + name + ", so falling back on default icon " - + DEFAULT_ICON_PATH); - } - String path = KEY_TO_ICON.getOrDefault(key, DEFAULT_ICON_PATH); - return Objects.requireNonNull(IconTheme.class.getResource(path), "Path must not be null for key " + key); - } - - /** - * Read a typical java property url into a Map. Currently doesn't support escaping - * of the '=' character - it simply looks for the first '=' to determine where the key ends. - * Both the key and the value is trimmed for whitespace at the ends. - * - * @param url The URL to read information from. - * @param prefix A String to prefix to all values read. Can represent e.g. the directory - * where icon files are to be found. - * @return A Map containing all key-value pairs found. - */ - // FIXME: prefix can be removed?! - private static Map readIconThemeFile(URL url, String prefix) { - Objects.requireNonNull(url, "url"); - Objects.requireNonNull(prefix, "prefix"); - - Map result = new HashMap<>(); - - try (BufferedReader in = new BufferedReader( - new InputStreamReader(url.openStream(), StandardCharsets.ISO_8859_1))) { - String line; - while ((line = in.readLine()) != null) { - if (!line.contains("=")) { - continue; - } - - int index = line.indexOf('='); - String key = line.substring(0, index).trim(); - String value = prefix + line.substring(index + 1).trim(); - result.put(key, value); - } - } catch (IOException e) { - LOGGER.warn("Unable to read default icon theme.", e); - } - return result; - } } diff --git a/src/main/java/org/jabref/gui/Main.css b/src/main/java/org/jabref/gui/Main.css index d89d1b4d694..735592b4c0b 100644 --- a/src/main/java/org/jabref/gui/Main.css +++ b/src/main/java/org/jabref/gui/Main.css @@ -48,7 +48,6 @@ .icon { -fx-font-family: 'Material Design Icons'; -fx-font-size: 16.0; - -fx-fill : -fx-mid-text-color; } .tooltip { diff --git a/src/main/java/org/jabref/gui/groups/GroupNodeViewModel.java b/src/main/java/org/jabref/gui/groups/GroupNodeViewModel.java index 17db77bbdef..ac32e641980 100644 --- a/src/main/java/org/jabref/gui/groups/GroupNodeViewModel.java +++ b/src/main/java/org/jabref/gui/groups/GroupNodeViewModel.java @@ -15,17 +15,17 @@ import javafx.beans.property.SimpleIntegerProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; +import javafx.scene.paint.Color; +import org.jabref.gui.IconTheme; import org.jabref.gui.StateManager; import org.jabref.gui.util.BindingsHelper; import org.jabref.logic.groups.DefaultGroupsFactory; -import org.jabref.logic.l10n.Localization; import org.jabref.logic.layout.format.LatexToUnicodeFormatter; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.event.EntryEvent; import org.jabref.model.groups.AbstractGroup; -import org.jabref.model.groups.AllEntriesGroup; import org.jabref.model.groups.AutomaticGroup; import org.jabref.model.groups.GroupTreeNode; import org.jabref.model.strings.StringUtil; @@ -37,7 +37,6 @@ public class GroupNodeViewModel { private final String displayName; private final boolean isRoot; - private final String iconCode; private final ObservableList children; private final BibDatabaseContext databaseContext; private final GroupTreeNode groupNode; @@ -53,7 +52,6 @@ public GroupNodeViewModel(BibDatabaseContext databaseContext, StateManager state LatexToUnicodeFormatter formatter = new LatexToUnicodeFormatter(); displayName = formatter.format(groupNode.getName()); isRoot = groupNode.isRoot(); - iconCode = ""; if (groupNode.getGroup() instanceof AutomaticGroup) { AutomaticGroup automaticGroup = (AutomaticGroup) groupNode.getGroup(); @@ -72,6 +70,8 @@ public GroupNodeViewModel(BibDatabaseContext databaseContext, StateManager state hasChildren.bind(Bindings.isNotEmpty(children)); hits = new SimpleIntegerProperty(0); calculateNumberOfMatches(); + expandedProperty.set(groupNode.getGroup().isExpanded()); + expandedProperty.addListener((observable, oldValue, newValue) -> groupNode.getGroup().setExpanded(newValue)); // Register listener databaseContext.getDatabase().registerListener(this); @@ -124,7 +124,7 @@ public boolean isRoot() { } public String getDescription() { - return "Some group named " + getDisplayName(); + return groupNode.getGroup().getDescription().orElse(""); } public SimpleIntegerProperty getHits() { @@ -147,7 +147,7 @@ public String toString() { return "GroupNodeViewModel{" + "displayName='" + displayName + '\'' + ", isRoot=" + isRoot + - ", iconCode='" + iconCode + '\'' + + ", iconCode='" + getIconCode() + '\'' + ", children=" + children + ", databaseContext=" + databaseContext + ", groupNode=" + groupNode + @@ -161,7 +161,7 @@ public int hashCode() { } public String getIconCode() { - return iconCode; + return groupNode.getGroup().getIconCode().orElse(IconTheme.JabRefIcon.DEFAULT_GROUP_ICON.getCode()); } public ObservableList getChildren() { @@ -201,4 +201,8 @@ void toggleExpansion() { boolean isMatchedBy(String searchString) { return StringUtil.isBlank(searchString) || getDisplayName().contains(searchString); } + + public Color getColor() { + return groupNode.getGroup().getColor().orElse(IconTheme.getDefaultColor()); + } } diff --git a/src/main/java/org/jabref/gui/groups/GroupTree.css b/src/main/java/org/jabref/gui/groups/GroupTree.css index 284c08f7f68..2f88e2b1652 100644 --- a/src/main/java/org/jabref/gui/groups/GroupTree.css +++ b/src/main/java/org/jabref/gui/groups/GroupTree.css @@ -101,9 +101,6 @@ } .tree-table-row-cell > .tree-table-cell > .icon { - -fx-font-family: 'MaterialDesignIcons'; - -fx-font-size: 16; - -fx-fill: #5e5f5e; -fx-translate-x: -5px; } diff --git a/src/main/java/org/jabref/gui/groups/GroupTreeController.java b/src/main/java/org/jabref/gui/groups/GroupTreeController.java index a38f63a68d0..5500b9e3617 100644 --- a/src/main/java/org/jabref/gui/groups/GroupTreeController.java +++ b/src/main/java/org/jabref/gui/groups/GroupTreeController.java @@ -75,7 +75,7 @@ public void initialize() { mainColumn.setCellValueFactory(cellData -> cellData.getValue().valueProperty()); mainColumn.setCellFactory(new ViewModelTreeTableCellFactory() .withText(GroupNodeViewModel::getDisplayName) - .withIcon(GroupNodeViewModel::getIconCode) + .withIcon(GroupNodeViewModel::getIconCode, GroupNodeViewModel::getColor) .withTooltip(GroupNodeViewModel::getDescription) ); diff --git a/src/main/java/org/jabref/gui/util/ViewModelTreeTableCellFactory.java b/src/main/java/org/jabref/gui/util/ViewModelTreeTableCellFactory.java index 294292481bd..1033a1c3502 100644 --- a/src/main/java/org/jabref/gui/util/ViewModelTreeTableCellFactory.java +++ b/src/main/java/org/jabref/gui/util/ViewModelTreeTableCellFactory.java @@ -6,6 +6,7 @@ import javafx.scene.control.TreeTableCell; import javafx.scene.control.TreeTableColumn; import javafx.scene.input.MouseEvent; +import javafx.scene.paint.Paint; import javafx.scene.text.Text; import javafx.util.Callback; @@ -32,10 +33,11 @@ public ViewModelTreeTableCellFactory withGraphic(Callback toGraph return this; } - public ViewModelTreeTableCellFactory withIcon(Callback toIcon) { + public ViewModelTreeTableCellFactory withIcon(Callback toIcon, Callback toColor) { this.toGraphic = viewModel -> { Text graphic = new Text(toIcon.call(viewModel)); graphic.getStyleClass().add("icon"); + graphic.setFill(toColor.call(viewModel)); return graphic; }; return this; diff --git a/src/main/java/org/jabref/logic/groups/DefaultGroupsFactory.java b/src/main/java/org/jabref/logic/groups/DefaultGroupsFactory.java index e71af583a3a..23c7a2a2bd6 100644 --- a/src/main/java/org/jabref/logic/groups/DefaultGroupsFactory.java +++ b/src/main/java/org/jabref/logic/groups/DefaultGroupsFactory.java @@ -1,10 +1,13 @@ package org.jabref.logic.groups; +import org.jabref.gui.IconTheme; import org.jabref.logic.l10n.Localization; import org.jabref.model.groups.AllEntriesGroup; public class DefaultGroupsFactory { public static AllEntriesGroup getAllEntriesGroup() { - return new AllEntriesGroup(Localization.lang("All entries")); + AllEntriesGroup group = new AllEntriesGroup(Localization.lang("All entries")); + group.setIconCode(IconTheme.JabRefIcon.ALL_ENTRIES_GROUP_ICON.getCode()); + return group; } } diff --git a/src/main/java/org/jabref/model/groups/AbstractGroup.java b/src/main/java/org/jabref/model/groups/AbstractGroup.java index 66759e1007d..f8b5bd7ad56 100644 --- a/src/main/java/org/jabref/model/groups/AbstractGroup.java +++ b/src/main/java/org/jabref/model/groups/AbstractGroup.java @@ -22,10 +22,10 @@ public abstract class AbstractGroup implements SearchMatcher { * The hierarchical context of the group. */ protected final GroupHierarchyType context; - protected Optional color; + protected Optional color = Optional.empty(); protected boolean isExpanded = true; - protected Optional description; - protected Optional iconCode; + protected Optional description = Optional.empty(); + protected Optional iconCode = Optional.empty(); protected AbstractGroup(String name, GroupHierarchyType context) { this.name = name;