Skip to content

Commit

Permalink
Add icon + color and description to groups (#2612)
Browse files Browse the repository at this point in the history
* Create default group factory

* Add color, description and icon to abstract groups class

* Add color, description and icon in groups dialog

* Show icon (in correct color) and description (as tooltip) in groups panel

* Fix code issues
  • Loading branch information
tobiasdiez committed Mar 6, 2017
1 parent 7963bdd commit 8295109
Show file tree
Hide file tree
Showing 29 changed files with 225 additions and 121 deletions.
4 changes: 2 additions & 2 deletions src/main/java/org/jabref/collab/GroupChange.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
import org.jabref.gui.groups.GroupTreeNodeViewModel;
import org.jabref.gui.groups.UndoableModifySubtree;
import org.jabref.gui.undo.NamedCompound;
import org.jabref.logic.groups.DefaultGroupsFactory;
import org.jabref.logic.l10n.Localization;
import org.jabref.model.database.BibDatabase;
import org.jabref.model.groups.AllEntriesGroup;
import org.jabref.model.groups.GroupTreeNode;

class GroupChange extends Change {
Expand All @@ -34,7 +34,7 @@ public boolean makeChange(BasePanel panel, BibDatabase secondary, NamedCompound
root.removeAllChildren();
if (changedGroups == null) {
// I think setting root to null is not possible
root.setGroup(new AllEntriesGroup(Localization.lang("All entries")));
root.setGroup(DefaultGroupsFactory.getAllEntriesGroup());
} else {
// change root group, even though it'll be AllEntries anyway
root.setGroup(changedGroups.getGroup());
Expand Down
189 changes: 96 additions & 93 deletions src/main/java/org/jabref/gui/IconTheme.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,24 +32,22 @@

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
/**
* JabRef's default color
*/
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<String, String> 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<String, String> 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);
private static Font FONT_16;
private static javafx.scene.text.Font FX_FONT;

static {
try (InputStream stream = FontBasedIcon.class.getResourceAsStream("/fonts/materialdesignicons-webfont.ttf")) {
Expand All @@ -63,6 +61,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<String, String> readIconThemeFile(URL url, String prefix) {
Objects.requireNonNull(url, "url");
Objects.requireNonNull(prefix, "prefix");

Map<String, String> 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*/,
Expand Down Expand Up @@ -165,6 +247,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);

Expand Down Expand Up @@ -259,85 +343,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<String, String> readIconThemeFile(URL url, String prefix) {
Objects.requireNonNull(url, "url");
Objects.requireNonNull(prefix, "prefix");

Map<String, String> 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;
}
}
1 change: 0 additions & 1 deletion src/main/java/org/jabref/gui/Main.css
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
.icon {
-fx-font-family: 'Material Design Icons';
-fx-font-size: 16.0;
-fx-fill : -fx-mid-text-color;
}

.tooltip {
Expand Down
41 changes: 35 additions & 6 deletions src/main/java/org/jabref/gui/groups/GroupDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import javax.swing.SwingConstants;
import javax.swing.event.CaretListener;

import javafx.scene.paint.Color;

import org.jabref.Globals;
import org.jabref.JabRefGUI;
import org.jabref.gui.Dialog;
Expand Down Expand Up @@ -80,6 +82,10 @@ class GroupDialog extends JDialog implements Dialog<AbstractGroup> {
Localization.lang("Refine supergroup: When selected, view entries contained in both this group and its supergroup"));
private final JRadioButton unionButton = new JRadioButton(
Localization.lang("Include subgroups: When selected, view entries contained in this group or its subgroups"));
private final JTextField colorField = new JTextField(GroupDialog.TEXTFIELD_LENGTH);
private final JTextField descriptionField = new JTextField(GroupDialog.TEXTFIELD_LENGTH);
private final JTextField iconField = new JTextField(GroupDialog.TEXTFIELD_LENGTH);

// for KeywordGroup
private final JTextField keywordGroupSearchField = new JTextField(GroupDialog.TEXTFIELD_LENGTH);
private final TextField keywordGroupSearchTerm = new TextField(FieldName.KEYWORDS, "", false);
Expand Down Expand Up @@ -209,7 +215,7 @@ public GroupDialog(JabRefFrame jabrefFrame, AbstractGroup editedGroup) {
// create layout
FormLayout layoutAll = new FormLayout(
"right:pref, 4dlu, fill:600px, 4dlu, fill:pref",
"p, 3dlu, p, 3dlu, p, 0dlu, p, 0dlu, p, 0dlu, p, 3dlu, p, 3dlu, p, "
"p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, p, 0dlu, p, 0dlu, p, 0dlu, p, 3dlu, p, 3dlu, p, "
+ "0dlu, p, 0dlu, p, 3dlu, p, 3dlu, "
+ "p, 3dlu, p, 3dlu, top:80dlu, 9dlu, p, 9dlu, p");

Expand All @@ -221,6 +227,18 @@ public GroupDialog(JabRefFrame jabrefFrame, AbstractGroup editedGroup) {
builderAll.append(nameField);
builderAll.nextLine();
builderAll.nextLine();
builderAll.append(Localization.lang("Description"));
builderAll.append(descriptionField);
builderAll.nextLine();
builderAll.nextLine();
builderAll.append(Localization.lang("Color"));
builderAll.append(colorField);
builderAll.nextLine();
builderAll.nextLine();
builderAll.append(Localization.lang("Icon"));
builderAll.append(iconField);
builderAll.nextLine();
builderAll.nextLine();
builderAll.append(explicitRadioButton, 5);
builderAll.nextLine();
builderAll.nextLine();
Expand Down Expand Up @@ -339,6 +357,14 @@ public void actionPerformed(ActionEvent e) {
autoGroupPersonsField.getText().trim());
}
}
try {
resultingGroup.setColor(Color.valueOf(colorField.getText()));
} catch (IllegalArgumentException ex) {
// Ignore invalid color (we should probably notify the user instead...)
}
resultingGroup.setDescription(descriptionField.getText());
resultingGroup.setIconCode(iconField.getText());

dispose();
} catch (IllegalArgumentException exception) {
jabrefFrame.showMessage(exception.getLocalizedMessage());
Expand All @@ -349,6 +375,9 @@ public void actionPerformed(ActionEvent e) {
ItemListener itemListener = e -> updateComponents();

nameField.addCaretListener(caretListener);
colorField.addCaretListener(caretListener);
descriptionField.addCaretListener(caretListener);
iconField.addCaretListener(caretListener);
keywordGroupSearchField.addCaretListener(caretListener);
keywordGroupSearchTerm.addCaretListener(caretListener);
keywordGroupCaseSensitive.addItemListener(itemListener);
Expand All @@ -363,9 +392,13 @@ public void actionPerformed(ActionEvent e) {
explicitRadioButton.setSelected(true);
setContext(GroupHierarchyType.INDEPENDENT);
} else {
nameField.setText(editedGroup.getName());
colorField.setText(editedGroup.getColor().map(Color::toString).orElse(""));
descriptionField.setText(editedGroup.getDescription().orElse(""));
iconField.setText(editedGroup.getIconCode().orElse(""));

if (editedGroup.getClass() == WordKeywordGroup.class) {
WordKeywordGroup group = (WordKeywordGroup) editedGroup;
nameField.setText(group.getName());
keywordGroupSearchField.setText(group.getSearchField());
keywordGroupSearchTerm.setText(group.getSearchExpression());
keywordGroupCaseSensitive.setSelected(group.isCaseSensitive());
Expand All @@ -374,7 +407,6 @@ public void actionPerformed(ActionEvent e) {
setContext(editedGroup.getHierarchicalContext());
} else if (editedGroup.getClass() == RegexKeywordGroup.class) {
RegexKeywordGroup group = (RegexKeywordGroup) editedGroup;
nameField.setText(group.getName());
keywordGroupSearchField.setText(group.getSearchField());
keywordGroupSearchTerm.setText(group.getSearchExpression());
keywordGroupCaseSensitive.setSelected(group.isCaseSensitive());
Expand All @@ -383,18 +415,15 @@ public void actionPerformed(ActionEvent e) {
setContext(editedGroup.getHierarchicalContext());
} else if (editedGroup.getClass() == SearchGroup.class) {
SearchGroup group = (SearchGroup) editedGroup;
nameField.setText(group.getName());
searchGroupSearchExpression.setText(group.getSearchExpression());
searchGroupCaseSensitive.setSelected(group.isCaseSensitive());
searchGroupRegExp.setSelected(group.isRegularExpression());
searchRadioButton.setSelected(true);
setContext(editedGroup.getHierarchicalContext());
} else if (editedGroup.getClass() == ExplicitGroup.class) {
nameField.setText(editedGroup.getName());
explicitRadioButton.setSelected(true);
setContext(editedGroup.getHierarchicalContext());
} else if (editedGroup.getClass() == AutomaticKeywordGroup.class) {
nameField.setText(editedGroup.getName());
autoRadioButton.setSelected(true);
setContext(editedGroup.getHierarchicalContext());

Expand Down
Loading

0 comments on commit 8295109

Please sign in to comment.