From 2ebc4395559a69a7400a66e3a8e046b3a1666d7f Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Thu, 28 Dec 2017 16:14:12 +0100 Subject: [PATCH 01/24] Start converting --- src/main/java/org/jabref/gui/BasePanel.java | 65 ++++++------------- .../jabref/gui/entryeditor/EntryEditor.java | 3 +- .../jabref/preferences/JabRefPreferences.java | 14 +++- .../preferences/PreviewPreferences.java | 22 +++---- 4 files changed, 46 insertions(+), 58 deletions(-) diff --git a/src/main/java/org/jabref/gui/BasePanel.java b/src/main/java/org/jabref/gui/BasePanel.java index 8cf926b0a4f..c77ce3c089b 100644 --- a/src/main/java/org/jabref/gui/BasePanel.java +++ b/src/main/java/org/jabref/gui/BasePanel.java @@ -1,6 +1,5 @@ package org.jabref.gui; -import java.awt.BorderLayout; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.ClipboardOwner; @@ -29,11 +28,8 @@ import java.util.stream.Collectors; import javax.swing.AbstractAction; -import javax.swing.BorderFactory; import javax.swing.JComponent; import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JSplitPane; import javax.swing.JTextArea; import javax.swing.SwingUtilities; import javax.swing.undo.CannotRedoException; @@ -41,7 +37,10 @@ import javafx.application.Platform; import javafx.embed.swing.JFXPanel; +import javafx.geometry.Orientation; import javafx.scene.Scene; +import javafx.scene.control.SplitPane; +import javafx.scene.layout.StackPane; import org.jabref.Globals; import org.jabref.JabRefExecutorService; @@ -148,14 +147,12 @@ import com.jgoodies.forms.layout.FormLayout; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.fxmisc.easybind.EasyBind; -public class BasePanel extends JPanel implements ClipboardOwner { +public class BasePanel extends StackPane implements ClipboardOwner { private static final Log LOGGER = LogFactory.getLog(BasePanel.class); - // Divider size for BaseFrame split pane. 0 means non-resizable. - private static final int SPLIT_PANE_DIVIDER_SIZE = 4; - private final BibDatabaseContext bibDatabaseContext; private final MainTableDataModel tableModel; @@ -180,7 +177,7 @@ public class BasePanel extends JPanel implements ClipboardOwner { private BasePanelMode mode = BasePanelMode.SHOWING_NOTHING; private EntryEditor currentEditor; private MainTableSelectionListener selectionListener; - private JSplitPane splitPane; + private SplitPane splitPane; private boolean saving; // AutoCompleter used in the search bar @@ -1348,8 +1345,8 @@ public void keyPressed(KeyEvent e) { } public void setupMainPanel() { - splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT); - splitPane.setDividerSize(SPLIT_PANE_DIVIDER_SIZE); + splitPane = new SplitPane(); + splitPane.setOrientation(Orientation.HORIZONTAL); adjustSplitter(); // restore last splitting state (before mainTable is created as creation affects the stored size of the entryEditors) // check whether a mainTable already existed and a floatSearch was active @@ -1357,26 +1354,17 @@ public void setupMainPanel() { createMainTable(); - splitPane.setTopComponent(mainTable.getPane()); - - // Remove borders - splitPane.setBorder(BorderFactory.createEmptyBorder()); - setBorder(BorderFactory.createEmptyBorder()); + splitPane.getItems().add(mainTable.getPane()); - // If an entry is currently being shown, make sure it stays shown, - // otherwise set the bottom component to null. + // If an entry is currently being shown, make sure it stays shown. if (mode == BasePanelMode.SHOWING_PREVIEW) { mode = BasePanelMode.SHOWING_NOTHING; highlightEntry(selectionListener.getPreview().getEntry()); } else if (mode == BasePanelMode.SHOWING_EDITOR) { mode = BasePanelMode.SHOWING_NOTHING; - } else { - splitPane.setBottomComponent(null); } - setLayout(new BorderLayout()); - removeAll(); - add(splitPane, BorderLayout.CENTER); + this.getChildren().setAll(splitPane); // Set up name autocompleter for search: instantiateSearchAutoCompleter(); @@ -1390,12 +1378,8 @@ public void setupMainPanel() { mainTable.showFloatSearch(); } - splitPane.revalidate(); - revalidate(); - repaint(); - // saves the divider position as soon as it changes - splitPane.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, event -> saveDividerLocation()); + EasyBind.subscribe(splitPane.getDividers().get(0).positionProperty(), position -> saveDividerLocation(position)); } /** @@ -1446,16 +1430,14 @@ public void updateStringDialog() { public void adjustSplitter() { if (mode == BasePanelMode.SHOWING_PREVIEW) { - splitPane.setDividerLocation( - splitPane.getHeight() - Globals.prefs.getPreviewPreferences().getPreviewPanelHeight()); + splitPane.setDividerPositions(Globals.prefs.getPreviewPreferences().getPreviewPanelDividerPosition().doubleValue()); } else { - splitPane.setDividerLocation( - splitPane.getHeight() - Globals.prefs.getInt(JabRefPreferences.ENTRY_EDITOR_HEIGHT)); + splitPane.setDividerPositions(Globals.prefs.getDouble(JabRefPreferences.ENTRY_EDITOR_HEIGHT)); } } private boolean isShowingEditor() { - return (splitPane.getBottomComponent() != null) && (splitPane.getBottomComponent() instanceof EntryEditor); + return mode == BasePanelMode.SHOWING_EDITOR; } public void showEntry(final BibEntry bibEntry) { @@ -1516,16 +1498,12 @@ public EntryEditor getCurrentEditor() { * @param editor The entry editor to add. */ public void showEntryEditor(EntryEditor editor) { - if (mode == BasePanelMode.SHOWING_EDITOR) { - Globals.prefs.putInt(JabRefPreferences.ENTRY_EDITOR_HEIGHT, - splitPane.getHeight() - splitPane.getDividerLocation()); - } mode = BasePanelMode.SHOWING_EDITOR; if (currentEditor != null) { currentEditor.setMovingToDifferentEntry(); } currentEditor = editor; - splitPane.setBottomComponent(editor); + splitPane.getItems().set(1, editor); if (editor.getEntry() != getShowing()) { newEntryShowing(editor.getEntry()); } @@ -1790,20 +1768,17 @@ public void autoGenerateKeysBeforeSaving() { } /** - * Depending on whether a preview or an entry editor is showing, save the current divider location in the correct - * preference setting. + * Depending on whether a preview or an entry editor is showing, save the current divider location in the correct preference setting. */ - public void saveDividerLocation() { + private void saveDividerLocation(Number position) { if (mode == BasePanelMode.SHOWING_PREVIEW) { - int previewPanelHeight = splitPane.getHeight() - splitPane.getDividerLocation(); PreviewPreferences previewPreferences = Globals.prefs.getPreviewPreferences() .getBuilder() - .withPreviewPanelHeight(previewPanelHeight) + .withPreviewPanelDividerPosition(position) .build(); Globals.prefs.storePreviewPreferences(previewPreferences); } else if (mode == BasePanelMode.SHOWING_EDITOR) { - Globals.prefs.putInt(JabRefPreferences.ENTRY_EDITOR_HEIGHT, - splitPane.getHeight() - splitPane.getDividerLocation()); + Globals.prefs.putDouble(JabRefPreferences.ENTRY_EDITOR_HEIGHT, position.doubleValue()); } } diff --git a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java index 140abc77233..3d2215d3fcf 100644 --- a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java +++ b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java @@ -6,6 +6,7 @@ import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; +import java.awt.Panel; import java.awt.RenderingHints; import java.awt.event.ActionEvent; import java.awt.event.KeyAdapter; @@ -100,7 +101,7 @@ * events whenever a field of the entry changes, enabling the text fields to * update themselves if the change is made from somewhere else. */ -public class EntryEditor extends JPanel implements EntryContainer { +public class EntryEditor extends Panel implements EntryContainer { private static final Log LOGGER = LogFactory.getLog(EntryEditor.class); diff --git a/src/main/java/org/jabref/preferences/JabRefPreferences.java b/src/main/java/org/jabref/preferences/JabRefPreferences.java index 155f53cd4ee..6e31892613a 100644 --- a/src/main/java/org/jabref/preferences/JabRefPreferences.java +++ b/src/main/java/org/jabref/preferences/JabRefPreferences.java @@ -1015,6 +1015,10 @@ public int getInt(String key) { return prefs.getInt(key, getIntDefault(key)); } + public double getDouble(String key) { + return prefs.getDouble(key, getDoubleDefault(key)); + } + public int getIntDefault(String key) { if (key.equals(JabRefPreferences.MENU_FONT_SIZE)) { Integer menuFontSize = (Integer) defaults.get(key); @@ -1028,6 +1032,10 @@ public int getIntDefault(String key) { } } + private double getDoubleDefault(String key) { + return (double) defaults.get(key); + } + public void put(String key, String value) { prefs.put(key, value); } @@ -1040,6 +1048,10 @@ public void putInt(String key, int value) { prefs.putInt(key, value); } + public void putDouble(String key, double value) { + prefs.putDouble(key, value); + } + public void remove(String key) { prefs.remove(key); } @@ -1454,7 +1466,7 @@ public VersionPreferences getVersionPreferences() { public JabRefPreferences storePreviewPreferences(PreviewPreferences previewPreferences) { putInt(CYCLE_PREVIEW_POS, previewPreferences.getPreviewCyclePosition()); putStringList(CYCLE_PREVIEW, previewPreferences.getPreviewCycle()); - putInt(PREVIEW_PANEL_HEIGHT, previewPreferences.getPreviewPanelHeight()); + putDouble(PREVIEW_PANEL_HEIGHT, previewPreferences.getPreviewPanelDividerPosition().doubleValue()); put(PREVIEW_STYLE, previewPreferences.getPreviewStyle()); putBoolean(PREVIEW_ENABLED, previewPreferences.isPreviewPanelEnabled()); return this; diff --git a/src/main/java/org/jabref/preferences/PreviewPreferences.java b/src/main/java/org/jabref/preferences/PreviewPreferences.java index 2a03b5d4fea..a4099ca8e54 100644 --- a/src/main/java/org/jabref/preferences/PreviewPreferences.java +++ b/src/main/java/org/jabref/preferences/PreviewPreferences.java @@ -2,20 +2,20 @@ import java.util.List; + public class PreviewPreferences { private final List previewCycle; private final int previewCyclePosition; - private final int previewPanelHeight; + private final Number previewPanelDividerPosition; private final boolean previewPanelEnabled; private final String previewStyle; private final String previewStyleDefault; - - public PreviewPreferences(List previewCycle, int previeCyclePosition, int previewPanelHeight, boolean previewPanelEnabled, String previewStyle, String previewStyleDefault) { + public PreviewPreferences(List previewCycle, int previeCyclePosition, Number previewPanelDividerPosition, boolean previewPanelEnabled, String previewStyle, String previewStyleDefault) { this.previewCycle = previewCycle; this.previewCyclePosition = previeCyclePosition; - this.previewPanelHeight = previewPanelHeight; + this.previewPanelDividerPosition = previewPanelDividerPosition; this.previewPanelEnabled = previewPanelEnabled; this.previewStyle = previewStyle; this.previewStyleDefault = previewStyleDefault; @@ -29,8 +29,8 @@ public int getPreviewCyclePosition() { return previewCyclePosition; } - public int getPreviewPanelHeight() { - return previewPanelHeight; + public Number getPreviewPanelDividerPosition() { + return previewPanelDividerPosition; } public boolean isPreviewPanelEnabled() { @@ -52,7 +52,7 @@ public Builder getBuilder() { public static class Builder { private List previewCycle; private int previeCyclePosition; - private int previewPanelHeight; + private Number previewPanelDividerPosition; private boolean previewPanelEnabled; private String previewStyle; private final String previewStyleDefault; @@ -61,7 +61,7 @@ public static class Builder { public Builder(PreviewPreferences previewPreferences) { this.previewCycle = previewPreferences.getPreviewCycle(); this.previeCyclePosition = previewPreferences.getPreviewCyclePosition(); - this.previewPanelHeight = previewPreferences.getPreviewPanelHeight(); + this.previewPanelDividerPosition = previewPreferences.getPreviewPanelDividerPosition(); this.previewPanelEnabled = previewPreferences.isPreviewPanelEnabled(); this.previewStyle = previewPreferences.getPreviewStyle(); this.previewStyleDefault = previewPreferences.getPreviewStyleDefault(); @@ -81,8 +81,8 @@ public Builder withPreviewCyclePosition(int position) { return this; } - public Builder withPreviewPanelHeight(int previewPanelHeight) { - this.previewPanelHeight = previewPanelHeight; + public Builder withPreviewPanelDividerPosition(Number previewPanelDividerPosition) { + this.previewPanelDividerPosition = previewPanelDividerPosition; return this; } @@ -97,7 +97,7 @@ public Builder withPreviewStyle(String previewStyle) { } public PreviewPreferences build() { - return new PreviewPreferences(previewCycle, previeCyclePosition, previewPanelHeight, previewPanelEnabled, previewStyle, previewStyleDefault); + return new PreviewPreferences(previewCycle, previeCyclePosition, previewPanelDividerPosition, previewPanelEnabled, previewStyle, previewStyleDefault); } } From f70ea5df7281127f0d62bd7336a9e6151b1ae12c Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Fri, 29 Dec 2017 22:24:58 +0100 Subject: [PATCH 02/24] Refactor icons (less awt) --- .../java/org/jabref/gui/DragDropPane.java | 6 +- .../jabref/gui/FindUnlinkedFilesDialog.java | 2 +- src/main/java/org/jabref/gui/GUIGlobals.java | 18 ++--- src/main/java/org/jabref/gui/IconTheme.java | 75 ++++++++++++------ .../gui/InternalMaterialDesignIcon.java | 75 ++++++++++++++++++ src/main/java/org/jabref/gui/JabRefIcon.java | 15 ++++ .../java/org/jabref/gui/PreambleEditor.java | 4 +- .../java/org/jabref/gui/PreviewPanel.java | 4 +- .../org/jabref/gui/SidePaneComponent.java | 8 +- .../java/org/jabref/gui/StringDialog.java | 10 +-- .../gui/actions/AutoLinkFilesAction.java | 4 +- .../jabref/gui/actions/NewDatabaseAction.java | 2 +- .../jabref/gui/actions/NewEntryAction.java | 2 +- .../gui/actions/NewSubDatabaseAction.java | 2 +- .../BibtexKeyPatternPanel.java | 2 +- .../jabref/gui/collab/FileUpdatePanel.java | 2 +- .../customentrytypes/FieldSetComponent.java | 4 +- .../org/jabref/gui/desktop/JabRefDesktop.java | 3 +- .../ShowDocumentViewerAction.java | 2 +- .../gui/entryeditor/DeprecatedFieldsTab.java | 2 +- .../gui/entryeditor/OptionalFields2Tab.java | 2 +- .../gui/entryeditor/OptionalFieldsTab.java | 2 +- .../gui/entryeditor/OtherFieldsTab.java | 2 +- .../gui/entryeditor/RequiredFieldsTab.java | 2 +- .../org/jabref/gui/entryeditor/SourceTab.java | 2 +- .../gui/entryeditor/UserDefinedFieldsTab.java | 2 +- .../errorconsole/ErrorConsoleController.java | 2 +- .../gui/errorconsole/LogEventViewModel.java | 9 ++- .../jabref/gui/exporter/SaveAllAction.java | 2 +- .../externalfiletype/ExternalFileType.java | 15 ++-- .../ExternalFileTypeEntryEditor.java | 4 +- .../externalfiletype/ExternalFileTypes.java | 77 ++++++------------- .../UnknownExternalFileType.java | 2 +- .../jabref/gui/groups/GroupNodeViewModel.java | 17 ++-- .../org/jabref/gui/groups/GroupSidePane.java | 4 +- .../gui/groups/GroupTreeController.java | 2 +- .../gui/groups/GroupTreeNodeViewModel.java | 4 +- .../java/org/jabref/gui/help/HelpAction.java | 6 +- .../gui/importer/EntryFromPDFCreator.java | 2 +- .../gui/importer/ImportInspectionDialog.java | 12 +-- .../gui/importer/fetcher/GeneralFetcher.java | 4 +- .../ManageJournalAbbreviationsController.java | 12 +-- .../jabref/gui/keyboard/KeyBindingAction.java | 2 +- .../gui/keyboard/KeyBindingViewModel.java | 7 +- .../keyboard/KeyBindingsDialogController.java | 4 +- .../gui/openoffice/StyleSelectDialog.java | 4 +- .../gui/plaintextimport/TextInputDialog.java | 10 +-- .../jabref/gui/preftabs/NameFormatterTab.java | 4 +- .../org/jabref/gui/preftabs/XmpPrefsTab.java | 4 +- .../protectedterms/ProtectedTermsDialog.java | 6 +- .../gui/push/PushToApplicationButton.java | 2 +- .../jabref/gui/search/SearchResultFrame.java | 10 +-- .../jabref/gui/search/SearchTextField.java | 2 +- .../SpecialFieldValueViewModel.java | 35 +++++---- .../specialfields/SpecialFieldViewModel.java | 32 ++++++-- .../util/ViewModelTreeTableCellFactory.java | 14 +--- 56 files changed, 336 insertions(+), 228 deletions(-) create mode 100644 src/main/java/org/jabref/gui/InternalMaterialDesignIcon.java create mode 100644 src/main/java/org/jabref/gui/JabRefIcon.java diff --git a/src/main/java/org/jabref/gui/DragDropPane.java b/src/main/java/org/jabref/gui/DragDropPane.java index 4382b1cfea5..8b8a139015a 100644 --- a/src/main/java/org/jabref/gui/DragDropPane.java +++ b/src/main/java/org/jabref/gui/DragDropPane.java @@ -124,14 +124,14 @@ public void mouseReleased(MouseEvent e) { static class MarkerPane extends JPanel { private Point locationP; - private final IconTheme.JabRefIcon moveTabArrow; + private final JabRefIcon moveTabArrow; public MarkerPane() { setOpaque(false); // Sets the marker fontIcon - moveTabArrow = IconTheme.JabRefIcon.MOVE_TAB_ARROW; + moveTabArrow = IconTheme.JabRefIcons.MOVE_TAB_ARROW; } @Override @@ -141,7 +141,7 @@ public void paintComponent(Graphics g) { g2.setComposite(AlphaComposite.getInstance( AlphaComposite.SRC_OVER, 0.9f)); // Set transparency g.setFont(IconTheme.FONT.deriveFont(Font.BOLD, 24f)); - g.drawString(moveTabArrow.getCode(), locationP.x - (moveTabArrow.getIcon().getIconWidth() / 2), + moveTabArrow.getSmallIcon().paintIcon(this, g, locationP.x - (moveTabArrow.getIcon().getIconWidth() / 2), locationP.y + (moveTabArrow.getIcon().getIconHeight() / 2)); } diff --git a/src/main/java/org/jabref/gui/FindUnlinkedFilesDialog.java b/src/main/java/org/jabref/gui/FindUnlinkedFilesDialog.java index fbf049a942d..3bc4e339797 100644 --- a/src/main/java/org/jabref/gui/FindUnlinkedFilesDialog.java +++ b/src/main/java/org/jabref/gui/FindUnlinkedFilesDialog.java @@ -987,7 +987,7 @@ public Component getListCellRendererComponent(JList list, Object value, int i if (value instanceof EntryFromFileCreator) { EntryFromFileCreator creator = (EntryFromFileCreator) value; if (creator.getExternalFileType() != null) { - label.setIcon(creator.getExternalFileType().getIcon()); + label.setIcon(creator.getExternalFileType().getIcon().getSmallIcon()); } } return label; diff --git a/src/main/java/org/jabref/gui/GUIGlobals.java b/src/main/java/org/jabref/gui/GUIGlobals.java index 61e3d4364ec..5d5c5dabfeb 100644 --- a/src/main/java/org/jabref/gui/GUIGlobals.java +++ b/src/main/java/org/jabref/gui/GUIGlobals.java @@ -76,40 +76,40 @@ public static void updateEntryEditorColors() { */ public static void init() { JLabel label; - label = new JLabel(IconTheme.JabRefIcon.PDF_FILE.getSmallIcon()); + label = new JLabel(IconTheme.JabRefIcons.PDF_FILE.getSmallIcon()); label.setToolTipText(Localization.lang("Open") + " PDF"); GUIGlobals.TABLE_ICONS.put(FieldName.PDF, label); - label = new JLabel(IconTheme.JabRefIcon.WWW.getSmallIcon()); + label = new JLabel(IconTheme.JabRefIcons.WWW.getSmallIcon()); label.setToolTipText(Localization.lang("Open") + " URL"); GUIGlobals.TABLE_ICONS.put(FieldName.URL, label); - label = new JLabel(IconTheme.JabRefIcon.WWW.getSmallIcon()); + label = new JLabel(IconTheme.JabRefIcons.WWW.getSmallIcon()); label.setToolTipText(Localization.lang("Open") + " CiteSeer URL"); GUIGlobals.TABLE_ICONS.put("citeseerurl", label); - label = new JLabel(IconTheme.JabRefIcon.WWW.getSmallIcon()); + label = new JLabel(IconTheme.JabRefIcons.WWW.getSmallIcon()); label.setToolTipText(Localization.lang("Open") + " ArXiv URL"); GUIGlobals.TABLE_ICONS.put(FieldName.EPRINT, label); - label = new JLabel(IconTheme.JabRefIcon.DOI.getSmallIcon()); + label = new JLabel(IconTheme.JabRefIcons.DOI.getSmallIcon()); label.setToolTipText(Localization.lang("Open") + " DOI " + Localization.lang("web link")); GUIGlobals.TABLE_ICONS.put(FieldName.DOI, label); - label = new JLabel(IconTheme.JabRefIcon.FILE.getSmallIcon()); + label = new JLabel(IconTheme.JabRefIcons.FILE.getSmallIcon()); label.setToolTipText(Localization.lang("Open") + " PS"); GUIGlobals.TABLE_ICONS.put(FieldName.PS, label); - label = new JLabel(IconTheme.JabRefIcon.FOLDER.getSmallIcon()); + label = new JLabel(IconTheme.JabRefIcons.FOLDER.getSmallIcon()); label.setToolTipText(Localization.lang("Open folder")); GUIGlobals.TABLE_ICONS.put(FieldName.FOLDER, label); - label = new JLabel(IconTheme.JabRefIcon.FILE.getSmallIcon()); + label = new JLabel(IconTheme.JabRefIcons.FILE.getSmallIcon()); label.setToolTipText(Localization.lang("Open file")); GUIGlobals.TABLE_ICONS.put(FieldName.FILE, label); for (ExternalFileType fileType : ExternalFileTypes.getInstance().getExternalFileTypeSelection()) { - label = new JLabel(fileType.getIcon()); + label = new JLabel(fileType.getIcon().getSmallIcon()); label.setToolTipText(Localization.lang("Open %0 file", fileType.getName())); GUIGlobals.TABLE_ICONS.put(fileType.getName(), label); } diff --git a/src/main/java/org/jabref/gui/IconTheme.java b/src/main/java/org/jabref/gui/IconTheme.java index 09488c333f6..da228780bd5 100644 --- a/src/main/java/org/jabref/gui/IconTheme.java +++ b/src/main/java/org/jabref/gui/IconTheme.java @@ -15,24 +15,23 @@ import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.stream.Collectors; import javax.swing.Icon; import javax.swing.ImageIcon; import javafx.scene.Node; import javafx.scene.image.Image; +import javafx.scene.image.ImageView; import org.jabref.logic.groups.DefaultGroupsFactory; import org.jabref.preferences.JabRefPreferences; import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon; -import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIconView; +import org.apache.commons.lang3.NotImplementedException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -166,8 +165,8 @@ public static List getLogoSet() { return jabrefLogos; } - - public enum JabRefIcon { + + public enum JabRefIcons implements JabRefIcon { ADD(MaterialDesignIcon.PLUS_BOX), ADD_NOBOX(MaterialDesignIcon.PLUS), @@ -257,6 +256,7 @@ public enum JabRefIcon { FILE_POWERPOINT(MaterialDesignIcon.FILE_POWERPOINT), /*css: file-powerpoint */ FILE_TEXT(MaterialDesignIcon.FILE_DOCUMENT), /*css: file-document */ FILE_MULTIPLE(MaterialDesignIcon.FILE_MULTIPLE), /*css: file-multiple */ + FILE_OPENOFFICE(IconTheme.getImage("openoffice")), KEY_BINDINGS(MaterialDesignIcon.KEYBOARD), /*css: keyboard */ FIND_DUPLICATES(MaterialDesignIcon.CODE_EQUAL), /*css: code-equal */ PULL(MaterialDesignIcon.SOURCE_PULL), /*source-pull*/ @@ -274,42 +274,67 @@ public enum JabRefIcon { // STILL MISSING: GROUP_REGULAR(Color.RED, MaterialDesignIcon.SYNC); - private final List icons; - private final Color color; - private final String unicode; + private final JabRefIcon icon; - JabRefIcon(MaterialDesignIcon... icons) { + JabRefIcons(MaterialDesignIcon... icons) { this(IconTheme.DEFAULT_COLOR, icons); } - JabRefIcon(Color color, MaterialDesignIcon... icons) { - this.icons = Arrays.asList(icons); - this.color = color; - this.unicode = Arrays.stream(icons).map(MaterialDesignIcon::unicode).collect(Collectors.joining()); + JabRefIcons(Color color, MaterialDesignIcon... icons) { + icon = new InternalMaterialDesignIcon(color, icons); } - public FontBasedIcon getIcon() { - return new FontBasedIcon(this.unicode, this.color); + JabRefIcons(ImageIcon imageIcon) { + icon = new InternalFileIcon(imageIcon); } - public List getUnderlyingIcons() { - return icons; + @Override + public Icon getIcon() { + return icon.getIcon(); } - public MaterialDesignIcon getUnderlyingIcon() { - return icons.get(0); + @Override + public Icon getSmallIcon() { + return icon.getSmallIcon(); } - public FontBasedIcon getSmallIcon() { - return new FontBasedIcon(this.unicode, this.color, JabRefPreferences.getInstance().getInt(JabRefPreferences.ICON_SIZE_SMALL)); + @Override + public Node getGraphicNode() { + return icon.getGraphicNode(); } - public Node getGraphicNode() { - return new MaterialDesignIconView(this.icons.get(0)); + @Override + public JabRefIcon disabled() { + return icon.disabled(); } - public String getCode() { - return this.unicode; + private class InternalFileIcon implements JabRefIcon { + + private final ImageIcon imageIcon; + + InternalFileIcon(ImageIcon imageIcon) { + this.imageIcon = imageIcon; + } + + @Override + public Icon getIcon() { + return imageIcon; + } + + @Override + public Icon getSmallIcon() { + return imageIcon; + } + + @Override + public Node getGraphicNode() { + return new ImageView(new Image(imageIcon.getDescription())); + } + + @Override + public JabRefIcon disabled() { + throw new NotImplementedException("Cannot create disabled version of a file-based icon"); + } } } diff --git a/src/main/java/org/jabref/gui/InternalMaterialDesignIcon.java b/src/main/java/org/jabref/gui/InternalMaterialDesignIcon.java new file mode 100644 index 00000000000..d8d9f44e338 --- /dev/null +++ b/src/main/java/org/jabref/gui/InternalMaterialDesignIcon.java @@ -0,0 +1,75 @@ +package org.jabref.gui; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import javax.swing.Icon; + +import javafx.scene.Node; +import javafx.scene.paint.Color; + +import org.jabref.preferences.JabRefPreferences; + +import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon; +import de.jensd.fx.glyphs.materialdesignicons.utils.MaterialDesignIconFactory; + +public class InternalMaterialDesignIcon implements JabRefIcon { + private final List icons; + private final Color color; + private final String unicode; + + public InternalMaterialDesignIcon(java.awt.Color color, MaterialDesignIcon... icons) { + this(toFX(color), Arrays.asList(icons)); + } + + public InternalMaterialDesignIcon(Color color, MaterialDesignIcon... icons) { + this(color, Arrays.asList(icons)); + } + + InternalMaterialDesignIcon(Color color, List icons) { + this.icons = icons; + this.color = color; + this.unicode = icons.stream().map(MaterialDesignIcon::unicode).collect(Collectors.joining()); + } + + public static java.awt.Color toAWT(Color color) { + return new java.awt.Color((float) color.getRed(), + (float) color.getGreen(), + (float) color.getBlue(), + (float) color.getOpacity()); + } + + public static Color toFX(java.awt.Color awtColor) { + int r = awtColor.getRed(); + int g = awtColor.getGreen(); + int b = awtColor.getBlue(); + int a = awtColor.getAlpha(); + double opacity = a / 255.0; + return javafx.scene.paint.Color.rgb(r, g, b, opacity); + } + + @Override + public Icon getIcon() { + return new IconTheme.FontBasedIcon(this.unicode, toAWT(this.color)); + } + + @Override + public Icon getSmallIcon() { + return new IconTheme.FontBasedIcon(this.unicode, toAWT(this.color), JabRefPreferences.getInstance().getInt(JabRefPreferences.ICON_SIZE_SMALL)); + } + + @Override + public Node getGraphicNode() { + return MaterialDesignIconFactory.get().createIcon(this.icons.get(0)); + } + + @Override + public JabRefIcon disabled() { + return new InternalMaterialDesignIcon(toFX(IconTheme.DEFAULT_DISABLED_COLOR), icons); + } + + public String getCode() { + return this.unicode; + } +} diff --git a/src/main/java/org/jabref/gui/JabRefIcon.java b/src/main/java/org/jabref/gui/JabRefIcon.java new file mode 100644 index 00000000000..08d4fc56e48 --- /dev/null +++ b/src/main/java/org/jabref/gui/JabRefIcon.java @@ -0,0 +1,15 @@ +package org.jabref.gui; + +import javax.swing.Icon; + +import javafx.scene.Node; + +public interface JabRefIcon { + Icon getIcon(); + + Icon getSmallIcon(); + + Node getGraphicNode(); + + JabRefIcon disabled(); +} diff --git a/src/main/java/org/jabref/gui/PreambleEditor.java b/src/main/java/org/jabref/gui/PreambleEditor.java index ffcfb095c7a..7f956290631 100644 --- a/src/main/java/org/jabref/gui/PreambleEditor.java +++ b/src/main/java/org/jabref/gui/PreambleEditor.java @@ -174,7 +174,7 @@ public void actionPerformed(ActionEvent e) { class UndoAction extends AbstractAction { public UndoAction() { - super("Undo", IconTheme.JabRefIcon.UNDO.getIcon()); + super("Undo", IconTheme.JabRefIcons.UNDO.getIcon()); putValue(Action.SHORT_DESCRIPTION, "Undo"); } @@ -187,7 +187,7 @@ public void actionPerformed(ActionEvent e) { class RedoAction extends AbstractAction { public RedoAction() { - super("Redo", IconTheme.JabRefIcon.REDO.getIcon()); + super("Redo", IconTheme.JabRefIcons.REDO.getIcon()); putValue(Action.SHORT_DESCRIPTION, "Redo"); } diff --git a/src/main/java/org/jabref/gui/PreviewPanel.java b/src/main/java/org/jabref/gui/PreviewPanel.java index d453aa0fff2..49958ceb3cf 100644 --- a/src/main/java/org/jabref/gui/PreviewPanel.java +++ b/src/main/java/org/jabref/gui/PreviewPanel.java @@ -123,10 +123,10 @@ private void createKeyBindings() { } private ContextMenu createPopupMenu() { - MenuItem copyPreview = new MenuItem(Localization.lang("Copy preview"), IconTheme.JabRefIcon.COPY.getGraphicNode()); + MenuItem copyPreview = new MenuItem(Localization.lang("Copy preview"), IconTheme.JabRefIcons.COPY.getGraphicNode()); copyPreview.setAccelerator(keyBindingRepository.getKeyCombination(KeyBinding.COPY_PREVIEW)); copyPreview.setOnAction(event -> copyPreviewToClipBoard()); - MenuItem printEntryPreview = new MenuItem(Localization.lang("Print entry preview"), IconTheme.JabRefIcon.PRINTED.getGraphicNode()); + MenuItem printEntryPreview = new MenuItem(Localization.lang("Print entry preview"), IconTheme.JabRefIcons.PRINTED.getGraphicNode()); printEntryPreview.setOnAction(event -> print()); MenuItem previousPreviewLayout = new MenuItem(Localization.menuTitleFX("Previous preview layout")); previousPreviewLayout.setAccelerator(keyBindingRepository.getKeyCombination(KeyBinding.PREVIOUS_PREVIEW_LAYOUT)); diff --git a/src/main/java/org/jabref/gui/SidePaneComponent.java b/src/main/java/org/jabref/gui/SidePaneComponent.java index d6d54678b57..911ed8b59c4 100644 --- a/src/main/java/org/jabref/gui/SidePaneComponent.java +++ b/src/main/java/org/jabref/gui/SidePaneComponent.java @@ -20,7 +20,7 @@ public abstract class SidePaneComponent extends JPanel { - protected final JButton close = new JButton(IconTheme.JabRefIcon.CLOSE.getSmallIcon()); + protected final JButton close = new JButton(IconTheme.JabRefIcons.CLOSE.getSmallIcon()); protected final SidePaneManager manager; @@ -37,12 +37,12 @@ public SidePaneComponent(SidePaneManager manager, Icon icon, String title) { close.setBorder(null); close.addActionListener(e -> hideAway()); - JButton up = new JButton(IconTheme.JabRefIcon.UP.getSmallIcon()); + JButton up = new JButton(IconTheme.JabRefIcons.UP.getSmallIcon()); up.setMargin(new Insets(0, 0, 0, 0)); up.setBorder(null); up.addActionListener(e -> moveUp()); - JButton down = new JButton(IconTheme.JabRefIcon.DOWN.getSmallIcon()); + JButton down = new JButton(IconTheme.JabRefIcons.DOWN.getSmallIcon()); down.setMargin(new Insets(0, 0, 0, 0)); down.setBorder(null); down.addActionListener(e -> moveDown()); @@ -123,7 +123,7 @@ public Dimension getMinimumSize() { public class ToggleAction extends MnemonicAwareAction { - public ToggleAction(String text, String description, KeyStroke key, IconTheme.JabRefIcon icon) { + public ToggleAction(String text, String description, KeyStroke key, JabRefIcon icon) { super(icon.getIcon()); putValue(Action.NAME, text); putValue(Action.ACCELERATOR_KEY, key); diff --git a/src/main/java/org/jabref/gui/StringDialog.java b/src/main/java/org/jabref/gui/StringDialog.java index d79dbb67383..445a9ab3bba 100644 --- a/src/main/java/org/jabref/gui/StringDialog.java +++ b/src/main/java/org/jabref/gui/StringDialog.java @@ -190,7 +190,7 @@ static class SaveDatabaseAction extends AbstractAction { public SaveDatabaseAction(StringDialog parent) { - super("Save library", IconTheme.JabRefIcon.SAVE.getIcon()); + super("Save library", IconTheme.JabRefIcons.SAVE.getIcon()); putValue(Action.SHORT_DESCRIPTION, Localization.lang("Save library")); this.parent = parent; } @@ -336,7 +336,7 @@ class NewStringAction extends AbstractAction { public NewStringAction(StringDialog parent) { - super("New string", IconTheme.JabRefIcon.ADD.getIcon()); + super("New string", IconTheme.JabRefIcons.ADD.getIcon()); putValue(Action.SHORT_DESCRIPTION, Localization.lang("New string")); this.parent = parent; } @@ -385,7 +385,7 @@ class RemoveStringAction extends AbstractAction { public RemoveStringAction(StringDialog parent) { - super("Remove selected strings", IconTheme.JabRefIcon.REMOVE.getIcon()); + super("Remove selected strings", IconTheme.JabRefIcons.REMOVE.getIcon()); putValue(Action.SHORT_DESCRIPTION, Localization.lang("Remove selected strings")); this.parent = parent; } @@ -430,7 +430,7 @@ public void actionPerformed(ActionEvent e) { class UndoAction extends AbstractAction { public UndoAction() { - super("Undo", IconTheme.JabRefIcon.UNDO.getIcon()); + super("Undo", IconTheme.JabRefIcons.UNDO.getIcon()); putValue(Action.SHORT_DESCRIPTION, Localization.lang("Undo")); } @@ -443,7 +443,7 @@ public void actionPerformed(ActionEvent e) { class RedoAction extends AbstractAction { public RedoAction() { - super("Redo", IconTheme.JabRefIcon.REDO.getIcon()); + super("Redo", IconTheme.JabRefIcons.REDO.getIcon()); putValue(Action.SHORT_DESCRIPTION, Localization.lang("Redo")); } diff --git a/src/main/java/org/jabref/gui/actions/AutoLinkFilesAction.java b/src/main/java/org/jabref/gui/actions/AutoLinkFilesAction.java index db9931a8f00..3e623f5179d 100644 --- a/src/main/java/org/jabref/gui/actions/AutoLinkFilesAction.java +++ b/src/main/java/org/jabref/gui/actions/AutoLinkFilesAction.java @@ -24,8 +24,8 @@ public class AutoLinkFilesAction extends AbstractAction { public AutoLinkFilesAction() { - putValue(Action.SMALL_ICON, IconTheme.JabRefIcon.AUTO_FILE_LINK.getSmallIcon()); - putValue(Action.LARGE_ICON_KEY, IconTheme.JabRefIcon.AUTO_FILE_LINK.getIcon()); + putValue(Action.SMALL_ICON, IconTheme.JabRefIcons.AUTO_FILE_LINK.getSmallIcon()); + putValue(Action.LARGE_ICON_KEY, IconTheme.JabRefIcons.AUTO_FILE_LINK.getIcon()); putValue(Action.NAME, Localization.lang("Automatically set file links")); putValue(Action.ACCELERATOR_KEY, Globals.getKeyPrefs().getKey(KeyBinding.AUTOMATICALLY_LINK_FILES)); } diff --git a/src/main/java/org/jabref/gui/actions/NewDatabaseAction.java b/src/main/java/org/jabref/gui/actions/NewDatabaseAction.java index 5aa52aa62b0..f546b9ef6e8 100644 --- a/src/main/java/org/jabref/gui/actions/NewDatabaseAction.java +++ b/src/main/java/org/jabref/gui/actions/NewDatabaseAction.java @@ -20,7 +20,7 @@ public class NewDatabaseAction extends MnemonicAwareAction { private final BibDatabaseMode mode; public NewDatabaseAction(JabRefFrame jabRefFrame, BibDatabaseMode mode) { - super(IconTheme.JabRefIcon.NEW.getIcon()); + super(IconTheme.JabRefIcons.NEW.getIcon()); this.jabRefFrame = jabRefFrame; this.mode = mode; putValue(Action.NAME, Localization.menuTitle("New %0 library", mode.getFormattedName())); diff --git a/src/main/java/org/jabref/gui/actions/NewEntryAction.java b/src/main/java/org/jabref/gui/actions/NewEntryAction.java index b404dfea3af..8245889ff4b 100644 --- a/src/main/java/org/jabref/gui/actions/NewEntryAction.java +++ b/src/main/java/org/jabref/gui/actions/NewEntryAction.java @@ -27,7 +27,7 @@ public class NewEntryAction extends MnemonicAwareAction { public NewEntryAction(JabRefFrame jabRefFrame, KeyStroke key) { // This action leads to a dialog asking for entry type. - super(IconTheme.JabRefIcon.ADD_ENTRY.getIcon()); + super(IconTheme.JabRefIcons.ADD_ENTRY.getIcon()); this.jabRefFrame = jabRefFrame; putValue(Action.NAME, Localization.menuTitle("New entry") + "..."); putValue(Action.ACCELERATOR_KEY, key); diff --git a/src/main/java/org/jabref/gui/actions/NewSubDatabaseAction.java b/src/main/java/org/jabref/gui/actions/NewSubDatabaseAction.java index 199f0400e4d..e5fc7c6bc4e 100644 --- a/src/main/java/org/jabref/gui/actions/NewSubDatabaseAction.java +++ b/src/main/java/org/jabref/gui/actions/NewSubDatabaseAction.java @@ -21,7 +21,7 @@ public class NewSubDatabaseAction extends MnemonicAwareAction { private final JabRefFrame jabRefFrame; public NewSubDatabaseAction(JabRefFrame jabRefFrame) { - super(IconTheme.JabRefIcon.NEW.getIcon()); + super(IconTheme.JabRefIcons.NEW.getIcon()); this.jabRefFrame = jabRefFrame; putValue(Action.NAME, Localization.menuTitle("New sublibrary based on AUX file") + "..."); putValue(Action.SHORT_DESCRIPTION, Localization.lang("New BibTeX sublibrary")); diff --git a/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java b/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java index f14b7ab073f..cabdd4b00bc 100644 --- a/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java +++ b/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java @@ -135,7 +135,7 @@ private void buildGUI() { con.weighty = 0; con.anchor = GridBagConstraints.SOUTHEAST; con.insets = new Insets(0, 5, 0, 5); - JButton hlb = new JButton(IconTheme.JabRefIcon.HELP.getSmallIcon()); + JButton hlb = new JButton(IconTheme.JabRefIcons.HELP.getSmallIcon()); hlb.setToolTipText(Localization.lang("Help on key patterns")); gbl.setConstraints(hlb, con); add(hlb); diff --git a/src/main/java/org/jabref/gui/collab/FileUpdatePanel.java b/src/main/java/org/jabref/gui/collab/FileUpdatePanel.java index b2e72606dec..912c203aec6 100644 --- a/src/main/java/org/jabref/gui/collab/FileUpdatePanel.java +++ b/src/main/java/org/jabref/gui/collab/FileUpdatePanel.java @@ -25,7 +25,7 @@ public class FileUpdatePanel extends SidePaneComponent implements ActionListener public FileUpdatePanel(BasePanel panel, SidePaneManager manager, File file, ChangeScanner scanner) { - super(manager, IconTheme.JabRefIcon.SAVE.getIcon(), Localization.lang("File changed")); + super(manager, IconTheme.JabRefIcons.SAVE.getIcon(), Localization.lang("File changed")); close.setEnabled(false); this.panel = panel; this.manager = manager; diff --git a/src/main/java/org/jabref/gui/customentrytypes/FieldSetComponent.java b/src/main/java/org/jabref/gui/customentrytypes/FieldSetComponent.java index f7d17f4a95b..3ccec8f86ec 100644 --- a/src/main/java/org/jabref/gui/customentrytypes/FieldSetComponent.java +++ b/src/main/java/org/jabref/gui/customentrytypes/FieldSetComponent.java @@ -125,8 +125,8 @@ private FieldSetComponent(String title, List fields, List preset con.gridwidth = 1; if (arrows) { con.weightx = 0; - up = new JButton(IconTheme.JabRefIcon.UP.getSmallIcon()); - down = new JButton(IconTheme.JabRefIcon.DOWN.getSmallIcon()); + up = new JButton(IconTheme.JabRefIcons.UP.getSmallIcon()); + down = new JButton(IconTheme.JabRefIcons.DOWN.getSmallIcon()); up.addActionListener(e -> move(-1)); down.addActionListener(e -> move(1)); up.setToolTipText(Localization.lang("Move up")); diff --git a/src/main/java/org/jabref/gui/desktop/JabRefDesktop.java b/src/main/java/org/jabref/gui/desktop/JabRefDesktop.java index c5ab1b21184..a362446b26f 100644 --- a/src/main/java/org/jabref/gui/desktop/JabRefDesktop.java +++ b/src/main/java/org/jabref/gui/desktop/JabRefDesktop.java @@ -194,8 +194,7 @@ public static boolean openExternalFileUnknown(JabRefFrame frame, BibEntry entry, return false; } else if (answer == JOptionPane.YES_OPTION) { // User wants to define the new file type. Show the dialog: - ExternalFileType newType = new ExternalFileType(fileType.getName(), "", "", "", "new", - IconTheme.JabRefIcon.FILE.getSmallIcon()); + ExternalFileType newType = new ExternalFileType(fileType.getName(), "", "", "", "new", IconTheme.JabRefIcons.FILE); ExternalFileTypeEntryEditor editor = new ExternalFileTypeEntryEditor(frame, newType); editor.setVisible(true); if (editor.okPressed()) { diff --git a/src/main/java/org/jabref/gui/documentviewer/ShowDocumentViewerAction.java b/src/main/java/org/jabref/gui/documentviewer/ShowDocumentViewerAction.java index e31e844f9c9..6735edaf1cc 100644 --- a/src/main/java/org/jabref/gui/documentviewer/ShowDocumentViewerAction.java +++ b/src/main/java/org/jabref/gui/documentviewer/ShowDocumentViewerAction.java @@ -21,7 +21,7 @@ public ShowDocumentViewerAction(String title, String tooltip, Icon iconFile) { public ShowDocumentViewerAction() { this(Localization.menuTitle("Show document viewer"), Localization.lang("Show document viewer"), - IconTheme.JabRefIcon.PDF_FILE.getIcon()); + IconTheme.JabRefIcons.PDF_FILE.getIcon()); } @Override diff --git a/src/main/java/org/jabref/gui/entryeditor/DeprecatedFieldsTab.java b/src/main/java/org/jabref/gui/entryeditor/DeprecatedFieldsTab.java index d56cec1b4d9..f52edafa728 100644 --- a/src/main/java/org/jabref/gui/entryeditor/DeprecatedFieldsTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/DeprecatedFieldsTab.java @@ -19,7 +19,7 @@ public DeprecatedFieldsTab(BibDatabaseContext databaseContext, SuggestionProvide setText(Localization.lang("Deprecated fields")); setTooltip(new Tooltip(Localization.lang("Show deprecated BibTeX fields"))); - setGraphic(IconTheme.JabRefIcon.OPTIONAL.getGraphicNode()); + setGraphic(IconTheme.JabRefIcons.OPTIONAL.getGraphicNode()); } @Override diff --git a/src/main/java/org/jabref/gui/entryeditor/OptionalFields2Tab.java b/src/main/java/org/jabref/gui/entryeditor/OptionalFields2Tab.java index 7057cc97c84..46f3dbd43d2 100644 --- a/src/main/java/org/jabref/gui/entryeditor/OptionalFields2Tab.java +++ b/src/main/java/org/jabref/gui/entryeditor/OptionalFields2Tab.java @@ -19,7 +19,7 @@ public OptionalFields2Tab(BibDatabaseContext databaseContext, SuggestionProvider setText(Localization.lang("Optional fields 2")); setTooltip(new Tooltip(Localization.lang("Show optional fields"))); - setGraphic(IconTheme.JabRefIcon.OPTIONAL.getGraphicNode()); + setGraphic(IconTheme.JabRefIcons.OPTIONAL.getGraphicNode()); } @Override diff --git a/src/main/java/org/jabref/gui/entryeditor/OptionalFieldsTab.java b/src/main/java/org/jabref/gui/entryeditor/OptionalFieldsTab.java index fe863c95a2c..d5aad5ee108 100644 --- a/src/main/java/org/jabref/gui/entryeditor/OptionalFieldsTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/OptionalFieldsTab.java @@ -19,7 +19,7 @@ public OptionalFieldsTab(BibDatabaseContext databaseContext, SuggestionProviders setText(Localization.lang("Optional fields")); setTooltip(new Tooltip(Localization.lang("Show optional fields"))); - setGraphic(IconTheme.JabRefIcon.OPTIONAL.getGraphicNode()); + setGraphic(IconTheme.JabRefIcons.OPTIONAL.getGraphicNode()); } @Override diff --git a/src/main/java/org/jabref/gui/entryeditor/OtherFieldsTab.java b/src/main/java/org/jabref/gui/entryeditor/OtherFieldsTab.java index 812a0be7ed9..4896d0a9236 100644 --- a/src/main/java/org/jabref/gui/entryeditor/OtherFieldsTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/OtherFieldsTab.java @@ -23,7 +23,7 @@ public OtherFieldsTab(BibDatabaseContext databaseContext, SuggestionProviders su setText(Localization.lang("Other fields")); setTooltip(new Tooltip(Localization.lang("Show remaining fields"))); - setGraphic(IconTheme.JabRefIcon.OPTIONAL.getGraphicNode()); + setGraphic(IconTheme.JabRefIcons.OPTIONAL.getGraphicNode()); } @Override diff --git a/src/main/java/org/jabref/gui/entryeditor/RequiredFieldsTab.java b/src/main/java/org/jabref/gui/entryeditor/RequiredFieldsTab.java index 77a61fe39f4..4f985b83def 100644 --- a/src/main/java/org/jabref/gui/entryeditor/RequiredFieldsTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/RequiredFieldsTab.java @@ -21,7 +21,7 @@ public RequiredFieldsTab(BibDatabaseContext databaseContext, SuggestionProviders setText(Localization.lang("Required fields")); setTooltip(new Tooltip(Localization.lang("Show required fields"))); - setGraphic(IconTheme.JabRefIcon.REQUIRED.getGraphicNode()); + setGraphic(IconTheme.JabRefIcons.REQUIRED.getGraphicNode()); } @Override diff --git a/src/main/java/org/jabref/gui/entryeditor/SourceTab.java b/src/main/java/org/jabref/gui/entryeditor/SourceTab.java index 6b61f9ccead..e53866a718a 100644 --- a/src/main/java/org/jabref/gui/entryeditor/SourceTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/SourceTab.java @@ -55,7 +55,7 @@ public SourceTab(BibDatabaseContext bibDatabaseContext, CountingUndoManager undo this.mode = bibDatabaseContext.getMode(); this.setText(Localization.lang("%0 source", mode.getFormattedName())); this.setTooltip(new Tooltip(Localization.lang("Show/edit %0 source", mode.getFormattedName()))); - this.setGraphic(IconTheme.JabRefIcon.SOURCE.getGraphicNode()); + this.setGraphic(IconTheme.JabRefIcons.SOURCE.getGraphicNode()); this.undoManager = undoManager; this.fieldFormatterPreferences = fieldFormatterPreferences; } diff --git a/src/main/java/org/jabref/gui/entryeditor/UserDefinedFieldsTab.java b/src/main/java/org/jabref/gui/entryeditor/UserDefinedFieldsTab.java index 34a0dc5c29d..13cc45f9bfa 100644 --- a/src/main/java/org/jabref/gui/entryeditor/UserDefinedFieldsTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/UserDefinedFieldsTab.java @@ -19,7 +19,7 @@ public UserDefinedFieldsTab(String name, List fields, BibDatabaseContext this.fields = fields; setText(name); - setGraphic(IconTheme.JabRefIcon.OPTIONAL.getGraphicNode()); + setGraphic(IconTheme.JabRefIcons.OPTIONAL.getGraphicNode()); } @Override diff --git a/src/main/java/org/jabref/gui/errorconsole/ErrorConsoleController.java b/src/main/java/org/jabref/gui/errorconsole/ErrorConsoleController.java index 641cec00f88..b4a33616966 100644 --- a/src/main/java/org/jabref/gui/errorconsole/ErrorConsoleController.java +++ b/src/main/java/org/jabref/gui/errorconsole/ErrorConsoleController.java @@ -52,7 +52,7 @@ private void initialize() { messagesListView.scrollTo(size - 1); } })); - descriptionLabel.setGraphic(IconTheme.JabRefIcon.CONSOLE.getGraphicNode()); + descriptionLabel.setGraphic(IconTheme.JabRefIcons.CONSOLE.getGraphicNode()); } private Callback, ListCell> createCellFactory() { diff --git a/src/main/java/org/jabref/gui/errorconsole/LogEventViewModel.java b/src/main/java/org/jabref/gui/errorconsole/LogEventViewModel.java index dd906d3c30b..096aedb2f87 100644 --- a/src/main/java/org/jabref/gui/errorconsole/LogEventViewModel.java +++ b/src/main/java/org/jabref/gui/errorconsole/LogEventViewModel.java @@ -4,6 +4,7 @@ import java.util.Optional; import org.jabref.gui.IconTheme; +import org.jabref.gui.JabRefIcon; import org.jabref.logic.util.OS; import com.google.common.base.Throwables; @@ -33,15 +34,15 @@ public String getStyleClass() { } } - public IconTheme.JabRefIcon getIcon() { + public JabRefIcon getIcon() { switch (logEvent.getLevel().getStandardLevel()) { case ERROR: - return (IconTheme.JabRefIcon.INTEGRITY_FAIL); + return (IconTheme.JabRefIcons.INTEGRITY_FAIL); case WARN: - return (IconTheme.JabRefIcon.INTEGRITY_WARN); + return (IconTheme.JabRefIcons.INTEGRITY_WARN); case INFO: default: - return (IconTheme.JabRefIcon.INTEGRITY_INFO); + return (IconTheme.JabRefIcons.INTEGRITY_INFO); } } diff --git a/src/main/java/org/jabref/gui/exporter/SaveAllAction.java b/src/main/java/org/jabref/gui/exporter/SaveAllAction.java index fee0a435a08..16c8f1ad454 100644 --- a/src/main/java/org/jabref/gui/exporter/SaveAllAction.java +++ b/src/main/java/org/jabref/gui/exporter/SaveAllAction.java @@ -27,7 +27,7 @@ public class SaveAllAction extends MnemonicAwareAction implements Runnable { /** Creates a new instance of SaveAllAction */ public SaveAllAction(JabRefFrame frame) { - super(IconTheme.JabRefIcon.SAVE_ALL.getIcon()); + super(IconTheme.JabRefIcons.SAVE_ALL.getIcon()); this.frame = frame; putValue(Action.ACCELERATOR_KEY, Globals.getKeyPrefs().getKey(KeyBinding.SAVE_ALL)); putValue(Action.SHORT_DESCRIPTION, Localization.lang("Save all open libraries")); diff --git a/src/main/java/org/jabref/gui/externalfiletype/ExternalFileType.java b/src/main/java/org/jabref/gui/externalfiletype/ExternalFileType.java index 335b78ffcfc..3a35e2f2b78 100644 --- a/src/main/java/org/jabref/gui/externalfiletype/ExternalFileType.java +++ b/src/main/java/org/jabref/gui/externalfiletype/ExternalFileType.java @@ -2,10 +2,10 @@ import java.util.Objects; -import javax.swing.Icon; import javax.swing.JLabel; import org.jabref.gui.IconTheme; +import org.jabref.gui.JabRefIcon; /** * This class defines a type of external files that can be linked to from JabRef. @@ -19,11 +19,11 @@ public class ExternalFileType implements Comparable { private String openWith; private String iconName; private String mimeType; - private Icon icon; + private JabRefIcon icon; private final JLabel label = new JLabel(); public ExternalFileType(String name, String extension, String mimeType, - String openWith, String iconName, Icon icon) { + String openWith, String iconName, JabRefIcon icon) { label.setText(null); this.name = name; label.setToolTipText(this.name); @@ -52,7 +52,6 @@ public static ExternalFileType buildFromArgs(String[] val) { String openWith; String mimeType; String iconName; - Icon icon; if (val.length == 4) { // Up to version 2.4b the mime type is not included: @@ -67,7 +66,7 @@ public static ExternalFileType buildFromArgs(String[] val) { } // set icon to default first - icon = IconTheme.JabRefIcon.FILE.getSmallIcon(); + JabRefIcon icon = IconTheme.JabRefIcons.FILE; // check whether there is another icon defined for this file type for (ExternalFileType fileType : ExternalFileTypes.getDefaultExternalFileTypes()) { @@ -171,13 +170,13 @@ public String getIconName() { return iconName; } - public Icon getIcon() { + public JabRefIcon getIcon() { return icon; } - public void setIcon(Icon icon) { + public void setIcon(JabRefIcon icon) { this.icon = icon; - label.setIcon(this.icon); + label.setIcon(this.icon.getSmallIcon()); } @Override diff --git a/src/main/java/org/jabref/gui/externalfiletype/ExternalFileTypeEntryEditor.java b/src/main/java/org/jabref/gui/externalfiletype/ExternalFileTypeEntryEditor.java index 5a327c96c0b..c8d20d41182 100644 --- a/src/main/java/org/jabref/gui/externalfiletype/ExternalFileTypeEntryEditor.java +++ b/src/main/java/org/jabref/gui/externalfiletype/ExternalFileTypeEntryEditor.java @@ -45,7 +45,7 @@ public class ExternalFileTypeEntryEditor { private final JTextField name = new JTextField(); private final JTextField mimeType = new JTextField(); private final JTextField application = new JTextField(); - private final JLabel icon = new JLabel(IconTheme.JabRefIcon.FILE.getSmallIcon()); + private final JLabel icon = new JLabel(IconTheme.JabRefIcons.FILE.getSmallIcon()); private final JButton ok = new JButton(Localization.lang("OK")); private final JButton cancel = new JButton(Localization.lang("Cancel")); private final JRadioButton useDefault = new JRadioButton(Localization.lang("Default")); @@ -218,7 +218,7 @@ private void setValues(ExternalFileType entry) { extension.setText(entry.getExtension()); mimeType.setText(entry.getMimeType()); application.setText(entry.getOpenWithApplication()); - icon.setIcon(entry.getIcon()); + icon.setIcon(entry.getIcon().getSmallIcon()); if (application.getText().isEmpty()) { useDefault.setSelected(true); } else { diff --git a/src/main/java/org/jabref/gui/externalfiletype/ExternalFileTypes.java b/src/main/java/org/jabref/gui/externalfiletype/ExternalFileTypes.java index 702b47048bd..0879f8b3ade 100644 --- a/src/main/java/org/jabref/gui/externalfiletype/ExternalFileTypes.java +++ b/src/main/java/org/jabref/gui/externalfiletype/ExternalFileTypes.java @@ -28,8 +28,7 @@ public class ExternalFileTypes { // Map containing all registered external file types: private final Set externalFileTypes = new TreeSet<>(); - private final ExternalFileType HTML_FALLBACK_TYPE = new ExternalFileType("URL", "html", "text/html", "", "www", - IconTheme.JabRefIcon.WWW.getSmallIcon()); + private final ExternalFileType HTML_FALLBACK_TYPE = new ExternalFileType("URL", "html", "text/html", "", "www", IconTheme.JabRefIcons.WWW); private ExternalFileTypes() { updateExternalFileTypes(); @@ -44,57 +43,29 @@ public static ExternalFileTypes getInstance() { public static List getDefaultExternalFileTypes() { List list = new ArrayList<>(); - list.add(new ExternalFileType("PDF", "pdf", "application/pdf", "evince", "pdfSmall", - IconTheme.JabRefIcon.PDF_FILE.getSmallIcon())); - list.add(new ExternalFileType("PostScript", "ps", "application/postscript", "evince", "psSmall", - IconTheme.JabRefIcon.FILE.getSmallIcon())); - list.add(new ExternalFileType("Word", "doc", "application/msword", "oowriter", "openoffice", - IconTheme.JabRefIcon.FILE_WORD.getSmallIcon())); - list.add(new ExternalFileType("Word 2007+", "docx", - "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "oowriter", "openoffice", - IconTheme.JabRefIcon.FILE_WORD.getSmallIcon())); - list.add(new ExternalFileType(Localization.lang("OpenDocument text"), "odt", - "application/vnd.oasis.opendocument.text", "oowriter", "openoffice", IconTheme.getImage("openoffice"))); - list.add(new ExternalFileType("Excel", "xls", "application/excel", "oocalc", "openoffice", - IconTheme.JabRefIcon.FILE_EXCEL.getSmallIcon())); - list.add(new ExternalFileType("Excel 2007+", "xlsx", - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "oocalc", "openoffice", - IconTheme.JabRefIcon.FILE_EXCEL.getSmallIcon())); - list.add(new ExternalFileType(Localization.lang("OpenDocument spreadsheet"), "ods", - "application/vnd.oasis.opendocument.spreadsheet", "oocalc", "openoffice", - IconTheme.getImage("openoffice"))); - list.add(new ExternalFileType("PowerPoint", "ppt", "application/vnd.ms-powerpoint", "ooimpress", "openoffice", - IconTheme.JabRefIcon.FILE_POWERPOINT.getSmallIcon())); - list.add(new ExternalFileType("PowerPoint 2007+", "pptx", - "application/vnd.openxmlformats-officedocument.presentationml.presentation", "ooimpress", "openoffice", - IconTheme.JabRefIcon.FILE_POWERPOINT.getSmallIcon())); - list.add(new ExternalFileType(Localization.lang("OpenDocument presentation"), "odp", - "application/vnd.oasis.opendocument.presentation", "ooimpress", "openoffice", - IconTheme.getImage("openoffice"))); - list.add(new ExternalFileType("Rich Text Format", "rtf", "application/rtf", "oowriter", "openoffice", - IconTheme.JabRefIcon.FILE_TEXT.getSmallIcon())); - list.add(new ExternalFileType(Localization.lang("%0 image", "PNG"), "png", "image/png", "gimp", "picture", - IconTheme.JabRefIcon.PICTURE.getSmallIcon())); - list.add(new ExternalFileType(Localization.lang("%0 image", "GIF"), "gif", "image/gif", "gimp", "picture", - IconTheme.JabRefIcon.PICTURE.getSmallIcon())); - list.add(new ExternalFileType(Localization.lang("%0 image", "JPG"), "jpg", "image/jpeg", "gimp", "picture", - IconTheme.JabRefIcon.PICTURE.getSmallIcon())); - list.add(new ExternalFileType("Djvu", "djvu", "image/vnd.djvu", "evince", "psSmall", - IconTheme.JabRefIcon.FILE.getSmallIcon())); - list.add(new ExternalFileType("Text", "txt", "text/plain", "emacs", "emacs", - IconTheme.JabRefIcon.FILE_TEXT.getSmallIcon())); - list.add(new ExternalFileType("LaTeX", "tex", "application/x-latex", "emacs", "emacs", - IconTheme.JabRefIcon.FILE_TEXT.getSmallIcon())); - list.add(new ExternalFileType("CHM", "chm", "application/mshelp", "gnochm", "www", - IconTheme.JabRefIcon.WWW.getSmallIcon())); - list.add(new ExternalFileType(Localization.lang("%0 image", "TIFF"), "tiff", "image/tiff", "gimp", "picture", - IconTheme.JabRefIcon.PICTURE.getSmallIcon())); - list.add(new ExternalFileType("URL", "html", "text/html", "firefox", "www", - IconTheme.JabRefIcon.WWW.getSmallIcon())); - list.add(new ExternalFileType("MHT", "mht", "multipart/related", "firefox", "www", - IconTheme.JabRefIcon.WWW.getSmallIcon())); - list.add(new ExternalFileType("ePUB", "epub", "application/epub+zip", "firefox", "www", - IconTheme.JabRefIcon.WWW.getSmallIcon())); + list.add(new ExternalFileType("PDF", "pdf", "application/pdf", "evince", "pdfSmall", IconTheme.JabRefIcons.PDF_FILE)); + list.add(new ExternalFileType("PostScript", "ps", "application/postscript", "evince", "psSmall", IconTheme.JabRefIcons.FILE)); + list.add(new ExternalFileType("Word", "doc", "application/msword", "oowriter", "openoffice", IconTheme.JabRefIcons.FILE_WORD)); + list.add(new ExternalFileType("Word 2007+", "docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "oowriter", "openoffice", IconTheme.JabRefIcons.FILE_WORD)); + list.add(new ExternalFileType(Localization.lang("OpenDocument text"), "odt", "application/vnd.oasis.opendocument.text", "oowriter", "openoffice", IconTheme.JabRefIcons.FILE_OPENOFFICE)); + list.add(new ExternalFileType("Excel", "xls", "application/excel", "oocalc", "openoffice", IconTheme.JabRefIcons.FILE_EXCEL)); + list.add(new ExternalFileType("Excel 2007+", "xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "oocalc", "openoffice", IconTheme.JabRefIcons.FILE_EXCEL)); + list.add(new ExternalFileType(Localization.lang("OpenDocument spreadsheet"), "ods", "application/vnd.oasis.opendocument.spreadsheet", "oocalc", "openoffice", IconTheme.JabRefIcons.FILE_OPENOFFICE)); + list.add(new ExternalFileType("PowerPoint", "ppt", "application/vnd.ms-powerpoint", "ooimpress", "openoffice", IconTheme.JabRefIcons.FILE_POWERPOINT)); + list.add(new ExternalFileType("PowerPoint 2007+", "pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation", "ooimpress", "openoffice", IconTheme.JabRefIcons.FILE_POWERPOINT)); + list.add(new ExternalFileType(Localization.lang("OpenDocument presentation"), "odp", "application/vnd.oasis.opendocument.presentation", "ooimpress", "openoffice", IconTheme.JabRefIcons.FILE_OPENOFFICE)); + list.add(new ExternalFileType("Rich Text Format", "rtf", "application/rtf", "oowriter", "openoffice", IconTheme.JabRefIcons.FILE_TEXT)); + list.add(new ExternalFileType(Localization.lang("%0 image", "PNG"), "png", "image/png", "gimp", "picture", IconTheme.JabRefIcons.PICTURE)); + list.add(new ExternalFileType(Localization.lang("%0 image", "GIF"), "gif", "image/gif", "gimp", "picture", IconTheme.JabRefIcons.PICTURE)); + list.add(new ExternalFileType(Localization.lang("%0 image", "JPG"), "jpg", "image/jpeg", "gimp", "picture", IconTheme.JabRefIcons.PICTURE)); + list.add(new ExternalFileType("Djvu", "djvu", "image/vnd.djvu", "evince", "psSmall", IconTheme.JabRefIcons.FILE)); + list.add(new ExternalFileType("Text", "txt", "text/plain", "emacs", "emacs", IconTheme.JabRefIcons.FILE_TEXT)); + list.add(new ExternalFileType("LaTeX", "tex", "application/x-latex", "emacs", "emacs", IconTheme.JabRefIcons.FILE_TEXT)); + list.add(new ExternalFileType("CHM", "chm", "application/mshelp", "gnochm", "www", IconTheme.JabRefIcons.WWW)); + list.add(new ExternalFileType(Localization.lang("%0 image", "TIFF"), "tiff", "image/tiff", "gimp", "picture", IconTheme.JabRefIcons.PICTURE)); + list.add(new ExternalFileType("URL", "html", "text/html", "firefox", "www", IconTheme.JabRefIcons.WWW)); + list.add(new ExternalFileType("MHT", "mht", "multipart/related", "firefox", "www", IconTheme.JabRefIcons.WWW)); + list.add(new ExternalFileType("ePUB", "epub", "application/epub+zip", "firefox", "www", IconTheme.JabRefIcons.WWW)); // On all OSes there is a generic application available to handle file opening, // so we don't need the default application settings anymore: diff --git a/src/main/java/org/jabref/gui/externalfiletype/UnknownExternalFileType.java b/src/main/java/org/jabref/gui/externalfiletype/UnknownExternalFileType.java index 59e9198887a..bb9f4873253 100644 --- a/src/main/java/org/jabref/gui/externalfiletype/UnknownExternalFileType.java +++ b/src/main/java/org/jabref/gui/externalfiletype/UnknownExternalFileType.java @@ -10,7 +10,7 @@ public class UnknownExternalFileType extends ExternalFileType { public UnknownExternalFileType(String name) { - super(name, "", "", "", "unknown", IconTheme.JabRefIcon.FILE.getSmallIcon()); + super(name, "", "", "", "unknown", IconTheme.JabRefIcons.FILE); } } diff --git a/src/main/java/org/jabref/gui/groups/GroupNodeViewModel.java b/src/main/java/org/jabref/gui/groups/GroupNodeViewModel.java index e53a54f5099..5afa8400a9e 100644 --- a/src/main/java/org/jabref/gui/groups/GroupNodeViewModel.java +++ b/src/main/java/org/jabref/gui/groups/GroupNodeViewModel.java @@ -17,6 +17,8 @@ import org.jabref.gui.DragAndDropDataFormats; import org.jabref.gui.IconTheme; +import org.jabref.gui.InternalMaterialDesignIcon; +import org.jabref.gui.JabRefIcon; import org.jabref.gui.StateManager; import org.jabref.gui.util.BackgroundTask; import org.jabref.gui.util.BindingsHelper; @@ -156,10 +158,7 @@ public boolean equals(Object o) { GroupNodeViewModel that = (GroupNodeViewModel) o; - if (!groupNode.equals(that.groupNode)) { - return false; - } - return true; + return groupNode.equals(that.groupNode); } @Override @@ -180,14 +179,16 @@ public int hashCode() { return groupNode.hashCode(); } - public MaterialDesignIcon getIcon() { + public JabRefIcon getIcon() { Optional iconName = groupNode.getGroup().getIconName(); return iconName.flatMap(this::parseIcon) - .orElse(IconTheme.JabRefIcon.DEFAULT_GROUP_ICON.getUnderlyingIcon()); + .orElse(IconTheme.JabRefIcons.DEFAULT_GROUP_ICON); } - private Optional parseIcon(String iconCode) { - return Enums.getIfPresent(MaterialDesignIcon.class, iconCode.toUpperCase(Locale.ENGLISH)).toJavaUtil(); + private Optional parseIcon(String iconCode) { + return Enums.getIfPresent(MaterialDesignIcon.class, iconCode.toUpperCase(Locale.ENGLISH)) + .toJavaUtil() + .map(icon -> new InternalMaterialDesignIcon(getColor(), icon)); } public ObservableList getChildren() { diff --git a/src/main/java/org/jabref/gui/groups/GroupSidePane.java b/src/main/java/org/jabref/gui/groups/GroupSidePane.java index fb6eed02fd6..cbbb38852af 100644 --- a/src/main/java/org/jabref/gui/groups/GroupSidePane.java +++ b/src/main/java/org/jabref/gui/groups/GroupSidePane.java @@ -40,7 +40,7 @@ public class GroupSidePane extends SidePaneComponent { * regexp for the group. */ public GroupSidePane(JabRefFrame frame, SidePaneManager manager) { - super(manager, IconTheme.JabRefIcon.TOGGLE_GROUPS.getIcon(), Localization.lang("Groups")); + super(manager, IconTheme.JabRefIcons.TOGGLE_GROUPS.getIcon(), Localization.lang("Groups")); Globals.stateManager.activeGroupProperty() .addListener((observable, oldValue, newValue) -> updateShownEntriesAccordingToSelectedGroups(newValue)); @@ -57,7 +57,7 @@ public GroupSidePane(JabRefFrame frame, SidePaneManager manager) { toggleAction = new ToggleAction(Localization.menuTitle("Toggle groups interface"), Localization.lang("Toggle groups interface"), Globals.getKeyPrefs().getKey(KeyBinding.TOGGLE_GROUPS_INTERFACE), - IconTheme.JabRefIcon.TOGGLE_GROUPS); + IconTheme.JabRefIcons.TOGGLE_GROUPS); this.frame = frame; diff --git a/src/main/java/org/jabref/gui/groups/GroupTreeController.java b/src/main/java/org/jabref/gui/groups/GroupTreeController.java index 357331789c3..e91f0e58e54 100644 --- a/src/main/java/org/jabref/gui/groups/GroupTreeController.java +++ b/src/main/java/org/jabref/gui/groups/GroupTreeController.java @@ -101,7 +101,7 @@ public void initialize() { mainColumn.setCellValueFactory(cellData -> cellData.getValue().valueProperty()); mainColumn.setCellFactory(new ViewModelTreeTableCellFactory() .withText(GroupNodeViewModel::getDisplayName) - .withIcon(GroupNodeViewModel::getIcon, GroupNodeViewModel::getColor) + .withIcon(GroupNodeViewModel::getIcon) .withTooltip(GroupNodeViewModel::getDescription)); // Number of hits diff --git a/src/main/java/org/jabref/gui/groups/GroupTreeNodeViewModel.java b/src/main/java/org/jabref/gui/groups/GroupTreeNodeViewModel.java index 9ba40973a42..f7f10458674 100644 --- a/src/main/java/org/jabref/gui/groups/GroupTreeNodeViewModel.java +++ b/src/main/java/org/jabref/gui/groups/GroupTreeNodeViewModel.java @@ -35,8 +35,8 @@ public class GroupTreeNodeViewModel implements Transferable, TreeNode { public static final DataFlavor FLAVOR; private static final Log LOGGER = LogFactory.getLog(GroupTreeNodeViewModel.class); - private static final Icon GROUP_REFINING_ICON = IconTheme.JabRefIcon.GROUP_REFINING.getSmallIcon(); - private static final Icon GROUP_INCLUDING_ICON = IconTheme.JabRefIcon.GROUP_INCLUDING.getSmallIcon(); + private static final Icon GROUP_REFINING_ICON = IconTheme.JabRefIcons.GROUP_REFINING.getSmallIcon(); + private static final Icon GROUP_INCLUDING_ICON = IconTheme.JabRefIcons.GROUP_INCLUDING.getSmallIcon(); private static final Icon GROUP_REGULAR_ICON = null; private static final DataFlavor[] FLAVORS; diff --git a/src/main/java/org/jabref/gui/help/HelpAction.java b/src/main/java/org/jabref/gui/help/HelpAction.java index dfe4cc631fa..384899e9788 100644 --- a/src/main/java/org/jabref/gui/help/HelpAction.java +++ b/src/main/java/org/jabref/gui/help/HelpAction.java @@ -41,7 +41,7 @@ public class HelpAction extends MnemonicAwareAction { public HelpAction(String title, String tooltip, HelpFile helpPage, KeyStroke key) { - this(title, tooltip, helpPage, IconTheme.JabRefIcon.HELP.getSmallIcon()); + this(title, tooltip, helpPage, IconTheme.JabRefIcons.HELP.getSmallIcon()); putValue(Action.ACCELERATOR_KEY, key); } @@ -53,7 +53,7 @@ private HelpAction(String title, String tooltip, HelpFile helpPage, Icon icon) { } public HelpAction(String tooltip, HelpFile helpPage) { - this(Localization.lang("Help"), tooltip, helpPage, IconTheme.JabRefIcon.HELP.getSmallIcon()); + this(Localization.lang("Help"), tooltip, helpPage, IconTheme.JabRefIcons.HELP.getSmallIcon()); } public HelpAction(HelpFile helpPage, Icon icon) { @@ -61,7 +61,7 @@ public HelpAction(HelpFile helpPage, Icon icon) { } public HelpAction(HelpFile helpPage) { - this(Localization.lang("Help"), Localization.lang("Help"), helpPage, IconTheme.JabRefIcon.HELP.getSmallIcon()); + this(Localization.lang("Help"), Localization.lang("Help"), helpPage, IconTheme.JabRefIcons.HELP.getSmallIcon()); } public JButton getHelpButton() { diff --git a/src/main/java/org/jabref/gui/importer/EntryFromPDFCreator.java b/src/main/java/org/jabref/gui/importer/EntryFromPDFCreator.java index 11538571332..de76e260708 100644 --- a/src/main/java/org/jabref/gui/importer/EntryFromPDFCreator.java +++ b/src/main/java/org/jabref/gui/importer/EntryFromPDFCreator.java @@ -40,7 +40,7 @@ public EntryFromPDFCreator() { private static ExternalFileType getPDFExternalFileType() { Optional pdfFileType = ExternalFileTypes.getInstance().getExternalFileTypeByExt("pdf"); if (!pdfFileType.isPresent()) { - return new ExternalFileType("PDF", "pdf", "application/pdf", "evince", "pdfSmall", IconTheme.JabRefIcon.PDF_FILE.getSmallIcon()); + return new ExternalFileType("PDF", "pdf", "application/pdf", "evince", "pdfSmall", IconTheme.JabRefIcons.PDF_FILE); } return pdfFileType.get(); } diff --git a/src/main/java/org/jabref/gui/importer/ImportInspectionDialog.java b/src/main/java/org/jabref/gui/importer/ImportInspectionDialog.java index 2accc567431..85564a70dc8 100644 --- a/src/main/java/org/jabref/gui/importer/ImportInspectionDialog.java +++ b/src/main/java/org/jabref/gui/importer/ImportInspectionDialog.java @@ -176,9 +176,9 @@ public class ImportInspectionDialog extends JabRefDialog implements ImportInspec private final Map> groupAdditions = new HashMap<>(); private final JCheckBox autoGenerate = new JCheckBox(Localization.lang("Generate keys"), Globals.prefs.getBoolean(JabRefPreferences.GENERATE_KEYS_AFTER_INSPECTION)); - private final JLabel duplLabel = new JLabel(IconTheme.JabRefIcon.DUPLICATE.getSmallIcon()); - private final JLabel fileLabel = new JLabel(IconTheme.JabRefIcon.FILE.getSmallIcon()); - private final JLabel urlLabel = new JLabel(IconTheme.JabRefIcon.WWW.getSmallIcon()); + private final JLabel duplLabel = new JLabel(IconTheme.JabRefIcons.DUPLICATE.getSmallIcon()); + private final JLabel fileLabel = new JLabel(IconTheme.JabRefIcons.FILE.getSmallIcon()); + private final JLabel urlLabel = new JLabel(IconTheme.JabRefIcons.WWW.getSmallIcon()); private BasePanel panel; private boolean generatedKeys; // Set to true after keys have been generated. private boolean defaultSelected = true; @@ -900,7 +900,7 @@ private List getSelectedEntries() { private class DeleteListener extends AbstractAction { public DeleteListener() { - super(Localization.lang("Delete"), IconTheme.JabRefIcon.DELETE_ENTRY.getSmallIcon()); + super(Localization.lang("Delete"), IconTheme.JabRefIcons.DELETE_ENTRY.getSmallIcon()); } @Override @@ -1046,7 +1046,7 @@ private void showFileFieldMenu(MouseEvent e) { description = flEntry.getLink(); } menu.add(new ExternalFileMenuItem(panel.frame(), entry, description, flEntry.getLink(), - flEntry.getType().get().getIcon(), panel.getBibDatabaseContext(), flEntry.getType())); + flEntry.getType().get().getIcon().getSmallIcon(), panel.getBibDatabaseContext(), flEntry.getType())); count++; } if (count == 0) { @@ -1431,7 +1431,7 @@ public Object getColumnValue(BibEntry entry, int i) { entry.getField(FieldName.FILE).ifPresent(model::setContent); fileLabel.setToolTipText(model.getToolTipHTMLRepresentation()); if ((model.getRowCount() > 0) && model.getEntry(0).getType().isPresent()) { - fileLabel.setIcon(model.getEntry(0).getType().get().getIcon()); + fileLabel.setIcon(model.getEntry(0).getType().get().getIcon().getSmallIcon()); } return fileLabel; } else { diff --git a/src/main/java/org/jabref/gui/importer/fetcher/GeneralFetcher.java b/src/main/java/org/jabref/gui/importer/fetcher/GeneralFetcher.java index 5bd10e6d06b..b1246e9fd97 100644 --- a/src/main/java/org/jabref/gui/importer/fetcher/GeneralFetcher.java +++ b/src/main/java/org/jabref/gui/importer/fetcher/GeneralFetcher.java @@ -47,7 +47,7 @@ public class GeneralFetcher extends SidePaneComponent implements ActionListener public GeneralFetcher(JabRefFrame frame, SidePaneManager sidePaneManager) { - super(sidePaneManager, IconTheme.JabRefIcon.WWW.getSmallIcon(), Localization.lang("Web search")); + super(sidePaneManager, IconTheme.JabRefIcons.WWW.getSmallIcon(), Localization.lang("Web search")); this.frame = frame; List fetchers = new EntryFetchers(Globals.journalAbbreviationLoader).getEntryFetchers(); EntryFetcher[] fetcherArray = fetchers.toArray(new EntryFetcher[fetchers.size()]); @@ -91,7 +91,7 @@ public GeneralFetcher(JabRefFrame frame, SidePaneManager sidePaneManager) { action = new ToggleAction(Localization.lang("Web search"), Localization.lang("Toggle web search interface"), Globals.getKeyPrefs().getKey(KeyBinding.WEB_SEARCH), - IconTheme.JabRefIcon.WWW); + IconTheme.JabRefIcons.WWW); helpBut.setMargin(new Insets(0, 0, 0, 0)); tf.setPreferredSize(new Dimension(1, tf.getPreferredSize().height)); diff --git a/src/main/java/org/jabref/gui/journals/ManageJournalAbbreviationsController.java b/src/main/java/org/jabref/gui/journals/ManageJournalAbbreviationsController.java index 7bc81684347..5e6bc92591d 100644 --- a/src/main/java/org/jabref/gui/journals/ManageJournalAbbreviationsController.java +++ b/src/main/java/org/jabref/gui/journals/ManageJournalAbbreviationsController.java @@ -53,9 +53,9 @@ private void initialize() { } private void setButtonStyles() { - addJournalFileButton.setGraphic(IconTheme.JabRefIcon.OPEN.getGraphicNode()); - addNewJournalFileButton.setGraphic(IconTheme.JabRefIcon.NEW.getGraphicNode()); - removeJournalAbbreviationsButton.setGraphic(IconTheme.JabRefIcon.CLOSE.getGraphicNode()); + addJournalFileButton.setGraphic(IconTheme.JabRefIcons.OPEN.getGraphicNode()); + addNewJournalFileButton.setGraphic(IconTheme.JabRefIcons.NEW.getGraphicNode()); + removeJournalAbbreviationsButton.setGraphic(IconTheme.JabRefIcons.CLOSE.getGraphicNode()); } private void setUpTable() { @@ -73,10 +73,10 @@ private void setUpTable() { journalTableEditColumn.setCellFactory(new ValueTableCellFactory(). withGraphic(isPseudoAbbreviation -> { if (isPseudoAbbreviation) { - return IconTheme.JabRefIcon.ADD.getGraphicNode(); + return IconTheme.JabRefIcons.ADD.getGraphicNode(); } else { return viewModel.isAbbreviationEditableAndRemovable() ? - IconTheme.JabRefIcon.EDIT.getGraphicNode() : null; + IconTheme.JabRefIcons.EDIT.getGraphicNode() : null; } }). withOnMouseClickedEvent(isPseudoAbbreviation -> { @@ -93,7 +93,7 @@ private void setUpTable() { journalTableDeleteColumn.setCellFactory(new ValueTableCellFactory(). withGraphic(isPseudoAbbreviation -> { if (!isPseudoAbbreviation && viewModel.isAbbreviationEditableAndRemovable()) { - return IconTheme.JabRefIcon.DELETE_ENTRY.getGraphicNode(); + return IconTheme.JabRefIcons.DELETE_ENTRY.getGraphicNode(); } else { return null; } diff --git a/src/main/java/org/jabref/gui/keyboard/KeyBindingAction.java b/src/main/java/org/jabref/gui/keyboard/KeyBindingAction.java index 6086057dde6..47c94c20d90 100644 --- a/src/main/java/org/jabref/gui/keyboard/KeyBindingAction.java +++ b/src/main/java/org/jabref/gui/keyboard/KeyBindingAction.java @@ -15,7 +15,7 @@ public class KeyBindingAction extends AbstractAction { public KeyBindingAction() { super(Localization.lang("Customize key bindings")); - this.putValue(Action.SMALL_ICON, IconTheme.JabRefIcon.KEY_BINDINGS.getSmallIcon()); + this.putValue(Action.SMALL_ICON, IconTheme.JabRefIcons.KEY_BINDINGS.getSmallIcon()); } @Override diff --git a/src/main/java/org/jabref/gui/keyboard/KeyBindingViewModel.java b/src/main/java/org/jabref/gui/keyboard/KeyBindingViewModel.java index aa7e86b26bd..ad99b8b3887 100644 --- a/src/main/java/org/jabref/gui/keyboard/KeyBindingViewModel.java +++ b/src/main/java/org/jabref/gui/keyboard/KeyBindingViewModel.java @@ -10,6 +10,7 @@ import javafx.scene.input.KeyEvent; import org.jabref.gui.IconTheme; +import org.jabref.gui.JabRefIcon; import com.google.common.base.CaseFormat; @@ -79,7 +80,7 @@ public StringProperty nameProperty() { } public boolean isCategory() { - return (keyBinding == null) ? true : false; + return keyBinding == null; } /** @@ -134,7 +135,7 @@ public void resetToDefault() { } } - public Optional getIcon() { - return isCategory() ? Optional.empty() : Optional.of(IconTheme.JabRefIcon.CLEANUP_ENTRIES); + public Optional getIcon() { + return isCategory() ? Optional.empty() : Optional.of(IconTheme.JabRefIcons.CLEANUP_ENTRIES); } } diff --git a/src/main/java/org/jabref/gui/keyboard/KeyBindingsDialogController.java b/src/main/java/org/jabref/gui/keyboard/KeyBindingsDialogController.java index 21767bb255d..4b37931ebea 100644 --- a/src/main/java/org/jabref/gui/keyboard/KeyBindingsDialogController.java +++ b/src/main/java/org/jabref/gui/keyboard/KeyBindingsDialogController.java @@ -11,7 +11,7 @@ import org.jabref.gui.AbstractController; import org.jabref.gui.DialogService; -import org.jabref.gui.IconTheme; +import org.jabref.gui.JabRefIcon; import org.jabref.gui.util.RecursiveTreeItem; import org.jabref.gui.util.ViewModelTreeTableCellFactory; import org.jabref.preferences.PreferencesService; @@ -47,7 +47,7 @@ private void initialize() { actionColumn.setCellValueFactory(cellData -> cellData.getValue().getValue().nameProperty()); shortcutColumn.setCellValueFactory(cellData -> cellData.getValue().getValue().shownBindingProperty()); resetColumn.setCellFactory(new ViewModelTreeTableCellFactory() - .withGraphic(keyBinding -> keyBinding.getIcon().map(IconTheme.JabRefIcon::getGraphicNode).orElse(null)) + .withGraphic(keyBinding -> keyBinding.getIcon().map(JabRefIcon::getGraphicNode).orElse(null)) .withOnMouseClickedEvent(keyBinding -> evt -> keyBinding.resetToDefault()) ); } diff --git a/src/main/java/org/jabref/gui/openoffice/StyleSelectDialog.java b/src/main/java/org/jabref/gui/openoffice/StyleSelectDialog.java index b26740ce10f..1c0caa80c2d 100644 --- a/src/main/java/org/jabref/gui/openoffice/StyleSelectDialog.java +++ b/src/main/java/org/jabref/gui/openoffice/StyleSelectDialog.java @@ -93,8 +93,8 @@ class StyleSelectDialog { private final JMenuItem show = new JMenuItem(Localization.lang("View")); private final JMenuItem remove = new JMenuItem(Localization.lang("Remove")); private final JMenuItem reload = new JMenuItem(Localization.lang("Reload")); - private final JButton addButton = new JButton(IconTheme.JabRefIcon.ADD_NOBOX.getIcon()); - private final JButton removeButton = new JButton(IconTheme.JabRefIcon.REMOVE_NOBOX.getIcon()); + private final JButton addButton = new JButton(IconTheme.JabRefIcons.ADD_NOBOX.getIcon()); + private final JButton removeButton = new JButton(IconTheme.JabRefIcons.REMOVE_NOBOX.getIcon()); private PreviewPanel preview; private ActionListener removeAction; diff --git a/src/main/java/org/jabref/gui/plaintextimport/TextInputDialog.java b/src/main/java/org/jabref/gui/plaintextimport/TextInputDialog.java index 6ce4035ede6..669deca3e54 100644 --- a/src/main/java/org/jabref/gui/plaintextimport/TextInputDialog.java +++ b/src/main/java/org/jabref/gui/plaintextimport/TextInputDialog.java @@ -526,7 +526,7 @@ private class PasteAction extends BasicAction { public PasteAction() { super(Localization.lang("Paste"), Localization.lang("Paste from clipboard"), - IconTheme.JabRefIcon.PASTE.getIcon()); + IconTheme.JabRefIcons.PASTE.getIcon()); } @Override @@ -549,7 +549,7 @@ public void actionPerformed(ActionEvent e) { private class LoadAction extends BasicAction { public LoadAction() { - super(Localization.lang("Open"), Localization.lang("Open file"), IconTheme.JabRefIcon.OPEN.getIcon()); + super(Localization.lang("Open"), Localization.lang("Open file"), IconTheme.JabRefIcons.OPEN.getIcon()); } @Override @@ -584,7 +584,7 @@ public void actionPerformed(ActionEvent e) { private class ClearAction extends BasicAction { public ClearAction() { - super(Localization.lang("Clear"), Localization.lang("Clear inputarea"), IconTheme.JabRefIcon.NEW.getIcon()); + super(Localization.lang("Clear"), Localization.lang("Clear inputarea"), IconTheme.JabRefIcons.NEW.getIcon()); } @Override @@ -626,8 +626,8 @@ private class SimpleCellRenderer extends DefaultListCellRenderer { private final Font baseFont; private final Font usedFont; - private final Icon okIcon = IconTheme.JabRefIcon.PLAIN_TEXT_IMPORT_DONE.getSmallIcon(); - private final Icon needIcon = IconTheme.JabRefIcon.PLAIN_TEXT_IMPORT_TODO.getSmallIcon(); + private final Icon okIcon = IconTheme.JabRefIcons.PLAIN_TEXT_IMPORT_DONE.getSmallIcon(); + private final Icon needIcon = IconTheme.JabRefIcons.PLAIN_TEXT_IMPORT_TODO.getSmallIcon(); private final Color requiredColor = Globals.prefs.getColor(JabRefPreferences.TABLE_REQ_FIELD_BACKGROUND); private final Color optionalColor = Globals.prefs.getColor(JabRefPreferences.TABLE_OPT_FIELD_BACKGROUND); diff --git a/src/main/java/org/jabref/gui/preftabs/NameFormatterTab.java b/src/main/java/org/jabref/gui/preftabs/NameFormatterTab.java index 13729c60779..6c726a2d997 100644 --- a/src/main/java/org/jabref/gui/preftabs/NameFormatterTab.java +++ b/src/main/java/org/jabref/gui/preftabs/NameFormatterTab.java @@ -213,7 +213,7 @@ public void setValues() { class DeleteRowAction extends AbstractAction { public DeleteRowAction() { - super("Delete row", IconTheme.JabRefIcon.REMOVE_NOBOX.getIcon()); + super("Delete row", IconTheme.JabRefIcons.REMOVE_NOBOX.getIcon()); putValue(Action.SHORT_DESCRIPTION, Localization.lang("Delete rows")); } @@ -246,7 +246,7 @@ public void actionPerformed(ActionEvent e) { class AddRowAction extends AbstractAction { public AddRowAction() { - super("Add row", IconTheme.JabRefIcon.ADD_NOBOX.getIcon()); + super("Add row", IconTheme.JabRefIcons.ADD_NOBOX.getIcon()); putValue(Action.SHORT_DESCRIPTION, Localization.lang("Insert rows")); } diff --git a/src/main/java/org/jabref/gui/preftabs/XmpPrefsTab.java b/src/main/java/org/jabref/gui/preftabs/XmpPrefsTab.java index 81e5fb10fde..d288f23d3a7 100644 --- a/src/main/java/org/jabref/gui/preftabs/XmpPrefsTab.java +++ b/src/main/java/org/jabref/gui/preftabs/XmpPrefsTab.java @@ -154,7 +154,7 @@ public void setValueAt(Object value, int row, int col) { class DeleteRowAction extends AbstractAction { public DeleteRowAction() { - super("Delete row", IconTheme.JabRefIcon.REMOVE_NOBOX.getIcon()); + super("Delete row", IconTheme.JabRefIcons.REMOVE_NOBOX.getIcon()); putValue(Action.SHORT_DESCRIPTION, Localization.lang("Delete rows")); } @@ -183,7 +183,7 @@ public void actionPerformed(ActionEvent e) { class AddRowAction extends AbstractAction { public AddRowAction() { - super("Add row", IconTheme.JabRefIcon.ADD_NOBOX.getIcon()); + super("Add row", IconTheme.JabRefIcons.ADD_NOBOX.getIcon()); putValue(Action.SHORT_DESCRIPTION, Localization.lang("Insert rows")); } diff --git a/src/main/java/org/jabref/gui/protectedterms/ProtectedTermsDialog.java b/src/main/java/org/jabref/gui/protectedterms/ProtectedTermsDialog.java index 7ff7856fa6b..ade27f62e5d 100644 --- a/src/main/java/org/jabref/gui/protectedterms/ProtectedTermsDialog.java +++ b/src/main/java/org/jabref/gui/protectedterms/ProtectedTermsDialog.java @@ -79,9 +79,9 @@ public class ProtectedTermsDialog { private final JMenuItem remove = new JMenuItem(Localization.lang("Remove")); private final JMenuItem reload = new JMenuItem(Localization.lang("Reload")); private final JMenuItem enabled = new JCheckBoxMenuItem(Localization.lang("Enabled")); - private final JButton loadButton = new JButton(IconTheme.JabRefIcon.OPEN.getIcon()); - private final JButton removeButton = new JButton(IconTheme.JabRefIcon.DELETE_ENTRY.getIcon()); - private final JButton newButton = new JButton(IconTheme.JabRefIcon.NEW.getIcon()); + private final JButton loadButton = new JButton(IconTheme.JabRefIcons.OPEN.getIcon()); + private final JButton removeButton = new JButton(IconTheme.JabRefIcons.DELETE_ENTRY.getIcon()); + private final JButton newButton = new JButton(IconTheme.JabRefIcons.NEW.getIcon()); private ActionListener removeAction; private final JButton ok = new JButton(Localization.lang("OK")); diff --git a/src/main/java/org/jabref/gui/push/PushToApplicationButton.java b/src/main/java/org/jabref/gui/push/PushToApplicationButton.java index 4bf755a0c68..ee9e3d9b4aa 100644 --- a/src/main/java/org/jabref/gui/push/PushToApplicationButton.java +++ b/src/main/java/org/jabref/gui/push/PushToApplicationButton.java @@ -44,7 +44,7 @@ */ public class PushToApplicationButton implements ActionListener { - private static final Icon ARROW_ICON = IconTheme.JabRefIcon.DOWN.getSmallIcon(); + private static final Icon ARROW_ICON = IconTheme.JabRefIcons.DOWN.getSmallIcon(); private final JabRefFrame frame; private final List pushActions; private JPanel comp; diff --git a/src/main/java/org/jabref/gui/search/SearchResultFrame.java b/src/main/java/org/jabref/gui/search/SearchResultFrame.java index 0a57087f8c0..94b82a245d0 100644 --- a/src/main/java/org/jabref/gui/search/SearchResultFrame.java +++ b/src/main/java/org/jabref/gui/search/SearchResultFrame.java @@ -96,8 +96,8 @@ public class SearchResultFrame { private final JabRefFrame frame; private JFrame searchResultFrame; - private final JLabel fileLabel = new JLabel(IconTheme.JabRefIcon.FILE.getSmallIcon()); - private final JLabel urlLabel = new JLabel(IconTheme.JabRefIcon.WWW.getSmallIcon()); + private final JLabel fileLabel = new JLabel(IconTheme.JabRefIcons.FILE.getSmallIcon()); + private final JLabel urlLabel = new JLabel(IconTheme.JabRefIcons.WWW.getSmallIcon()); private final JSplitPane contentPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT); @@ -521,7 +521,7 @@ public void processPopupTrigger(MouseEvent e) { description = flEntry.getLink(); } menu.add(new ExternalFileMenuItem(p.frame(), entry, description, flEntry.getLink(), - flEntry.getType().get().getIcon(), p.getBibDatabaseContext(), flEntry.getType())); + flEntry.getType().get().getIcon().getSmallIcon(), p.getBibDatabaseContext(), flEntry.getType())); count++; } @@ -591,9 +591,9 @@ public Object getColumnValue(BibEntry entry, int column) { fileLabel.setToolTipText(tmpModel.getToolTipHTMLRepresentation()); if (tmpModel.getRowCount() > 0) { if (tmpModel.getEntry(0).getType().isPresent()) { - fileLabel.setIcon(tmpModel.getEntry(0).getType().get().getIcon()); + fileLabel.setIcon(tmpModel.getEntry(0).getType().get().getIcon().getSmallIcon()); } else { - fileLabel.setIcon(IconTheme.JabRefIcon.FILE.getSmallIcon()); + fileLabel.setIcon(IconTheme.JabRefIcons.FILE.getSmallIcon()); } } return fileLabel; diff --git a/src/main/java/org/jabref/gui/search/SearchTextField.java b/src/main/java/org/jabref/gui/search/SearchTextField.java index e018ac2efd9..b96409b296a 100644 --- a/src/main/java/org/jabref/gui/search/SearchTextField.java +++ b/src/main/java/org/jabref/gui/search/SearchTextField.java @@ -13,7 +13,7 @@ public class SearchTextField { public static TextField create() { CustomTextField textField = (CustomTextField) TextFields.createClearableTextField(); textField.setPromptText(Localization.lang("Search") + "..."); - textField.setLeft(IconTheme.JabRefIcon.SEARCH.getGraphicNode()); + textField.setLeft(IconTheme.JabRefIcons.SEARCH.getGraphicNode()); return textField; } } diff --git a/src/main/java/org/jabref/gui/specialfields/SpecialFieldValueViewModel.java b/src/main/java/org/jabref/gui/specialfields/SpecialFieldValueViewModel.java index df4fc097198..54b6166d949 100644 --- a/src/main/java/org/jabref/gui/specialfields/SpecialFieldValueViewModel.java +++ b/src/main/java/org/jabref/gui/specialfields/SpecialFieldValueViewModel.java @@ -6,6 +6,7 @@ import javax.swing.JLabel; import org.jabref.gui.IconTheme; +import org.jabref.gui.JabRefIcon; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.specialfields.SpecialFieldValue; @@ -20,40 +21,48 @@ public SpecialFieldValueViewModel(SpecialFieldValue value) { } public Icon getSpecialFieldValueIcon() { + JabRefIcon icon = getIcon(); + if (icon == null) { + return null; + } else { + return icon.getSmallIcon(); + } + } + public JabRefIcon getIcon() { switch (value) { case PRINTED: - return IconTheme.JabRefIcon.PRINTED.getSmallIcon(); + return IconTheme.JabRefIcons.PRINTED; case CLEAR_PRIORITY: return null; case PRIORITY_HIGH: - return IconTheme.JabRefIcon.PRIORITY_HIGH.getSmallIcon(); + return IconTheme.JabRefIcons.PRIORITY_HIGH; case PRIORITY_MEDIUM: - return IconTheme.JabRefIcon.PRIORITY_MEDIUM.getSmallIcon(); + return IconTheme.JabRefIcons.PRIORITY_MEDIUM; case PRIORITY_LOW: - return IconTheme.JabRefIcon.PRIORITY_LOW.getSmallIcon(); + return IconTheme.JabRefIcons.PRIORITY_LOW; case QUALITY_ASSURED: - return IconTheme.JabRefIcon.QUALITY_ASSURED.getSmallIcon(); + return IconTheme.JabRefIcons.QUALITY_ASSURED; case CLEAR_RANK: return null; case RANK_1: - return IconTheme.JabRefIcon.RANK1.getSmallIcon(); + return IconTheme.JabRefIcons.RANK1; case RANK_2: - return IconTheme.JabRefIcon.RANK2.getSmallIcon(); + return IconTheme.JabRefIcons.RANK2; case RANK_3: - return IconTheme.JabRefIcon.RANK3.getSmallIcon(); + return IconTheme.JabRefIcons.RANK3; case RANK_4: - return IconTheme.JabRefIcon.RANK4.getSmallIcon(); + return IconTheme.JabRefIcons.RANK4; case RANK_5: - return IconTheme.JabRefIcon.RANK5.getSmallIcon(); + return IconTheme.JabRefIcons.RANK5; case CLEAR_READ_STATUS: return null; case READ: - return IconTheme.JabRefIcon.READ_STATUS_READ.getSmallIcon(); + return IconTheme.JabRefIcons.READ_STATUS_READ; case SKIMMED: - return IconTheme.JabRefIcon.READ_STATUS_SKIMMED.getSmallIcon(); + return IconTheme.JabRefIcons.READ_STATUS_SKIMMED; case RELEVANT: - return IconTheme.JabRefIcon.RELEVANCE.getSmallIcon(); + return IconTheme.JabRefIcons.RELEVANCE; default: throw new IllegalArgumentException("There is no icon mapping for special field value " + value); } diff --git a/src/main/java/org/jabref/gui/specialfields/SpecialFieldViewModel.java b/src/main/java/org/jabref/gui/specialfields/SpecialFieldViewModel.java index dcace6e65bd..a372ba71417 100644 --- a/src/main/java/org/jabref/gui/specialfields/SpecialFieldViewModel.java +++ b/src/main/java/org/jabref/gui/specialfields/SpecialFieldViewModel.java @@ -6,6 +6,7 @@ import org.jabref.gui.IconTheme; import org.jabref.gui.JabRefFrame; +import org.jabref.gui.JabRefIcon; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.specialfields.SpecialField; import org.jabref.model.entry.specialfields.SpecialFieldValue; @@ -30,17 +31,36 @@ public SpecialFieldAction getSpecialFieldAction(SpecialFieldValue value, JabRefF public Icon getRepresentingIcon() { switch (field) { case PRINTED: - return IconTheme.JabRefIcon.PRINTED.getSmallIcon(); + return IconTheme.JabRefIcons.PRINTED.getSmallIcon(); case PRIORITY: - return IconTheme.JabRefIcon.PRIORITY.getSmallIcon(); + return IconTheme.JabRefIcons.PRIORITY.getSmallIcon(); case QUALITY: - return IconTheme.JabRefIcon.QUALITY.getSmallIcon(); + return IconTheme.JabRefIcons.QUALITY.getSmallIcon(); case RANKING: - return IconTheme.JabRefIcon.RANKING.getIcon(); + return IconTheme.JabRefIcons.RANKING.getIcon(); case READ_STATUS: - return IconTheme.JabRefIcon.READ_STATUS.getSmallIcon(); + return IconTheme.JabRefIcons.READ_STATUS.getSmallIcon(); case RELEVANCE: - return IconTheme.JabRefIcon.RELEVANCE.getSmallIcon(); + return IconTheme.JabRefIcons.RELEVANCE.getSmallIcon(); + default: + throw new IllegalArgumentException("There is no icon mapping for special field " + field); + } + } + + public JabRefIcon getIcon() { + switch (field) { + case PRINTED: + return IconTheme.JabRefIcons.PRINTED; + case PRIORITY: + return IconTheme.JabRefIcons.PRIORITY; + case QUALITY: + return IconTheme.JabRefIcons.QUALITY; + case RANKING: + return IconTheme.JabRefIcons.RANKING; + case READ_STATUS: + return IconTheme.JabRefIcons.READ_STATUS; + case RELEVANCE: + return IconTheme.JabRefIcons.RELEVANCE; default: throw new IllegalArgumentException("There is no icon mapping for special field " + field); } diff --git a/src/main/java/org/jabref/gui/util/ViewModelTreeTableCellFactory.java b/src/main/java/org/jabref/gui/util/ViewModelTreeTableCellFactory.java index 98ade037f0a..d6e906e92ac 100644 --- a/src/main/java/org/jabref/gui/util/ViewModelTreeTableCellFactory.java +++ b/src/main/java/org/jabref/gui/util/ViewModelTreeTableCellFactory.java @@ -6,15 +6,11 @@ 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; +import org.jabref.gui.JabRefIcon; import org.jabref.model.strings.StringUtil; -import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon; -import de.jensd.fx.glyphs.materialdesignicons.utils.MaterialDesignIconFactory; - /** * Constructs a {@link TreeTableCell} based on the view model of the row and a bunch of specified converter methods. * @@ -38,12 +34,8 @@ public ViewModelTreeTableCellFactory withGraphic(Callback toGraph return this; } - public ViewModelTreeTableCellFactory withIcon(Callback toIcon, Callback toColor) { - this.toGraphic = viewModel -> { - Text graphic = MaterialDesignIconFactory.get().createIcon(toIcon.call(viewModel)); - graphic.setFill(toColor.call(viewModel)); - return graphic; - }; + public ViewModelTreeTableCellFactory withIcon(Callback toIcon) { + this.toGraphic = viewModel -> toIcon.call(viewModel).getGraphicNode(); return this; } From 952c03257a791d6bd33b21195d3557bef9a6ee9a Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Fri, 29 Dec 2017 22:29:01 +0100 Subject: [PATCH 03/24] More icon related changes --- src/main/java/org/jabref/gui/JabRefFrame.java | 66 +++++++++---------- .../externalfiles/SynchronizeFileField.java | 3 +- .../ExternalFileTypeEditor.java | 8 +-- .../importer/actions/OpenDatabaseAction.java | 2 +- .../org/jabref/gui/menus/RightClickMenu.java | 32 ++++----- .../gui/openoffice/OpenOfficePanel.java | 6 +- .../jabref/gui/preftabs/TableColumnsTab.java | 8 +-- .../jabref/gui/search/GlobalSearchBar.java | 10 +-- 8 files changed, 67 insertions(+), 68 deletions(-) diff --git a/src/main/java/org/jabref/gui/JabRefFrame.java b/src/main/java/org/jabref/gui/JabRefFrame.java index 3e30b97409c..c759ce7083e 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -194,10 +194,10 @@ public class JabRefFrame extends JFrame implements OutputPrinter { IconTheme.getImage("about"), IconTheme.getImage("about")); private final AbstractAction jabrefFacebookAction = new OpenBrowserAction("https://www.facebook.com/JabRef/", "Facebook", Localization.lang("Opens JabRef's Facebook page"), - IconTheme.JabRefIcon.FACEBOOK.getSmallIcon(), IconTheme.JabRefIcon.FACEBOOK.getIcon()); + IconTheme.JabRefIcons.FACEBOOK.getSmallIcon(), IconTheme.JabRefIcons.FACEBOOK.getIcon()); private final AbstractAction jabrefBlogAction = new OpenBrowserAction("https://blog.jabref.org/", Localization.menuTitle("Blog"), Localization.lang("Opens JabRef's blog"), - IconTheme.JabRefIcon.BLOG.getSmallIcon(), IconTheme.JabRefIcon.BLOG.getIcon()); + IconTheme.JabRefIcons.BLOG.getSmallIcon(), IconTheme.JabRefIcons.BLOG.getIcon()); private final AbstractAction developmentVersionAction = new OpenBrowserAction("https://builds.jabref.org/master/", Localization.menuTitle("Development version"), Localization.lang("Opens a link where the current development version can be downloaded")); @@ -205,22 +205,22 @@ public class JabRefFrame extends JFrame implements OutputPrinter { "https://github.com/JabRef/jabref/blob/master/CHANGELOG.md", Localization.menuTitle("View change log"), Localization.lang("See what has been changed in the JabRef versions")); private final AbstractAction forkMeOnGitHubAction = new OpenBrowserAction("https://github.com/JabRef/jabref", - Localization.menuTitle("Fork me on GitHub"), Localization.lang("Opens JabRef's GitHub page"), IconTheme.JabRefIcon.GITHUB.getSmallIcon(), IconTheme.JabRefIcon.GITHUB.getIcon()); + Localization.menuTitle("Fork me on GitHub"), Localization.lang("Opens JabRef's GitHub page"), IconTheme.JabRefIcons.GITHUB.getSmallIcon(), IconTheme.JabRefIcons.GITHUB.getIcon()); private final AbstractAction donationAction = new OpenBrowserAction("https://github.com/JabRef/jabref/wiki/Donations", - Localization.menuTitle("Donate to JabRef"), Localization.lang("Donate to JabRef"), IconTheme.JabRefIcon.DONATE.getSmallIcon(), IconTheme.JabRefIcon.DONATE.getIcon()); + Localization.menuTitle("Donate to JabRef"), Localization.lang("Donate to JabRef"), IconTheme.JabRefIcons.DONATE.getSmallIcon(), IconTheme.JabRefIcons.DONATE.getIcon()); private final AbstractAction openForumAction = new OpenBrowserAction("http://discourse.jabref.org/", - Localization.menuTitle("Online help forum"), Localization.lang("Online help forum"), IconTheme.JabRefIcon.FORUM.getSmallIcon(), IconTheme.JabRefIcon.FORUM.getIcon()); + Localization.menuTitle("Online help forum"), Localization.lang("Online help forum"), IconTheme.JabRefIcons.FORUM.getSmallIcon(), IconTheme.JabRefIcons.FORUM.getIcon()); private final AbstractAction help = new HelpAction(Localization.menuTitle("Online help"), Localization.lang("Online help"), HelpFile.CONTENTS, Globals.getKeyPrefs().getKey(KeyBinding.HELP)); private final AbstractAction about = new AboutAction(Localization.menuTitle("About JabRef"), Localization.lang("About JabRef"), IconTheme.getImage("about")); private final AbstractAction editEntry = new GeneralAction(Actions.EDIT, Localization.menuTitle("Edit entry"), - Localization.lang("Edit entry"), Globals.getKeyPrefs().getKey(KeyBinding.EDIT_ENTRY), IconTheme.JabRefIcon.EDIT_ENTRY.getIcon()); + Localization.lang("Edit entry"), Globals.getKeyPrefs().getKey(KeyBinding.EDIT_ENTRY), IconTheme.JabRefIcons.EDIT_ENTRY.getIcon()); private final AbstractAction focusTable = new GeneralAction(Actions.FOCUS_TABLE, Localization.menuTitle("Focus entry table"), Localization.lang("Move the keyboard focus to the entry table"), Globals.getKeyPrefs().getKey(KeyBinding.FOCUS_ENTRY_TABLE)); private final AbstractAction save = new GeneralAction(Actions.SAVE, Localization.menuTitle("Save library"), - Localization.lang("Save library"), Globals.getKeyPrefs().getKey(KeyBinding.SAVE_DATABASE), IconTheme.JabRefIcon.SAVE.getIcon()); + Localization.lang("Save library"), Globals.getKeyPrefs().getKey(KeyBinding.SAVE_DATABASE), IconTheme.JabRefIcons.SAVE.getIcon()); private final AbstractAction saveAs = new GeneralAction(Actions.SAVE_AS, Localization.menuTitle("Save library as..."), Localization.lang("Save library as..."), Globals.getKeyPrefs().getKey(KeyBinding.SAVE_DATABASE_AS)); @@ -234,55 +234,55 @@ public class JabRefFrame extends JFrame implements OutputPrinter { private final AbstractAction importNew = ImportFormats.getImportAction(this, true); private final AbstractAction sortTabs = new SortTabsAction(this); private final AbstractAction undo = new GeneralAction(Actions.UNDO, Localization.menuTitle("Undo"), - Localization.lang("Undo"), Globals.getKeyPrefs().getKey(KeyBinding.UNDO), IconTheme.JabRefIcon.UNDO.getIcon()); + Localization.lang("Undo"), Globals.getKeyPrefs().getKey(KeyBinding.UNDO), IconTheme.JabRefIcons.UNDO.getIcon()); private final AbstractAction redo = new GeneralAction(Actions.REDO, Localization.menuTitle("Redo"), - Localization.lang("Redo"), Globals.getKeyPrefs().getKey(KeyBinding.REDO), IconTheme.JabRefIcon.REDO.getIcon()); + Localization.lang("Redo"), Globals.getKeyPrefs().getKey(KeyBinding.REDO), IconTheme.JabRefIcons.REDO.getIcon()); private final AbstractAction forward = new GeneralAction(Actions.FORWARD, Localization.menuTitle("Forward"), - Localization.lang("Forward"), Globals.getKeyPrefs().getKey(KeyBinding.FORWARD), IconTheme.JabRefIcon.RIGHT.getIcon()); + Localization.lang("Forward"), Globals.getKeyPrefs().getKey(KeyBinding.FORWARD), IconTheme.JabRefIcons.RIGHT.getIcon()); private final AbstractAction back = new GeneralAction(Actions.BACK, Localization.menuTitle("Back"), - Localization.lang("Back"), Globals.getKeyPrefs().getKey(KeyBinding.BACK), IconTheme.JabRefIcon.LEFT.getIcon()); + Localization.lang("Back"), Globals.getKeyPrefs().getKey(KeyBinding.BACK), IconTheme.JabRefIcons.LEFT.getIcon()); private final AbstractAction deleteEntry = new GeneralAction(Actions.DELETE, Localization.menuTitle("Delete entry"), - Localization.lang("Delete entry"), Globals.getKeyPrefs().getKey(KeyBinding.DELETE_ENTRY), IconTheme.JabRefIcon.DELETE_ENTRY.getIcon()); + Localization.lang("Delete entry"), Globals.getKeyPrefs().getKey(KeyBinding.DELETE_ENTRY), IconTheme.JabRefIcons.DELETE_ENTRY.getIcon()); private final AbstractAction copy = new EditAction(Actions.COPY, Localization.menuTitle("Copy"), - Localization.lang("Copy"), Globals.getKeyPrefs().getKey(KeyBinding.COPY), IconTheme.JabRefIcon.COPY.getIcon()); + Localization.lang("Copy"), Globals.getKeyPrefs().getKey(KeyBinding.COPY), IconTheme.JabRefIcons.COPY.getIcon()); private final AbstractAction paste = new EditAction(Actions.PASTE, Localization.menuTitle("Paste"), - Localization.lang("Paste"), Globals.getKeyPrefs().getKey(KeyBinding.PASTE), IconTheme.JabRefIcon.PASTE.getIcon()); + Localization.lang("Paste"), Globals.getKeyPrefs().getKey(KeyBinding.PASTE), IconTheme.JabRefIcons.PASTE.getIcon()); private final AbstractAction cut = new EditAction(Actions.CUT, Localization.menuTitle("Cut"), - Localization.lang("Cut"), Globals.getKeyPrefs().getKey(KeyBinding.CUT), IconTheme.JabRefIcon.CUT.getIcon()); + Localization.lang("Cut"), Globals.getKeyPrefs().getKey(KeyBinding.CUT), IconTheme.JabRefIcons.CUT.getIcon()); private final AbstractAction openConsole = new GeneralAction(Actions.OPEN_CONSOLE, Localization.menuTitle("Open terminal here"), Localization.lang("Open terminal here"), Globals.getKeyPrefs().getKey(KeyBinding.OPEN_CONSOLE), - IconTheme.JabRefIcon.CONSOLE.getIcon()); + IconTheme.JabRefIcons.CONSOLE.getIcon()); private final AbstractAction pullChangesFromSharedDatabase = new GeneralAction(Actions.PULL_CHANGES_FROM_SHARED_DATABASE, Localization.menuTitle("Pull changes from shared database"), Localization.lang("Pull changes from shared database"), Globals.getKeyPrefs().getKey(KeyBinding.PULL_CHANGES_FROM_SHARED_DATABASE), - IconTheme.JabRefIcon.PULL.getIcon()); + IconTheme.JabRefIcons.PULL.getIcon()); private final AbstractAction mark = new GeneralAction(Actions.MARK_ENTRIES, Localization.menuTitle("Mark entries"), - Localization.lang("Mark entries"), Globals.getKeyPrefs().getKey(KeyBinding.MARK_ENTRIES), IconTheme.JabRefIcon.MARK_ENTRIES.getIcon()); + Localization.lang("Mark entries"), Globals.getKeyPrefs().getKey(KeyBinding.MARK_ENTRIES), IconTheme.JabRefIcons.MARK_ENTRIES.getIcon()); private final JMenu markSpecific = JabRefFrame.subMenu(Localization.menuTitle("Mark specific color")); private final AbstractAction unmark = new GeneralAction(Actions.UNMARK_ENTRIES, Localization.menuTitle("Unmark entries"), Localization.lang("Unmark entries"), - Globals.getKeyPrefs().getKey(KeyBinding.UNMARK_ENTRIES), IconTheme.JabRefIcon.UNMARK_ENTRIES.getIcon()); + Globals.getKeyPrefs().getKey(KeyBinding.UNMARK_ENTRIES), IconTheme.JabRefIcons.UNMARK_ENTRIES.getIcon()); private final AbstractAction unmarkAll = new GeneralAction(Actions.UNMARK_ALL, Localization.menuTitle("Unmark all")); private final AbstractAction toggleRelevance = new GeneralAction( new SpecialFieldValueViewModel(SpecialField.RELEVANCE.getValues().get(0)).getActionName(), new SpecialFieldValueViewModel(SpecialField.RELEVANCE.getValues().get(0)).getMenuString(), new SpecialFieldValueViewModel(SpecialField.RELEVANCE.getValues().get(0)).getToolTipText(), - IconTheme.JabRefIcon.RELEVANCE.getIcon()); + IconTheme.JabRefIcons.RELEVANCE.getIcon()); private final AbstractAction toggleQualityAssured = new GeneralAction( new SpecialFieldValueViewModel(SpecialField.QUALITY.getValues().get(0)).getActionName(), new SpecialFieldValueViewModel(SpecialField.QUALITY.getValues().get(0)).getMenuString(), new SpecialFieldValueViewModel(SpecialField.QUALITY.getValues().get(0)).getToolTipText(), - IconTheme.JabRefIcon.QUALITY_ASSURED.getIcon()); + IconTheme.JabRefIcons.QUALITY_ASSURED.getIcon()); private final AbstractAction togglePrinted = new GeneralAction( new SpecialFieldValueViewModel(SpecialField.PRINTED.getValues().get(0)).getActionName(), new SpecialFieldValueViewModel(SpecialField.PRINTED.getValues().get(0)).getMenuString(), new SpecialFieldValueViewModel(SpecialField.PRINTED.getValues().get(0)).getToolTipText(), - IconTheme.JabRefIcon.PRINTED.getIcon()); + IconTheme.JabRefIcons.PRINTED.getIcon()); private final AbstractAction normalSearch = new GeneralAction(Actions.SEARCH, Localization.menuTitle("Search"), - Localization.lang("Search"), Globals.getKeyPrefs().getKey(KeyBinding.SEARCH), IconTheme.JabRefIcon.SEARCH.getIcon()); + Localization.lang("Search"), Globals.getKeyPrefs().getKey(KeyBinding.SEARCH), IconTheme.JabRefIcons.SEARCH.getIcon()); private final AbstractAction manageSelectors = new GeneralAction(Actions.MANAGE_SELECTORS, Localization.menuTitle("Manage content selectors")); private final AbstractAction copyPreview = new GeneralAction(Actions.COPY_CITATION_HTML, Localization.lang("Copy preview"), @@ -314,7 +314,7 @@ public class JabRefFrame extends JFrame implements OutputPrinter { Localization.menuTitle("Edit strings"), Localization.lang("Edit strings"), Globals.getKeyPrefs().getKey(KeyBinding.EDIT_STRINGS), - IconTheme.JabRefIcon.EDIT_STRINGS.getIcon()); + IconTheme.JabRefIcons.EDIT_STRINGS.getIcon()); private final AbstractAction customizeAction = new CustomizeEntryTypeAction(); private final Action toggleToolbar = enableToggle(new AbstractAction(Localization.menuTitle("Hide/show toolbar")) { @@ -336,7 +336,7 @@ public void actionPerformed(ActionEvent e) { Localization.menuTitle("Toggle entry preview"), Localization.lang("Toggle entry preview"), Globals.getKeyPrefs().getKey(KeyBinding.TOGGLE_ENTRY_PREVIEW), - IconTheme.JabRefIcon.TOGGLE_ENTRY_PREVIEW.getIcon())); + IconTheme.JabRefIcons.TOGGLE_ENTRY_PREVIEW.getIcon())); private final AbstractAction nextPreviewStyle = new GeneralAction(Actions.NEXT_PREVIEW_STYLE, Localization.menuTitle("Next preview layout"), Globals.getKeyPrefs().getKey(KeyBinding.NEXT_PREVIEW_LAYOUT)); @@ -347,7 +347,7 @@ public void actionPerformed(ActionEvent e) { Localization.menuTitle("Autogenerate BibTeX keys"), Localization.lang("Autogenerate BibTeX keys"), Globals.getKeyPrefs().getKey(KeyBinding.AUTOGENERATE_BIBTEX_KEYS), - IconTheme.JabRefIcon.MAKE_KEY.getIcon()); + IconTheme.JabRefIcons.MAKE_KEY.getIcon()); private final AbstractAction writeXmpAction = new GeneralAction(Actions.WRITE_XMP, Localization.menuTitle("Write XMP-metadata to PDFs"), Localization.lang("Will write XMP-metadata to the PDFs linked from selected entries."), @@ -359,14 +359,14 @@ public void actionPerformed(ActionEvent e) { Localization.menuTitle("Open file"), Localization.lang("Open file"), Globals.getKeyPrefs().getKey(KeyBinding.OPEN_FILE), - IconTheme.JabRefIcon.FILE.getIcon()); + IconTheme.JabRefIcons.FILE.getIcon()); private final AbstractAction openUrl = new GeneralAction(Actions.OPEN_URL, Localization.menuTitle("Open URL or DOI"), Localization.lang("Open URL or DOI"), Globals.getKeyPrefs().getKey(KeyBinding.OPEN_URL_OR_DOI), - IconTheme.JabRefIcon.WWW.getIcon()); + IconTheme.JabRefIcons.WWW.getIcon()); private final AbstractAction dupliCheck = new GeneralAction(Actions.DUPLI_CHECK, - Localization.menuTitle("Find duplicates"), IconTheme.JabRefIcon.FIND_DUPLICATES.getIcon()); + Localization.menuTitle("Find duplicates"), IconTheme.JabRefIcons.FIND_DUPLICATES.getIcon()); private final AbstractAction plainTextImport = new GeneralAction(Actions.PLAIN_TEXT_IMPORT, Localization.menuTitle("New entry from plain text") + ELLIPSES, Globals.getKeyPrefs().getKey(KeyBinding.NEW_FROM_PLAIN_TEXT)); @@ -375,7 +375,7 @@ public void actionPerformed(ActionEvent e) { private final AbstractAction customFileTypesAction = ExternalFileTypeEditor.getAction(this); private final AbstractAction exportToClipboard = new GeneralAction(Actions.EXPORT_TO_CLIPBOARD, Localization.menuTitle("Export selected entries to clipboard"), - IconTheme.JabRefIcon.EXPORT_TO_CLIPBOARD.getIcon()); + IconTheme.JabRefIcons.EXPORT_TO_CLIPBOARD.getIcon()); private final AbstractAction autoSetFile = new GeneralAction(Actions.AUTO_SET_FILE, Localization.lang("Synchronize file links") + ELLIPSES, Globals.getKeyPrefs().getKey(KeyBinding.SYNCHRONIZE_FILES)); @@ -399,11 +399,11 @@ public void actionPerformed(ActionEvent e) { Localization.menuTitle("Cleanup entries") + ELLIPSES, Localization.lang("Cleanup entries"), Globals.getKeyPrefs().getKey(KeyBinding.CLEANUP), - IconTheme.JabRefIcon.CLEANUP_ENTRIES.getIcon()); + IconTheme.JabRefIcons.CLEANUP_ENTRIES.getIcon()); private final AbstractAction mergeEntries = new GeneralAction(Actions.MERGE_ENTRIES, Localization.menuTitle("Merge entries") + ELLIPSES, Localization.lang("Merge entries"), - IconTheme.JabRefIcon.MERGE_ENTRIES.getIcon()); + IconTheme.JabRefIcons.MERGE_ENTRIES.getIcon()); private final AbstractAction downloadFullText = new GeneralAction(Actions.DOWNLOAD_FULL_TEXT, Localization.menuTitle("Look up full text documents"), Globals.getKeyPrefs().getKey(KeyBinding.DOWNLOAD_FULL_TEXT)); @@ -415,7 +415,7 @@ public void actionPerformed(ActionEvent e) { Localization.lang("Find and remove duplicate BibTeX keys"), Globals.getKeyPrefs().getKey(KeyBinding.RESOLVE_DUPLICATE_BIBTEX_KEYS)); private final AbstractAction sendAsEmail = new GeneralAction(Actions.SEND_AS_EMAIL, - Localization.lang("Send as email"), IconTheme.JabRefIcon.EMAIL.getIcon()); + Localization.lang("Send as email"), IconTheme.JabRefIcons.EMAIL.getIcon()); private final MassSetFieldAction massSetField = new MassSetFieldAction(this); private final ManageKeywordsAction manageKeywords = new ManageKeywordsAction(this); private final JMenu lookupIdentifiers = JabRefFrame.subMenu(Localization.menuTitle("Look up document identifier...")); diff --git a/src/main/java/org/jabref/gui/externalfiles/SynchronizeFileField.java b/src/main/java/org/jabref/gui/externalfiles/SynchronizeFileField.java index 7f8a5011fa7..c822f61458f 100644 --- a/src/main/java/org/jabref/gui/externalfiles/SynchronizeFileField.java +++ b/src/main/java/org/jabref/gui/externalfiles/SynchronizeFileField.java @@ -207,8 +207,7 @@ public void run() { // User doesn't want to handle this unknown link type. } else if (answer == JOptionPane.YES_OPTION) { // User wants to define the new file type. Show the dialog: - ExternalFileType newType = new ExternalFileType(flEntry.getType().get().getName(), "", "", - "", "new", IconTheme.JabRefIcon.FILE.getSmallIcon()); + ExternalFileType newType = new ExternalFileType(flEntry.getType().get().getName(), "", "", "", "new", IconTheme.JabRefIcons.FILE); ExternalFileTypeEntryEditor editor = new ExternalFileTypeEntryEditor(panel.frame(), newType); editor.setVisible(true); if (editor.okPressed()) { diff --git a/src/main/java/org/jabref/gui/externalfiletype/ExternalFileTypeEditor.java b/src/main/java/org/jabref/gui/externalfiletype/ExternalFileTypeEditor.java index ebfaa5c707d..bf286e86ed3 100644 --- a/src/main/java/org/jabref/gui/externalfiletype/ExternalFileTypeEditor.java +++ b/src/main/java/org/jabref/gui/externalfiletype/ExternalFileTypeEditor.java @@ -53,9 +53,9 @@ public class ExternalFileTypeEditor extends JabRefDialog { private FileTypeTableModel tableModel; private final JButton ok = new JButton(Localization.lang("OK")); private final JButton cancel = new JButton(Localization.lang("Cancel")); - private final JButton add = new JButton(IconTheme.JabRefIcon.ADD_NOBOX.getIcon()); - private final JButton remove = new JButton(IconTheme.JabRefIcon.REMOVE_NOBOX.getIcon()); - private final JButton edit = new JButton(IconTheme.JabRefIcon.EDIT.getIcon()); + private final JButton add = new JButton(IconTheme.JabRefIcons.ADD_NOBOX.getIcon()); + private final JButton remove = new JButton(IconTheme.JabRefIcons.REMOVE_NOBOX.getIcon()); + private final JButton edit = new JButton(IconTheme.JabRefIcons.EDIT.getIcon()); private final JButton toDefaults = new JButton(Localization.lang("Default")); private final EditListener editListener = new EditListener(); @@ -125,7 +125,7 @@ public void actionPerformed(ActionEvent e) { add.addActionListener(e -> { // Generate a new file type: ExternalFileType type = new ExternalFileType("", "", "", "", "new", - IconTheme.JabRefIcon.FILE.getSmallIcon()); + IconTheme.JabRefIcons.FILE); // Show the file type editor: getEditor(type).setVisible(true); if (entryEditor.okPressed()) { diff --git a/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java b/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java index a31abf7db04..814daa83dd8 100644 --- a/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java +++ b/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java @@ -71,7 +71,7 @@ public class OpenDatabaseAction extends MnemonicAwareAction { private final JabRefFrame frame; public OpenDatabaseAction(JabRefFrame frame, boolean showDialog) { - super(IconTheme.JabRefIcon.OPEN.getIcon()); + super(IconTheme.JabRefIcons.OPEN.getIcon()); this.frame = frame; this.showDialog = showDialog; putValue(Action.NAME, Localization.menuTitle("Open library")); diff --git a/src/main/java/org/jabref/gui/menus/RightClickMenu.java b/src/main/java/org/jabref/gui/menus/RightClickMenu.java index 9de2ba35609..f77f2ed3101 100644 --- a/src/main/java/org/jabref/gui/menus/RightClickMenu.java +++ b/src/main/java/org/jabref/gui/menus/RightClickMenu.java @@ -88,42 +88,42 @@ public RightClickMenu(JabRefFrame frame, BasePanel panel) { } copySpecialMenu.add(new GeneralAction(Actions.EXPORT_TO_CLIPBOARD, Localization.lang("Export to clipboard"), - IconTheme.JabRefIcon.EXPORT_TO_CLIPBOARD.getSmallIcon())); + IconTheme.JabRefIcons.EXPORT_TO_CLIPBOARD.getSmallIcon())); - add(new GeneralAction(Actions.COPY, Localization.lang("Copy"), IconTheme.JabRefIcon.COPY.getSmallIcon(), KeyBinding.COPY)); + add(new GeneralAction(Actions.COPY, Localization.lang("Copy"), IconTheme.JabRefIcons.COPY.getSmallIcon(), KeyBinding.COPY)); add(copySpecialMenu); - add(new GeneralAction(Actions.PASTE, Localization.lang("Paste"), IconTheme.JabRefIcon.PASTE.getSmallIcon(), KeyBinding.PASTE)); - add(new GeneralAction(Actions.CUT, Localization.lang("Cut"), IconTheme.JabRefIcon.CUT.getSmallIcon(), KeyBinding.CUT)); - add(new GeneralAction(Actions.DELETE, Localization.lang("Delete"), IconTheme.JabRefIcon.DELETE_ENTRY.getSmallIcon(), KeyBinding.DELETE_ENTRY)); - GeneralAction printPreviewAction = new GeneralAction(Actions.PRINT_PREVIEW, Localization.lang("Print entry preview"), IconTheme.JabRefIcon.PRINTED.getSmallIcon()); + add(new GeneralAction(Actions.PASTE, Localization.lang("Paste"), IconTheme.JabRefIcons.PASTE.getSmallIcon(), KeyBinding.PASTE)); + add(new GeneralAction(Actions.CUT, Localization.lang("Cut"), IconTheme.JabRefIcons.CUT.getSmallIcon(), KeyBinding.CUT)); + add(new GeneralAction(Actions.DELETE, Localization.lang("Delete"), IconTheme.JabRefIcons.DELETE_ENTRY.getSmallIcon(), KeyBinding.DELETE_ENTRY)); + GeneralAction printPreviewAction = new GeneralAction(Actions.PRINT_PREVIEW, Localization.lang("Print entry preview"), IconTheme.JabRefIcons.PRINTED.getSmallIcon()); printPreviewAction.setEnabled(!multiple); add(printPreviewAction); addSeparator(); - add(new GeneralAction(Actions.SEND_AS_EMAIL, Localization.lang("Send as email"), IconTheme.JabRefIcon.EMAIL.getSmallIcon())); + add(new GeneralAction(Actions.SEND_AS_EMAIL, Localization.lang("Send as email"), IconTheme.JabRefIcons.EMAIL.getSmallIcon())); addSeparator(); add(new CopyFilesAction()); JMenu markSpecific = JabRefFrame.subMenu(Localization.menuTitle("Mark specific color")); - markSpecific.setIcon(IconTheme.JabRefIcon.MARK_ENTRIES.getSmallIcon()); + markSpecific.setIcon(IconTheme.JabRefIcons.MARK_ENTRIES.getSmallIcon()); for (int i = 0; i < EntryMarker.MAX_MARKING_LEVEL; i++) { markSpecific.add(new MarkEntriesAction(frame, i).getMenuItem()); } if (multiple) { - add(new GeneralAction(Actions.MARK_ENTRIES, Localization.lang("Mark entries"), IconTheme.JabRefIcon.MARK_ENTRIES.getSmallIcon(), KeyBinding.MARK_ENTRIES)); + add(new GeneralAction(Actions.MARK_ENTRIES, Localization.lang("Mark entries"), IconTheme.JabRefIcons.MARK_ENTRIES.getSmallIcon(), KeyBinding.MARK_ENTRIES)); add(markSpecific); - add(new GeneralAction(Actions.UNMARK_ENTRIES, Localization.lang("Unmark entries"), IconTheme.JabRefIcon.UNMARK_ENTRIES.getSmallIcon(), KeyBinding.UNMARK_ENTRIES)); + add(new GeneralAction(Actions.UNMARK_ENTRIES, Localization.lang("Unmark entries"), IconTheme.JabRefIcons.UNMARK_ENTRIES.getSmallIcon(), KeyBinding.UNMARK_ENTRIES)); } else if (be != null) { Optional marked = be.getField(FieldName.MARKED_INTERNAL); // We have to check for "" too as the marked field may be empty if ((!marked.isPresent()) || marked.get().isEmpty()) { - add(new GeneralAction(Actions.MARK_ENTRIES, Localization.lang("Mark entry"), IconTheme.JabRefIcon.MARK_ENTRIES.getSmallIcon(), KeyBinding.MARK_ENTRIES)); + add(new GeneralAction(Actions.MARK_ENTRIES, Localization.lang("Mark entry"), IconTheme.JabRefIcons.MARK_ENTRIES.getSmallIcon(), KeyBinding.MARK_ENTRIES)); add(markSpecific); } else { add(markSpecific); - add(new GeneralAction(Actions.UNMARK_ENTRIES, Localization.lang("Unmark entry"), IconTheme.JabRefIcon.UNMARK_ENTRIES.getSmallIcon(), KeyBinding.UNMARK_ENTRIES)); + add(new GeneralAction(Actions.UNMARK_ENTRIES, Localization.lang("Unmark entry"), IconTheme.JabRefIcons.UNMARK_ENTRIES.getSmallIcon(), KeyBinding.UNMARK_ENTRIES)); } } @@ -174,7 +174,7 @@ public RightClickMenu(JabRefFrame frame, BasePanel panel) { add(openFileAction); GeneralAction openUrlAction = new GeneralAction(Actions.OPEN_URL, Localization.lang("Open URL or DOI"), - IconTheme.JabRefIcon.WWW.getSmallIcon(), KeyBinding.OPEN_URL_OR_DOI); + IconTheme.JabRefIcons.WWW.getSmallIcon(), KeyBinding.OPEN_URL_OR_DOI); openUrlAction.setEnabled(isFieldSetForSelectedEntry(FieldName.URL) || isFieldSetForSelectedEntry(FieldName.DOI)); add(openUrlAction); @@ -190,14 +190,14 @@ public RightClickMenu(JabRefFrame frame, BasePanel panel) { add(frame.getMassSetField()); GeneralAction attachFileAction = new GeneralAction(Actions.ADD_FILE_LINK, Localization.lang("Attach file"), - IconTheme.JabRefIcon.ATTACH_FILE.getSmallIcon()); + IconTheme.JabRefIcons.ATTACH_FILE.getSmallIcon()); attachFileAction.setEnabled(!multiple); add(attachFileAction); add(frame.getManageKeywords()); GeneralAction mergeEntriesAction = new GeneralAction(Actions.MERGE_ENTRIES, - Localization.lang("Merge entries") + "...", IconTheme.JabRefIcon.MERGE_ENTRIES.getSmallIcon()); + Localization.lang("Merge entries") + "...", IconTheme.JabRefIcons.MERGE_ENTRIES.getSmallIcon()); mergeEntriesAction.setEnabled(areExactlyTwoEntriesSelected()); add(mergeEntriesAction); @@ -279,7 +279,7 @@ private Icon getFileIconForSelectedEntry() { } } } - return IconTheme.JabRefIcon.FILE.getSmallIcon(); + return IconTheme.JabRefIcons.FILE.getSmallIcon(); } class GeneralAction extends AbstractAction { diff --git a/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java b/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java index 81e76f6f6f4..0ea66468474 100644 --- a/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java +++ b/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java @@ -114,7 +114,7 @@ public class OpenOfficePanel extends AbstractWorker { private final StyleLoader loader; public OpenOfficePanel(JabRefFrame jabRefFrame, SidePaneManager spManager) { - Icon connectImage = IconTheme.JabRefIcon.CONNECT_OPEN_OFFICE.getSmallIcon(); + Icon connectImage = IconTheme.JabRefIcons.CONNECT_OPEN_OFFICE.getSmallIcon(); connect = new JButton(connectImage); manualConnect = new JButton(connectImage); @@ -123,10 +123,10 @@ public OpenOfficePanel(JabRefFrame jabRefFrame, SidePaneManager spManager) { connect.setPreferredSize(new Dimension(24, 24)); manualConnect.setPreferredSize(new Dimension(24, 24)); - selectDocument = new JButton(IconTheme.JabRefIcon.OPEN.getSmallIcon()); + selectDocument = new JButton(IconTheme.JabRefIcons.OPEN.getSmallIcon()); selectDocument.setToolTipText(Localization.lang("Select Writer document")); selectDocument.setPreferredSize(new Dimension(24, 24)); - update = new JButton(IconTheme.JabRefIcon.REFRESH.getSmallIcon()); + update = new JButton(IconTheme.JabRefIcons.REFRESH.getSmallIcon()); update.setToolTipText(Localization.lang("Sync OpenOffice/LibreOffice bibliography")); update.setPreferredSize(new Dimension(24, 24)); preferences = new OpenOfficePreferences(Globals.prefs); diff --git a/src/main/java/org/jabref/gui/preftabs/TableColumnsTab.java b/src/main/java/org/jabref/gui/preftabs/TableColumnsTab.java index 5176a32b1a3..6e600ed7e13 100644 --- a/src/main/java/org/jabref/gui/preftabs/TableColumnsTab.java +++ b/src/main/java/org/jabref/gui/preftabs/TableColumnsTab.java @@ -453,7 +453,7 @@ public void setValues() { class DeleteRowAction extends AbstractAction { public DeleteRowAction() { - super("Delete row", IconTheme.JabRefIcon.REMOVE_NOBOX.getIcon()); + super("Delete row", IconTheme.JabRefIcons.REMOVE_NOBOX.getIcon()); putValue(Action.SHORT_DESCRIPTION, Localization.lang("Delete rows")); } @@ -483,7 +483,7 @@ public void actionPerformed(ActionEvent e) { class AddRowAction extends AbstractAction { public AddRowAction() { - super("Add row", IconTheme.JabRefIcon.ADD_NOBOX.getIcon()); + super("Add row", IconTheme.JabRefIcons.ADD_NOBOX.getIcon()); putValue(Action.SHORT_DESCRIPTION, Localization.lang("Insert rows")); } @@ -534,7 +534,7 @@ public void swap(int i, int j) { class MoveRowUpAction extends AbstractMoveRowAction { public MoveRowUpAction() { - super("Up", IconTheme.JabRefIcon.UP.getIcon()); + super("Up", IconTheme.JabRefIcons.UP.getIcon()); putValue(Action.SHORT_DESCRIPTION, Localization.lang("Move up")); } @@ -567,7 +567,7 @@ public void actionPerformed(ActionEvent e) { class MoveRowDownAction extends AbstractMoveRowAction { public MoveRowDownAction() { - super("Down", IconTheme.JabRefIcon.DOWN.getIcon()); + super("Down", IconTheme.JabRefIcons.DOWN.getIcon()); putValue(Action.SHORT_DESCRIPTION, Localization.lang("Down")); } diff --git a/src/main/java/org/jabref/gui/search/GlobalSearchBar.java b/src/main/java/org/jabref/gui/search/GlobalSearchBar.java index 0ae87009cae..5ded0d496b0 100644 --- a/src/main/java/org/jabref/gui/search/GlobalSearchBar.java +++ b/src/main/java/org/jabref/gui/search/GlobalSearchBar.java @@ -69,7 +69,7 @@ public class GlobalSearchBar extends JPanel { private final JButton searchModeButton = new JButton(); private final JLabel currentResults = new JLabel(""); private final SearchQueryHighlightObservable searchQueryHighlightObservable = new SearchQueryHighlightObservable(); - private final JButton openCurrentResultsInDialog = new JButton(IconTheme.JabRefIcon.OPEN_IN_NEW_WINDOW.getSmallIcon()); + private final JButton openCurrentResultsInDialog = new JButton(IconTheme.JabRefIcons.OPEN_IN_NEW_WINDOW.getSmallIcon()); private final JFXPanel container; private SearchWorker searchWorker; private GlobalSearchWorker globalSearchWorker; @@ -93,7 +93,7 @@ public GlobalSearchBar(JabRefFrame frame) { currentResults.setPreferredSize(new Dimension(150, 5)); currentResults.setFont(currentResults.getFont().deriveFont(Font.BOLD)); - JToggleButton globalSearch = new JToggleButton(IconTheme.JabRefIcon.GLOBAL_SEARCH.getSmallIcon(), searchPreferences.isGlobalSearch()); + JToggleButton globalSearch = new JToggleButton(IconTheme.JabRefIcons.GLOBAL_SEARCH.getSmallIcon(), searchPreferences.isGlobalSearch()); globalSearch.setToolTipText(Localization.lang("Search in all open libraries")); // default action to be performed for toggling globalSearch @@ -152,7 +152,7 @@ public void actionPerformed(ActionEvent e) { globalSearch.addActionListener(globalSearchStandardAction); - openCurrentResultsInDialog.setDisabledIcon(IconTheme.JabRefIcon.OPEN_IN_NEW_WINDOW.getSmallIcon().createDisabledIcon()); + openCurrentResultsInDialog.setDisabledIcon(IconTheme.JabRefIcons.OPEN_IN_NEW_WINDOW.disabled().getSmallIcon()); openCurrentResultsInDialog.addActionListener(event -> { if (globalSearch.isSelected()) { performGlobalSearch(); @@ -163,7 +163,7 @@ public void actionPerformed(ActionEvent e) { openCurrentResultsInDialog.setEnabled(false); updateOpenCurrentResultsTooltip(globalSearch.isSelected()); - regularExp = new JToggleButton(IconTheme.JabRefIcon.REG_EX.getSmallIcon(), + regularExp = new JToggleButton(IconTheme.JabRefIcons.REG_EX.getSmallIcon(), searchPreferences.isRegularExpression()); regularExp.setToolTipText(Localization.lang("regular expression")); regularExp.addActionListener(event -> { @@ -171,7 +171,7 @@ public void actionPerformed(ActionEvent e) { performSearch(); }); - caseSensitive = new JToggleButton(IconTheme.JabRefIcon.CASE_SENSITIVE.getSmallIcon(), + caseSensitive = new JToggleButton(IconTheme.JabRefIcons.CASE_SENSITIVE.getSmallIcon(), searchPreferences.isCaseSensitive()); caseSensitive.setToolTipText(Localization.lang("Case sensitive")); caseSensitive.addActionListener(event -> { From 41eeb3c97c7ce7b06ac8a40213ae025c215737cd Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sun, 31 Dec 2017 12:48:55 +0100 Subject: [PATCH 04/24] First working prototype --- src/main/java/org/jabref/gui/BasePanel.java | 262 +++++-------- .../java/org/jabref/gui/EntryTypeDialog.java | 2 +- src/main/java/org/jabref/gui/GUIGlobals.java | 95 ----- src/main/java/org/jabref/gui/JabRefFrame.java | 220 +++++------ src/main/java/org/jabref/gui/Main.css | 5 + .../java/org/jabref/gui/PreviewPanel.java | 2 +- .../java/org/jabref/gui/SidePaneManager.java | 8 +- .../gui/actions/IntegrityCheckAction.java | 2 +- .../jabref/gui/actions/SortTabsAction.java | 15 +- .../jabref/gui/auximport/FromAuxDialog.java | 13 +- .../EntryCustomizationDialog.java | 9 - .../jabref/gui/customjfx/CustomJFXPanel.java | 2 + .../gui/exporter/SaveDatabaseAction.java | 4 +- .../externalfiles/SynchronizeFileField.java | 1 - .../gui/externalfiles/WriteXMPAction.java | 9 +- .../ExternalFileTypeEditor.java | 3 - .../gui/groups/EntryTableTransferHandler.java | 3 + .../jabref/gui/importer/ImportMenuItem.java | 2 +- .../actions/AppendDatabaseAction.java | 4 +- .../importer/actions/OpenDatabaseAction.java | 6 +- .../org/jabref/gui/maintable/CellFactory.java | 103 +++++ .../org/jabref/gui/maintable/MainTable.css | 48 +++ .../org/jabref/gui/maintable/MainTable.java | 355 +++++------------- .../jabref/gui/maintable/MainTableColumn.java | 159 +------- .../gui/maintable/MainTableDataModel.java | 17 +- .../jabref/gui/maintable/MainTableFormat.java | 153 -------- .../maintable/MainTableHeaderRenderer.java | 41 -- .../maintable/MainTableSelectionListener.java | 71 ++-- .../PersistenceTableColumnListener.java | 10 +- .../PreventDraggingJTableHeader.java | 97 ----- .../SpecialMainTableColumnsBuilder.java | 203 ---------- .../org/jabref/gui/menus/RightClickMenu.java | 16 +- .../gui/openoffice/OpenOfficePanel.java | 4 +- .../jabref/gui/preftabs/TableColumnsTab.java | 8 +- .../jabref/gui/preftabs/TablePrefsTab.java | 7 +- .../jabref/gui/search/GlobalSearchBar.java | 15 +- .../jabref/gui/search/SearchResultFrame.java | 2 +- .../org/jabref/gui/search/SearchWorker.java | 3 +- .../gui/shared/SharedDatabaseUIManager.java | 3 +- .../org/jabref/gui/util/BindingsHelper.java | 15 + .../gui/util/ValueTableCellFactory.java | 2 +- .../gui/util/ViewModelTableRowFactory.java | 39 ++ .../org/jabref/pdfimport/PdfImporter.java | 4 +- .../jabref/preferences/JabRefPreferences.java | 9 +- .../jabref/gui/search/SearchResultsTest.java | 10 +- 45 files changed, 624 insertions(+), 1437 deletions(-) create mode 100644 src/main/java/org/jabref/gui/maintable/CellFactory.java create mode 100644 src/main/java/org/jabref/gui/maintable/MainTable.css delete mode 100644 src/main/java/org/jabref/gui/maintable/MainTableFormat.java delete mode 100644 src/main/java/org/jabref/gui/maintable/MainTableHeaderRenderer.java delete mode 100644 src/main/java/org/jabref/gui/maintable/PreventDraggingJTableHeader.java delete mode 100644 src/main/java/org/jabref/gui/maintable/SpecialMainTableColumnsBuilder.java create mode 100644 src/main/java/org/jabref/gui/util/ViewModelTableRowFactory.java diff --git a/src/main/java/org/jabref/gui/BasePanel.java b/src/main/java/org/jabref/gui/BasePanel.java index 1303101ed58..4eced8b9227 100644 --- a/src/main/java/org/jabref/gui/BasePanel.java +++ b/src/main/java/org/jabref/gui/BasePanel.java @@ -5,9 +5,6 @@ import java.awt.datatransfer.ClipboardOwner; import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.Transferable; -import java.awt.event.ActionEvent; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; import java.io.File; import java.io.IOException; import java.io.StringReader; @@ -27,7 +24,6 @@ import java.util.Set; import java.util.stream.Collectors; -import javax.swing.AbstractAction; import javax.swing.JComponent; import javax.swing.JOptionPane; import javax.swing.JTextArea; @@ -35,11 +31,12 @@ import javax.swing.undo.CannotRedoException; import javax.swing.undo.CannotUndoException; -import javafx.application.Platform; -import javafx.embed.swing.JFXPanel; +import javafx.beans.binding.Bindings; import javafx.geometry.Orientation; -import javafx.scene.Scene; +import javafx.scene.Node; +import javafx.scene.control.ScrollPane; import javafx.scene.control.SplitPane; +import javafx.scene.layout.AnchorPane; import javafx.scene.layout.StackPane; import org.jabref.Globals; @@ -56,7 +53,6 @@ import org.jabref.gui.collab.DatabaseChangeMonitor; import org.jabref.gui.collab.FileUpdatePanel; import org.jabref.gui.contentselector.ContentSelectorDialog; -import org.jabref.gui.customjfx.CustomJFXPanel; import org.jabref.gui.desktop.JabRefDesktop; import org.jabref.gui.entryeditor.EntryEditor; import org.jabref.gui.exporter.ExportToClipboardAction; @@ -75,11 +71,8 @@ import org.jabref.gui.importer.actions.AppendDatabaseAction; import org.jabref.gui.journals.AbbreviateAction; import org.jabref.gui.journals.UnabbreviateAction; -import org.jabref.gui.keyboard.KeyBinding; import org.jabref.gui.maintable.MainTable; import org.jabref.gui.maintable.MainTableDataModel; -import org.jabref.gui.maintable.MainTableFormat; -import org.jabref.gui.maintable.MainTableSelectionListener; import org.jabref.gui.mergeentries.MergeEntriesDialog; import org.jabref.gui.mergeentries.MergeWithFetchedEntryAction; import org.jabref.gui.plaintextimport.TextInputDialog; @@ -170,14 +163,11 @@ public class BasePanel extends StackPane implements ClipboardOwner { private final Map actions = new HashMap<>(); private final SidePaneManager sidePaneManager; private final PreviewPanel preview; - private final JFXPanel previewContainer; // To contain instantiated entry editors. This is to save time // As most enums, this must not be null private BasePanelMode mode = BasePanelMode.SHOWING_NOTHING; private final EntryEditor entryEditor; - private final JFXPanel entryEditorContainer; - private MainTableSelectionListener selectionListener; private SplitPane splitPane; private boolean saving; @@ -187,7 +177,6 @@ public class BasePanel extends StackPane implements ClipboardOwner { private boolean nonUndoableChange; // Used to track whether the base has changed since last save. private MainTable mainTable; - private MainTableFormat tableFormat; private BibEntry showing; // Variable to prevent erroneous update of back/forward histories at the time // when a Back or Forward operation is being processed: @@ -244,38 +233,9 @@ public BasePanel(JabRefFrame frame, BibDatabaseContext bibDatabaseContext) { this.getDatabase().registerListener(new UpdateTimestampListener(Globals.prefs)); entryEditor = new EntryEditor(this); - entryEditorContainer = setupEntryEditor(entryEditor); this.preview = new PreviewPanel(this, getBibDatabaseContext()); DefaultTaskExecutor.runInJavaFXThread(() -> frame().getGlobalSearchBar().getSearchQueryHighlightObservable().addSearchListener(preview)); - this.previewContainer = CustomJFXPanel.wrap(new Scene(preview)); - } - - private static JFXPanel setupEntryEditor(EntryEditor entryEditor) { - JFXPanel container = CustomJFXPanel.wrap(new Scene(entryEditor)); - container.addKeyListener(new KeyAdapter() { - - @Override - public void keyPressed(KeyEvent e) { - - //We need to consume this event here to prevent the propgation of keybinding events back to the JFrame - Optional keyBinding = Globals.getKeyPrefs().mapToKeyBinding(e); - if (keyBinding.isPresent()) { - switch (keyBinding.get()) { - case CUT: - case COPY: - case PASTE: - case DELETE_ENTRY: - case SELECT_ALL: - e.consume(); - break; - default: - //do nothing - } - } - } - }); - return container; } public static void runWorker(AbstractWorker worker) throws Exception { @@ -373,7 +333,7 @@ private void setupActions() { }); // The action for opening an entry editor. - actions.put(Actions.EDIT, (BaseAction) selectionListener::editSignalled); + actions.put(Actions.EDIT, (BaseAction) this::showAndEdit); // The action for saving a database. actions.put(Actions.SAVE, saveAction); @@ -404,7 +364,7 @@ private void setupActions() { // only the text representation seems to get as far as the X clipboard, at least on my system) actions.put(Actions.PASTE, (BaseAction) () -> paste()); - actions.put(Actions.SELECT_ALL, (BaseAction) mainTable::selectAll); + actions.put(Actions.SELECT_ALL, (BaseAction) mainTable.getSelectionModel()::selectAll); // The action for opening the preamble editor actions.put(Actions.EDIT_PREAMBLE, (BaseAction) () -> { @@ -513,19 +473,6 @@ public void update() { } markBaseChanged(); numSelected = entries.size(); - - //////////////////////////////////////////////////////////////////////////////// - // Prevent selection loss for autogenerated BibTeX-Keys - //////////////////////////////////////////////////////////////////////////////// - for (final BibEntry bibEntry : entries) { - SwingUtilities.invokeLater(() -> { - final int row = mainTable.findEntry(bibEntry); - if ((row >= 0) && (mainTable.getSelectedRowCount() < entries.size())) { - mainTable.addRowSelectionInterval(row, row); - } - }); - } - //////////////////////////////////////////////////////////////////////////////// output(formatOutputMessage(Localization.lang("Generated BibTeX key for"), numSelected)); frame.unblock(); } @@ -629,7 +576,7 @@ public void update() { actions.put(Actions.PLAIN_TEXT_IMPORT, (BaseAction) () -> { // get Type of new entry EntryTypeDialog etd = new EntryTypeDialog(frame); - etd.setLocationRelativeTo(BasePanel.this); + etd.setLocationRelativeTo(frame); etd.setVisible(true); EntryType tp = etd.getChoice(); if (tp == null) { @@ -638,7 +585,7 @@ public void update() { BibEntry bibEntry = new BibEntry(tp.getName()); TextInputDialog tidialog = new TextInputDialog(frame, bibEntry); - tidialog.setLocationRelativeTo(BasePanel.this); + tidialog.setLocationRelativeTo(frame); tidialog.setVisible(true); if (tidialog.okPressed()) { @@ -720,7 +667,7 @@ public void update() { .withPreviewPanelEnabled(enabled) .build(); Globals.prefs.storePreviewPreferences(newPreviewPreferences); - setPreviewActiveBasePanels(enabled); + DefaultTaskExecutor.runInJavaFXThread(() -> setPreviewActiveBasePanels(enabled)); frame.setPreviewToggle(enabled); }); @@ -767,22 +714,7 @@ private void copyCitationToClipboard(CitationStyleOutputFormat outputFormat) { private void copy() { List bes = mainTable.getSelectedEntries(); - if (bes.isEmpty()) { - // The user maybe selected a single cell. - // TODO: Check if this can actually happen - int[] rows = mainTable.getSelectedRows(); - int[] cols = mainTable.getSelectedColumns(); - if ((cols.length == 1) && (rows.length == 1)) { - // Copy single value. - Object o = mainTable.getValueAt(rows[0], cols[0]); - if (o != null) { - StringSelection ss = new StringSelection(o.toString()); - Toolkit.getDefaultToolkit().getSystemClipboard().setContents(ss, BasePanel.this); - - output(Localization.lang("Copied cell contents") + '.'); - } - } - } else { + if (!bes.isEmpty()) { TransferableBibtexEntry trbe = new TransferableBibtexEntry(bes); // ! look at ClipBoardManager Toolkit.getDefaultToolkit().getSystemClipboard().setContents(trbe, BasePanel.this); @@ -820,12 +752,13 @@ private void delete(boolean cut, List entries) { return; } + // TODO: check if needed // select the next entry to stay at the same place as before (or the previous if we're already at the end) - if (mainTable.getSelectedRow() != (mainTable.getRowCount() - 1)) { - selectNextEntry(); - } else { - selectPreviousEntry(); - } + //if (mainTable.getSelectedRow() != (mainTable.getRowCount() - 1)) { + // selectNextEntry(); + //} else { + // selectPreviousEntry(); + //} NamedCompound compound; if (cut) { @@ -894,11 +827,11 @@ private void paste() { output(formatOutputMessage(Localization.lang("Pasted"), bes.size())); markBaseChanged(); - highlightEntry(firstBE); + clearAndSelect(firstBE); mainTable.requestFocus(); if (Globals.prefs.getBoolean(JabRefPreferences.AUTO_OPEN_FORM)) { - selectionListener.editSignalled(firstBE); + showAndEdit(firstBE); } } } @@ -1055,7 +988,7 @@ private void openExternalFile() { } FileListEntry flEntry = fileListTableModel.getEntry(0); ExternalFileMenuItem item = new ExternalFileMenuItem(frame(), entry, "", flEntry.getLink(), - flEntry.getType().get().getIcon(), bibDatabaseContext, flEntry.getType()); + flEntry.getType().get().getIcon().getSmallIcon(), bibDatabaseContext, flEntry.getType()); item.doClick(); }); } @@ -1116,7 +1049,7 @@ private boolean saveDatabase(File file, boolean selectedOnly, Charset enc, } catch (SaveException ex) { if (ex.specificEntry()) { // Error occurred during processing of the entry. Highlight it: - highlightEntry(ex.getEntry()); + clearAndSelect(ex.getEntry()); showAndEdit(ex.getEntry()); } else { LOGGER.warn("Could not save", ex); @@ -1218,7 +1151,7 @@ public BibEntry newEntry(EntryType type) { mode = BasePanelMode.WILL_SHOW_EDITOR; } - highlightEntry(be); + clearAndSelect(be); // The database just changed. markBaseChanged(); @@ -1252,9 +1185,9 @@ public void insertEntry(final BibEntry bibEntry) { markBaseChanged(); // The database just changed. if (Globals.prefs.getBoolean(JabRefPreferences.AUTO_OPEN_FORM)) { - selectionListener.editSignalled(bibEntry); + showAndEdit(bibEntry); } - highlightEntry(bibEntry); + clearAndSelect(bibEntry); } catch (KeyCollisionException ex) { LOGGER.info("Collision for bibtex key" + bibEntry.getId(), ex); } @@ -1263,8 +1196,8 @@ public void insertEntry(final BibEntry bibEntry) { public void editEntryByIdAndFocusField(final String entryId, final String fieldName) { bibDatabaseContext.getDatabase().getEntryById(entryId).ifPresent(entry -> { - mainTable.setSelected(mainTable.findEntry(entry)); - selectionListener.editSignalled(); + clearAndSelect(entry); + //selectionListener.editSignalled(); showAndEdit(entry); entryEditor.setFocusToField(fieldName); }); @@ -1278,21 +1211,15 @@ private void createMainTable() { bibDatabaseContext.getDatabase().registerListener(tableModel.getListSynchronizer()); bibDatabaseContext.getDatabase().registerListener(SpecialFieldDatabaseChangeListener.getInstance()); - tableFormat = new MainTableFormat(bibDatabaseContext.getDatabase()); - tableFormat.updateTableFormat(); - mainTable = new MainTable(tableFormat, tableModel, frame, this); + mainTable = new MainTable(tableModel, frame, this, bibDatabaseContext.getDatabase()); - selectionListener = new MainTableSelectionListener(this, mainTable); mainTable.updateFont(); - mainTable.addSelectionListener(selectionListener); - mainTable.addMouseListener(selectionListener); - mainTable.addKeyListener(selectionListener); - mainTable.addFocusListener(selectionListener); // Add the listener that binds selection to state manager (TODO: should be replaced by proper JavaFX binding as soon as table is implemented in JavaFX) - mainTable.addSelectionListener(listEvent -> Platform - .runLater(() -> Globals.stateManager.setSelectedEntries(mainTable.getSelectedEntries()))); + mainTable.addSelectionListener(listEvent -> Globals.stateManager.setSelectedEntries(mainTable.getSelectedEntries())); + // TODO: Register these actions globally + /* String clearSearch = "clearSearch"; mainTable.getInputMap().put(Globals.getKeyPrefs().getKey(KeyBinding.CLEAR_SEARCH), clearSearch); mainTable.getActionMap().put(clearSearch, new AbstractAction() { @@ -1381,11 +1308,12 @@ public void keyPressed(KeyEvent e) { } } }); + */ } public void setupMainPanel() { splitPane = new SplitPane(); - splitPane.setOrientation(Orientation.HORIZONTAL); + splitPane.setOrientation(Orientation.VERTICAL); adjustSplitter(); // restore last splitting state (before mainTable is created as creation affects the stored size of the entryEditors) // check whether a mainTable already existed and a floatSearch was active @@ -1393,16 +1321,13 @@ public void setupMainPanel() { createMainTable(); - splitPane.getItems().add(mainTable.getPane()); - - // If an entry is currently being shown, make sure it stays shown. - if (mode == BasePanelMode.SHOWING_PREVIEW) { - mode = BasePanelMode.SHOWING_NOTHING; - highlightEntry(selectionListener.getPreview().getEntry()); - } else if (mode == BasePanelMode.SHOWING_EDITOR) { - mode = BasePanelMode.SHOWING_NOTHING; - } - + ScrollPane pane = mainTable.getPane(); + AnchorPane anchorPane = new AnchorPane(pane); + AnchorPane.setBottomAnchor(pane, 0.0); + AnchorPane.setTopAnchor(pane, 0.0); + AnchorPane.setLeftAnchor(pane, 0.0); + AnchorPane.setRightAnchor(pane, 0.0); + splitPane.getItems().add(anchorPane); this.getChildren().setAll(splitPane); // Set up name autocompleter for search: @@ -1416,9 +1341,10 @@ public void setupMainPanel() { if (floatSearchActive) { mainTable.showFloatSearch(); } - - // saves the divider position as soon as it changes - EasyBind.subscribe(splitPane.getDividers().get(0).positionProperty(), position -> saveDividerLocation(position)); + // Saves the divider position as soon as it changes + EasyBind.monadic(Bindings.valueAt(splitPane.getDividers(), 0)) + .flatMap(SplitPane.Divider::positionProperty) + .subscribe((observable, oldValue, newValue) -> saveDividerLocation(newValue)); } /** @@ -1487,35 +1413,46 @@ public EntryEditor getEntryEditor() { * @param entry The entry to edit. */ public void showAndEdit(BibEntry entry) { - if (mode == BasePanelMode.SHOWING_EDITOR) { - Globals.prefs.putInt(JabRefPreferences.ENTRY_EDITOR_HEIGHT, splitPane.getHeight() - splitPane.getDividerLocation()); - } mode = BasePanelMode.SHOWING_EDITOR; - splitPane.setBottomComponent(entryEditorContainer); + showBottomPane(entryEditor); if (entry != getShowing()) { entryEditor.setEntry(entry); newEntryShowing(entry); } entryEditor.requestFocus(); + } + + private void showBottomPane(Node pane) { + if (splitPane.getItems().size() == 2) { + splitPane.getItems().set(1, pane); + } else { + splitPane.getItems().add(1, pane); + } adjustSplitter(); } + private void showAndEdit() { + if (!mainTable.getSelectedEntries().isEmpty()) { + showAndEdit(mainTable.getSelectedEntries().get(0)); + } + } + /** * Sets the given preview panel as the bottom component in the split panel. Updates the mode to SHOWING_PREVIEW. * * @param entry The entry to show in the preview. */ - public void showPreview(BibEntry entry) { - preview.setEntry(entry); + private void showPreview(BibEntry entry) { mode = BasePanelMode.SHOWING_PREVIEW; - splitPane.setBottomComponent(previewContainer); - adjustSplitter(); + showBottomPane(preview); + + preview.setEntry(entry); } private void showPreview() { - if (!mainTable.getSelected().isEmpty()) { - showPreview(mainTable.getSelected().get(0)); + if (!mainTable.getSelectedEntries().isEmpty()) { + showPreview(mainTable.getSelectedEntries().get(0)); } } @@ -1540,44 +1477,53 @@ private void cyclePreview(int newPosition) { /** * Removes the bottom component. */ - public void hideBottomComponent() { + public void closeBottomPane() { mode = BasePanelMode.SHOWING_NOTHING; - splitPane.setBottomComponent(null); + splitPane.getItems().removeAll(entryEditor, preview); } /** * This method selects the given entry, and scrolls it into view in the table. If an entryEditor is shown, it is * given focus afterwards. */ - public void highlightEntry(final BibEntry bibEntry) { - highlightEntry(mainTable.findEntry(bibEntry)); + public void clearAndSelect(final BibEntry bibEntry) { + mainTable.findEntry(bibEntry) + .ifPresent(entry -> { + mainTable.getSelectionModel().clearSelection(); + mainTable.getSelectionModel().select(entry); + }); } /** * This method selects the entry on the given position, and scrolls it into view in the table. * If an entryEditor is shown, it is given focus afterwards. + * + * @deprecated use select by entry not by row */ - public void highlightEntry(int pos) { - if ((pos >= 0) && (pos < mainTable.getRowCount())) { - mainTable.setRowSelectionInterval(pos, pos); - mainTable.ensureVisible(pos); + @Deprecated + private void clearAndSelect(int pos) { + if ((pos >= 0) && (pos < mainTable.getItems().size())) { + mainTable.getSelectionModel().clearAndSelect(pos); } } public void selectPreviousEntry() { - highlightEntry(((mainTable.getSelectedRow() - 1) + mainTable.getRowCount()) % mainTable.getRowCount()); + mainTable.getSelectionModel().clearSelection(); + mainTable.getSelectionModel().selectPrevious(); } public void selectNextEntry() { - highlightEntry((mainTable.getSelectedRow() + 1) % mainTable.getRowCount()); + mainTable.getSelectionModel().clearSelection(); + mainTable.getSelectionModel().selectNext(); } public void selectFirstEntry() { - highlightEntry(0); + clearAndSelect(0); } public void selectLastEntry() { - highlightEntry(mainTable.getRowCount() - 1); + mainTable.getSelectionModel().clearSelection(); + mainTable.getSelectionModel().selectLast(); } /** @@ -1587,10 +1533,12 @@ public void selectLastEntry() { * @param editor The entry editor to close. */ public void entryEditorClosing(EntryEditor editor) { - // Store divider location for next time: - Globals.prefs.putInt(JabRefPreferences.ENTRY_EDITOR_HEIGHT, - splitPane.getHeight() - splitPane.getDividerLocation()); - selectionListener.entryEditorClosing(editor); + if (Globals.prefs.getPreviewPreferences().isPreviewPanelEnabled()) { + showPreview(editor.getEntry()); + } else { + closeBottomPane(); + } + mainTable.requestFocus(); } /** @@ -1598,15 +1546,14 @@ public void entryEditorClosing(EntryEditor editor) { */ public void ensureNotShowingBottomPanel(BibEntry entry) { if (((mode == BasePanelMode.SHOWING_EDITOR) && (entryEditor.getEntry() == entry)) - || ((mode == BasePanelMode.SHOWING_PREVIEW) && (selectionListener.getPreview().getEntry() == entry))) { - hideBottomComponent(); + || ((mode == BasePanelMode.SHOWING_PREVIEW) && (preview.getEntry() == entry))) { + closeBottomPane(); } } public void updateEntryEditorIfShowing() { if (mode == BasePanelMode.SHOWING_EDITOR) { BibEntry currentEntry = entryEditor.getEntry(); - showAndEdit(null); showAndEdit(currentEntry); } } @@ -1628,7 +1575,7 @@ public void markBaseChanged() { private void markBasedChangedInternal() { // Put an asterisk behind the filename to indicate the database has changed. frame.setWindowTitle(); - frame.updateAllTabTitles(); + DefaultTaskExecutor.runInJavaFXThread(frame::updateAllTabTitles); // If the status line states that the base has been saved, we // remove this message, since it is no longer relevant. If a // different message is shown, we leave it. @@ -1682,10 +1629,9 @@ private void changeType(List entries, String newType) { } if (entries.size() > 1) { - int choice = JOptionPane.showConfirmDialog(this, - Localization.lang("Multiple entries selected. Do you want to change the type of all these to '%0'?", newType), - Localization.lang("Change entry type"), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); - if (choice == JOptionPane.NO_OPTION) { + DialogService dialogService = new FXDialogService(); + boolean proceed = dialogService.showConfirmationDialogAndWait(Localization.lang("Change entry type"), Localization.lang("Multiple entries selected. Do you want to change the type of all these to '%0'?")); + if (!proceed) { return; } } @@ -1881,7 +1827,7 @@ private void back() { nextEntries.add(showing); } backOrForwardInProgress = true; // to avoid the history getting updated erroneously - highlightEntry(toShow); + clearAndSelect(toShow); } } @@ -1894,7 +1840,7 @@ private void forward() { previousEntries.add(showing); } backOrForwardInProgress = true; // to avoid the history getting updated erroneously - highlightEntry(toShow); + clearAndSelect(toShow); } } @@ -1912,7 +1858,7 @@ private String formatOutputMessage(String start, int count) { * Set the preview active state for all BasePanel instances. */ private void setPreviewActiveBasePanels(boolean enabled) { - for (int i = 0; i < frame.getTabbedPane().getTabCount(); i++) { + for (int i = 0; i < frame.getTabbedPane().getTabs().size(); i++) { frame.getBasePanelAt(i).setPreviewActive(enabled); } } @@ -2038,15 +1984,7 @@ private class EntryRemovedListener { @Subscribe public void listen(EntryRemovedEvent entryRemovedEvent) { - // if the entry that is displayed in the current entry editor is removed, close the entry editor - if (mode == BasePanelMode.SHOWING_EDITOR && entryEditor.getEntry().equals(entryRemovedEvent.getBibEntry())) { - entryEditor.close(); - } - - BibEntry previewEntry = selectionListener.getPreview().getEntry(); - if ((previewEntry != null) && previewEntry.equals(entryRemovedEvent.getBibEntry())) { - preview.close(); - } + ensureNotShowingBottomPanel(entryRemovedEvent.getBibEntry()); } } diff --git a/src/main/java/org/jabref/gui/EntryTypeDialog.java b/src/main/java/org/jabref/gui/EntryTypeDialog.java index 84a736773c4..b95a1aef051 100644 --- a/src/main/java/org/jabref/gui/EntryTypeDialog.java +++ b/src/main/java/org/jabref/gui/EntryTypeDialog.java @@ -309,7 +309,7 @@ protected void done() { final BibEntry bibEntry = result.get(); if ((DuplicateCheck.containsDuplicate(frame.getCurrentBasePanel().getDatabase(), bibEntry, frame.getCurrentBasePanel().getBibDatabaseContext().getMode()).isPresent())) { //If there are duplicates starts ImportInspectionDialog - final BasePanel panel = (BasePanel) frame.getTabbedPane().getSelectedComponent(); + final BasePanel panel = frame.getCurrentBasePanel(); ImportInspectionDialog diag = new ImportInspectionDialog(frame, panel, Localization.lang("Import"), false); diag.addEntry(bibEntry); diff --git a/src/main/java/org/jabref/gui/GUIGlobals.java b/src/main/java/org/jabref/gui/GUIGlobals.java index 5d5c5dabfeb..4824b0504f0 100644 --- a/src/main/java/org/jabref/gui/GUIGlobals.java +++ b/src/main/java/org/jabref/gui/GUIGlobals.java @@ -3,20 +3,11 @@ import java.awt.Color; import java.awt.Font; import java.awt.Toolkit; -import java.util.HashMap; -import java.util.Map; - -import javax.swing.JLabel; import org.jabref.Globals; -import org.jabref.gui.externalfiletype.ExternalFileType; -import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.gui.keyboard.EmacsKeyBindings; -import org.jabref.gui.specialfields.SpecialFieldViewModel; import org.jabref.logic.l10n.Localization; import org.jabref.logic.util.OS; -import org.jabref.model.entry.FieldName; -import org.jabref.model.entry.specialfields.SpecialField; import org.jabref.preferences.JabRefPreferences; import org.apache.commons.logging.Log; @@ -44,24 +35,11 @@ public class GUIGlobals { // Colors. public static final Color ENTRY_EDITOR_LABEL_COLOR = new Color(100, 100, 150); // Empty field, blue. - static final Color INACTIVE_TABBED_COLOR = Color.black; // inactive Database private static final Log LOGGER = LogFactory.getLog(GUIGlobals.class); - private static final Map TABLE_ICONS = new HashMap<>(); // Contains table icon mappings. Set up - static final Color ACTIVE_TABBED_COLOR = ENTRY_EDITOR_LABEL_COLOR.darker(); // active Database (JTabbedPane) private GUIGlobals() { } - public static JLabel getTableIcon(String fieldType) { - JLabel label = GUIGlobals.TABLE_ICONS.get(fieldType); - if (label == null) { - LOGGER.info("Error: no table icon defined for type '" + fieldType + "'."); - return null; - } else { - return label; - } - } - public static void updateEntryEditorColors() { GUIGlobals.activeBackgroundColor = JabRefPreferences.getInstance().getColor(JabRefPreferences.ACTIVE_FIELD_EDITOR_BACKGROUND_COLOR); GUIGlobals.validFieldBackgroundColor = JabRefPreferences.getInstance().getColor(JabRefPreferences.VALID_FIELD_BACKGROUND_COLOR); @@ -75,79 +53,6 @@ public static void updateEntryEditorColors() { * on Un*x is unavailable. */ public static void init() { - JLabel label; - label = new JLabel(IconTheme.JabRefIcons.PDF_FILE.getSmallIcon()); - label.setToolTipText(Localization.lang("Open") + " PDF"); - GUIGlobals.TABLE_ICONS.put(FieldName.PDF, label); - - label = new JLabel(IconTheme.JabRefIcons.WWW.getSmallIcon()); - label.setToolTipText(Localization.lang("Open") + " URL"); - GUIGlobals.TABLE_ICONS.put(FieldName.URL, label); - - label = new JLabel(IconTheme.JabRefIcons.WWW.getSmallIcon()); - label.setToolTipText(Localization.lang("Open") + " CiteSeer URL"); - GUIGlobals.TABLE_ICONS.put("citeseerurl", label); - - label = new JLabel(IconTheme.JabRefIcons.WWW.getSmallIcon()); - label.setToolTipText(Localization.lang("Open") + " ArXiv URL"); - GUIGlobals.TABLE_ICONS.put(FieldName.EPRINT, label); - - label = new JLabel(IconTheme.JabRefIcons.DOI.getSmallIcon()); - label.setToolTipText(Localization.lang("Open") + " DOI " + Localization.lang("web link")); - GUIGlobals.TABLE_ICONS.put(FieldName.DOI, label); - - label = new JLabel(IconTheme.JabRefIcons.FILE.getSmallIcon()); - label.setToolTipText(Localization.lang("Open") + " PS"); - GUIGlobals.TABLE_ICONS.put(FieldName.PS, label); - - label = new JLabel(IconTheme.JabRefIcons.FOLDER.getSmallIcon()); - label.setToolTipText(Localization.lang("Open folder")); - GUIGlobals.TABLE_ICONS.put(FieldName.FOLDER, label); - - label = new JLabel(IconTheme.JabRefIcons.FILE.getSmallIcon()); - label.setToolTipText(Localization.lang("Open file")); - GUIGlobals.TABLE_ICONS.put(FieldName.FILE, label); - - for (ExternalFileType fileType : ExternalFileTypes.getInstance().getExternalFileTypeSelection()) { - label = new JLabel(fileType.getIcon().getSmallIcon()); - label.setToolTipText(Localization.lang("Open %0 file", fileType.getName())); - GUIGlobals.TABLE_ICONS.put(fileType.getName(), label); - } - - SpecialFieldViewModel relevanceViewModel = new SpecialFieldViewModel(SpecialField.RELEVANCE); - label = new JLabel(relevanceViewModel.getRepresentingIcon()); - label.setToolTipText(relevanceViewModel.getLocalization()); - GUIGlobals.TABLE_ICONS.put(SpecialField.RELEVANCE.getFieldName(), label); - - SpecialFieldViewModel qualityViewModel = new SpecialFieldViewModel(SpecialField.QUALITY); - label = new JLabel(qualityViewModel.getRepresentingIcon()); - label.setToolTipText(qualityViewModel.getLocalization()); - GUIGlobals.TABLE_ICONS.put(SpecialField.QUALITY.getFieldName(), label); - - // Ranking item in the menu uses one star - SpecialFieldViewModel rankViewModel = new SpecialFieldViewModel(SpecialField.RANKING); - label = new JLabel(rankViewModel.getRepresentingIcon()); - label.setToolTipText(rankViewModel.getLocalization()); - GUIGlobals.TABLE_ICONS.put(SpecialField.RANKING.getFieldName(), label); - - // Priority icon used for the menu - SpecialFieldViewModel priorityViewModel = new SpecialFieldViewModel(SpecialField.PRIORITY); - label = new JLabel(priorityViewModel.getRepresentingIcon()); - label.setToolTipText(priorityViewModel.getLocalization()); - GUIGlobals.TABLE_ICONS.put(SpecialField.PRIORITY.getFieldName(), label); - - // Read icon used for menu - SpecialFieldViewModel readViewModel = new SpecialFieldViewModel(SpecialField.READ_STATUS); - label = new JLabel(readViewModel.getRepresentingIcon()); - label.setToolTipText(readViewModel.getLocalization()); - GUIGlobals.TABLE_ICONS.put(SpecialField.READ_STATUS.getFieldName(), label); - - // Print icon used for menu - SpecialFieldViewModel printedViewModel = new SpecialFieldViewModel(SpecialField.PRINTED); - label = new JLabel(printedViewModel.getRepresentingIcon()); - label.setToolTipText(printedViewModel.getLocalization()); - GUIGlobals.TABLE_ICONS.put(SpecialField.PRINTED.getFieldName(), label); - if (Globals.prefs.getBoolean(JabRefPreferences.EDITOR_EMACS_KEYBINDINGS)) { EmacsKeyBindings.load(); } diff --git a/src/main/java/org/jabref/gui/JabRefFrame.java b/src/main/java/org/jabref/gui/JabRefFrame.java index c759ce7083e..cf8cb11071d 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -49,7 +49,6 @@ import javax.swing.JPopupMenu; import javax.swing.JProgressBar; import javax.swing.JSplitPane; -import javax.swing.JTabbedPane; import javax.swing.JToggleButton; import javax.swing.KeyStroke; import javax.swing.MenuElement; @@ -60,6 +59,12 @@ import javax.swing.WindowConstants; import javafx.application.Platform; +import javafx.collections.ListChangeListener; +import javafx.embed.swing.JFXPanel; +import javafx.scene.Scene; +import javafx.scene.control.Tab; +import javafx.scene.control.TabPane; +import javafx.scene.control.Tooltip; import org.jabref.Globals; import org.jabref.JabRefExecutorService; @@ -82,6 +87,7 @@ import org.jabref.gui.bibtexkeypattern.BibtexKeyPatternDialog; import org.jabref.gui.copyfiles.CopyFilesAction; import org.jabref.gui.customentrytypes.EntryCustomizationDialog; +import org.jabref.gui.customjfx.CustomJFXPanel; import org.jabref.gui.dbproperties.DatabasePropertiesDialog; import org.jabref.gui.documentviewer.ShowDocumentViewerAction; import org.jabref.gui.exporter.ExportAction; @@ -147,6 +153,7 @@ import com.jgoodies.looks.Options; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.fxmisc.easybind.EasyBind; import osx.macadapter.MacAdapter; /** @@ -447,10 +454,9 @@ public void actionPerformed(ActionEvent e) { private final List twoEntriesOnlyActions = new LinkedList<>(); private final List atLeastOneEntryActions = new LinkedList<>(); private PreferencesDialog prefsDialog; - private int lastTabbedPanelSelectionIndex = -1; // The sidepane manager takes care of populating the sidepane. private SidePaneManager sidePaneManager; - private JTabbedPane tabbedPane; // initialized at constructor + private final TabPane tabbedPane = new TabPane(); private final AbstractAction exportAll = ExportAction.getExportAction(this, false); private final AbstractAction exportSelected = ExportAction.getExportAction(this, true); /* References to the toggle buttons in the toolbar */ @@ -461,12 +467,10 @@ public void actionPerformed(ActionEvent e) { private GeneralFetcher generalFetcher; private OpenOfficePanel openOfficePanel; private GroupSidePane groupSidePane; - private int previousTabCount = -1; private JMenu newSpec; public JabRefFrame() { init(); - updateEnabledState(); } private static Action enableToggle(Action a, boolean initialValue) { @@ -560,7 +564,8 @@ private JPopupMenu tabPopupMenu() { private void init() { - tabbedPane = new DragDropPopupPane(tabPopupMenu()); + // TODO: popup + // tabbedPane = new DragDropPopupPane(tabPopupMenu()); MyGlassPane glassPane = new MyGlassPane(); setGlassPane(glassPane); @@ -596,16 +601,18 @@ public void windowClosing(WindowEvent e) { pw.displayWindowAtStoredLocation(); tabbedPane.setBorder(null); - tabbedPane.setForeground(GUIGlobals.INACTIVE_TABBED_COLOR); + // TODO: Color + //tabbedPane.setForeground(GUIGlobals.INACTIVE_TABBED_COLOR); /* * The following state listener makes sure focus is registered with the * correct database when the user switches tabs. Without this, * cut/paste/copy operations would some times occur in the wrong tab. */ - tabbedPane.addChangeListener(e -> { - - markActiveBasePanel(); + EasyBind.subscribe(tabbedPane.getSelectionModel().selectedItemProperty(), e -> { + if (e == null) { + return; + } BasePanel currentBasePanel = getCurrentBasePanel(); if (currentBasePanel == null) { @@ -634,7 +641,8 @@ public void windowClosing(WindowEvent e) { previewToggle.setSelected(Globals.prefs.getPreviewPreferences().isPreviewPanelEnabled()); generalFetcher.getToggleAction().setSelected(sidePaneManager.isComponentVisible(GeneralFetcher.class)); openOfficePanel.getToggleAction().setSelected(sidePaneManager.isComponentVisible(OpenOfficeSidePanel.class)); - Globals.getFocusListener().setFocused(currentBasePanel.getMainTable()); + // TODO: Can't notify focus listener since it is expecting a swing component + //Globals.getFocusListener().setFocused(currentBasePanel.getMainTable()); setWindowTitle(); editModeAction.initName(); // Update search autocompleter with information for the correct database: @@ -832,12 +840,11 @@ public boolean quit() { boolean close = true; List filenames = new ArrayList<>(); - if (tabbedPane.getTabCount() > 0) { - for (int i = 0; i < tabbedPane.getTabCount(); i++) { + for (int i = 0; i < tabbedPane.getTabs().size(); i++) { BibDatabaseContext context = getBasePanelAt(i).getBibDatabaseContext(); if (getBasePanelAt(i).isModified() && (context.getLocation() == DatabaseLocation.LOCAL)) { - tabbedPane.setSelectedIndex(i); + tabbedPane.getSelectionModel().select(i); String filename = context.getDatabaseFile().map(File::getAbsolutePath).orElse(GUIGlobals.UNTITLED_TITLE); int answer = showSaveDialog(filename); @@ -873,10 +880,9 @@ public boolean quit() { BackupManager.shutdown(context); context.getDatabaseFile().map(File::getAbsolutePath).ifPresent(filenames::add); } - } if (close) { - for (int i = 0; i < tabbedPane.getTabCount(); i++) { + for (int i = 0; i < tabbedPane.getTabs().size(); i++) { if (getBasePanelAt(i).isSaving()) { // There is a database still being saved, so we need to wait. WaitForSaveOperation w = new WaitForSaveOperation(this); @@ -895,8 +901,6 @@ public boolean quit() { } private void initLayout() { - tabbedPane.putClientProperty(Options.NO_CONTENT_BORDER_KEY, Boolean.TRUE); - setProgressBarVisible(false); pushApplications = new PushToApplications(); @@ -913,7 +917,8 @@ private void initLayout() { splitPane.setDividerSize(2); splitPane.setBorder(null); - splitPane.setRightComponent(tabbedPane); + JFXPanel tabbedPaneContainer = CustomJFXPanel.wrap(new Scene(tabbedPane)); + splitPane.setRightComponent(tabbedPaneContainer); splitPane.setLeftComponent(sidePaneManager.getPanel()); getContentPane().add(splitPane, BorderLayout.CENTER); @@ -947,7 +952,8 @@ private void initLayout() { // Drag and drop for tabbedPane: TransferHandler xfer = new EntryTableTransferHandler(null, this, null); - tabbedPane.setTransferHandler(xfer); + // TODO: + //tabbedPane.setTransferHandler(xfer); tlb.setTransferHandler(xfer); mb.setTransferHandler(xfer); sidePaneManager.getPanel().setTransferHandler(xfer); @@ -959,7 +965,7 @@ private void initLayout() { * @param i Index of base */ public BasePanel getBasePanelAt(int i) { - return (BasePanel) tabbedPane.getComponentAt(i); + return (BasePanel) tabbedPane.getTabs().get(i).getContent(); } /** @@ -969,68 +975,57 @@ public BasePanel getBasePanelAt(int i) { public List getBasePanelList() { List returnList = new ArrayList<>(); for (int i = 0; i < getBasePanelCount(); i++) { - returnList.add((BasePanel) tabbedPane.getComponentAt(i)); + returnList.add(getBasePanelAt(i)); } return returnList; } public void showBasePanelAt(int i) { - tabbedPane.setSelectedIndex(i); + tabbedPane.getSelectionModel().select(i); } public void showBasePanel(BasePanel bp) { - tabbedPane.setSelectedComponent(bp); + tabbedPane.getSelectionModel().select(getTab(bp)); } /** * Returns the currently viewed BasePanel. */ public BasePanel getCurrentBasePanel() { - if (tabbedPane == null) { + if (tabbedPane == null || tabbedPane.getSelectionModel().getSelectedItem() == null) { return null; } - return (BasePanel) tabbedPane.getSelectedComponent(); + return (BasePanel) tabbedPane.getSelectionModel().getSelectedItem().getContent(); } /** * @return the BasePanel count. */ public int getBasePanelCount() { - return tabbedPane.getComponentCount(); - } - - /** - * handle the color of active and inactive JTabbedPane tabs - */ - private void markActiveBasePanel() { - int now = tabbedPane.getSelectedIndex(); - int len = tabbedPane.getTabCount(); - if ((lastTabbedPanelSelectionIndex > -1) && (lastTabbedPanelSelectionIndex < len)) { - tabbedPane.setForegroundAt(lastTabbedPanelSelectionIndex, GUIGlobals.INACTIVE_TABBED_COLOR); - } - if ((now > -1) && (now < len)) { - tabbedPane.setForegroundAt(now, GUIGlobals.ACTIVE_TABBED_COLOR); - } - lastTabbedPanelSelectionIndex = now; + return tabbedPane.getTabs().size(); } - private int getTabIndex(JComponent comp) { - for (int i = 0; i < tabbedPane.getTabCount(); i++) { - if (tabbedPane.getComponentAt(i) == comp) { - return i; + private Tab getTab(BasePanel comp) { + for (Tab tab : tabbedPane.getTabs()) { + if (tab.getContent() == comp) { + return tab; } } - return -1; + return null; } - public JTabbedPane getTabbedPane() { + /** + * @deprecated do not operate on tabs but on BibDatabaseContexts + */ + @Deprecated + public TabPane getTabbedPane() { return tabbedPane; } - public void setTabTitle(JComponent comp, String title, String toolTip) { - int index = getTabIndex(comp); - tabbedPane.setTitleAt(index, title); - tabbedPane.setToolTipTextAt(index, toolTip); + public void setTabTitle(BasePanel comp, String title, String toolTip) { + Tab tab = getTab(comp); + tab.setText(title); + tab.setTooltip(new Tooltip(toolTip)); } private void fillMenu() { @@ -1299,7 +1294,7 @@ public void addParserResult(ParserResult pr, boolean focusPanel) { .filter(p -> p.getBibDatabaseContext().getDatabaseFile().equals(pr.getFile())).findFirst(); if (panel.isPresent()) { - tabbedPane.setSelectedComponent(panel.get()); + tabbedPane.getSelectionModel().select(getTab(panel.get())); } else { addTab(pr.getDatabaseContext(), focusPanel); } @@ -1445,8 +1440,7 @@ dupliCheck, autoSetFile, newEntryAction, newSpec, customizeAction, plainTextImpo atLeastOneEntryActions.clear(); atLeastOneEntryActions.addAll(Arrays.asList(downloadFullText, lookupIdentifiers, exportLinkedFiles)); - tabbedPane.addChangeListener(event -> updateEnabledState()); - + tabbedPane.getTabs().addListener(this::updateEnabledState); } /** @@ -1454,10 +1448,12 @@ dupliCheck, autoSetFile, newEntryAction, newSpec, customizeAction, plainTextImpo *

* The action that are affected are set in initActions. */ - public void updateEnabledState() { - int tabCount = tabbedPane.getTabCount(); - if (tabCount != previousTabCount) { - previousTabCount = tabCount; + public void updateEnabledState(ListChangeListener.Change change) { + int tabCount = tabbedPane.getTabs().size(); + if (!change.next()) { + return; + } + if (change.wasAdded() || change.wasRemoved()) { setEnabled(openDatabaseOnlyActions, tabCount > 0); setEnabled(severalDatabasesOnlyActions, tabCount > 1); } @@ -1503,7 +1499,7 @@ public void setupAllTables() { // We want to notify all tabs about the changes to // avoid problems when changing the column set. - for (int i = 0; i < tabbedPane.getTabCount(); i++) { + for (int i = 0; i < tabbedPane.getTabs().size(); i++) { BasePanel bf = getBasePanelAt(i); // Update tables: @@ -1548,43 +1544,46 @@ public void updateAllTabTitles() { if (!uniqPath.equals(file.get().getName()) && uniqPath.contains(File.separator)) { // remove filename uniqPath = uniqPath.substring(0, uniqPath.lastIndexOf(File.separator)); - tabbedPane.setTitleAt(i, getBasePanelAt(i).getTabTitle() + " \u2014 " + uniqPath); + tabbedPane.getTabs().get(i).setText(getBasePanelAt(i).getTabTitle() + " \u2014 " + uniqPath); } else { // set original filename (again) - tabbedPane.setTitleAt(i, getBasePanelAt(i).getTabTitle()); + tabbedPane.getTabs().get(i).setText(getBasePanelAt(i).getTabTitle()); } } else { - tabbedPane.setTitleAt(i, getBasePanelAt(i).getTabTitle()); + tabbedPane.getTabs().get(i).setText(getBasePanelAt(i).getTabTitle()); } - tabbedPane.setToolTipTextAt(i, file.map(File::getAbsolutePath).orElse(null)); + tabbedPane.getTabs().get(i).setTooltip(new Tooltip(file.map(File::getAbsolutePath).orElse(null))); } } public void addTab(BasePanel basePanel, boolean raisePanel) { - // add tab - tabbedPane.add(basePanel.getTabTitle(), basePanel); + DefaultTaskExecutor.runInJavaFXThread(() -> { + // add tab + Tab newTab = new Tab(basePanel.getTabTitle(), basePanel); + tabbedPane.getTabs().add(newTab); - // update all tab titles - updateAllTabTitles(); + // update all tab titles + updateAllTabTitles(); - if (raisePanel) { - tabbedPane.setSelectedComponent(basePanel); - } + if (raisePanel) { + tabbedPane.getSelectionModel().select(newTab); + } - // Register undo/redo listener - basePanel.getUndoManager().registerListener(new UndoRedoEventManager()); + // Register undo/redo listener + basePanel.getUndoManager().registerListener(new UndoRedoEventManager()); - BibDatabaseContext context = basePanel.getBibDatabaseContext(); + BibDatabaseContext context = basePanel.getBibDatabaseContext(); - if (readyForAutosave(context)) { - AutosaveManager autosaver = AutosaveManager.start(context); - autosaver.registerListener(new AutosaveUIManager(basePanel)); - } + if (readyForAutosave(context)) { + AutosaveManager autosaver = AutosaveManager.start(context); + autosaver.registerListener(new AutosaveUIManager(basePanel)); + } - BackupManager.start(context); + BackupManager.start(context); - // Track opening - trackOpenNewDatabase(basePanel); + // Track opening + trackOpenNewDatabase(basePanel); + }); } private void trackOpenNewDatabase(BasePanel basePanel) { @@ -1642,6 +1641,15 @@ public void createDisabledIconsForButtons(Container container) { } } + public void sortTabs() { + // We are going to be crude: remove all tabs and re-add them in a sorted way + // This is ugly, but otherwise we run into issues: https://stackoverflow.com/questions/37328760/javafx-tabpane-sorting-tabs-creates-havoc + List tabs = new ArrayList<>(tabbedPane.getTabs()); + tabs.sort((o1, o2) -> o2.getText().compareTo(o1.getText())); + tabbedPane.getTabs().clear(); + tabbedPane.getTabs().setAll(tabs); + } + /** * This method does the job of adding imported entries into the active * database, or into a new one. It shows the ImportInspectionDialog if @@ -1815,6 +1823,14 @@ private int showSaveDialog(String filename) { JOptionPane.WARNING_MESSAGE, null, options, options[2]); } + private void closeTab(Tab tab) { + closeTab(getBasePanel(tab)); + } + + private BasePanel getBasePanel(Tab tab) { + return (BasePanel) tab.getContent(); + } + private void closeTab(BasePanel panel) { // empty tab without database if (panel == null) { @@ -1868,12 +1884,8 @@ private boolean confirmClose(BasePanel panel) { private void removeTab(BasePanel panel) { panel.cleanUp(); - tabbedPane.remove(panel); - if (tabbedPane.getTabCount() > 0) { - markActiveBasePanel(); - } + tabbedPane.getTabs().remove(getTab(panel)); setWindowTitle(); - updateEnabledState(); output(Localization.lang("Closed library") + '.'); // update tab titles updateAllTabTitles(); @@ -1988,7 +2000,7 @@ public void actionPerformed(ActionEvent evt) { initName(); // update all elements in current base panel - JabRefFrame.this.getCurrentBasePanel().hideBottomComponent(); + JabRefFrame.this.getCurrentBasePanel().closeBottomPane(); JabRefFrame.this.getCurrentBasePanel().updateEntryEditorIfShowing(); } } @@ -2047,9 +2059,9 @@ public GeneralAction(String command, String text, String description, KeyStroke @Override public void actionPerformed(ActionEvent e) { - if (tabbedPane.getTabCount() > 0) { + if (tabbedPane.getTabs().size() > 0) { try { - ((BasePanel) tabbedPane.getSelectedComponent()).runCommand(command); + getCurrentBasePanel().runCommand(command); } catch (Throwable ex) { LOGGER.error("Problem with executing command: " + command, ex); } @@ -2080,7 +2092,7 @@ public void actionPerformed(ActionEvent e) { private class ShowPrefsAction extends MnemonicAwareAction { public ShowPrefsAction() { - super(IconTheme.JabRefIcon.PREFERENCES.getIcon()); + super(IconTheme.JabRefIcons.PREFERENCES.getIcon()); putValue(Action.NAME, Localization.menuTitle("Preferences")); putValue(Action.SHORT_DESCRIPTION, Localization.lang("Preferences")); } @@ -2105,15 +2117,11 @@ public ChangeTabAction(boolean next) { @Override public void actionPerformed(ActionEvent e) { - int i = tabbedPane.getSelectedIndex(); - int newI = next ? i + 1 : i - 1; - if (newI < 0) { - newI = tabbedPane.getTabCount() - 1; - } - if (newI == tabbedPane.getTabCount()) { - newI = 0; + if (next) { + tabbedPane.getSelectionModel().selectNext(); + } else { + tabbedPane.getSelectionModel().selectPrevious(); } - tabbedPane.setSelectedIndex(newI); } } @@ -2317,7 +2325,7 @@ public void actionPerformed(ActionEvent event) { private class CloseDatabaseAction extends MnemonicAwareAction { public CloseDatabaseAction() { - super(IconTheme.JabRefIcon.CLOSE.getSmallIcon()); + super(IconTheme.JabRefIcons.CLOSE.getSmallIcon()); putValue(Action.NAME, Localization.menuTitle("Close library")); putValue(Action.SHORT_DESCRIPTION, Localization.lang("Close the current library")); putValue(Action.ACCELERATOR_KEY, Globals.getKeyPrefs().getKey(KeyBinding.CLOSE_DATABASE)); @@ -2333,10 +2341,10 @@ private class CloseAllDatabasesAction extends MnemonicAwareAction { @Override public void actionPerformed(ActionEvent e) { - final Component[] panels = tabbedPane.getComponents(); + final List tabs = tabbedPane.getTabs(); - for (Component p : panels) { - closeTab((BasePanel) p); + for (Tab tab : tabs) { + closeTab(tab); } } } @@ -2346,11 +2354,11 @@ private class CloseOtherDatabasesAction extends MnemonicAwareAction { @Override public void actionPerformed(ActionEvent e) { final BasePanel active = getCurrentBasePanel(); - final Component[] panels = tabbedPane.getComponents(); + final List tabs = tabbedPane.getTabs(); - for (Component p : panels) { - if (!Objects.equals(p, active)) { - closeTab((BasePanel) p); + for (Tab tab : tabs) { + if (!tab.getContent().equals(active)) { + closeTab(tab); } } } diff --git a/src/main/java/org/jabref/gui/Main.css b/src/main/java/org/jabref/gui/Main.css index 5f01e7afd41..95a63836304 100644 --- a/src/main/java/org/jabref/gui/Main.css +++ b/src/main/java/org/jabref/gui/Main.css @@ -23,6 +23,11 @@ */ -fx-info: #2c3e50; + /* + * A dark gray to indicate something not so important + */ + -fx-unimportant: #595959; + /* * A light gray for accented background */ diff --git a/src/main/java/org/jabref/gui/PreviewPanel.java b/src/main/java/org/jabref/gui/PreviewPanel.java index 49958ceb3cf..181c4395c45 100644 --- a/src/main/java/org/jabref/gui/PreviewPanel.java +++ b/src/main/java/org/jabref/gui/PreviewPanel.java @@ -297,7 +297,7 @@ public void print() { } public void close() { - basePanel.ifPresent(BasePanel::hideBottomComponent); + basePanel.ifPresent(BasePanel::closeBottomPane); } private void copyPreviewToClipBoard() { diff --git a/src/main/java/org/jabref/gui/SidePaneManager.java b/src/main/java/org/jabref/gui/SidePaneManager.java index 500c78af892..e6b22170a11 100644 --- a/src/main/java/org/jabref/gui/SidePaneManager.java +++ b/src/main/java/org/jabref/gui/SidePaneManager.java @@ -9,8 +9,6 @@ import java.util.Map; import java.util.stream.Collectors; -import javax.swing.SwingUtilities; - import org.jabref.Globals; import org.jabref.gui.maintable.MainTable; import org.jabref.preferences.JabRefPreferences; @@ -40,8 +38,8 @@ public SidePaneManager(JabRefFrame frame) { * side pane components, we get rid of the annoying latency when * switching tabs: */ - frame.getTabbedPane().addChangeListener(event -> SwingUtilities.invokeLater( - () -> setActiveBasePanel(SidePaneManager.this.frame.getCurrentBasePanel()))); + //frame.getTabbedPane().addChangeListener(event -> SwingUtilities.invokeLater( + // () -> setActiveBasePanel(SidePaneManager.this.frame.getCurrentBasePanel()))); sidep = new SidePane(); sidep.setVisible(false); } @@ -105,7 +103,7 @@ public synchronized void hide(Class sidePaneCom hideComponent(component); if (frame.getCurrentBasePanel() != null) { MainTable mainTable = frame.getCurrentBasePanel().getMainTable(); - mainTable.setSelected(mainTable.getSelectedRow()); + //mainTable.setSelected(mainTable.getSelectedRow()); mainTable.requestFocus(); } } diff --git a/src/main/java/org/jabref/gui/actions/IntegrityCheckAction.java b/src/main/java/org/jabref/gui/actions/IntegrityCheckAction.java index 590c2795028..177ddb1efc5 100644 --- a/src/main/java/org/jabref/gui/actions/IntegrityCheckAction.java +++ b/src/main/java/org/jabref/gui/actions/IntegrityCheckAction.java @@ -88,7 +88,7 @@ protected void done() { } if (messages.isEmpty()) { - JOptionPane.showMessageDialog(frame.getCurrentBasePanel(), Localization.lang("No problems found.")); + JOptionPane.showMessageDialog(frame, Localization.lang("No problems found.")); } else { Map showMessage = new HashMap<>(); // prepare data model diff --git a/src/main/java/org/jabref/gui/actions/SortTabsAction.java b/src/main/java/org/jabref/gui/actions/SortTabsAction.java index 55f2432b0ce..952ad7ca64c 100644 --- a/src/main/java/org/jabref/gui/actions/SortTabsAction.java +++ b/src/main/java/org/jabref/gui/actions/SortTabsAction.java @@ -3,12 +3,9 @@ import java.awt.event.ActionEvent; import java.util.Comparator; import java.util.Locale; -import java.util.Map; -import java.util.TreeMap; import javax.swing.Action; -import org.jabref.gui.BasePanel; import org.jabref.gui.JabRefFrame; import org.jabref.logic.l10n.Localization; @@ -27,17 +24,7 @@ public SortTabsAction(JabRefFrame frame) { @Override public void actionPerformed(ActionEvent e) { - // Make a sorted Map that compares case-insensitively: - Map map = new TreeMap<>(this); - - for (BasePanel panel : frame.getBasePanelList()) { - map.put(panel.getTabTitle(), panel); - } - - frame.getTabbedPane().removeAll(); - for (Map.Entry entry : map.entrySet()) { - frame.addTab(entry.getValue(), false); - } + frame.sortTabs(); } @Override diff --git a/src/main/java/org/jabref/gui/auximport/FromAuxDialog.java b/src/main/java/org/jabref/gui/auximport/FromAuxDialog.java index 2de98920b40..88e80b993c0 100644 --- a/src/main/java/org/jabref/gui/auximport/FromAuxDialog.java +++ b/src/main/java/org/jabref/gui/auximport/FromAuxDialog.java @@ -16,10 +16,11 @@ import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; -import javax.swing.JTabbedPane; import javax.swing.JTextArea; import javax.swing.JTextField; +import javafx.scene.control.TabPane; + import org.jabref.Globals; import org.jabref.gui.BasePanel; import org.jabref.gui.DialogService; @@ -58,7 +59,7 @@ public class FromAuxDialog extends JabRefDialog { private JTextArea statusInfos; // all open databases from JabRefFrame - private final JTabbedPane parentTabbedPane; + private final TabPane parentTabbedPane; private boolean generatePressed; @@ -66,7 +67,7 @@ public class FromAuxDialog extends JabRefDialog { private final JabRefFrame parentFrame; - public FromAuxDialog(JabRefFrame frame, String title, boolean modal, JTabbedPane viewedDBs) { + public FromAuxDialog(JabRefFrame frame, String title, boolean modal, TabPane viewedDBs) { super(frame, title, modal, FromAuxDialog.class); parentTabbedPane = viewedDBs; @@ -143,10 +144,10 @@ public void actionPerformed(ActionEvent e) { private void initPanels() { // collect the names of all open databases - int len = parentTabbedPane.getTabCount(); + int len = parentTabbedPane.getTabs().size(); int toSelect = -1; for (int i = 0; i < len; i++) { - dbChooser.addItem(parentTabbedPane.getTitleAt(i)); + dbChooser.addItem(parentTabbedPane.getTabs().get(i).getText()); if (parentFrame.getBasePanelAt(i) == parentFrame.getCurrentBasePanel()) { toSelect = i; } @@ -200,7 +201,7 @@ private void initPanels() { private void parseActionPerformed() { parseButton.setEnabled(false); - BasePanel bp = (BasePanel) parentTabbedPane.getComponentAt(dbChooser.getSelectedIndex()); + BasePanel bp = (BasePanel) parentTabbedPane.getTabs().get(dbChooser.getSelectedIndex()).getContent(); notFoundList.removeAll(); statusInfos.setText(null); BibDatabase refBase = bp.getDatabase(); diff --git a/src/main/java/org/jabref/gui/customentrytypes/EntryCustomizationDialog.java b/src/main/java/org/jabref/gui/customentrytypes/EntryCustomizationDialog.java index ef63583e117..edad6d83284 100644 --- a/src/main/java/org/jabref/gui/customentrytypes/EntryCustomizationDialog.java +++ b/src/main/java/org/jabref/gui/customentrytypes/EntryCustomizationDialog.java @@ -32,7 +32,6 @@ import javax.swing.event.ListDataListener; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; -import javax.swing.table.AbstractTableModel; import org.jabref.Globals; import org.jabref.gui.BasePanel; @@ -315,7 +314,6 @@ private void applyChanges() { } } - updateTables(); CustomEntryTypesManager.saveCustomEntryTypes(Globals.prefs); } @@ -357,13 +355,6 @@ private void updateEntriesForChangedTypes(List actuallyChangedTypes) { } } - private void updateTables() { - for (BasePanel basePanel : frame.getBasePanelList()) { - ((AbstractTableModel) basePanel.getMainTable().getModel()).fireTableDataChanged(); - } - } - - // DEFAULT button pressed. Remember that this entry should be reset to default, // unless changes are made later. private class DefaultListener implements ActionListener { diff --git a/src/main/java/org/jabref/gui/customjfx/CustomJFXPanel.java b/src/main/java/org/jabref/gui/customjfx/CustomJFXPanel.java index d1459537890..e54b390b9e1 100644 --- a/src/main/java/org/jabref/gui/customjfx/CustomJFXPanel.java +++ b/src/main/java/org/jabref/gui/customjfx/CustomJFXPanel.java @@ -6,6 +6,7 @@ import javafx.embed.swing.JFXPanel; import javafx.scene.Scene; +import org.jabref.gui.AbstractView; import org.jabref.gui.customjfx.support.InputMethodSupport; import org.jabref.gui.util.DefaultTaskExecutor; import org.jabref.logic.util.OS; @@ -41,6 +42,7 @@ public static JFXPanel create() { public static JFXPanel wrap(Scene scene) { JFXPanel container = OS.LINUX ? new CustomJFXPanel() : new JFXPanel(); + scene.getStylesheets().add(AbstractView.class.getResource("Main.css").toExternalForm()); DefaultTaskExecutor.runInJavaFXThread(() -> container.setScene(scene)); return container; } diff --git a/src/main/java/org/jabref/gui/exporter/SaveDatabaseAction.java b/src/main/java/org/jabref/gui/exporter/SaveDatabaseAction.java index 25007ea94a2..5d09c8f3c2f 100644 --- a/src/main/java/org/jabref/gui/exporter/SaveDatabaseAction.java +++ b/src/main/java/org/jabref/gui/exporter/SaveDatabaseAction.java @@ -205,7 +205,7 @@ private boolean saveDatabase(File file, boolean selectedOnly, Charset encoding) if (ex.specificEntry()) { BibEntry entry = ex.getEntry(); // Error occured during processing of an entry. Highlight it! - panel.highlightEntry(entry); + panel.clearAndSelect(entry); } else { LOGGER.error("A problem occured when trying to save the file", ex); } @@ -287,7 +287,6 @@ public void runCommand() throws Exception { public void save() throws Exception { runCommand(); - frame.updateEnabledState(); } public void saveAs() throws Exception { @@ -357,7 +356,6 @@ public void saveAs(File file) throws Exception { } context.getDatabaseFile().ifPresent(presentFile -> frame.getFileHistory().newFile(presentFile.getPath())); - frame.updateEnabledState(); } private boolean readyForAutosave(BibDatabaseContext context) { diff --git a/src/main/java/org/jabref/gui/externalfiles/SynchronizeFileField.java b/src/main/java/org/jabref/gui/externalfiles/SynchronizeFileField.java index c822f61458f..3ac4f7313d1 100644 --- a/src/main/java/org/jabref/gui/externalfiles/SynchronizeFileField.java +++ b/src/main/java/org/jabref/gui/externalfiles/SynchronizeFileField.java @@ -217,7 +217,6 @@ public void run() { fileTypes.add(newType); Collections.sort(fileTypes); ExternalFileTypes.getInstance().setExternalFileTypes(fileTypes); - panel.getMainTable().repaint(); } } else { // User wants to change the type of this link. diff --git a/src/main/java/org/jabref/gui/externalfiles/WriteXMPAction.java b/src/main/java/org/jabref/gui/externalfiles/WriteXMPAction.java index 9eb50acadbf..f2673716b55 100644 --- a/src/main/java/org/jabref/gui/externalfiles/WriteXMPAction.java +++ b/src/main/java/org/jabref/gui/externalfiles/WriteXMPAction.java @@ -28,6 +28,7 @@ import org.jabref.Globals; import org.jabref.gui.BasePanel; import org.jabref.gui.JabRefDialog; +import org.jabref.gui.JabRefFrame; import org.jabref.gui.keyboard.KeyBinding; import org.jabref.gui.worker.AbstractWorker; import org.jabref.logic.l10n.Localization; @@ -45,6 +46,7 @@ public class WriteXMPAction extends AbstractWorker { private final BasePanel panel; + private final JabRefFrame frame; private Collection entries; @@ -61,6 +63,7 @@ public class WriteXMPAction extends AbstractWorker { public WriteXMPAction(BasePanel panel) { this.panel = panel; + this.frame = panel.frame(); } @Override @@ -76,7 +79,7 @@ public void init() { if (entries.isEmpty()) { - JOptionPane.showMessageDialog(panel, + JOptionPane.showMessageDialog(frame, Localization.lang("This operation requires one or more entries to be selected."), Localization.lang("Write XMP-metadata"), JOptionPane.ERROR_MESSAGE); goOn = false; @@ -84,7 +87,7 @@ public void init() { } else { - int response = JOptionPane.showConfirmDialog(panel, Localization.lang("Write XMP-metadata for all PDFs in current library?"), + int response = JOptionPane.showConfirmDialog(frame, Localization.lang("Write XMP-metadata for all PDFs in current library?"), Localization.lang("Write XMP-metadata"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); @@ -218,8 +221,6 @@ public void actionPerformed(ActionEvent e) { d.height += scrollPane.getHorizontalScrollBar().getHeight() + 15; d.width += scrollPane.getVerticalScrollBar().getWidth() + 15; - panel.setSize(d); - progressArea.setBackground(Color.WHITE); progressArea.setEditable(false); progressArea.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, diff --git a/src/main/java/org/jabref/gui/externalfiletype/ExternalFileTypeEditor.java b/src/main/java/org/jabref/gui/externalfiletype/ExternalFileTypeEditor.java index bf286e86ed3..76e07c9592c 100644 --- a/src/main/java/org/jabref/gui/externalfiletype/ExternalFileTypeEditor.java +++ b/src/main/java/org/jabref/gui/externalfiletype/ExternalFileTypeEditor.java @@ -372,9 +372,6 @@ public void actionPerformed(ActionEvent e) { } editor.setValues(); editor.setVisible(true); - if ((frame != null) && (frame.getCurrentBasePanel() != null)) { - frame.getCurrentBasePanel().getMainTable().repaint(); - } } } diff --git a/src/main/java/org/jabref/gui/groups/EntryTableTransferHandler.java b/src/main/java/org/jabref/gui/groups/EntryTableTransferHandler.java index 7b669fb0e90..e5c2521e75b 100644 --- a/src/main/java/org/jabref/gui/groups/EntryTableTransferHandler.java +++ b/src/main/java/org/jabref/gui/groups/EntryTableTransferHandler.java @@ -172,12 +172,15 @@ public boolean canImport(JComponent comp, DataFlavor[] transferFlavors) { @Override public void exportAsDrag(JComponent comp, InputEvent e, int action) { if (e instanceof MouseEvent) { + // TODO: Reimplement drag & drop + /* int columnIndex = entryTable.columnAtPoint(((MouseEvent) e).getPoint()); int modelIndex = entryTable.getColumnModel().getColumn(columnIndex).getModelIndex(); if (entryTable.isFileColumn(modelIndex)) { LOGGER.info("Dragging file"); draggingFile = true; } + */ } super.exportAsDrag(comp, e, DnDConstants.ACTION_LINK); } diff --git a/src/main/java/org/jabref/gui/importer/ImportMenuItem.java b/src/main/java/org/jabref/gui/importer/ImportMenuItem.java index d85d1cb5136..fd5c54965e0 100644 --- a/src/main/java/org/jabref/gui/importer/ImportMenuItem.java +++ b/src/main/java/org/jabref/gui/importer/ImportMenuItem.java @@ -178,7 +178,7 @@ public void update() { frame.output( Localization.lang("Imported entries") + ": " + bibtexResult.getDatabase().getEntryCount()); } else { - final BasePanel panel = (BasePanel) frame.getTabbedPane().getSelectedComponent(); + final BasePanel panel = frame.getCurrentBasePanel(); ImportInspectionDialog diag = new ImportInspectionDialog(frame, panel, Localization.lang("Import"), openInNew); diff --git a/src/main/java/org/jabref/gui/importer/actions/AppendDatabaseAction.java b/src/main/java/org/jabref/gui/importer/actions/AppendDatabaseAction.java index 76b7350198a..3797481171a 100644 --- a/src/main/java/org/jabref/gui/importer/actions/AppendDatabaseAction.java +++ b/src/main/java/org/jabref/gui/importer/actions/AppendDatabaseAction.java @@ -147,7 +147,7 @@ private static void addGroups(GroupTreeNode newGroups, CompoundEdit ce) { public void action() { filesToOpen.clear(); final MergeDialog dialog = new MergeDialog(frame, Localization.lang("Append library"), true); - dialog.setLocationRelativeTo(panel); + dialog.setLocationRelativeTo(frame); dialog.setVisible(true); if (dialog.isOkPressed()) { @@ -187,7 +187,7 @@ private void openIt(boolean importEntries, boolean importStrings, boolean import panel.output(Localization.lang("Imported from library") + " '" + file + "'"); } catch (IOException | KeyCollisionException ex) { LOGGER.warn("Could not open database", ex); - JOptionPane.showMessageDialog(panel, ex.getMessage(), Localization.lang("Open library"), + JOptionPane.showMessageDialog(frame, ex.getMessage(), Localization.lang("Open library"), JOptionPane.ERROR_MESSAGE); } } diff --git a/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java b/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java index 814daa83dd8..af02bd48f03 100644 --- a/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java +++ b/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java @@ -89,7 +89,7 @@ public static void performPostOpenActions(BasePanel panel, ParserResult result) for (GUIPostOpenAction action : OpenDatabaseAction.POST_OPEN_ACTIONS) { if (action.isActionNecessary(result)) { action.performAction(panel, result); - panel.frame().getTabbedPane().setSelectedComponent(panel); + panel.frame().showBasePanel(panel); } } } @@ -148,7 +148,7 @@ public void openFiles(List filesToOpen, boolean raisePanel) { // Check if any of the files are already open: for (Iterator iterator = filesToOpen.iterator(); iterator.hasNext();) { Path file = iterator.next(); - for (int i = 0; i < frame.getTabbedPane().getTabCount(); i++) { + for (int i = 0; i < frame.getTabbedPane().getTabs().size(); i++) { BasePanel basePanel = frame.getBasePanelAt(i); if ((basePanel.getBibDatabaseContext().getDatabasePath().isPresent()) && basePanel.getBibDatabaseContext().getDatabasePath().get().equals(file)) { @@ -183,7 +183,7 @@ public void openFiles(List filesToOpen, boolean raisePanel) { else if (toRaise != null) { frame.output(Localization.lang("File '%0' is already open.", toRaise.getBibDatabaseContext().getDatabaseFile().get().getPath())); - frame.getTabbedPane().setSelectedComponent(toRaise); + frame.showBasePanel(toRaise); } frame.output(Localization.lang("Files opened") + ": " + (filesToOpen.size())); diff --git a/src/main/java/org/jabref/gui/maintable/CellFactory.java b/src/main/java/org/jabref/gui/maintable/CellFactory.java new file mode 100644 index 00000000000..263343eb986 --- /dev/null +++ b/src/main/java/org/jabref/gui/maintable/CellFactory.java @@ -0,0 +1,103 @@ +package org.jabref.gui.maintable; + +import java.util.HashMap; +import java.util.Map; + +import javafx.scene.Node; + +import org.jabref.gui.IconTheme; +import org.jabref.gui.externalfiletype.ExternalFileType; +import org.jabref.gui.externalfiletype.ExternalFileTypes; +import org.jabref.gui.specialfields.SpecialFieldViewModel; +import org.jabref.model.entry.FieldName; +import org.jabref.model.entry.specialfields.SpecialField; + +public class CellFactory { + + private final Map TABLE_ICONS = new HashMap<>(); + + public CellFactory() { + Node label; + label = IconTheme.JabRefIcons.PDF_FILE.getGraphicNode(); + //label.setToo(Localization.lang("Open") + " PDF"); + TABLE_ICONS.put(FieldName.PDF, label); + + label = IconTheme.JabRefIcons.WWW.getGraphicNode(); + //label.setToolTipText(Localization.lang("Open") + " URL"); + TABLE_ICONS.put(FieldName.URL, label); + + label = IconTheme.JabRefIcons.WWW.getGraphicNode(); + //label.setToolTipText(Localization.lang("Open") + " CiteSeer URL"); + TABLE_ICONS.put("citeseerurl", label); + + label = IconTheme.JabRefIcons.WWW.getGraphicNode(); + //label.setToolTipText(Localization.lang("Open") + " ArXiv URL"); + TABLE_ICONS.put(FieldName.EPRINT, label); + + label = IconTheme.JabRefIcons.DOI.getGraphicNode(); + //label.setToolTipText(Localization.lang("Open") + " DOI " + Localization.lang("web link")); + TABLE_ICONS.put(FieldName.DOI, label); + + label = IconTheme.JabRefIcons.FILE.getGraphicNode(); + //label.setToolTipText(Localization.lang("Open") + " PS"); + TABLE_ICONS.put(FieldName.PS, label); + + label = IconTheme.JabRefIcons.FOLDER.getGraphicNode(); + //label.setToolTipText(Localization.lang("Open folder")); + TABLE_ICONS.put(FieldName.FOLDER, label); + + label = IconTheme.JabRefIcons.FILE.getGraphicNode(); + //label.setToolTipText(Localization.lang("Open file")); + TABLE_ICONS.put(FieldName.FILE, label); + + for (ExternalFileType fileType : ExternalFileTypes.getInstance().getExternalFileTypeSelection()) { + label = fileType.getIcon().getGraphicNode(); + //label.setToolTipText(Localization.lang("Open %0 file", fileType.getName())); + TABLE_ICONS.put(fileType.getName(), label); + } + + SpecialFieldViewModel relevanceViewModel = new SpecialFieldViewModel(SpecialField.RELEVANCE); + label = relevanceViewModel.getIcon().getGraphicNode(); + //label.setToolTipText(relevanceViewModel.getLocalization()); + TABLE_ICONS.put(SpecialField.RELEVANCE.getFieldName(), label); + + SpecialFieldViewModel qualityViewModel = new SpecialFieldViewModel(SpecialField.QUALITY); + label = qualityViewModel.getIcon().getGraphicNode(); + //label.setToolTipText(qualityViewModel.getLocalization()); + TABLE_ICONS.put(SpecialField.QUALITY.getFieldName(), label); + + // Ranking item in the menu uses one star + SpecialFieldViewModel rankViewModel = new SpecialFieldViewModel(SpecialField.RANKING); + label = rankViewModel.getIcon().getGraphicNode(); + //label.setToolTipText(rankViewModel.getLocalization()); + TABLE_ICONS.put(SpecialField.RANKING.getFieldName(), label); + + // Priority icon used for the menu + SpecialFieldViewModel priorityViewModel = new SpecialFieldViewModel(SpecialField.PRIORITY); + label = priorityViewModel.getIcon().getGraphicNode(); + //label.setToolTipText(priorityViewModel.getLocalization()); + TABLE_ICONS.put(SpecialField.PRIORITY.getFieldName(), label); + + // Read icon used for menu + SpecialFieldViewModel readViewModel = new SpecialFieldViewModel(SpecialField.READ_STATUS); + label = readViewModel.getIcon().getGraphicNode(); + //label.setToolTipText(readViewModel.getLocalization()); + TABLE_ICONS.put(SpecialField.READ_STATUS.getFieldName(), label); + + // Print icon used for menu + SpecialFieldViewModel printedViewModel = new SpecialFieldViewModel(SpecialField.PRINTED); + label = printedViewModel.getIcon().getGraphicNode(); + //label.setToolTipText(printedViewModel.getLocalization()); + TABLE_ICONS.put(SpecialField.PRINTED.getFieldName(), label); + } + + public Node getTableIcon(String fieldType) { + Node label = TABLE_ICONS.get(fieldType); + if (label == null) { + //LOGGER.info("Error: no table icon defined for type '" + fieldType + "'."); + return null; + } else { + return label; + } + } +} diff --git a/src/main/java/org/jabref/gui/maintable/MainTable.css b/src/main/java/org/jabref/gui/maintable/MainTable.css new file mode 100644 index 00000000000..651b8376d4a --- /dev/null +++ b/src/main/java/org/jabref/gui/maintable/MainTable.css @@ -0,0 +1,48 @@ +.table-view { + +} + +.table-view .column-header-background { + -fx-background-color: -fx-control-inner-background; +} + +.table-view .column-header, +.table-view .filler { + -fx-background-color: -fx-control-inner-background; + -fx-font-weight: bold; + -fx-size: 3em; + -fx-border-width: 0 0 1 0; + -fx-border-color: darkgrey; +} + +.table-view .column-header > .label { + -fx-padding: 0 1em 0 1em; + -fx-alignment: center-left; + -fx-text-fill: -fx-unimportant; +} + +.table-view .column-header .glyph-icon { + -fx-alignment: baseline-center; + -fx-text-fill: -fx-unimportant; + -fx-fill: -fx-unimportant; +} + +.table-cell { + -fx-padding: 0.5em 1em 0.5em 1em; + -fx-cell-size: 4.0em; +} + +.table-row-cell:odd { + -fx-background: -fx-control-inner-background; +} + +.column-icon { + -fx-alignment: baseline-center; + -fx-padding: 0; +} + +.column-header.column-icon > .label { + -fx-padding: 0; + -fx-alignment: baseline-center; +} + diff --git a/src/main/java/org/jabref/gui/maintable/MainTable.java b/src/main/java/org/jabref/gui/maintable/MainTable.java index 9edd6805dba..ca003724cc6 100644 --- a/src/main/java/org/jabref/gui/maintable/MainTable.java +++ b/src/main/java/org/jabref/gui/maintable/MainTable.java @@ -1,68 +1,36 @@ package org.jabref.gui.maintable; import java.awt.Color; -import java.awt.Dimension; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.event.ActionEvent; -import java.awt.event.MouseEvent; import java.util.ArrayList; -import java.util.Comparator; import java.util.List; -import java.util.Locale; import java.util.Optional; +import java.util.stream.Collectors; -import javax.swing.AbstractAction; -import javax.swing.ActionMap; -import javax.swing.BorderFactory; -import javax.swing.InputMap; -import javax.swing.JScrollBar; -import javax.swing.JScrollPane; import javax.swing.JTable; -import javax.swing.JViewport; -import javax.swing.TransferHandler; -import javax.swing.plaf.TableUI; -import javax.swing.table.DefaultTableCellRenderer; -import javax.swing.table.TableCellRenderer; -import javax.swing.table.TableColumnModel; + +import javafx.collections.ListChangeListener; +import javafx.scene.control.ScrollPane; +import javafx.scene.control.SelectionMode; +import javafx.scene.control.TableView; import org.jabref.Globals; import org.jabref.gui.BasePanel; import org.jabref.gui.EntryMarker; -import org.jabref.gui.GUIGlobals; import org.jabref.gui.JabRefFrame; -import org.jabref.gui.groups.EntryTableTransferHandler; -import org.jabref.gui.groups.GroupMatcher; -import org.jabref.gui.keyboard.KeyBinding; import org.jabref.gui.renderer.CompleteRenderer; import org.jabref.gui.renderer.GeneralRenderer; import org.jabref.gui.renderer.IncompleteRenderer; -import org.jabref.gui.search.matchers.SearchMatcher; -import org.jabref.gui.util.comparator.FirstColumnComparator; -import org.jabref.gui.util.comparator.IconComparator; -import org.jabref.gui.util.comparator.RankingFieldComparator; +import org.jabref.gui.util.ViewModelTableRowFactory; import org.jabref.logic.TypedBibEntry; -import org.jabref.logic.bibtex.comparator.FieldComparator; -import org.jabref.model.EntryTypes; +import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.BibtexSingleField; -import org.jabref.model.entry.EntryType; -import org.jabref.model.entry.FieldName; -import org.jabref.model.entry.specialfields.SpecialField; import org.jabref.preferences.JabRefPreferences; -import ca.odell.glazedlists.EventList; -import ca.odell.glazedlists.SortedList; -import ca.odell.glazedlists.event.ListEventListener; -import ca.odell.glazedlists.gui.AbstractTableComparatorChooser; import ca.odell.glazedlists.matchers.Matcher; -import ca.odell.glazedlists.swing.DefaultEventSelectionModel; -import ca.odell.glazedlists.swing.GlazedListsSwing; -import ca.odell.glazedlists.swing.TableComparatorChooser; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -public class MainTable extends JTable { +public class MainTable extends TableView { private static GeneralRenderer defRenderer; private static GeneralRenderer reqRenderer; private static GeneralRenderer optRenderer; @@ -80,17 +48,14 @@ public class MainTable extends JTable { private static List markedNumberRenderers; private static final Log LOGGER = LogFactory.getLog(MainTable.class); - private final MainTableFormat tableFormat; private final BasePanel panel; private final boolean tableColorCodes; private final boolean tableResolvedColorCodes; - private final DefaultEventSelectionModel localSelectionModel; - private final TableComparatorChooser comparatorChooser; - private final JScrollPane pane; + private final ScrollPane pane; // needed to activate/deactivate the listener - private final PersistenceTableColumnListener tableColumnListener; + private PersistenceTableColumnListener tableColumnListener; private final MainTableDataModel model; // Enum used to define how a cell should be rendered. @@ -105,60 +70,73 @@ private enum CellRendererMode { MainTable.updateRenderers(); } - public MainTable(MainTableFormat tableFormat, MainTableDataModel model, JabRefFrame frame, - BasePanel panel) { + public MainTable(MainTableDataModel model, JabRefFrame frame, + BasePanel panel, BibDatabase database) { super(); this.model = model; - addFocusListener(Globals.getFocusListener()); - setAutoResizeMode(Globals.prefs.getInt(JabRefPreferences.AUTO_RESIZE_MODE)); + this.getColumns().addAll(new ColumnFactory(database).createColumns()); + this.setRowFactory(new ViewModelTableRowFactory() + .withOnMouseClickedEvent((entry, event) -> { + if (event.getClickCount() == 2) { + panel.showAndEdit(entry.getEntry()); + } + })); + if (Globals.prefs.getBoolean(JabRefPreferences.AUTO_RESIZE_MODE)) { + this.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); + } + this.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); + this.setItems(model.getTableRows()); + + // TODO: Cannot add focus listener as it is expecting an swing component + //addFocusListener(Globals.getFocusListener()); - this.tableFormat = tableFormat; this.panel = panel; - setModel(GlazedListsSwing - .eventTableModelWithThreadProxyList(model.getTableRows(), tableFormat)); + pane = new ScrollPane(this); + pane.setFitToHeight(true); + pane.setFitToWidth(true); + this.pane.getStylesheets().add(MainTable.class.getResource("MainTable.css").toExternalForm()); + // TODO: Color tableColorCodes = Globals.prefs.getBoolean(JabRefPreferences.TABLE_COLOR_CODES_ON); tableResolvedColorCodes = Globals.prefs.getBoolean(JabRefPreferences.TABLE_RESOLVED_COLOR_CODES_ON); - localSelectionModel = (DefaultEventSelectionModel) GlazedListsSwing - .eventSelectionModelWithThreadProxyList(model.getTableRows()); - setSelectionModel(localSelectionModel); - pane = new JScrollPane(this); - pane.setBorder(BorderFactory.createEmptyBorder()); - pane.getViewport().setBackground(Globals.prefs.getColor(JabRefPreferences.TABLE_BACKGROUND)); - setGridColor(Globals.prefs.getColor(JabRefPreferences.GRID_COLOR)); - if (Globals.prefs.getBoolean(JabRefPreferences.TABLE_SHOW_GRID)) { - setShowGrid(true); - } else { - setShowGrid(false); - setIntercellSpacing(new Dimension(0, 0)); + //pane.getViewport().setBackground(Globals.prefs.getColor(JabRefPreferences.TABLE_BACKGROUND)); + //setGridColor(Globals.prefs.getColor(JabRefPreferences.GRID_COLOR)); + if (!Globals.prefs.getBoolean(JabRefPreferences.TABLE_SHOW_GRID)) { + this.setStyle("-fx-table-cell-border-color: transparent;"); } - this.setTableHeader(new PreventDraggingJTableHeader(this, tableFormat)); - - comparatorChooser = this.createTableComparatorChooser(this, model.getSortedForUserDefinedTableColumnSorting(), - AbstractTableComparatorChooser.MULTIPLE_COLUMN_KEYBOARD); - - this.tableColumnListener = new PersistenceTableColumnListener(this); + // TODO: Tooltip for column header + /* + @Override + public String getToolTipText(MouseEvent event) { + int index = columnModel.getColumnIndexAtX(event.getX()); + int realIndex = columnModel.getColumn(index).getModelIndex(); + MainTableColumn column = tableFormat.getTableColumn(realIndex); + return column.getDisplayName(); + } + */ - // set table header render AFTER creation of comparatorChooser (this enables sort arrow rendering) - this.getTableHeader().setDefaultRenderer(new MainTableHeaderRenderer(this.getTableHeader().getDefaultRenderer())); + // TODO: store column widths + //this.tableColumnListener = new PersistenceTableColumnListener(this); + //setWidths(); - // TODO: Figure out, whether this call is needed. - getSelected(); + // TODO: enable DnD + //setDragEnabled(true); + //TransferHandler xfer = new EntryTableTransferHandler(this, frame, panel); + //setTransferHandler(xfer); + //pane.setTransferHandler(xfer); - // enable DnD - setDragEnabled(true); - TransferHandler xfer = new EntryTableTransferHandler(this, frame, panel); - setTransferHandler(xfer); - pane.setTransferHandler(xfer); + // Todo: Set default sort order + // setupComparatorChooser(); - setupComparatorChooser(); - model.updateMarkingState(Globals.prefs.getBoolean(JabRefPreferences.FLOAT_MARKED_ENTRIES)); - setWidths(); + // TODO: Float marked entries + //model.updateMarkingState(Globals.prefs.getBoolean(JabRefPreferences.FLOAT_MARKED_ENTRIES)); + // TODO: Keybindings //Override 'selectNextColumnCell' and 'selectPreviousColumnCell' to move rows instead of cells on TAB + /* ActionMap actionMap = getActionMap(); InputMap inputMap = getInputMap(); actionMap.put("selectNextColumnCell", new AbstractAction() { @@ -202,14 +180,14 @@ public void actionPerformed(ActionEvent event) { public void actionPerformed(ActionEvent event) { panel.selectLastEntry(); } - }); + });*/ } - public void addSelectionListener(ListEventListener listener) { - getSelected().addListEventListener(listener); + public void addSelectionListener(ListChangeListener listener) { + getSelectionModel().getSelectedItems().addListener(listener); } - public JScrollPane getPane() { + public ScrollPane getPane() { return pane; } @@ -217,6 +195,8 @@ public MainTableDataModel getTableModel() { return model; } + /* + // TODO: if the content of the cell is bigger than the cell itself render it as the tooltip @Override public String getToolTipText(MouseEvent e) { String toolTipText = super.getToolTipText(e); @@ -233,6 +213,7 @@ public String getToolTipText(MouseEvent e) { return toolTipText; } + // TODO: Support float mode @Override public TableCellRenderer getCellRenderer(int row, int column) { @@ -304,6 +285,7 @@ else if (column == 0) { return renderer; } + // TODO: Set column widths private void setWidths() { // Setting column widths: int ncWidth = Globals.prefs.getInt(JabRefPreferences.NUMBER_COL_WIDTH); @@ -338,40 +320,17 @@ private void setWidths() { } } } + */ public BibEntry getEntryAt(int row) { - return model.getTableRows().get(row); + return model.getTableRows().get(row).getEntry(); } - /** - * @return the return value is never null - */ public List getSelectedEntries() { - return new ArrayList<>(getSelected()); - } - - private List getCurrentSortOrder() { - List order = new ArrayList<>(); - List sortCols = comparatorChooser.getSortingColumns(); - for (Integer i : sortCols) { - order.add(comparatorChooser.isColumnReverse(i)); - } - return order; - } - - private List getCurrentSortFields() { - List sortCols = comparatorChooser.getSortingColumns(); - List fields = new ArrayList<>(); - for (Integer i : sortCols) { - // TODO check whether this really works - String name = tableFormat.getColumnName(i); - //TODO OLD - // String name = tableFormat.getColumnType(i); - if (name != null) { - fields.add(name.toLowerCase(Locale.ROOT)); - } - } - return fields; + return getSelectionModel() + .getSelectedItems().stream() + .map(BibEntryTableViewModel::getEntry) + .collect(Collectors.toList()); } /** @@ -381,6 +340,8 @@ private List getCurrentSortFields() { * is initialized with the sort order defined in Preferences. */ private void setupComparatorChooser() { + // TODO: Proper sorting + /* // First column: List comparators = comparatorChooser.getComparatorsForColumn(0); comparators.clear(); @@ -468,9 +429,10 @@ private void setupComparatorChooser() { Globals.prefs.putBoolean(JabRefPreferences.TABLE_TERTIARY_SORT_DESCENDING, false); } }); - +*/ } - +/* + // TODO: Reenable background coloring of fields (required/optional/...) private CellRendererMode getCellStatus(int row, int col, boolean checkResolved) { try { BibEntry be = getEntryAt(row); @@ -492,48 +454,12 @@ private CellRendererMode getCellStatus(int row, int col, boolean checkResolved) return CellRendererMode.OTHER; } } + */ - /** - * Use with caution! If you modify an entry in the table, the selection changes - * - * You can avoid it with - * .getSelected().getReadWriteLock().writeLock().lock() - * and then .unlock() - */ - public EventList getSelected() { - return localSelectionModel.getSelected(); - } - - /** - * Selects the given row - * - * @param row the row to select - */ - public void setSelected(int row) { - localSelectionModel.setSelectionInterval(row, row); - } - - public int findEntry(BibEntry entry) { - EventList tableRows = model.getTableRows(); - for (int row = 0; row < tableRows.size(); row++) { - BibEntry bibEntry = tableRows.get(row); - if (entry == bibEntry) { // NOPMD (equals doesn't recognise duplicates) - return row; - } - } - return -1; - } - - /** - * Method to check whether a MainTableColumn at the modelIndex refers to the file field (either as a specific - * file extension filter or not) - * - * @param modelIndex model index of the column to check - * @return true if the column shows the "file" field; false otherwise - */ - public boolean isFileColumn(int modelIndex) { - return (tableFormat.getTableColumn(modelIndex) != null) && tableFormat.getTableColumn(modelIndex) - .getBibtexFields().contains(FieldName.FILE); + public Optional findEntry(BibEntry entry) { + return model.getTableRows().stream() + .filter(viewModel -> viewModel.getEntry().equals(entry)) + .findFirst(); } private boolean matches(int row, Matcher m) { @@ -561,17 +487,12 @@ private int isMarked(int row) { private Optional getBibEntry(int row) { try { - return Optional.of(model.getTableRows().get(row)); + return Optional.of(model.getTableRows().get(row).getEntry()); } catch (IndexOutOfBoundsException e) { return Optional.empty(); } } - public void scrollTo(int y) { - JScrollBar scb = pane.getVerticalScrollBar(); - scb.setValue(y * scb.getUnitIncrement(1)); - } - public void showFloatSearch() { this.getTableModel().updateSearchState(MainTableDataModel.DisplayOption.FLOAT); @@ -582,79 +503,17 @@ public void showFloatSearch() { * Repaints the table with the most recent font configuration */ public void updateFont() { + /* + // TODO: Font & padding customization setFont(GUIGlobals.currentFont); int maxOfIconsAndFontSize = Math.max(GUIGlobals.currentFont.getSize(), Globals.prefs.getInt(JabRefPreferences.ICON_SIZE_SMALL)); setRowHeight(Globals.prefs.getInt(JabRefPreferences.TABLE_ROW_PADDING) + maxOfIconsAndFontSize); // Update Table header with new settings this.getTableHeader().setDefaultRenderer(new MainTableHeaderRenderer(this.getTableHeader().getDefaultRenderer())); this.getTableHeader().resizeAndRepaint(); + */ } - public void ensureVisible(int row) { - JScrollBar vert = pane.getVerticalScrollBar(); - int y = row * getRowHeight(); - if ((y < vert.getValue()) || ((y >= (vert.getValue() + vert.getVisibleAmount())) - && (model.getSearchState() != MainTableDataModel.DisplayOption.FLOAT))) { - scrollToCenter(row, 1); - } - } - - /** - * Ensures that the given entry is shown in the maintable. - * It also selects the given entry - * The execution is executed directly. Be sure that it happens in the EDT. - * - * @param entry the BibEntry to be shown - */ - public void ensureVisible(BibEntry entry) { - final int row = this.findEntry(entry); - if (row >= 0) { - if (this.getSelectedRowCount() == 0) { - this.setRowSelectionInterval(row, row); - } - this.ensureVisible(row); - } - } - - public void scrollToCenter(int rowIndex, int vColIndex) { - if (!(this.getParent() instanceof JViewport)) { - return; - } - - JViewport viewport = (JViewport) this.getParent(); - - // This rectangle is relative to the table where the - // northwest corner of cell (0,0) is always (0,0). - Rectangle rect = this.getCellRect(rowIndex, vColIndex, true); - - // The location of the view relative to the table - Rectangle viewRect = viewport.getViewRect(); - - // Translate the cell location so that it is relative - // to the view, assuming the northwest corner of the - // view is (0,0). - rect.setLocation(rect.x - viewRect.x, rect.y - viewRect.y); - - // Calculate location of rect if it were at the center of view - int centerX = (viewRect.width - rect.width) / 2; - int centerY = (viewRect.height - rect.height) / 2; - - // Fake the location of the cell so that scrollRectToVisible - // will move the cell to the center - if (rect.x < centerX) { - centerX = -centerX; - } - if (rect.y < centerY) { - centerY = -centerY; - } - rect.translate(centerX, centerY); - - // Scroll the area into view. - viewport.scrollRectToVisible(rect); - - revalidate(); - repaint(); - } public static void updateRenderers() { @@ -692,40 +551,4 @@ public static void updateRenderers() { private static Color mixColors(Color one, Color two) { return new Color((one.getRed() + two.getRed()) / 2, (one.getGreen() + two.getGreen()) / 2, (one.getBlue() + two.getBlue()) / 2); } - - private TableComparatorChooser createTableComparatorChooser(JTable table, SortedList list, Object sortingStrategy) { - return TableComparatorChooser.install(table, list, sortingStrategy); - } - - /** - * Morten Alver: This override is a workaround NullPointerException when - * dragging stuff into the table. I found this in a forum, but have no idea - * why it works. - * @param newUI - */ - @Override - public void setUI(TableUI newUI) { - super.setUI(newUI); - TransferHandler handler = getTransferHandler(); - setTransferHandler(null); - setTransferHandler(handler); - } - - /** - * Find out which column is set as sort column. - * @param number The position in the sort hierarchy (primary, secondary, etc.) - * @return The sort column number. - */ - public int getSortingColumn(int number) { - List l = comparatorChooser.getSortingColumns(); - if (l.size() <= number) { - return -1; - } else { - return l.get(number); - } - } - - public MainTableColumn getMainTableColumn(int modelIndex) { - return tableFormat.getTableColumn(modelIndex); - } } diff --git a/src/main/java/org/jabref/gui/maintable/MainTableColumn.java b/src/main/java/org/jabref/gui/maintable/MainTableColumn.java index 18fd5e141dc..815f623f3a0 100644 --- a/src/main/java/org/jabref/gui/maintable/MainTableColumn.java +++ b/src/main/java/org/jabref/gui/maintable/MainTableColumn.java @@ -1,160 +1,15 @@ package org.jabref.gui.maintable; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.StringJoiner; +import javafx.beans.value.ObservableValue; +import javafx.scene.control.TableColumn; -import javax.swing.JLabel; +abstract class MainTableColumn extends TableColumn { -import org.jabref.logic.layout.LayoutFormatter; -import org.jabref.logic.layout.format.LatexToUnicodeFormatter; -import org.jabref.model.database.BibDatabase; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.FieldName; -import org.jabref.model.entry.FieldProperty; -import org.jabref.model.entry.InternalBibtexFields; + MainTableColumn(String text) { + super(text); -public class MainTableColumn { - - private final String columnName; - - private final List bibtexFields; - - private final boolean isIconColumn; - - private final Optional iconLabel; - - private final Optional database; - - private final LayoutFormatter toUnicode = new LatexToUnicodeFormatter(); - - public MainTableColumn(String columnName) { - this.columnName = columnName; - this.bibtexFields = Collections.emptyList(); - this.isIconColumn = false; - this.iconLabel = Optional.empty(); - this.database = Optional.empty(); - } - - public MainTableColumn(String columnName, List bibtexFields, BibDatabase database) { - this.columnName = columnName; - this.bibtexFields = Collections.unmodifiableList(bibtexFields); - this.isIconColumn = false; - this.iconLabel = Optional.empty(); - this.database = Optional.of(database); - } - - public MainTableColumn(String columnName, List bibtexFields, JLabel iconLabel) { - this.columnName = columnName; - this.bibtexFields = Collections.unmodifiableList(bibtexFields); - this.isIconColumn = true; - this.iconLabel = Optional.of(iconLabel); - this.database = Optional.empty(); - } - - /** - * Get the table column name to be displayed in the UI - * - * @return name to be displayed. null if field is empty. - */ - public String getDisplayName() { - if (bibtexFields.isEmpty()) { - return null; - } - - StringJoiner joiner = new StringJoiner(FieldName.FIELD_SEPARATOR); - for (String field : bibtexFields) { - joiner.add(field); - } - return joiner.toString(); - } - - public String getColumnName() { - return columnName; - } - - public List getBibtexFields() { - return bibtexFields; - } - - public boolean isIconColumn() { - return isIconColumn; - } - - public boolean isFileFilter() { - return false; // Overridden in SpecialMainTableColumns for file filter columns + setCellValueFactory(param -> getColumnValue(param.getValue())); } - public Object getColumnValue(BibEntry entry) { - if (bibtexFields.isEmpty()) { - return null; - } - boolean isNameColumn = false; - - Optional content = Optional.empty(); - for (String field : bibtexFields) { - content = entry.getResolvedFieldOrAlias(field, database.orElse(null)); - if (content.isPresent()) { - isNameColumn = InternalBibtexFields.getFieldProperties(field).contains(FieldProperty.PERSON_NAMES); - break; - } - } - - String result = content.orElse(null); - - if (isNameColumn) { - result = toUnicode.format(MainTableNameFormatter.formatName(result)); - } - - if (result != null && !BibEntry.KEY_FIELD.equals(columnName)) { - result = toUnicode.format(result).trim(); - } - - return result; - } - - public JLabel getHeaderLabel() { - if (isIconColumn) { - return iconLabel.get(); - } else { - return new JLabel(getDisplayName()); - } - } - - /** - * Check if the value returned by getColumnValue() is the same as a simple check of the entry's field(s) would give - * The reasons for being different are (combinations may also happen): - * - The entry has a crossref where the field content is obtained from - * - The field has a string in it (which getColumnValue() resolves) - * - There are some alias fields. For example, if the entry has a date field but no year field, - * {@link BibEntry#getResolvedFieldOrAlias(String, BibDatabase)} will return the year value from the date field - * when queried for year - * - * @param entry the BibEntry - * @return true if the value returned by getColumnValue() is resolved as outlined above - */ - public boolean isResolved(BibEntry entry) { - if (bibtexFields.isEmpty()) { - return false; - } - - Optional resolvedFieldContent = Optional.empty(); - Optional plainFieldContent = Optional.empty(); - for (String field : bibtexFields) { - // entry type or bibtex key will never be resolved - if (BibEntry.TYPE_HEADER.equals(field) || BibEntry.OBSOLETE_TYPE_HEADER.equals(field) - || BibEntry.KEY_FIELD.equals(field)) { - return false; - } else { - plainFieldContent = entry.getField(field); - resolvedFieldContent = entry.getResolvedFieldOrAlias(field, database.orElse(null)); - } - - if (resolvedFieldContent.isPresent()) { - break; - } - } - return (!resolvedFieldContent.equals(plainFieldContent)); - } + abstract ObservableValue getColumnValue(BibEntryTableViewModel entry); } diff --git a/src/main/java/org/jabref/gui/maintable/MainTableDataModel.java b/src/main/java/org/jabref/gui/maintable/MainTableDataModel.java index 3fc3065d8ac..b2696d6d04f 100644 --- a/src/main/java/org/jabref/gui/maintable/MainTableDataModel.java +++ b/src/main/java/org/jabref/gui/maintable/MainTableDataModel.java @@ -6,6 +6,9 @@ import java.util.Objects; import java.util.stream.Collectors; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; + import org.jabref.gui.groups.GroupMatcher; import org.jabref.gui.search.HitOrMissComparator; import org.jabref.gui.search.matchers.EverythingMatcher; @@ -27,7 +30,7 @@ public class MainTableDataModel { private final SortedList sortedForMarkingSearchGrouping; private final StartStopListFilterAction filterSearchToggle; private final StartStopListFilterAction filterGroupToggle; - private final EventList finalList; + private final ObservableList finalList; private final FilterAndSortingState filterAndSortingState = new FilterAndSortingState(); public MainTableDataModel(BibDatabaseContext context) { @@ -51,7 +54,9 @@ public MainTableDataModel(BibDatabaseContext context) { filterSearchToggle = new StartStopListFilterAction(searchFilterList, SearchMatcher.INSTANCE, EverythingMatcher.INSTANCE); - finalList = searchFilterList; + // TODO + //finalList = searchFilterList; + finalList = FXCollections.observableArrayList(entries.stream().map(BibEntryTableViewModel::new).collect(Collectors.toList())); } public void updateSortOrder() { @@ -146,15 +151,11 @@ public void updateMarkingState(boolean floatMarkedEntries) { return; } - if (floatMarkedEntries) { - filterAndSortingState.markingState = true; - } else { - filterAndSortingState.markingState = false; - } + filterAndSortingState.markingState = floatMarkedEntries; updateSortOrder(); } - EventList getTableRows() { + ObservableList getTableRows() { return finalList; } diff --git a/src/main/java/org/jabref/gui/maintable/MainTableFormat.java b/src/main/java/org/jabref/gui/maintable/MainTableFormat.java deleted file mode 100644 index 2dda88ae52f..00000000000 --- a/src/main/java/org/jabref/gui/maintable/MainTableFormat.java +++ /dev/null @@ -1,153 +0,0 @@ -package org.jabref.gui.maintable; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import javax.swing.JLabel; - -import org.jabref.Globals; -import org.jabref.gui.IconTheme; -import org.jabref.model.database.BibDatabase; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.FieldName; -import org.jabref.preferences.JabRefPreferences; - -import ca.odell.glazedlists.gui.TableFormat; - -/** - * Class defining the contents and column headers of the main table. - */ -public class MainTableFormat implements TableFormat { - - // Values to gather iconImages for those columns - // These values are also used to put a heading into the table; see getColumnName(int) - private static final List URL_FIRST = Arrays.asList(FieldName.URL, FieldName.DOI); - private static final List DOI_FIRST = Arrays.asList(FieldName.DOI, FieldName.URL); - private static final List ARXIV = Collections.singletonList(FieldName.EPRINT); - - private final BibDatabase database; - - private final List tableColumns = new ArrayList<>(); - - public MainTableFormat(BibDatabase database) { - this.database = database; - } - - @Override - public int getColumnCount() { - return tableColumns.size(); - } - - /** - * @return the string that should be put in the column header. null if field is empty. - */ - @Override - public String getColumnName(int col) { - return tableColumns.get(col).getDisplayName(); - - } - - public MainTableColumn getTableColumn(int index) { - return tableColumns.get(index); - } - - /** - * Finds the column index for the given column name. - * - * @param colName The column name - * @return The column index if any, or -1 if no column has that name. - */ - public int getColumnIndex(String colName) { - - for (MainTableColumn tableColumn : tableColumns) { - if (tableColumn.getColumnName().equalsIgnoreCase(colName)) { - return tableColumns.lastIndexOf(tableColumn); - } - } - - return -1; - } - - @Override - public Object getColumnValue(BibEntry be, int col) { - return tableColumns.get(col).getColumnValue(be); - } - - public void updateTableFormat() { - // clear existing column configuration - tableColumns.clear(); - - SpecialMainTableColumnsBuilder builder = new SpecialMainTableColumnsBuilder(); - // Add numbering column to tableColumns - tableColumns.add(builder.buildNumberColumn()); - - // Add all file based columns - if (Globals.prefs.getBoolean(JabRefPreferences.FILE_COLUMN)) { - tableColumns.add(builder.buildFileColumn()); - } - - if (Globals.prefs.getBoolean(JabRefPreferences.URL_COLUMN)) { - if (Globals.prefs.getBoolean(JabRefPreferences.PREFER_URL_DOI)) { - tableColumns.add(builder - .createIconColumn(JabRefPreferences.URL_COLUMN, MainTableFormat.DOI_FIRST, - new JLabel(IconTheme.JabRefIcon.DOI.getSmallIcon()))); - } else { - tableColumns.add(builder - .createIconColumn(JabRefPreferences.URL_COLUMN, MainTableFormat.URL_FIRST, - new JLabel(IconTheme.JabRefIcon.WWW.getSmallIcon()))); - } - - } - - if (Globals.prefs.getBoolean(JabRefPreferences.ARXIV_COLUMN)) { - tableColumns.add(builder - .createIconColumn(JabRefPreferences.ARXIV_COLUMN, MainTableFormat.ARXIV, - new JLabel(IconTheme.JabRefIcon.WWW.getSmallIcon()))); - } - - if (Globals.prefs.getBoolean(JabRefPreferences.EXTRA_FILE_COLUMNS)) { - List desiredColumns = Globals.prefs.getStringList(JabRefPreferences.LIST_OF_FILE_COLUMNS); - for (String desiredColumn : desiredColumns) { - tableColumns.add(builder.createFileIconColumn(desiredColumn)); - } - } - - // Add 'normal' bibtex fields as configured in the preferences - // Read table columns from prefs: - List colSettings = Globals.prefs.getStringList(JabRefPreferences.COLUMN_NAMES); - - for (String columnName : colSettings) { - // stored column name will be used as columnName - // There might be more than one field to display, e.g., "author/editor" or "date/year" - so split - // at MainTableFormat.COL_DEFINITION_FIELD_SEPARATOR - String[] fields = columnName.split(FieldName.FIELD_SEPARATOR); - tableColumns.add(new MainTableColumn(columnName, Arrays.asList(fields), database)); - } - - // Add the "special" icon columns (e.g., ranking, file, ...) that are enabled in preferences. - if (Globals.prefs.getBoolean(JabRefPreferences.SPECIALFIELDSENABLED)) { - if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_RANKING)) { - tableColumns.add(builder.buildRankingColumn()); - } - if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_RELEVANCE)) { - tableColumns.add(builder.buildRelevanceColumn()); - } - if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_QUALITY)) { - tableColumns.add(builder.buildQualityColumn()); - } - if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_PRIORITY)) { - tableColumns.add(builder.buildPriorityColumn()); - } - if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_PRINTED)) { - tableColumns.add(builder.buildPrintedColumn()); - } - if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_READ)) { - tableColumns.add(builder.buildReadStatusColumn()); - } - } - - } - -} diff --git a/src/main/java/org/jabref/gui/maintable/MainTableHeaderRenderer.java b/src/main/java/org/jabref/gui/maintable/MainTableHeaderRenderer.java deleted file mode 100644 index 475ed261b0c..00000000000 --- a/src/main/java/org/jabref/gui/maintable/MainTableHeaderRenderer.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.jabref.gui.maintable; - -import java.awt.Component; - -import javax.swing.Icon; -import javax.swing.JLabel; -import javax.swing.JTable; -import javax.swing.table.TableCellRenderer; - -import org.jabref.gui.GUIGlobals; - -public class MainTableHeaderRenderer implements TableCellRenderer { - - private final TableCellRenderer delegate; - - public MainTableHeaderRenderer(TableCellRenderer delegate) { - this.delegate = delegate; - } - - @Override - public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, - boolean hasFocus, int row, int column) { - // delegate to previously used TableCellRenderer which styles the component - Component resultFromDelegate = delegate.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); - - // Changing style is only possible if both value and resultFromDelegate are JLabels - if ((value instanceof JLabel) && (resultFromDelegate instanceof JLabel)) { - String text = ((JLabel) value).getText(); - Icon icon = ((JLabel) value).getIcon(); - if (icon == null) { - ((JLabel) resultFromDelegate).setText(text); - resultFromDelegate.setFont(GUIGlobals.currentFont); - } else { - ((JLabel) resultFromDelegate).setIcon(icon); - ((JLabel) resultFromDelegate).setText(null); - } - } - - return resultFromDelegate; - } -} diff --git a/src/main/java/org/jabref/gui/maintable/MainTableSelectionListener.java b/src/main/java/org/jabref/gui/maintable/MainTableSelectionListener.java index 8977efcf50a..dcbf0fdc7d7 100644 --- a/src/main/java/org/jabref/gui/maintable/MainTableSelectionListener.java +++ b/src/main/java/org/jabref/gui/maintable/MainTableSelectionListener.java @@ -6,43 +6,17 @@ import java.awt.event.KeyListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; -import java.io.IOException; -import java.util.List; -import java.util.Locale; -import java.util.Optional; -import javax.swing.Icon; -import javax.swing.JLabel; import javax.swing.JPopupMenu; -import javax.swing.SwingUtilities; import javax.swing.Timer; -import org.jabref.Globals; -import org.jabref.JabRefExecutorService; -import org.jabref.JabRefGUI; import org.jabref.gui.BasePanel; import org.jabref.gui.BasePanelMode; -import org.jabref.gui.GUIGlobals; -import org.jabref.gui.IconTheme; import org.jabref.gui.PreviewPanel; -import org.jabref.gui.actions.CopyDoiUrlAction; -import org.jabref.gui.desktop.JabRefDesktop; import org.jabref.gui.entryeditor.EntryEditor; -import org.jabref.gui.externalfiletype.ExternalFileMenuItem; -import org.jabref.gui.externalfiletype.ExternalFileType; -import org.jabref.gui.filelist.FileListEntry; -import org.jabref.gui.filelist.FileListTableModel; -import org.jabref.gui.menus.RightClickMenu; -import org.jabref.gui.specialfields.SpecialFieldMenuAction; -import org.jabref.gui.specialfields.SpecialFieldValueViewModel; -import org.jabref.gui.specialfields.SpecialFieldViewModel; -import org.jabref.logic.l10n.Localization; -import org.jabref.logic.util.OS; import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.FieldName; -import org.jabref.model.entry.specialfields.SpecialField; -import org.jabref.model.entry.specialfields.SpecialFieldValue; +import ca.odell.glazedlists.BasicEventList; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.event.ListEvent; import ca.odell.glazedlists.event.ListEventListener; @@ -74,7 +48,7 @@ public class MainTableSelectionListener implements ListEventListener, public MainTableSelectionListener(BasePanel panel, MainTable table) { this.table = table; this.panel = panel; - this.tableRows = table.getTableModel().getTableRows(); + this.tableRows = new BasicEventList<>(); preview = panel.getPreviewPanel(); } @@ -101,6 +75,8 @@ public void listChanged(ListEvent e) { } if (newSelected != null) { + // TODO: Update entry editor / preview on selection change + /* final BasePanelMode mode = panel.getMode(); // What is the panel already showing? if ((mode == BasePanelMode.WILL_SHOW_EDITOR) || (mode == BasePanelMode.SHOWING_EDITOR)) { panel.showAndEdit(newSelected); @@ -109,6 +85,7 @@ public void listChanged(ListEvent e) { // Either nothing or a preview was shown. Update the preview. updatePreview(newSelected); } + */ } } @@ -126,6 +103,7 @@ private void updatePreview(final BibEntry toShow, int repeats) { t.start(); return; } + /* EventList list = table.getSelected(); // Check if the entry to preview is still selected: if ((list.size() != 1) || (list.get(0) != toShow)) { @@ -136,28 +114,13 @@ private void updatePreview(final BibEntry toShow, int repeats) { panel.showPreview(toShow); workingOnPreview = false; }); - } - - public void editSignalled() { - if (table.getSelected().size() == 1) { - editSignalled(table.getSelected().get(0)); - } - } - - public void editSignalled(BibEntry entry) { - panel.showAndEdit(entry); + */ } @Override public void mouseReleased(MouseEvent e) { - // First find the column and row on which the user has clicked. - final int col = table.columnAtPoint(e.getPoint()); - final int row = table.rowAtPoint(e.getPoint()); - - // get the MainTableColumn which is currently visible at col - int modelIndex = table.getColumnModel().getColumn(col).getModelIndex(); - MainTableColumn modelColumn = table.getMainTableColumn(modelIndex); - + // TODO: Right-click menu for special columns + /* // Check if the user has right-clicked. If so, open the right-click menu. if (e.isPopupTrigger() || (e.getButton() == MouseEvent.BUTTON3)) { if ((modelColumn == null) || !modelColumn.isIconColumn()) { @@ -168,6 +131,7 @@ public void mouseReleased(MouseEvent e) { showIconRightClickMenu(e, row, modelColumn); } } + */ } @Override @@ -177,14 +141,14 @@ public void mousePressed(MouseEvent e) { @Override public void mouseClicked(MouseEvent e) { - + /* // First find the column on which the user has clicked. final int row = table.rowAtPoint(e.getPoint()); // A double click on an entry should open the entry's editor. if (e.getClickCount() == 2) { BibEntry toShow = tableRows.get(row); - editSignalled(toShow); + panel.showAndEdit(toShow); return; } @@ -269,6 +233,7 @@ public void mouseClicked(MouseEvent e) { .ifPresent(crossref -> panel.getDatabase().getEntryByKey(crossref).ifPresent(entry -> panel.highlightEntry(entry))); } panel.frame().updateEnabledState(); + */ } /** @@ -279,6 +244,7 @@ public void mouseClicked(MouseEvent e) { * @param columnName the name of the specialfield column */ private void handleSpecialFieldLeftClick(MouseEvent e, String columnName) { + /* if ((e.getClickCount() == 1)) { SpecialField.getSpecialFieldInstanceFromFieldName(columnName).ifPresent(field -> { // special field found @@ -294,6 +260,7 @@ private void handleSpecialFieldLeftClick(MouseEvent e, String columnName) { } }); } + */ } /** @@ -303,12 +270,14 @@ private void handleSpecialFieldLeftClick(MouseEvent e, String columnName) { * @param row The row where the event occurred. */ private void processPopupTrigger(MouseEvent e, int row) { + /* int selRow = table.getSelectedRow(); if ((selRow == -1) || !table.isRowSelected(table.rowAtPoint(e.getPoint()))) { table.setRowSelectionInterval(row, row); } RightClickMenu rightClickMenu = new RightClickMenu(JabRefGUI.getMainFrame(), panel); rightClickMenu.show(table, e.getX(), e.getY()); + */ } /** @@ -325,6 +294,7 @@ private void showIconRightClickMenu(MouseEvent e, int row, MainTableColumn colum JPopupMenu menu = new JPopupMenu(); boolean showDefaultPopup = true; + /* // See if this is a simple file link field, or if it is a file-list // field that can specify a list of links: if (!column.getBibtexFields().isEmpty()) { @@ -378,9 +348,11 @@ private void showIconRightClickMenu(MouseEvent e, int row, MainTableColumn colum menu.show(table, e.getX(), e.getY()); } } + */ } public void entryEditorClosing(EntryEditor editor) { + /* if (Globals.prefs.getPreviewPreferences().isPreviewPanelEnabled()) { panel.showPreview(editor.getEntry()); } else { @@ -388,6 +360,7 @@ public void entryEditorClosing(EntryEditor editor) { panel.adjustSplitter(); } table.requestFocus(); + */ } @Override @@ -408,6 +381,7 @@ public void mouseExited(MouseEvent e) { */ @Override public void keyTyped(KeyEvent e) { + /* if ((!e.isActionKey()) && Character.isLetterOrDigit(e.getKeyChar()) && (e.getModifiers() == 0)) { long time = System.currentTimeMillis(); @@ -456,6 +430,7 @@ public void keyTyped(KeyEvent e) { lastPressedCount = 0; } panel.frame().updateEnabledState(); + */ } @Override diff --git a/src/main/java/org/jabref/gui/maintable/PersistenceTableColumnListener.java b/src/main/java/org/jabref/gui/maintable/PersistenceTableColumnListener.java index 538d9ac695f..a2fde3ff259 100644 --- a/src/main/java/org/jabref/gui/maintable/PersistenceTableColumnListener.java +++ b/src/main/java/org/jabref/gui/maintable/PersistenceTableColumnListener.java @@ -1,18 +1,10 @@ package org.jabref.gui.maintable; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - import javax.swing.event.ChangeEvent; import javax.swing.event.ListSelectionEvent; import javax.swing.event.TableColumnModelEvent; import javax.swing.event.TableColumnModelListener; -import org.jabref.Globals; -import org.jabref.model.entry.FieldName; -import org.jabref.preferences.JabRefPreferences; - /** * Listens for TableColumnModelEvents to keep track of changes made to the * MainTable columns, like reordering or resizing. @@ -46,6 +38,7 @@ public PersistenceTableColumnListener(final MainTable mainTable) { * update columns names and their width, store it in the global prefs. */ private void updateColumnPrefs() { + /* final int columnCount = mainTable.getColumnCount(); List storedColumns = new ArrayList<>(columnCount - 1); List columnsWidths = new ArrayList<>(columnCount - 1); @@ -69,6 +62,7 @@ private void updateColumnPrefs() { // width of the number ("#") column Globals.prefs.putInt(JabRefPreferences.NUMBER_COL_WIDTH, ncWidth); + */ } /** diff --git a/src/main/java/org/jabref/gui/maintable/PreventDraggingJTableHeader.java b/src/main/java/org/jabref/gui/maintable/PreventDraggingJTableHeader.java deleted file mode 100644 index cefacd64f2c..00000000000 --- a/src/main/java/org/jabref/gui/maintable/PreventDraggingJTableHeader.java +++ /dev/null @@ -1,97 +0,0 @@ -package org.jabref.gui.maintable; - -import java.awt.event.MouseEvent; -import java.util.Collections; -import java.util.Enumeration; - -import javax.swing.JTable; -import javax.swing.table.JTableHeader; -import javax.swing.table.TableColumn; - -/** - * Related to MainTable class.
- * Prevents dragging of the first header column ("#") and shows icons in the table header if an icon has to be set. - * - * This might not be the best way to solve this problem. Overriding - * getDraggedColumn produces some ugly gui dragging artifacts if a - * user attempts to drag something before the first columns. - * - * @author Daniel Waeber - * @author Fabian Bieker - * @since 12/2008 - */ -class PreventDraggingJTableHeader extends JTableHeader { - - private final MainTableFormat tableFormat; - - public PreventDraggingJTableHeader(JTable table, MainTableFormat tableFormat) { - super(table.getColumnModel()); - this.setTable(table); - this.tableFormat = tableFormat; - setupTableHeaderIcons(); - } - - private void setupTableHeaderIcons() { - - Enumeration columns = columnModel.getColumns(); - for (TableColumn column : Collections.list(columns)) { - MainTableColumn mainTableColumn = tableFormat.getTableColumn(column.getModelIndex()); - column.setHeaderValue(mainTableColumn.getHeaderLabel()); - } - - } - - @Override - public String getToolTipText(MouseEvent event) { - int index = columnModel.getColumnIndexAtX(event.getX()); - int realIndex = columnModel.getColumn(index).getModelIndex(); - MainTableColumn column = tableFormat.getTableColumn(realIndex); - return column.getDisplayName(); - } - - /** - * Overridden to prevent dragging of first column ("#") - */ - @Override - public void setDraggedColumn(TableColumn column) { - - if ((column != null) && (column.getModelIndex() == 0)) { - return; - } - super.setDraggedColumn(column); - } - - /** - * Overridden to prevent dragging of an other column before the first column ("#"). - */ - @Override - public TableColumn getDraggedColumn() { - TableColumn column = super.getDraggedColumn(); - if (column != null) { - PreventDraggingJTableHeader.preventDragBeforeNumberColumn(this.getTable(), column.getModelIndex()); - } - - return column; - } - - /** - * Transform model index modelIndex to a view based index and - * prevent dragging before model index toIndex (inclusive). - */ - private static void preventDragBeforeNumberColumn(JTable table, int modelIndex) { - - for (int columnIndex = 0; columnIndex < table.getColumnCount(); columnIndex++) { - - TableColumn col = table.getColumnModel().getColumn(columnIndex); - - // found the element in the view ... - // ... and check if it should not be dragged - if ((col.getModelIndex() == modelIndex) && (columnIndex < 1)) { - // prevent dragging (move it back ...) - table.getColumnModel().moveColumn(columnIndex, 1); - return; // we are done now - } - - } - } -} diff --git a/src/main/java/org/jabref/gui/maintable/SpecialMainTableColumnsBuilder.java b/src/main/java/org/jabref/gui/maintable/SpecialMainTableColumnsBuilder.java deleted file mode 100644 index 415b3082fe5..00000000000 --- a/src/main/java/org/jabref/gui/maintable/SpecialMainTableColumnsBuilder.java +++ /dev/null @@ -1,203 +0,0 @@ -package org.jabref.gui.maintable; - -import java.util.Collections; -import java.util.List; -import java.util.Optional; - -import javax.swing.JLabel; - -import org.jabref.gui.GUIGlobals; -import org.jabref.gui.IconTheme; -import org.jabref.gui.externalfiletype.ExternalFileType; -import org.jabref.gui.filelist.FileListTableModel; -import org.jabref.gui.specialfields.SpecialFieldValueViewModel; -import org.jabref.gui.specialfields.SpecialFieldViewModel; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.FieldName; -import org.jabref.model.entry.specialfields.SpecialField; - -class SpecialMainTableColumnsBuilder { - - MainTableColumn buildNumberColumn() { - - return new MainTableColumn(FieldName.NUMBER_COL) { - - @Override - public Object getColumnValue(BibEntry entry) { - return "#"; - } - - @Override - public String getDisplayName() { - return "#"; - } - } - - ; - } - - MainTableColumn buildRankingColumn() { - - return new MainTableColumn(SpecialField.RANKING.getFieldName(), - Collections.singletonList(SpecialField.RANKING.getFieldName()), - new JLabel(SpecialField.RANKING.getFieldName())) { - - @Override - public Object getColumnValue(BibEntry entry) { - - return entry.getField(SpecialField.RANKING.getFieldName()) - .flatMap(SpecialField.RANKING::parse).map(rank -> new SpecialFieldValueViewModel(rank).createSpecialFieldValueLabel()).orElse(null); - } - }; - } - - MainTableColumn buildPriorityColumn() { - return new MainTableColumn(SpecialField.PRIORITY.getFieldName(), - Collections.singletonList(SpecialField.PRIORITY.getFieldName()), - new JLabel(new SpecialFieldViewModel(SpecialField.PRIORITY).getRepresentingIcon())) { - - @Override - public Object getColumnValue(BibEntry entry) { - - return entry.getField(SpecialField.PRIORITY.getFieldName()) - .flatMap(SpecialField.PRIORITY::parse).map(prio -> new SpecialFieldValueViewModel(prio).createSpecialFieldValueLabel()).orElse(null); - } - }; - } - - MainTableColumn buildReadStatusColumn() { - return new MainTableColumn(SpecialField.READ_STATUS.getFieldName(), - Collections.singletonList(SpecialField.READ_STATUS.getFieldName()), - new JLabel(new SpecialFieldViewModel(SpecialField.READ_STATUS).getRepresentingIcon())) { - - @Override - public Object getColumnValue(BibEntry entry) { - - return entry.getField(SpecialField.READ_STATUS.getFieldName()) - .flatMap(SpecialField.READ_STATUS::parse).map(status -> new SpecialFieldValueViewModel(status).createSpecialFieldValueLabel()).orElse(null); - } - }; - } - - MainTableColumn buildRelevanceColumn() { - return createIconColumn(SpecialField.RELEVANCE.getFieldName(), - Collections.singletonList(SpecialField.RELEVANCE.getFieldName()), - new JLabel(new SpecialFieldViewModel(SpecialField.RELEVANCE).getRepresentingIcon())); - } - - MainTableColumn buildPrintedColumn() { - return createIconColumn(SpecialField.PRINTED.getFieldName(), - Collections.singletonList(SpecialField.PRINTED.getFieldName()), - new JLabel(new SpecialFieldViewModel(SpecialField.PRINTED).getRepresentingIcon())); - } - - MainTableColumn buildQualityColumn() { - return createIconColumn(SpecialField.QUALITY.getFieldName(), - Collections.singletonList(SpecialField.QUALITY.getFieldName()), - new JLabel(new SpecialFieldViewModel(SpecialField.QUALITY).getRepresentingIcon())); - } - - MainTableColumn buildFileColumn() { - - return new MainTableColumn(FieldName.FILE, - Collections.singletonList(FieldName.FILE), new JLabel(IconTheme.JabRefIcon.FILE.getSmallIcon())) { - - @Override - public Object getColumnValue(BibEntry entry) { - // We use a FileListTableModel to parse the field content: - FileListTableModel fileList = new FileListTableModel(); - entry.getField(FieldName.FILE).ifPresent(fileList::setContent); - if (fileList.getRowCount() > 1) { - return new JLabel(IconTheme.JabRefIcon.FILE_MULTIPLE.getSmallIcon()); - } else if (fileList.getRowCount() == 1) { - Optional type = fileList.getEntry(0).getType(); - if (type.isPresent()) { - return type.get().getIconLabel(); - } else { - return new JLabel(IconTheme.JabRefIcon.FILE.getSmallIcon()); - } - } - - return null; - } - }; - } - - /** - * Creates a MainTableColumn which shows an icon instead textual content - * - * @param columnName the name of the column - * @param fields the entry fields which should be shown - * @return the crated MainTableColumn - */ - MainTableColumn createIconColumn(String columnName, List fields, JLabel iconLabel) { - return new MainTableColumn(columnName, fields, iconLabel) { - - @Override - public Object getColumnValue(BibEntry entry) { - JLabel iconLabel = null; - boolean iconFound = false; - - // check for each field whether content is available - for (String field : fields) { - if (entry.hasField(field)) { - if (iconFound) { - return new JLabel(IconTheme.JabRefIcon.FILE_MULTIPLE.getSmallIcon()); - } else { - iconLabel = GUIGlobals.getTableIcon(field); - iconFound = true; - } - - } - } - return iconLabel; - } - }; - } - - /** - * create a MainTableColumn for specific file types. - *

- * Shows the icon for the given type (or the FILE_MULTIPLE icon) - * - * @param externalFileTypeName the name of the externalFileType - * @return the created MainTableColumn - */ - MainTableColumn createFileIconColumn(String externalFileTypeName) { - - return new MainTableColumn(externalFileTypeName, Collections.singletonList(FieldName.FILE), new JLabel()) { - - @Override - public boolean isFileFilter() { - return true; - } - - @Override - public String getDisplayName() { - return externalFileTypeName; - } - - @Override - public Object getColumnValue(BibEntry entry) { - - boolean iconFound = false; - JLabel iconLabel = null; - FileListTableModel fileList = new FileListTableModel(); - entry.getField(FieldName.FILE).ifPresent(fileList::setContent); - for (int i = 0; i < fileList.getRowCount(); i++) { - if ((fileList.getEntry(i).getType().isPresent()) - && externalFileTypeName.equalsIgnoreCase(fileList.getEntry(i).getType().get().getName())) { - if (iconFound) { - // already found another file of the desired type - show FILE_MULTIPLE Icon - return new JLabel(IconTheme.JabRefIcon.FILE_MULTIPLE.getSmallIcon()); - } else { - iconLabel = fileList.getEntry(i).getType().get().getIconLabel(); - iconFound = true; - } - } - } - return iconLabel; - } - }; - } -} diff --git a/src/main/java/org/jabref/gui/menus/RightClickMenu.java b/src/main/java/org/jabref/gui/menus/RightClickMenu.java index f77f2ed3101..4903310c535 100644 --- a/src/main/java/org/jabref/gui/menus/RightClickMenu.java +++ b/src/main/java/org/jabref/gui/menus/RightClickMenu.java @@ -59,8 +59,8 @@ public RightClickMenu(JabRefFrame frame, BasePanel panel) { // If only one entry is selected, get a reference to it for adapting the menu. BibEntry be = null; - if (panel.getMainTable().getSelectedRowCount() == 1) { - be = panel.getMainTable().getSelected().get(0); + if (panel.getMainTable().getSelectedEntries().size() == 1) { + be = panel.getMainTable().getSelectedEntries().get(0); } addPopupMenuListener(this); @@ -229,11 +229,11 @@ public static void populateSpecialFieldMenu(JMenu menu, SpecialField field, JabR } private boolean areMultipleEntriesSelected() { - return panel.getMainTable().getSelectedRowCount() > 1; + return panel.getMainTable().getSelectedEntries().size() > 1; } private boolean areExactlyTwoEntriesSelected() { - return panel.getMainTable().getSelectedRowCount() == 2; + return panel.getMainTable().getSelectedEntries().size() == 2; } /** @@ -262,16 +262,16 @@ private boolean isFieldSetForSelectedEntry(String fieldname) { } private boolean isAnyFieldSetForSelectedEntry(List fieldnames) { - if (panel.getMainTable().getSelectedRowCount() == 1) { - BibEntry entry = panel.getMainTable().getSelected().get(0); + if (panel.getMainTable().getSelectedEntries().size() == 1) { + BibEntry entry = panel.getMainTable().getSelectedEntries().get(0); return !Collections.disjoint(fieldnames, entry.getFieldNames()); } return false; } private Icon getFileIconForSelectedEntry() { - if (panel.getMainTable().getSelectedRowCount() == 1) { - BibEntry entry = panel.getMainTable().getSelected().get(0); + if (panel.getMainTable().getSelectedEntries().size() == 1) { + BibEntry entry = panel.getMainTable().getSelectedEntries().get(0); if (entry.hasField(FieldName.FILE)) { JLabel label = FileListTableModel.getFirstLabel(entry.getField(FieldName.FILE).get()); if (label != null) { diff --git a/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java b/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java index 0ea66468474..71ddb2eb270 100644 --- a/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java +++ b/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java @@ -22,7 +22,6 @@ import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JCheckBoxMenuItem; -import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JMenuItem; @@ -43,7 +42,6 @@ import org.jabref.gui.desktop.JabRefDesktop; import org.jabref.gui.desktop.os.NativeDesktop; import org.jabref.gui.help.HelpAction; -import org.jabref.gui.keyboard.KeyBinding; import org.jabref.gui.undo.NamedCompound; import org.jabref.gui.undo.UndoableKeyChange; import org.jabref.gui.util.DefaultTaskExecutor; @@ -304,9 +302,11 @@ public void actionPerformed(ActionEvent e) { content.setLayout(new BorderLayout()); content.add(mainBuilder.getPanel(), BorderLayout.CENTER); + /* frame.getTabbedPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(Globals.getKeyPrefs().getKey(KeyBinding.REFRESH_OO), "Refresh OO"); frame.getTabbedPane().getActionMap().put("Refresh OO", updateAction); + */ } diff --git a/src/main/java/org/jabref/gui/preftabs/TableColumnsTab.java b/src/main/java/org/jabref/gui/preftabs/TableColumnsTab.java index 6e600ed7e13..525b223b06e 100644 --- a/src/main/java/org/jabref/gui/preftabs/TableColumnsTab.java +++ b/src/main/java/org/jabref/gui/preftabs/TableColumnsTab.java @@ -614,12 +614,14 @@ public void actionPerformed(ActionEvent e) { final HashMap map = new HashMap<>(); // first element (#) not inside tableRows - for (int i = 1; i < panel.getMainTable().getColumnCount(); i++) { - String name = panel.getMainTable().getColumnName(i); + /* + for (TableColumn column : panel.getMainTable().getColumns()) { + String name = column.getText(); if ((name != null) && !name.isEmpty()) { map.put(name.toLowerCase(Locale.ROOT), i); } } + */ Collections.sort(tableRows, (o1, o2) -> { Integer n1 = map.get(o1.getName()); Integer n2 = map.get(o2.getName()); @@ -647,6 +649,7 @@ public void actionPerformed(ActionEvent e) { if (panel == null) { return; } + /* TableColumnModel colMod = panel.getMainTable().getColumnModel(); colSetup.setValueAt(String.valueOf(colMod.getColumn(0).getWidth()), 0, 1); for (int i = 1; i < colMod.getColumnCount(); i++) { @@ -669,6 +672,7 @@ public void actionPerformed(ActionEvent e) { colSetup.revalidate(); colSetup.repaint(); } + */ } } diff --git a/src/main/java/org/jabref/gui/preftabs/TablePrefsTab.java b/src/main/java/org/jabref/gui/preftabs/TablePrefsTab.java index 6d73757e08d..0ae9570d1c9 100644 --- a/src/main/java/org/jabref/gui/preftabs/TablePrefsTab.java +++ b/src/main/java/org/jabref/gui/preftabs/TablePrefsTab.java @@ -13,7 +13,6 @@ import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JRadioButton; -import javax.swing.JTable; import javax.swing.JTextField; import org.jabref.Globals; @@ -208,8 +207,7 @@ public TablePrefsTab(JabRefPreferences prefs) { @Override public void setValues() { - autoResizeMode - .setSelected(prefs.getInt(JabRefPreferences.AUTO_RESIZE_MODE) == JTable.AUTO_RESIZE_ALL_COLUMNS); + autoResizeMode.setSelected(prefs.getBoolean(JabRefPreferences.AUTO_RESIZE_MODE)); priField.setText(prefs.get(JabRefPreferences.TABLE_PRIMARY_SORT_FIELD)); secField.setText(prefs.get(JabRefPreferences.TABLE_SECONDARY_SORT_FIELD)); @@ -267,8 +265,7 @@ public void storeSettings() { prefs.putBoolean(JabRefPreferences.NAMES_LAST_ONLY, lastNamesOnly.isSelected()); prefs.putBoolean(JabRefPreferences.ABBR_AUTHOR_NAMES, abbrNames.isSelected()); - prefs.putInt(JabRefPreferences.AUTO_RESIZE_MODE, - autoResizeMode.isSelected() ? JTable.AUTO_RESIZE_ALL_COLUMNS : JTable.AUTO_RESIZE_OFF); + prefs.putBoolean(JabRefPreferences.AUTO_RESIZE_MODE, autoResizeMode.isSelected()); prefs.putBoolean(JabRefPreferences.TABLE_PRIMARY_SORT_DESCENDING, priDesc.isSelected()); prefs.putBoolean(JabRefPreferences.TABLE_SECONDARY_SORT_DESCENDING, secDesc.isSelected()); prefs.putBoolean(JabRefPreferences.TABLE_TERTIARY_SORT_DESCENDING, terDesc.isSelected()); diff --git a/src/main/java/org/jabref/gui/search/GlobalSearchBar.java b/src/main/java/org/jabref/gui/search/GlobalSearchBar.java index 5ded0d496b0..1ea33721900 100644 --- a/src/main/java/org/jabref/gui/search/GlobalSearchBar.java +++ b/src/main/java/org/jabref/gui/search/GlobalSearchBar.java @@ -18,7 +18,6 @@ import javax.swing.JPanel; import javax.swing.JToggleButton; import javax.swing.JToolBar; -import javax.swing.SwingUtilities; import javafx.css.PseudoClass; import javafx.embed.swing.JFXPanel; @@ -29,7 +28,6 @@ import javafx.scene.text.TextFlow; import org.jabref.Globals; -import org.jabref.gui.AbstractView; import org.jabref.gui.BasePanel; import org.jabref.gui.GUIGlobals; import org.jabref.gui.IconTheme; @@ -184,13 +182,8 @@ public void actionPerformed(ActionEvent e) { EasyBind.subscribe(searchField.textProperty(), searchText -> performSearch()); - container = CustomJFXPanel.create(); - DefaultTaskExecutor.runInJavaFXThread(() -> { - Scene scene = new Scene(searchField); - scene.getStylesheets().add(AbstractView.class.getResource("Main.css").toExternalForm()); - container.setScene(scene); - container.addKeyListener(new SearchKeyAdapter()); - }); + container = CustomJFXPanel.wrap(new Scene(searchField)); + container.addKeyListener(new SearchKeyAdapter()); setLayout(new FlowLayout(FlowLayout.RIGHT)); JToolBar toolBar = new OSXCompatibleToolbar(); @@ -284,9 +277,9 @@ public void endSearch() { if (currentBasePanel != null) { clearSearch(currentBasePanel); MainTable mainTable = frame.getCurrentBasePanel().getMainTable(); - Globals.getFocusListener().setFocused(mainTable); + //Globals.getFocusListener().setFocused(mainTable); mainTable.requestFocus(); - SwingUtilities.invokeLater(() -> mainTable.ensureVisible(mainTable.getSelectedRow())); + //SwingUtilities.invokeLater(() -> mainTable.ensureVisible(mainTable.getSelectedRow())); } } diff --git a/src/main/java/org/jabref/gui/search/SearchResultFrame.java b/src/main/java/org/jabref/gui/search/SearchResultFrame.java index 94b82a245d0..7b119820756 100644 --- a/src/main/java/org/jabref/gui/search/SearchResultFrame.java +++ b/src/main/java/org/jabref/gui/search/SearchResultFrame.java @@ -406,7 +406,7 @@ private void selectEntryInBasePanel(BibEntry entry) { BasePanel basePanel = entryHome.get(entry); frame.showBasePanel(basePanel); basePanel.requestFocus(); - basePanel.highlightEntry(entry); + basePanel.clearAndSelect(entry); } public void dispose() { diff --git a/src/main/java/org/jabref/gui/search/SearchWorker.java b/src/main/java/org/jabref/gui/search/SearchWorker.java index db3c4495cfc..0a67414f214 100644 --- a/src/main/java/org/jabref/gui/search/SearchWorker.java +++ b/src/main/java/org/jabref/gui/search/SearchWorker.java @@ -99,13 +99,14 @@ private void updateUIWithSearchResult(List matchedEntries) { List selectedEntries = basePanel.getSelectedEntries(); boolean isHitSelected = selectedEntries.stream().anyMatch(BibEntry::isSearchHit); if (!isHitSelected && !matchedEntries.isEmpty()) { - for (int i = 0; i < basePanel.getMainTable().getRowCount(); i++) { + /*for (int i = 0; i < basePanel.getMainTable().getRowCount(); i++) { BibEntry entry = basePanel.getMainTable().getEntryAt(i); if (entry.isSearchHit()) { basePanel.getMainTable().setSelected(i); break; } } + */ } } diff --git a/src/main/java/org/jabref/gui/shared/SharedDatabaseUIManager.java b/src/main/java/org/jabref/gui/shared/SharedDatabaseUIManager.java index 4825c7f0c05..a129af12f07 100644 --- a/src/main/java/org/jabref/gui/shared/SharedDatabaseUIManager.java +++ b/src/main/java/org/jabref/gui/shared/SharedDatabaseUIManager.java @@ -60,7 +60,6 @@ public void listen(ConnectionLostEvent connectionLostEvent) { } else if (answer == 1) { connectionLostEvent.getBibDatabaseContext().convertToLocalDatabase(); jabRefFrame.refreshTitleAndTabs(); - jabRefFrame.updateEnabledState(); jabRefFrame.output(Localization.lang("Working offline.")); } else { jabRefFrame.closeCurrentTab(); @@ -90,7 +89,7 @@ public void listen(SharedEntryNotPresentEvent event) { + "\n" + Localization.lang("You can restore the entry using the \"Undo\" operation."), Localization.lang("Shared entry is no longer present"), JOptionPane.INFORMATION_MESSAGE); - SwingUtilities.invokeLater(() -> panel.hideBottomComponent()); + SwingUtilities.invokeLater(() -> panel.closeBottomPane()); } } diff --git a/src/main/java/org/jabref/gui/util/BindingsHelper.java b/src/main/java/org/jabref/gui/util/BindingsHelper.java index 22b26f2db82..959190c060a 100644 --- a/src/main/java/org/jabref/gui/util/BindingsHelper.java +++ b/src/main/java/org/jabref/gui/util/BindingsHelper.java @@ -14,6 +14,7 @@ import javafx.beans.property.Property; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; +import javafx.collections.FXCollections; import javafx.collections.ListChangeListener; import javafx.collections.MapChangeListener; import javafx.collections.ObservableList; @@ -21,6 +22,7 @@ import javafx.css.PseudoClass; import javafx.scene.Node; +import org.fxmisc.easybind.PreboundBinding; /** * Helper methods for javafx binding. @@ -72,6 +74,19 @@ public static MappedList mapBacked(ObservableList source, Function(source, mapper); } + public static ObservableList map(ObservableValue source, Function> mapper) { + PreboundBinding> binding = new PreboundBinding>(source) { + @Override + protected List computeValue() { + return mapper.apply(source.getValue()); + } + }; + + ObservableList list = FXCollections.observableArrayList(); + binding.addListener((observable, oldValue, newValue) -> list.setAll(newValue)); + return list; + } + /** * Binds propertA bidirectional to propertyB using the provided map functions to convert between them. */ diff --git a/src/main/java/org/jabref/gui/util/ValueTableCellFactory.java b/src/main/java/org/jabref/gui/util/ValueTableCellFactory.java index 56dff50f25c..2d4892086de 100644 --- a/src/main/java/org/jabref/gui/util/ValueTableCellFactory.java +++ b/src/main/java/org/jabref/gui/util/ValueTableCellFactory.java @@ -13,7 +13,7 @@ /** * Constructs a {@link TableCell} based on the value of the cell and a bunch of specified converter methods. * - * @param view model + * @param view model of table row * @param cell value */ public class ValueTableCellFactory implements Callback, TableCell> { diff --git a/src/main/java/org/jabref/gui/util/ViewModelTableRowFactory.java b/src/main/java/org/jabref/gui/util/ViewModelTableRowFactory.java new file mode 100644 index 00000000000..4f43b5e072e --- /dev/null +++ b/src/main/java/org/jabref/gui/util/ViewModelTableRowFactory.java @@ -0,0 +1,39 @@ +package org.jabref.gui.util; + +import java.util.function.BiConsumer; + +import javafx.scene.control.TableRow; +import javafx.scene.control.TableView; +import javafx.scene.control.TreeTableCell; +import javafx.scene.input.MouseEvent; +import javafx.util.Callback; + +/** + * Constructs a {@link TreeTableCell} based on the view model of the row and a bunch of specified converter methods. + * + * @param view model + */ +public class ViewModelTableRowFactory implements Callback, TableRow> { + + private BiConsumer onMouseClickedEvent; + + public ViewModelTableRowFactory withOnMouseClickedEvent(BiConsumer onMouseClickedEvent) { + this.onMouseClickedEvent = onMouseClickedEvent; + return this; + } + + @Override + public TableRow call(TableView tableView) { + TableRow row = new TableRow<>(); + + if (onMouseClickedEvent != null) { + row.setOnMouseClicked(event -> { + if (!row.isEmpty()) { + onMouseClickedEvent.accept(row.getItem(), event); + } + }); + } + + return row; + } +} diff --git a/src/main/java/org/jabref/pdfimport/PdfImporter.java b/src/main/java/org/jabref/pdfimport/PdfImporter.java index f5273dbc88a..07e4d6df5de 100644 --- a/src/main/java/org/jabref/pdfimport/PdfImporter.java +++ b/src/main/java/org/jabref/pdfimport/PdfImporter.java @@ -133,7 +133,7 @@ private List importPdfFilesInternal(List fileNames) { if (dropRow >= 0) { dfh.linkPdfToEntry(fileName, entryTable, dropRow); } else { - dfh.linkPdfToEntry(fileName, entryTable, entryTable.getSelectedRow()); + entryTable.getSelectedEntries().forEach(entry -> dfh.linkPdfToEntry(fileName, entry)); } break; default: @@ -220,7 +220,7 @@ private void doContentImport(String fileName, List res) { DroppedFileHandler dfh = new DroppedFileHandler(frame, panel); dfh.linkPdfToEntry(fileName, entry); - SwingUtilities.invokeLater(() -> panel.highlightEntry(entry)); + SwingUtilities.invokeLater(() -> panel.clearAndSelect(entry)); if (Globals.prefs.getBoolean(JabRefPreferences.AUTO_OPEN_FORM)) { panel.showAndEdit(entry); diff --git a/src/main/java/org/jabref/preferences/JabRefPreferences.java b/src/main/java/org/jabref/preferences/JabRefPreferences.java index 6e31892613a..631f0b48f1a 100644 --- a/src/main/java/org/jabref/preferences/JabRefPreferences.java +++ b/src/main/java/org/jabref/preferences/JabRefPreferences.java @@ -31,7 +31,6 @@ import java.util.prefs.Preferences; import java.util.stream.Collectors; -import javax.swing.JTable; import javax.swing.UIManager; import org.jabref.JabRefException; @@ -502,8 +501,8 @@ private JabRefPreferences() { defaults.put(SIZE_X, 1024); defaults.put(SIZE_Y, 768); defaults.put(WINDOW_MAXIMISED, Boolean.FALSE); - defaults.put(AUTO_RESIZE_MODE, JTable.AUTO_RESIZE_ALL_COLUMNS); - defaults.put(ENTRY_EDITOR_HEIGHT, 400); + defaults.put(AUTO_RESIZE_MODE, Boolean.TRUE); + defaults.put(ENTRY_EDITOR_HEIGHT, 0.75); defaults.put(TABLE_COLOR_CODES_ON, Boolean.FALSE); defaults.put(TABLE_RESOLVED_COLOR_CODES_ON, Boolean.FALSE); defaults.put(NAMES_AS_IS, Boolean.FALSE); // "Show names unchanged" @@ -1033,7 +1032,7 @@ public int getIntDefault(String key) { } private double getDoubleDefault(String key) { - return (double) defaults.get(key); + return ((Number) defaults.get(key)).doubleValue(); } public void put(String key, String value) { @@ -1475,7 +1474,7 @@ public JabRefPreferences storePreviewPreferences(PreviewPreferences previewPrefe public PreviewPreferences getPreviewPreferences() { int cyclePos = getInt(CYCLE_PREVIEW_POS); List cycle = getStringList(CYCLE_PREVIEW); - int panelHeight = getInt(PREVIEW_PANEL_HEIGHT); + double panelHeight = getDouble(PREVIEW_PANEL_HEIGHT); String style = get(PREVIEW_STYLE); String styleDefault = (String) defaults.get(PREVIEW_STYLE); boolean enabled = getBoolean(PREVIEW_ENABLED); diff --git a/src/test/java/org/jabref/gui/search/SearchResultsTest.java b/src/test/java/org/jabref/gui/search/SearchResultsTest.java index add7153d26b..33def0c2c4e 100644 --- a/src/test/java/org/jabref/gui/search/SearchResultsTest.java +++ b/src/test/java/org/jabref/gui/search/SearchResultsTest.java @@ -1,12 +1,9 @@ package org.jabref.gui.search; -import java.util.Collection; import java.util.concurrent.TimeUnit; import javax.swing.JFrame; -import org.jabref.gui.BasePanel; -import org.jabref.model.entry.BibEntry; import org.jabref.testutils.TestUtils; import org.jabref.testutils.category.GUITest; @@ -16,7 +13,6 @@ import org.assertj.swing.fixture.FrameFixture; import org.assertj.swing.fixture.JTextComponentFixture; import org.assertj.swing.junit.testcase.AssertJSwingJUnitTestCase; -import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import org.junit.experimental.categories.Category; @@ -51,6 +47,7 @@ public void testSearchFieldQuery() { frameFixture.menuItemWithPath("Search", "Search").click(); JTextComponentFixture searchField = frameFixture.textBox(); ComponentFinder finder = robot().finder(); + /* BasePanel panel = finder.findByType(BasePanel.class); Collection entries = panel.getDatabase().getEntries(); @@ -68,10 +65,12 @@ public void testSearchFieldQuery() { searchField.deleteText().enterText("entrytype=book"); Assert.assertFalse(entries.stream().noneMatch(entry -> entry.isSearchHit())); Assert.assertEquals(1, entries.stream().filter(entry -> entry.isSearchHit()).count()); + */ } @Test public void testSeachWithoutResults() { + /* frameFixture.menuItemWithPath("Search", "Search").click(); JTextComponentFixture searchField = frameFixture.textBox(); ComponentFinder finder = robot().finder(); @@ -80,10 +79,12 @@ public void testSeachWithoutResults() { searchField.deleteText().enterText("asdf"); Assert.assertTrue(entries.stream().noneMatch(entry -> entry.isSearchHit())); + */ } @Test public void testSearchInvalidQuery() { + /* frameFixture.menuItemWithPath("Search", "Search").click(); JTextComponentFixture searchField = frameFixture.textBox(); ComponentFinder finder = robot().finder(); @@ -92,6 +93,7 @@ public void testSearchInvalidQuery() { searchField.deleteText().enterText("asdf["); Assert.assertTrue(entries.stream().noneMatch(entry -> entry.isSearchHit())); + */ } } From b2335176959afaad7a48122608350edaf90aa030 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sun, 31 Dec 2017 12:49:26 +0100 Subject: [PATCH 05/24] Add new classes --- .../gui/maintable/BibEntryTableViewModel.java | 46 ++++ .../jabref/gui/maintable/ColumnFactory.java | 207 ++++++++++++++++++ .../gui/maintable/StringTableColumn.java | 158 +++++++++++++ 3 files changed, 411 insertions(+) create mode 100644 src/main/java/org/jabref/gui/maintable/BibEntryTableViewModel.java create mode 100644 src/main/java/org/jabref/gui/maintable/ColumnFactory.java create mode 100644 src/main/java/org/jabref/gui/maintable/StringTableColumn.java diff --git a/src/main/java/org/jabref/gui/maintable/BibEntryTableViewModel.java b/src/main/java/org/jabref/gui/maintable/BibEntryTableViewModel.java new file mode 100644 index 00000000000..61e02904f88 --- /dev/null +++ b/src/main/java/org/jabref/gui/maintable/BibEntryTableViewModel.java @@ -0,0 +1,46 @@ +package org.jabref.gui.maintable; + +import java.util.List; +import java.util.Optional; + +import javafx.beans.binding.ObjectBinding; +import javafx.beans.value.ObservableValue; + +import org.jabref.gui.specialfields.SpecialFieldValueViewModel; +import org.jabref.model.database.BibDatabase; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.FieldName; +import org.jabref.model.entry.FileFieldParser; +import org.jabref.model.entry.LinkedFile; +import org.jabref.model.entry.specialfields.SpecialField; + +import org.fxmisc.easybind.EasyBind; + +public class BibEntryTableViewModel { + private final BibEntry entry; + + public BibEntryTableViewModel(BibEntry entry) { + this.entry = entry; + } + + public BibEntry getEntry() { + return entry; + } + + public Optional getResolvedFieldOrAlias(String field, BibDatabase database) { + return entry.getResolvedFieldOrAlias(field, database); + } + + public ObjectBinding getField(String fieldName) { + return entry.getFieldBinding(fieldName); + } + + public ObservableValue> getSpecialField(SpecialField field) { + return EasyBind.map(getField(field.getFieldName()), + value -> field.parse(value).map(SpecialFieldValueViewModel::new)); + } + + public ObservableValue> getLinkedFiles() { + return EasyBind.map(getField(FieldName.FILE), FileFieldParser::parse); + } +} diff --git a/src/main/java/org/jabref/gui/maintable/ColumnFactory.java b/src/main/java/org/jabref/gui/maintable/ColumnFactory.java new file mode 100644 index 00000000000..b93b5dff34c --- /dev/null +++ b/src/main/java/org/jabref/gui/maintable/ColumnFactory.java @@ -0,0 +1,207 @@ +package org.jabref.gui.maintable; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import javafx.scene.Node; +import javafx.scene.control.TableColumn; + +import org.jabref.Globals; +import org.jabref.gui.IconTheme; +import org.jabref.gui.JabRefIcon; +import org.jabref.gui.externalfiletype.ExternalFileType; +import org.jabref.gui.externalfiletype.ExternalFileTypes; +import org.jabref.gui.specialfields.SpecialFieldValueViewModel; +import org.jabref.gui.specialfields.SpecialFieldViewModel; +import org.jabref.gui.util.ValueTableCellFactory; +import org.jabref.model.database.BibDatabase; +import org.jabref.model.entry.FieldName; +import org.jabref.model.entry.LinkedFile; +import org.jabref.model.entry.specialfields.SpecialField; +import org.jabref.preferences.JabRefPreferences; + +import org.fxmisc.easybind.EasyBind; + +class ColumnFactory { + + private static final String STYLE_ICON = "column-icon"; + + private final ExternalFileTypes externalFileTypes; + private final BibDatabase database; + private final CellFactory cellFactory; + + public ColumnFactory(BibDatabase database) { + this.database = database; + externalFileTypes = ExternalFileTypes.getInstance(); + cellFactory = new CellFactory(); + } + + public List> createColumns() { + List> columns = new ArrayList<>(); + + // Add column for linked files + if (Globals.prefs.getBoolean(JabRefPreferences.FILE_COLUMN)) { + columns.add(createFileColumn()); + } + + // Add column for DOI/URL + if (Globals.prefs.getBoolean(JabRefPreferences.URL_COLUMN)) { + if (Globals.prefs.getBoolean(JabRefPreferences.PREFER_URL_DOI)) { + columns.add(createIconColumn(IconTheme.JabRefIcons.DOI, FieldName.DOI, FieldName.URL)); + } else { + columns.add(createIconColumn(IconTheme.JabRefIcons.WWW, FieldName.URL, FieldName.DOI)); + } + } + + // Add column for eprints + if (Globals.prefs.getBoolean(JabRefPreferences.ARXIV_COLUMN)) { + columns.add(createIconColumn(IconTheme.JabRefIcons.WWW, FieldName.EPRINT)); + } + + // Add columns for other file types + if (Globals.prefs.getBoolean(JabRefPreferences.EXTRA_FILE_COLUMNS)) { + List desiredColumns = Globals.prefs.getStringList(JabRefPreferences.LIST_OF_FILE_COLUMNS); + for (String desiredColumn : desiredColumns) { + columns.add(createExtraFileColumn(desiredColumn)); + } + } + + // Add 'normal' bibtex fields as configured in the preferences + columns.addAll(createNormalColumns()); + + // Add the "special" icon columns (e.g., ranking, file, ...) that are enabled in preferences + if (Globals.prefs.getBoolean(JabRefPreferences.SPECIALFIELDSENABLED)) { + if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_RANKING)) { + columns.add(createSpecialFieldColumn(SpecialField.RANKING)); + } + if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_RELEVANCE)) { + columns.add(createSpecialFieldColumn(SpecialField.RELEVANCE)); + } + if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_QUALITY)) { + columns.add(createSpecialFieldColumn(SpecialField.QUALITY)); + } + + if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_PRIORITY)) { + columns.add(createSpecialFieldColumn(SpecialField.PRIORITY)); + } + + if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_PRINTED)) { + columns.add(createSpecialFieldColumn(SpecialField.PRINTED)); + } + + if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_READ)) { + columns.add(createSpecialFieldColumn(SpecialField.READ_STATUS)); + } + } + + return columns; + } + + private List> createNormalColumns() { + List> columns = new ArrayList<>(); + + // Read table columns from preferences + List columnSettings = Globals.prefs.getStringList(JabRefPreferences.COLUMN_NAMES); + for (String columnName : columnSettings) { + // Stored column name will be used as header + // There might be more than one field to display, e.g., "author/editor" or "date/year" - so split + String[] fields = columnName.split(FieldName.FIELD_SEPARATOR); + columns.add(new StringTableColumn(columnName, Arrays.asList(fields), database)); + } + return columns; + } + + private TableColumn> createSpecialFieldColumn(SpecialField specialField) { + TableColumn> column = new TableColumn<>(); + column.setGraphic(new SpecialFieldViewModel(specialField).getIcon().getGraphicNode()); + column.getStyleClass().add(STYLE_ICON); + column.setMinWidth(30); + column.setMaxWidth(30); + column.setCellValueFactory(cellData -> cellData.getValue().getSpecialField(specialField)); + column.setCellFactory( + new ValueTableCellFactory>() + .withGraphic(param -> param.map(specialFieldValue -> specialFieldValue.getIcon().getGraphicNode()).orElse(null))); + + return column; + } + + private TableColumn> createFileColumn() { + TableColumn> column = new TableColumn<>(); + column.setGraphic(IconTheme.JabRefIcons.FILE.getGraphicNode()); + column.getStyleClass().add(STYLE_ICON); + column.setMinWidth(30); + column.setMaxWidth(30); + column.setCellValueFactory(cellData -> cellData.getValue().getLinkedFiles()); + column.setCellFactory( + new ValueTableCellFactory>() + .withGraphic(this::createFileIcon)); + return column; + } + + /** + * Creates a column which shows an icon instead of the textual content + */ + private TableColumn createIconColumn(JabRefIcon icon, String firstField, String secondField) { + TableColumn column = new TableColumn<>(); + column.setGraphic(icon.getGraphicNode()); + column.getStyleClass().add(STYLE_ICON); + column.setMinWidth(30); + column.setMaxWidth(30); + column.setCellValueFactory(cellData -> EasyBind.monadic(cellData.getValue().getField(firstField)).orElse(cellData.getValue().getField(secondField))); + column.setCellFactory( + new ValueTableCellFactory() + .withGraphic(cellFactory::getTableIcon)); + return column; + } + + private TableColumn createIconColumn(JabRefIcon icon, String field) { + TableColumn column = new TableColumn<>(); + column.setGraphic(icon.getGraphicNode()); + column.getStyleClass().add(STYLE_ICON); + column.setMinWidth(30); + column.setMaxWidth(30); + column.setCellValueFactory(cellData -> cellData.getValue().getField(field)); + column.setCellFactory( + new ValueTableCellFactory() + .withGraphic(cellFactory::getTableIcon)); + return column; + } + + /** + * Creates a column for specific file types. Shows the icon for the given type (or the FILE_MULTIPLE icon) + * + * @param externalFileTypeName the name of the externalFileType + */ + private TableColumn> createExtraFileColumn(String externalFileTypeName) { + TableColumn> column = new TableColumn<>(); + column.setGraphic( + externalFileTypes.getExternalFileTypeByName(externalFileTypeName) + .map(ExternalFileType::getIcon).orElse(IconTheme.JabRefIcons.FILE) + .getGraphicNode()); + column.getStyleClass().add(STYLE_ICON); + column.setMinWidth(30); + column.setMaxWidth(30); + column.setCellValueFactory(cellData -> cellData.getValue().getLinkedFiles()); + column.setCellFactory( + new ValueTableCellFactory>() + .withGraphic(linkedFiles -> createFileIcon(linkedFiles.stream().filter(linkedFile -> linkedFile.getFileType().equalsIgnoreCase(externalFileTypeName)).collect(Collectors.toList())))); + + return column; + } + + private Node createFileIcon(List linkedFiles) { + if (linkedFiles.size() > 1) { + return IconTheme.JabRefIcons.FILE_MULTIPLE.getGraphicNode(); + } else if (linkedFiles.size() == 1) { + return externalFileTypes.fromLinkedFile(linkedFiles.get(0), false) + .map(ExternalFileType::getIcon) + .orElse(IconTheme.JabRefIcons.FILE) + .getGraphicNode(); + } else { + return null; + } + } +} diff --git a/src/main/java/org/jabref/gui/maintable/StringTableColumn.java b/src/main/java/org/jabref/gui/maintable/StringTableColumn.java new file mode 100644 index 00000000000..7b6bfaa0e65 --- /dev/null +++ b/src/main/java/org/jabref/gui/maintable/StringTableColumn.java @@ -0,0 +1,158 @@ +package org.jabref.gui.maintable; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.StringJoiner; + +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.value.ObservableValue; +import javafx.scene.Node; +import javafx.scene.control.Label; + +import org.jabref.gui.JabRefIcon; +import org.jabref.logic.layout.LayoutFormatter; +import org.jabref.logic.layout.format.LatexToUnicodeFormatter; +import org.jabref.model.database.BibDatabase; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.FieldName; +import org.jabref.model.entry.FieldProperty; +import org.jabref.model.entry.InternalBibtexFields; + +public class StringTableColumn extends MainTableColumn { + + private final List bibtexFields; + + private final boolean isIconColumn; + + private final Optional iconLabel; + + private final Optional database; + + private final LayoutFormatter toUnicode = new LatexToUnicodeFormatter(); + + public StringTableColumn(String columnName) { + super(columnName); + this.bibtexFields = Collections.emptyList(); + this.isIconColumn = false; + this.iconLabel = Optional.empty(); + this.database = Optional.empty(); + } + + public StringTableColumn(String columnName, List bibtexFields, BibDatabase database) { + super(columnName); + this.bibtexFields = Collections.unmodifiableList(bibtexFields); + this.isIconColumn = false; + this.iconLabel = Optional.empty(); + this.database = Optional.of(database); + } + + public StringTableColumn(String columnName, List bibtexFields, JabRefIcon iconLabel) { + super(columnName); + this.bibtexFields = Collections.unmodifiableList(bibtexFields); + this.isIconColumn = true; + this.iconLabel = Optional.of(iconLabel); + this.database = Optional.empty(); + } + + /** + * Get the table column name to be displayed in the UI + * + * @return name to be displayed. null if field is empty. + */ + public String getDisplayName() { + if (bibtexFields.isEmpty()) { + return null; + } + + StringJoiner joiner = new StringJoiner(FieldName.FIELD_SEPARATOR); + for (String field : bibtexFields) { + joiner.add(field); + } + return joiner.toString(); + } + + public List getBibtexFields() { + return bibtexFields; + } + + public boolean isIconColumn() { + return isIconColumn; + } + + public boolean isFileFilter() { + return false; // Overridden in SpecialMainTableColumns for file filter columns + } + + @Override + public ObservableValue getColumnValue(BibEntryTableViewModel entry) { + if (bibtexFields.isEmpty()) { + return null; + } + boolean isNameColumn = false; + + Optional content = Optional.empty(); + for (String field : bibtexFields) { + content = entry.getResolvedFieldOrAlias(field, database.orElse(null)); + if (content.isPresent()) { + isNameColumn = InternalBibtexFields.getFieldProperties(field).contains(FieldProperty.PERSON_NAMES); + break; + } + } + + String result = content.orElse(null); + + if (isNameColumn) { + result = toUnicode.format(MainTableNameFormatter.formatName(result)); + } + + if (result != null && !bibtexFields.contains(BibEntry.KEY_FIELD)) { + result = toUnicode.format(result).trim(); + } + + return new SimpleStringProperty(result); + } + + public Node getHeaderLabel() { + if (isIconColumn) { + return iconLabel.map(JabRefIcon::getGraphicNode).get(); + } else { + return new Label(getDisplayName()); + } + } + + /** + * Check if the value returned by getColumnValue() is the same as a simple check of the entry's field(s) would give + * The reasons for being different are (combinations may also happen): - The entry has a crossref where the field + * content is obtained from - The field has a string in it (which getColumnValue() resolves) - There are some alias + * fields. For example, if the entry has a date field but no year field, {@link + * BibEntry#getResolvedFieldOrAlias(String, BibDatabase)} will return the year value from the date field when + * queried for year + * + * @param entry the BibEntry + * @return true if the value returned by getColumnValue() is resolved as outlined above + */ + public boolean isResolved(BibEntry entry) { + if (bibtexFields.isEmpty()) { + return false; + } + + Optional resolvedFieldContent = Optional.empty(); + Optional plainFieldContent = Optional.empty(); + for (String field : bibtexFields) { + // entry type or bibtex key will never be resolved + if (BibEntry.TYPE_HEADER.equals(field) || BibEntry.OBSOLETE_TYPE_HEADER.equals(field) + || BibEntry.KEY_FIELD.equals(field)) { + return false; + } else { + plainFieldContent = entry.getField(field); + resolvedFieldContent = entry.getResolvedFieldOrAlias(field, database.orElse(null)); + } + + if (resolvedFieldContent.isPresent()) { + break; + } + } + return (!resolvedFieldContent.equals(plainFieldContent)); + } +} From c2b70c3fe8ec92ebcd1fa4e936262ffac056a4b6 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 1 Jan 2018 15:21:43 +0100 Subject: [PATCH 06/24] Hold reference of divider pane position binding --- src/main/java/org/jabref/gui/BasePanel.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jabref/gui/BasePanel.java b/src/main/java/org/jabref/gui/BasePanel.java index 4eced8b9227..21bfd44fb1b 100644 --- a/src/main/java/org/jabref/gui/BasePanel.java +++ b/src/main/java/org/jabref/gui/BasePanel.java @@ -141,6 +141,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.fxmisc.easybind.EasyBind; +import org.fxmisc.easybind.Subscription; public class BasePanel extends StackPane implements ClipboardOwner { @@ -187,6 +188,8 @@ public class BasePanel extends StackPane implements ClipboardOwner { private StringDialog stringDialog; private SuggestionProviders suggestionProviders; + private Subscription dividerPositionSubscription; + // the query the user searches when this BasePanel is active private Optional currentSearchQuery = Optional.empty(); @@ -232,7 +235,7 @@ public BasePanel(JabRefFrame frame, BibDatabaseContext bibDatabaseContext) { this.getDatabase().registerListener(new UpdateTimestampListener(Globals.prefs)); - entryEditor = new EntryEditor(this); + this.entryEditor = new EntryEditor(this); this.preview = new PreviewPanel(this, getBibDatabaseContext()); DefaultTaskExecutor.runInJavaFXThread(() -> frame().getGlobalSearchBar().getSearchQueryHighlightObservable().addSearchListener(preview)); @@ -346,7 +349,7 @@ private void setupActions() { new SaveSelectedAction(SavePreferences.DatabaseSaveType.PLAIN_BIBTEX)); // The action for copying selected entries. - actions.put(Actions.COPY, (BaseAction) () -> copy()); + actions.put(Actions.COPY, (BaseAction) this::copy); actions.put(Actions.PRINT_PREVIEW, new PrintPreviewAction()); @@ -362,7 +365,7 @@ private void setupActions() { // This allows you to (a) paste entire bibtex entries from a text editor, web browser, etc // (b) copy and paste entries between multiple instances of JabRef (since // only the text representation seems to get as far as the X clipboard, at least on my system) - actions.put(Actions.PASTE, (BaseAction) () -> paste()); + actions.put(Actions.PASTE, (BaseAction) this::paste); actions.put(Actions.SELECT_ALL, (BaseAction) mainTable.getSelectionModel()::selectAll); @@ -1342,7 +1345,8 @@ public void setupMainPanel() { mainTable.showFloatSearch(); } // Saves the divider position as soon as it changes - EasyBind.monadic(Bindings.valueAt(splitPane.getDividers(), 0)) + // We need to keep a reference to the subscription, otherwise the binding gets garbage collected + dividerPositionSubscription = EasyBind.monadic(Bindings.valueAt(splitPane.getDividers(), 0)) .flatMap(SplitPane.Divider::positionProperty) .subscribe((observable, oldValue, newValue) -> saveDividerLocation(newValue)); } From 452147d241d0995631f2c9a20b14cf1a5b86ece9 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 1 Jan 2018 22:58:39 +0100 Subject: [PATCH 07/24] Fix divider location storage --- build.gradle | 4 +- src/main/java/org/jabref/gui/BasePanel.java | 72 +++++++----- .../org/jabref/gui/BasePanelPreferences.java | 80 +++++++++++++ .../org/jabref/gui/GenFieldsCustomizer.java | 10 +- src/main/java/org/jabref/gui/JabRefFrame.java | 13 ++- .../java/org/jabref/gui/PreviewPanel.java | 69 ++++++----- .../gui/actions/NewSubDatabaseAction.java | 4 +- .../ResolveDuplicateLabelDialog.java | 2 +- .../gui/collab/EntryAddChangeViewModel.java | 3 +- .../collab/EntryDeleteChangeViewModel.java | 3 +- .../jabref/gui/entryeditor/EntryEditor.java | 28 +++-- .../entryeditor/EntryEditorPreferences.java | 69 +++++++++++ .../gui/entryeditor/EntryEditorTabList.java | 49 +++----- .../gui/entryeditor/FieldsEditorTab.java | 6 + .../gui/entryeditor/OtherFieldsTab.java | 8 +- .../gui/entryeditor/RelatedArticlesTab.java | 6 +- .../org/jabref/gui/entryeditor/SourceTab.java | 13 +-- .../gui/importer/ImportInspectionDialog.java | 6 +- .../importer/actions/OpenDatabaseAction.java | 4 +- .../org/jabref/gui/maintable/CellFactory.java | 4 +- .../jabref/gui/maintable/ColumnFactory.java | 56 +++------ .../gui/maintable/ColumnPreferences.java | 107 ++++++++++++++++++ .../org/jabref/gui/maintable/MainTable.java | 19 ++-- .../gui/maintable/MainTablePreferences.java | 36 ++++++ .../jabref/gui/menus/ChangeEntryTypeMenu.java | 20 ++-- .../org/jabref/gui/menus/RightClickMenu.java | 2 +- .../jabref/gui/mergeentries/MergeEntries.java | 2 +- .../gui/openoffice/StyleSelectDialog.java | 2 +- .../jabref/gui/preftabs/PreviewPrefsTab.java | 4 +- .../jabref/gui/search/SearchResultFrame.java | 2 +- .../SpecialFieldDatabaseChangeListener.java | 13 +-- .../migrations/FileLinksUpgradeWarning.java | 14 +-- .../jabref/preferences/JabRefPreferences.java | 6 +- .../preferences/PreviewPreferences.java | 10 ++ .../java/org/jabref/gui/BasePanelTest.java | 69 +++++++++++ .../gui/entryeditor/EntryEditorTest.java | 38 ++++--- 36 files changed, 603 insertions(+), 250 deletions(-) create mode 100644 src/main/java/org/jabref/gui/BasePanelPreferences.java create mode 100644 src/main/java/org/jabref/gui/entryeditor/EntryEditorPreferences.java create mode 100644 src/main/java/org/jabref/gui/maintable/ColumnPreferences.java create mode 100644 src/main/java/org/jabref/gui/maintable/MainTablePreferences.java create mode 100644 src/test/java/org/jabref/gui/BasePanelTest.java diff --git a/build.gradle b/build.gradle index d7d66b3d18f..48cc742b8c3 100644 --- a/build.gradle +++ b/build.gradle @@ -169,7 +169,7 @@ dependencies { testCompile 'com.tngtech.archunit:archunit-junit:0.5.0' testCompile 'org.slf4j:slf4j-jcl:1.7.25' // required by ArchUnit to enable logging over jcl testCompile "org.testfx:testfx-core:4.0.+" - testCompile "org.testfx:testfx-junit:4.0.+" + testCompile "org.testfx:testfx-junit5:4.0.+" checkstyle 'com.puppycrawl.tools:checkstyle:8.5' } @@ -503,7 +503,7 @@ task releaseJar(dependsOn: "shadowJar") { } } // set executable with read permissions (first true) and for all (false) - file("$buildDir/releases/JabRef-${project.version}.jar").setExecutable(true, false); + file("$buildDir/releases/JabRef-${project.version}.jar").setExecutable(true, false) } } diff --git a/src/main/java/org/jabref/gui/BasePanel.java b/src/main/java/org/jabref/gui/BasePanel.java index 5da42396d01..27de1eee72e 100644 --- a/src/main/java/org/jabref/gui/BasePanel.java +++ b/src/main/java/org/jabref/gui/BasePanel.java @@ -43,7 +43,6 @@ import org.jabref.JabRefExecutorService; import org.jabref.gui.actions.Actions; import org.jabref.gui.actions.BaseAction; -import org.jabref.gui.actions.CleanupAction; import org.jabref.gui.actions.CopyBibTeXKeyAndLinkAction; import org.jabref.gui.autocompleter.AutoCompletePreferences; import org.jabref.gui.autocompleter.AutoCompleteUpdater; @@ -92,7 +91,6 @@ import org.jabref.gui.worker.AbstractWorker; import org.jabref.gui.worker.CallBack; import org.jabref.gui.worker.CitationStyleToClipboardWorker; -import org.jabref.gui.worker.MarkEntriesAction; import org.jabref.gui.worker.SendAsEMailAction; import org.jabref.logic.bibtexkeypattern.BibtexKeyPatternUtil; import org.jabref.logic.citationstyle.CitationStyleCache; @@ -138,6 +136,7 @@ import com.google.common.eventbus.Subscribe; import com.jgoodies.forms.builder.FormBuilder; import com.jgoodies.forms.layout.FormLayout; +import org.apache.commons.lang3.NotImplementedException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.fxmisc.easybind.EasyBind; @@ -164,6 +163,8 @@ public class BasePanel extends StackPane implements ClipboardOwner { private final Map actions = new HashMap<>(); private final SidePaneManager sidePaneManager; private final PreviewPanel preview; + private final BasePanelPreferences preferences; + private final ExternalFileTypes externalFileTypes; // To contain instantiated entry editors. This is to save time // As most enums, this must not be null @@ -195,25 +196,21 @@ public class BasePanel extends StackPane implements ClipboardOwner { private Optional changeMonitor = Optional.empty(); - public BasePanel(JabRefFrame frame, BibDatabaseContext bibDatabaseContext) { - Objects.requireNonNull(frame); - Objects.requireNonNull(bibDatabaseContext); + public BasePanel(JabRefFrame frame, BasePanelPreferences preferences, BibDatabaseContext bibDatabaseContext, ExternalFileTypes externalFileTypes) { + this.preferences = Objects.requireNonNull(preferences); + this.frame = Objects.requireNonNull(frame); + this.bibDatabaseContext = Objects.requireNonNull(bibDatabaseContext); + this.externalFileTypes = Objects.requireNonNull(externalFileTypes); - this.bibDatabaseContext = bibDatabaseContext; bibDatabaseContext.getDatabase().registerListener(this); bibDatabaseContext.getMetaData().registerListener(this); this.sidePaneManager = frame.getSidePaneManager(); - this.frame = frame; this.tableModel = new MainTableDataModel(getBibDatabaseContext()); citationStyleCache = new CitationStyleCache(bibDatabaseContext); annotationCache = new FileAnnotationCache(bibDatabaseContext); - this.preview = new PreviewPanel(this, getBibDatabaseContext()); - DefaultTaskExecutor.runInJavaFXThread(() -> frame().getGlobalSearchBar().getSearchQueryHighlightObservable().addSearchListener(preview)); - this.previewContainer = CustomJFXPanel.wrap(new Scene(preview)); - setupMainPanel(); setupActions(); @@ -239,9 +236,9 @@ public BasePanel(JabRefFrame frame, BibDatabaseContext bibDatabaseContext) { this.getDatabase().registerListener(new UpdateTimestampListener(Globals.prefs)); - this.entryEditor = new EntryEditor(this); + this.entryEditor = new EntryEditor(this, preferences.getEntryEditorPreferences()); - this.preview = new PreviewPanel(this, getBibDatabaseContext()); + this.preview = new PreviewPanel(this, getBibDatabaseContext(), preferences.getKeyBindings(), preferences.getPreviewPreferences()); DefaultTaskExecutor.runInJavaFXThread(() -> frame().getGlobalSearchBar().getSearchQueryHighlightObservable().addSearchListener(preview)); } @@ -267,7 +264,8 @@ public static void runWorker(AbstractWorker worker) throws Exception { @Subscribe public void listen(BibDatabaseContextChangedEvent event) { - SwingUtilities.invokeLater(() -> this.markBaseChanged()); + // TODO: + //SwingUtilities.invokeLater(() -> this.markBaseChanged()); } @@ -330,7 +328,8 @@ public void output(String s) { private void setupActions() { SaveDatabaseAction saveAction = new SaveDatabaseAction(this); - CleanupAction cleanUpAction = new CleanupAction(this, Globals.prefs); + // TODO + //CleanupAction cleanUpAction = new CleanupAction(this, Globals.prefs); actions.put(Actions.UNDO, undoAction); actions.put(Actions.REDO, redoAction); @@ -486,7 +485,7 @@ public void update() { }); // The action for cleaning up entry. - actions.put(Actions.CLEANUP, cleanUpAction); + //actions.put(Actions.CLEANUP, cleanUpAction); actions.put(Actions.MERGE_ENTRIES, (BaseAction) () -> new MergeEntriesDialog(BasePanel.this)); @@ -602,7 +601,8 @@ public void update() { } }); - actions.put(Actions.MARK_ENTRIES, new MarkEntriesAction(frame, 0)); + // TODO + //actions.put(Actions.MARK_ENTRIES, new MarkEntriesAction(frame, 0)); actions.put(Actions.UNMARK_ENTRIES, (BaseAction) () -> { try { @@ -1218,7 +1218,7 @@ private void createMainTable() { bibDatabaseContext.getDatabase().registerListener(tableModel.getListSynchronizer()); bibDatabaseContext.getDatabase().registerListener(SpecialFieldDatabaseChangeListener.getInstance()); - mainTable = new MainTable(tableModel, frame, this, bibDatabaseContext.getDatabase()); + mainTable = new MainTable(tableModel, frame, this, bibDatabaseContext.getDatabase(), preferences.getTablePreferences(), externalFileTypes); mainTable.updateFont(); @@ -1359,7 +1359,7 @@ public void setupMainPanel() { * Set up auto completion for this database */ private void setupAutoCompletion() { - AutoCompletePreferences autoCompletePreferences = Globals.prefs.getAutoCompletePreferences(); + AutoCompletePreferences autoCompletePreferences = preferences.getAutoCompletePreferences(); if (autoCompletePreferences.shouldAutoComplete()) { suggestionProviders = new SuggestionProviders(autoCompletePreferences, Globals.journalAbbreviationLoader); suggestionProviders.indexDatabase(getDatabase()); @@ -1401,11 +1401,11 @@ public void updateStringDialog() { } } - public void adjustSplitter() { + private void adjustSplitter() { if (mode == BasePanelMode.SHOWING_PREVIEW) { splitPane.setDividerPositions(Globals.prefs.getPreviewPreferences().getPreviewPanelDividerPosition().doubleValue()); - } else { - splitPane.setDividerPositions(Globals.prefs.getDouble(JabRefPreferences.ENTRY_EDITOR_HEIGHT)); + } else if (mode == BasePanelMode.SHOWING_EDITOR) { + splitPane.setDividerPositions(preferences.getEntryEditorDividerPosition()); } } @@ -1421,8 +1421,7 @@ public EntryEditor getEntryEditor() { * @param entry The entry to edit. */ public void showAndEdit(BibEntry entry) { - mode = BasePanelMode.SHOWING_EDITOR; - showBottomPane(entryEditor); + showBottomPane(BasePanelMode.SHOWING_EDITOR); if (entry != getShowing()) { entryEditor.setEntry(entry); @@ -1431,12 +1430,27 @@ public void showAndEdit(BibEntry entry) { entryEditor.requestFocus(); } - private void showBottomPane(Node pane) { + private void showBottomPane(BasePanelMode newMode) { + Node pane; + switch (newMode) { + case SHOWING_PREVIEW: + pane = preview; + break; + case SHOWING_EDITOR: + pane = entryEditor; + break; + default: + throw new NotImplementedException("new mode not recognized: " + newMode.name()); + } + if (splitPane.getItems().size() == 2) { splitPane.getItems().set(1, pane); } else { splitPane.getItems().add(1, pane); } + + mode = newMode; + adjustSplitter(); } @@ -1452,8 +1466,7 @@ private void showAndEdit() { * @param entry The entry to show in the preview. */ private void showPreview(BibEntry entry) { - mode = BasePanelMode.SHOWING_PREVIEW; - showBottomPane(preview); + showBottomPane(BasePanelMode.SHOWING_PREVIEW); preview.setEntry(entry); } @@ -1720,7 +1733,7 @@ private void saveDividerLocation(Number position) { .build(); Globals.prefs.storePreviewPreferences(previewPreferences); } else if (mode == BasePanelMode.SHOWING_EDITOR) { - Globals.prefs.putDouble(JabRefPreferences.ENTRY_EDITOR_HEIGHT, position.doubleValue()); + preferences.setEntryEditorDividerPosition(position.doubleValue()); } } @@ -1979,12 +1992,15 @@ public void listen(EntryAddedEvent addedEntryEvent) { return; } + // TODO: // Automatically add new entry to the selected group (or set of groups) + /* if (Globals.prefs.getBoolean(JabRefPreferences.AUTO_ASSIGN_GROUP)) { final List entries = Collections.singletonList(addedEntryEvent.getBibEntry()); Globals.stateManager.getSelectedGroup(bibDatabaseContext).forEach( selectedGroup -> selectedGroup.addEntriesToGroup(entries)); } + */ } } diff --git a/src/main/java/org/jabref/gui/BasePanelPreferences.java b/src/main/java/org/jabref/gui/BasePanelPreferences.java new file mode 100644 index 00000000000..52415e959b4 --- /dev/null +++ b/src/main/java/org/jabref/gui/BasePanelPreferences.java @@ -0,0 +1,80 @@ +package org.jabref.gui; + +import javafx.beans.property.DoubleProperty; +import javafx.beans.property.SimpleDoubleProperty; + +import org.jabref.Globals; +import org.jabref.gui.autocompleter.AutoCompletePreferences; +import org.jabref.gui.entryeditor.EntryEditorPreferences; +import org.jabref.gui.keyboard.KeyBindingRepository; +import org.jabref.gui.maintable.MainTablePreferences; +import org.jabref.preferences.JabRefPreferences; +import org.jabref.preferences.PreviewPreferences; + +import org.fxmisc.easybind.EasyBind; + +public class BasePanelPreferences { + private MainTablePreferences tablePreferences; + private AutoCompletePreferences autoCompletePreferences; + private EntryEditorPreferences entryEditorPreferences; + private KeyBindingRepository keyBindings; + private PreviewPreferences previewPreferences; + private DoubleProperty entryEditorDividerPosition = new SimpleDoubleProperty(); + + public BasePanelPreferences(MainTablePreferences tablePreferences, AutoCompletePreferences autoCompletePreferences, EntryEditorPreferences entryEditorPreferences, KeyBindingRepository keyBindings, PreviewPreferences previewPreferences, Double entryEditorDividerPosition) { + this.tablePreferences = tablePreferences; + this.autoCompletePreferences = autoCompletePreferences; + this.entryEditorPreferences = entryEditorPreferences; + this.keyBindings = keyBindings; + this.previewPreferences = previewPreferences; + this.entryEditorDividerPosition.setValue(entryEditorDividerPosition); + } + + public static BasePanelPreferences from(JabRefPreferences preferences) { + BasePanelPreferences basePanelPreferences = new BasePanelPreferences( + MainTablePreferences.from(preferences), + preferences.getAutoCompletePreferences(), + EntryEditorPreferences.from(preferences), + Globals.getKeyPrefs(), + preferences.getPreviewPreferences(), + preferences.getDouble(JabRefPreferences.ENTRY_EDITOR_HEIGHT)); + EasyBind.subscribe(basePanelPreferences.entryEditorDividerPosition, value -> preferences.putDouble(JabRefPreferences.ENTRY_EDITOR_HEIGHT, value.doubleValue())); + return basePanelPreferences; + } + + public double getEntryEditorDividerPosition() { + return entryEditorDividerPosition.get(); + } + + public void setEntryEditorDividerPosition(double entryEditorDividerPosition) { + this.entryEditorDividerPosition.set(entryEditorDividerPosition); + } + + public DoubleProperty entryEditorDividerPositionProperty() { + return entryEditorDividerPosition; + } + + public MainTablePreferences getTablePreferences() { + return tablePreferences; + } + + public AutoCompletePreferences getAutoCompletePreferences() { + return autoCompletePreferences; + } + + public void setAutoCompletePreferences(AutoCompletePreferences autoCompletePreferences) { + this.autoCompletePreferences = autoCompletePreferences; + } + + public EntryEditorPreferences getEntryEditorPreferences() { + return entryEditorPreferences; + } + + public KeyBindingRepository getKeyBindings() { + return keyBindings; + } + + public PreviewPreferences getPreviewPreferences() { + return previewPreferences; + } +} diff --git a/src/main/java/org/jabref/gui/GenFieldsCustomizer.java b/src/main/java/org/jabref/gui/GenFieldsCustomizer.java index d7b93d7b349..1136dc163f5 100644 --- a/src/main/java/org/jabref/gui/GenFieldsCustomizer.java +++ b/src/main/java/org/jabref/gui/GenFieldsCustomizer.java @@ -6,7 +6,9 @@ import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; +import java.util.List; import java.util.Locale; +import java.util.Map; import javax.swing.AbstractAction; import javax.swing.ActionMap; @@ -21,7 +23,6 @@ import javax.swing.JTextArea; import org.jabref.Globals; -import org.jabref.gui.entryeditor.EntryEditorTabList; import org.jabref.gui.help.HelpAction; import org.jabref.gui.keyboard.KeyBinding; import org.jabref.logic.bibtexkeypattern.BibtexKeyPatternUtil; @@ -143,11 +144,10 @@ private void okActionPerformed() { private void setFieldsText() { StringBuilder sb = new StringBuilder(); - EntryEditorTabList tabList = Globals.prefs.getEntryEditorTabList(); - for (int i = 0; i < tabList.getTabCount(); i++) { - sb.append(tabList.getTabName(i)); + for (Map.Entry> tab : Globals.prefs.getEntryEditorTabList().entrySet()) { + sb.append(tab.getKey()); sb.append(':'); - sb.append(String.join(";", tabList.getTabFields(i))); + sb.append(String.join(";", tab.getValue())); sb.append('\n'); } diff --git a/src/main/java/org/jabref/gui/JabRefFrame.java b/src/main/java/org/jabref/gui/JabRefFrame.java index cf8cb11071d..732c43aadbf 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -95,6 +95,7 @@ import org.jabref.gui.exporter.SaveAllAction; import org.jabref.gui.exporter.SaveDatabaseAction; import org.jabref.gui.externalfiletype.ExternalFileTypeEditor; +import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.gui.groups.EntryTableTransferHandler; import org.jabref.gui.groups.GroupSidePane; import org.jabref.gui.help.AboutAction; @@ -525,7 +526,7 @@ private List getNewEntryActions() { // only Bibtex List actions = new ArrayList<>(); for (EntryType type : BibtexEntryTypes.ALL) { - KeyStroke keyStroke = new ChangeEntryTypeMenu().entryShortCuts.get(type.getName()); + KeyStroke keyStroke = new ChangeEntryTypeMenu(Globals.getKeyPrefs()).entryShortCuts.get(type.getName()); if (keyStroke == null) { actions.add(new NewEntryAction(this, type.getName())); } else { @@ -635,7 +636,7 @@ public void windowClosing(WindowEvent e) { globalSearchBar.setSearchTerm(content); } - currentBasePanel.getPreviewPanel().updateLayout(); + currentBasePanel.getPreviewPanel().updateLayout(Globals.prefs.getPreviewPreferences()); groupSidePane.getToggleAction().setSelected(sidePaneManager.isComponentVisible(GroupSidePane.class)); previewToggle.setSelected(Globals.prefs.getPreviewPreferences().isPreviewPanelEnabled()); @@ -1597,9 +1598,11 @@ private void trackOpenNewDatabase(BasePanel basePanel) { public BasePanel addTab(BibDatabaseContext databaseContext, boolean raisePanel) { Objects.requireNonNull(databaseContext); - BasePanel bp = new BasePanel(JabRefFrame.this, databaseContext); - addTab(bp, raisePanel); - return bp; + return DefaultTaskExecutor.runInJavaFXThread(() -> { + BasePanel bp = new BasePanel(this, BasePanelPreferences.from(Globals.prefs), databaseContext, ExternalFileTypes.getInstance()); + addTab(bp, raisePanel); + return bp; + }); } private boolean readyForAutosave(BibDatabaseContext context) { diff --git a/src/main/java/org/jabref/gui/PreviewPanel.java b/src/main/java/org/jabref/gui/PreviewPanel.java index 181c4395c45..57b03c3d86d 100644 --- a/src/main/java/org/jabref/gui/PreviewPanel.java +++ b/src/main/java/org/jabref/gui/PreviewPanel.java @@ -26,6 +26,7 @@ import org.jabref.logic.exporter.ExportFormats; import org.jabref.logic.l10n.Localization; import org.jabref.logic.layout.Layout; +import org.jabref.logic.layout.LayoutFormatterPreferences; import org.jabref.logic.layout.LayoutHelper; import org.jabref.logic.search.SearchQueryHighlightListener; import org.jabref.model.database.BibDatabaseContext; @@ -66,41 +67,40 @@ public class PreviewPanel extends ScrollPane implements SearchQueryHighlightList private Optional> citationStyleFuture = Optional.empty(); /** + * @param preferences * @param panel (may be null) Only set this if the preview is associated to the main window. * @param databaseContext (may be null) Used for resolving pdf directories for links. */ - public PreviewPanel(BasePanel panel, BibDatabaseContext databaseContext) { + public PreviewPanel(BasePanel panel, BibDatabaseContext databaseContext, KeyBindingRepository keyBindingRepository, PreviewPreferences preferences) { this.databaseContext = Optional.ofNullable(databaseContext); this.basePanel = Optional.ofNullable(panel); this.clipBoardManager = new ClipBoardManager(); this.dialogService = new FXDialogService(); - this.keyBindingRepository = Globals.getKeyPrefs(); + this.keyBindingRepository = keyBindingRepository; + + // Set up scroll pane for preview pane + setFitToHeight(true); + setFitToWidth(true); + previewView = new WebView(); + setContent(previewView); + previewView.setContextMenuEnabled(false); + setContextMenu(createPopupMenu()); + + if (this.basePanel.isPresent()) { + // Handler for drag content of preview to different window + // only created for main window (not for windows like the search results dialog) + setOnDragDetected(event -> { + Dragboard dragboard = startDragAndDrop(TransferMode.COPY); + ClipboardContent content = new ClipboardContent(); + content.putHtml((String) previewView.getEngine().executeScript("window.getSelection().toString()")); + dragboard.setContent(content); - DefaultTaskExecutor.runInJavaFXThread(() -> { - // Set up scroll pane for preview pane - setFitToHeight(true); - setFitToWidth(true); - previewView = new WebView(); - setContent(previewView); - previewView.setContextMenuEnabled(false); - setContextMenu(createPopupMenu()); - - if (this.basePanel.isPresent()) { - // Handler for drag content of preview to different window - // only created for main window (not for windows like the search results dialog) - setOnDragDetected(event -> { - Dragboard dragboard = startDragAndDrop(TransferMode.COPY); - ClipboardContent content = new ClipboardContent(); - content.putHtml((String) previewView.getEngine().executeScript("window.getSelection().toString()")); - dragboard.setContent(content); - - event.consume(); - } - ); - } - createKeyBindings(); - updateLayout(); - }); + event.consume(); + } + ); + } + createKeyBindings(); + updateLayout(preferences); } private void createKeyBindings() { @@ -162,8 +162,7 @@ public void updateLayout(PreviewPreferences previewPreferences) { return; } - String style = previewPreferences.getPreviewCycle().get(previewPreferences.getPreviewCyclePosition()); - + String style = previewPreferences.getCurrentPreviewStyle(); if (CitationStyle.isCitationStyleFile(style)) { if (basePanel.isPresent()) { layout = Optional.empty(); @@ -174,22 +173,18 @@ public void updateLayout(PreviewPreferences previewPreferences) { } } } else { - updatePreviewLayout(previewPreferences.getPreviewStyle()); + updatePreviewLayout(previewPreferences.getPreviewStyle(), previewPreferences.getLayoutFormatterPreferences()); basePanel.ifPresent(panel -> panel.output(Localization.lang("Preview style changed to: %0", Localization.lang("Preview")))); } update(); } - public void updateLayout() { - updateLayout(Globals.prefs.getPreviewPreferences()); - } - - private void updatePreviewLayout(String layoutFile) { + private void updatePreviewLayout(String layoutFile, LayoutFormatterPreferences layoutFormatterPreferences) { StringReader sr = new StringReader(layoutFile.replace("__NEWLINE__", "\n")); try { layout = Optional.of( - new LayoutHelper(sr, Globals.prefs.getLayoutFormatterPreferences(Globals.journalAbbreviationLoader)) + new LayoutHelper(sr, layoutFormatterPreferences) .getLayoutFromText()); } catch (IOException e) { layout = Optional.empty(); @@ -276,7 +271,7 @@ public void highlightPattern(Optional newPattern) { */ public void setFixedLayout(String layout) { this.fixedLayout = true; - updatePreviewLayout(layout); + updatePreviewLayout(layout, Globals.prefs.getLayoutFormatterPreferences(Globals.journalAbbreviationLoader)); } public void print() { diff --git a/src/main/java/org/jabref/gui/actions/NewSubDatabaseAction.java b/src/main/java/org/jabref/gui/actions/NewSubDatabaseAction.java index e5fc7c6bc4e..6de3ce4fedf 100644 --- a/src/main/java/org/jabref/gui/actions/NewSubDatabaseAction.java +++ b/src/main/java/org/jabref/gui/actions/NewSubDatabaseAction.java @@ -6,9 +6,11 @@ import org.jabref.Globals; import org.jabref.gui.BasePanel; +import org.jabref.gui.BasePanelPreferences; import org.jabref.gui.IconTheme; import org.jabref.gui.JabRefFrame; import org.jabref.gui.auximport.FromAuxDialog; +import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.logic.l10n.Localization; import org.jabref.model.Defaults; import org.jabref.model.database.BibDatabaseContext; @@ -38,7 +40,7 @@ public void actionPerformed(ActionEvent e) { if (dialog.generatePressed()) { Defaults defaults = new Defaults(Globals.prefs.getDefaultBibDatabaseMode()); - BasePanel bp = new BasePanel(jabRefFrame, new BibDatabaseContext(dialog.getGenerateDB(), defaults)); + BasePanel bp = new BasePanel(jabRefFrame, BasePanelPreferences.from(Globals.prefs), new BibDatabaseContext(dialog.getGenerateDB(), defaults), ExternalFileTypes.getInstance()); jabRefFrame.addTab(bp, true); jabRefFrame.output(Localization.lang("New library created.")); } diff --git a/src/main/java/org/jabref/gui/bibtexkeypattern/ResolveDuplicateLabelDialog.java b/src/main/java/org/jabref/gui/bibtexkeypattern/ResolveDuplicateLabelDialog.java index 88b21423bdb..f82cecc4adc 100644 --- a/src/main/java/org/jabref/gui/bibtexkeypattern/ResolveDuplicateLabelDialog.java +++ b/src/main/java/org/jabref/gui/bibtexkeypattern/ResolveDuplicateLabelDialog.java @@ -56,7 +56,7 @@ public ResolveDuplicateLabelDialog(BasePanel panel, String key, List e JCheckBox cb = new JCheckBox(Localization.lang("Generate BibTeX key"), !first); b.appendRows("1dlu, p"); b.add(cb).xy(1, row); - PreviewPanel previewPanel = new PreviewPanel(null, null); + PreviewPanel previewPanel = new PreviewPanel(null, null, Globals.getKeyPrefs(), Globals.prefs.getPreviewPreferences()); previewPanel.setEntry(entry); JFXPanel container = CustomJFXPanel.wrap(new Scene(previewPanel)); container.setPreferredSize(new Dimension(800, 90)); diff --git a/src/main/java/org/jabref/gui/collab/EntryAddChangeViewModel.java b/src/main/java/org/jabref/gui/collab/EntryAddChangeViewModel.java index 5905d1a67ff..d0cdf431ea7 100644 --- a/src/main/java/org/jabref/gui/collab/EntryAddChangeViewModel.java +++ b/src/main/java/org/jabref/gui/collab/EntryAddChangeViewModel.java @@ -5,6 +5,7 @@ import javafx.embed.swing.JFXPanel; import javafx.scene.Scene; +import org.jabref.Globals; import org.jabref.gui.BasePanel; import org.jabref.gui.PreviewPanel; import org.jabref.gui.customjfx.CustomJFXPanel; @@ -25,7 +26,7 @@ public EntryAddChangeViewModel(BibEntry diskEntry) { super(Localization.lang("Added entry")); this.diskEntry = diskEntry; - PreviewPanel previewPanel = new PreviewPanel(null, null); + PreviewPanel previewPanel = new PreviewPanel(null, null, Globals.getKeyPrefs(), Globals.prefs.getPreviewPreferences()); previewPanel.setEntry(diskEntry); container = CustomJFXPanel.wrap(new Scene(previewPanel)); } diff --git a/src/main/java/org/jabref/gui/collab/EntryDeleteChangeViewModel.java b/src/main/java/org/jabref/gui/collab/EntryDeleteChangeViewModel.java index 425f0bae798..9e7499e9c1c 100644 --- a/src/main/java/org/jabref/gui/collab/EntryDeleteChangeViewModel.java +++ b/src/main/java/org/jabref/gui/collab/EntryDeleteChangeViewModel.java @@ -5,6 +5,7 @@ import javafx.embed.swing.JFXPanel; import javafx.scene.Scene; +import org.jabref.Globals; import org.jabref.gui.BasePanel; import org.jabref.gui.PreviewPanel; import org.jabref.gui.customjfx.CustomJFXPanel; @@ -42,7 +43,7 @@ public EntryDeleteChangeViewModel(BibEntry memEntry, BibEntry tmpEntry) { LOGGER.debug("Modified entry: " + memEntry.getCiteKeyOptional().orElse("") + "\n Modified locally: " + isModifiedLocally); - PreviewPanel previewPanel = new PreviewPanel(null, null); + PreviewPanel previewPanel = new PreviewPanel(null, null, Globals.getKeyPrefs(), Globals.prefs.getPreviewPreferences()); previewPanel.setEntry(memEntry); container = CustomJFXPanel.wrap(new Scene(previewPanel)); } diff --git a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java index 3bfc5967dd3..3e5e4cc22a7 100644 --- a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java +++ b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; @@ -18,7 +19,6 @@ import javafx.scene.input.KeyEvent; import javafx.scene.layout.BorderPane; -import org.jabref.Globals; import org.jabref.gui.BasePanel; import org.jabref.gui.entryeditor.fileannotationtab.FileAnnotationTab; import org.jabref.gui.help.HelpAction; @@ -35,7 +35,6 @@ import org.jabref.logic.search.SearchQueryHighlightListener; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; -import org.jabref.preferences.JabRefPreferences; import org.fxmisc.easybind.EasyBind; @@ -66,16 +65,17 @@ public class EntryEditor extends BorderPane { private final List tabs; private SourceTab sourceTab; @FXML private Label typeLabel; + private final EntryEditorPreferences preferences; - public EntryEditor(BasePanel panel) { + public EntryEditor(BasePanel panel, EntryEditorPreferences preferences) { this.panel = panel; this.bibDatabaseContext = panel.getBibDatabaseContext(); this.undoManager = panel.getUndoManager(); + this.preferences = Objects.requireNonNull(preferences); ControlHelper.loadFXMLForControl(this); getStylesheets().add(EntryEditor.class.getResource("EntryEditor.css").toExternalForm()); - setStyle("-fx-font-size: " + Globals.prefs.getFontSizeFX() + "pt;"); EasyBind.subscribe(tabbed.getSelectionModel().selectedItemProperty(), tab -> { EntryEditorTab activeTab = (EntryEditorTab) tab; @@ -94,7 +94,7 @@ public EntryEditor(BasePanel panel) { */ private void setupKeyBindings() { tabbed.addEventFilter(KeyEvent.KEY_PRESSED, event -> { - Optional keyBinding = Globals.getKeyPrefs().mapToKeyBinding(event); + Optional keyBinding = preferences.getKeyBindings().mapToKeyBinding(event); if (keyBinding.isPresent()) { switch (keyBinding.get()) { case ENTRY_EDITOR_NEXT_PANEL: @@ -154,21 +154,20 @@ private List createTabs() { tabs.add(new DeprecatedFieldsTab(panel.getDatabaseContext(), panel.getSuggestionProviders(), undoManager)); // Other fields - tabs.add(new OtherFieldsTab(panel.getDatabaseContext(), panel.getSuggestionProviders(), undoManager)); + tabs.add(new OtherFieldsTab(panel.getDatabaseContext(), panel.getSuggestionProviders(), undoManager, preferences.getCustomTabFieldNames())); // General fields from preferences - EntryEditorTabList tabList = Globals.prefs.getEntryEditorTabList(); - for (int i = 0; i < tabList.getTabCount(); i++) { - tabs.add(new UserDefinedFieldsTab(tabList.getTabName(i), tabList.getTabFields(i), panel.getDatabaseContext(), panel.getSuggestionProviders(), undoManager)); + for (Map.Entry> tab : preferences.getEntryEditorTabList().entrySet()) { + tabs.add(new UserDefinedFieldsTab(tab.getKey(), tab.getValue(), panel.getDatabaseContext(), panel.getSuggestionProviders(), undoManager)); } // Special tabs tabs.add(new MathSciNetTab()); tabs.add(new FileAnnotationTab(panel.getAnnotationCache())); - tabs.add(new RelatedArticlesTab(Globals.prefs)); + tabs.add(new RelatedArticlesTab(preferences)); // Source tab - sourceTab = new SourceTab(bibDatabaseContext, undoManager, Globals.prefs.getLatexFieldFormatterPreferences(), Globals.prefs); + sourceTab = new SourceTab(bibDatabaseContext, undoManager, preferences.getLatexFieldFormatterPreferences(), preferences.getImportFormatPreferences()); tabs.add(sourceTab); return tabs; } @@ -215,7 +214,7 @@ public void setEntry(BibEntry entry) { DefaultTaskExecutor.runInJavaFXThread(() -> { recalculateVisibleTabs(); - if (Globals.prefs.getBoolean(JabRefPreferences.DEFAULT_SHOW_SOURCE)) { + if (preferences.showSourceTabByDefault()) { tabbed.getSelectionModel().select(sourceTab); } @@ -233,14 +232,13 @@ private void setupToolBar() { typeLabel.setText(typedEntry.getTypeForDisplay()); // Add type change menu - ContextMenu typeMenu = new ChangeEntryTypeMenu().getChangeEntryTypePopupMenu(entry, bibDatabaseContext, undoManager); + ContextMenu typeMenu = new ChangeEntryTypeMenu(preferences.getKeyBindings()).getChangeEntryTypePopupMenu(entry, bibDatabaseContext, undoManager); typeLabel.setOnMouseClicked(event -> typeMenu.show(typeLabel, Side.RIGHT, 0, 0)); typeChangeButton.setOnMouseClicked(event -> typeMenu.show(typeChangeButton, Side.RIGHT, 0, 0)); // Add menu for fetching bibliographic information ContextMenu fetcherMenu = new ContextMenu(); - for (EntryBasedFetcher fetcher : WebFetchers - .getEntryBasedFetchers(Globals.prefs.getImportFormatPreferences())) { + for (EntryBasedFetcher fetcher : WebFetchers.getEntryBasedFetchers(preferences.getImportFormatPreferences())) { MenuItem fetcherMenuItem = new MenuItem(fetcher.getName()); fetcherMenuItem.setOnAction(event -> new EntryFetchAndMergeWorker(panel, getEntry(), fetcher).execute()); fetcherMenu.getItems().add(fetcherMenuItem); diff --git a/src/main/java/org/jabref/gui/entryeditor/EntryEditorPreferences.java b/src/main/java/org/jabref/gui/entryeditor/EntryEditorPreferences.java new file mode 100644 index 00000000000..0cf074aaf6a --- /dev/null +++ b/src/main/java/org/jabref/gui/entryeditor/EntryEditorPreferences.java @@ -0,0 +1,69 @@ +package org.jabref.gui.entryeditor; + +import java.util.List; +import java.util.Map; + +import org.jabref.Globals; +import org.jabref.gui.keyboard.KeyBindingRepository; +import org.jabref.logic.bibtex.LatexFieldFormatterPreferences; +import org.jabref.logic.importer.ImportFormatPreferences; +import org.jabref.preferences.JabRefPreferences; + +public class EntryEditorPreferences { + private Map> entryEditorTabList; + private LatexFieldFormatterPreferences latexFieldFormatterPreferences; + private ImportFormatPreferences importFormatPreferences; + private List customTabFieldNames; + private boolean shouldShowRecommendationsTab; + private boolean showSourceTabByDefault; + private KeyBindingRepository keyBindings; + + public EntryEditorPreferences(Map> entryEditorTabList, LatexFieldFormatterPreferences latexFieldFormatterPreferences, ImportFormatPreferences importFormatPreferences, List customTabFieldNames, boolean shouldShowRecommendationsTab, boolean showSourceTabByDefault, KeyBindingRepository keyBindings) { + this.entryEditorTabList = entryEditorTabList; + this.latexFieldFormatterPreferences = latexFieldFormatterPreferences; + this.importFormatPreferences = importFormatPreferences; + this.customTabFieldNames = customTabFieldNames; + this.shouldShowRecommendationsTab = shouldShowRecommendationsTab; + this.showSourceTabByDefault = showSourceTabByDefault; + this.keyBindings = keyBindings; + } + + public static EntryEditorPreferences from(JabRefPreferences preferences) { + return new EntryEditorPreferences( + preferences.getEntryEditorTabList(), + preferences.getLatexFieldFormatterPreferences(), + preferences.getImportFormatPreferences(), + preferences.getCustomTabFieldNames(), + preferences.getBoolean(JabRefPreferences.SHOW_RECOMMENDATIONS), + preferences.getBoolean(JabRefPreferences.DEFAULT_SHOW_SOURCE), + Globals.getKeyPrefs()); + } + + public Map> getEntryEditorTabList() { + return entryEditorTabList; + } + + public LatexFieldFormatterPreferences getLatexFieldFormatterPreferences() { + return latexFieldFormatterPreferences; + } + + public ImportFormatPreferences getImportFormatPreferences() { + return importFormatPreferences; + } + + public List getCustomTabFieldNames() { + return customTabFieldNames; + } + + public boolean shouldShowRecommendationsTab() { + return shouldShowRecommendationsTab; + } + + public boolean showSourceTabByDefault() { + return showSourceTabByDefault; + } + + public KeyBindingRepository getKeyBindings() { + return keyBindings; + } +} diff --git a/src/main/java/org/jabref/gui/entryeditor/EntryEditorTabList.java b/src/main/java/org/jabref/gui/entryeditor/EntryEditorTabList.java index ac5033e002e..f35f8c94ad6 100644 --- a/src/main/java/org/jabref/gui/entryeditor/EntryEditorTabList.java +++ b/src/main/java/org/jabref/gui/entryeditor/EntryEditorTabList.java @@ -1,61 +1,44 @@ package org.jabref.gui.entryeditor; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; +import java.util.TreeMap; -import org.jabref.Globals; import org.jabref.preferences.JabRefPreferences; /** - * Class for holding the information about customizable entry editor tabs. + * Class for creating the information about customizable entry editor tabs. */ public final class EntryEditorTabList { - private List> list; - private List names; + private EntryEditorTabList() { - public EntryEditorTabList() { - init(); } - private void init() { - list = new ArrayList<>(); - names = new ArrayList<>(); + public static Map> create(JabRefPreferences preferences) { + Map> tabs = new TreeMap<>(); int i = 0; String name; - if (Globals.prefs.hasKey(JabRefPreferences.CUSTOM_TAB_NAME + 0)) { + if (preferences.hasKey(JabRefPreferences.CUSTOM_TAB_NAME + 0)) { // The user has modified from the default values: - while (Globals.prefs.hasKey(JabRefPreferences.CUSTOM_TAB_NAME + i)) { - name = Globals.prefs.get(JabRefPreferences.CUSTOM_TAB_NAME + i); + while (preferences.hasKey(JabRefPreferences.CUSTOM_TAB_NAME + i)) { + name = preferences.get(JabRefPreferences.CUSTOM_TAB_NAME + i); List entry = Arrays - .asList(Globals.prefs.get(JabRefPreferences.CUSTOM_TAB_FIELDS + i).split(";")); - names.add(name); - list.add(entry); + .asList(preferences.get(JabRefPreferences.CUSTOM_TAB_FIELDS + i).split(";")); + tabs.put(name, entry); i++; } } else { // Nothing set, so we use the default values: - while (Globals.prefs.get(JabRefPreferences.CUSTOM_TAB_NAME + "_def" + i) != null) { - name = Globals.prefs.get(JabRefPreferences.CUSTOM_TAB_NAME + "_def" + i); + while (preferences.get(JabRefPreferences.CUSTOM_TAB_NAME + "_def" + i) != null) { + name = preferences.get(JabRefPreferences.CUSTOM_TAB_NAME + "_def" + i); List entry = Arrays - .asList(Globals.prefs.get(JabRefPreferences.CUSTOM_TAB_FIELDS + "_def" + i).split(";")); - names.add(name); - list.add(entry); + .asList(preferences.get(JabRefPreferences.CUSTOM_TAB_FIELDS + "_def" + i).split(";")); + tabs.put(name, entry); i++; } } - } - - public int getTabCount() { - return list.size(); - } - - public String getTabName(int tab) { - return names.get(tab); - } - - public List getTabFields(int tab) { - return list.get(tab); + return tabs; } } diff --git a/src/main/java/org/jabref/gui/entryeditor/FieldsEditorTab.java b/src/main/java/org/jabref/gui/entryeditor/FieldsEditorTab.java index b1ac6b38071..6ed9ce119af 100644 --- a/src/main/java/org/jabref/gui/entryeditor/FieldsEditorTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/FieldsEditorTab.java @@ -71,6 +71,12 @@ private String convertToHex(java.awt.Color color) { } private Region setupPanel(BibEntry entry, boolean compressed, SuggestionProviders suggestionProviders, UndoManager undoManager) { + // The preferences might be not initialized in tests -> return empty node + // TODO: Replace this ugly workaround by proper injection propagation + if (Globals.prefs == null) { + return new Region(); + } + editors.clear(); EntryType entryType = EntryTypes.getTypeOrDefault(entry.getType(), databaseContext.getMode()); diff --git a/src/main/java/org/jabref/gui/entryeditor/OtherFieldsTab.java b/src/main/java/org/jabref/gui/entryeditor/OtherFieldsTab.java index 4896d0a9236..ba9e55cf341 100644 --- a/src/main/java/org/jabref/gui/entryeditor/OtherFieldsTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/OtherFieldsTab.java @@ -8,7 +8,6 @@ import javafx.scene.control.Tooltip; -import org.jabref.Globals; import org.jabref.gui.IconTheme; import org.jabref.gui.autocompleter.SuggestionProviders; import org.jabref.logic.l10n.Localization; @@ -18,12 +17,15 @@ public class OtherFieldsTab extends FieldsEditorTab { - public OtherFieldsTab(BibDatabaseContext databaseContext, SuggestionProviders suggestionProviders, UndoManager undoManager) { + private final List customTabFieldNames; + + public OtherFieldsTab(BibDatabaseContext databaseContext, SuggestionProviders suggestionProviders, UndoManager undoManager, List customTabFieldNames) { super(false, databaseContext, suggestionProviders, undoManager); setText(Localization.lang("Other fields")); setTooltip(new Tooltip(Localization.lang("Show remaining fields"))); setGraphic(IconTheme.JabRefIcons.OPTIONAL.getGraphicNode()); + this.customTabFieldNames = customTabFieldNames; } @Override @@ -35,7 +37,7 @@ protected Collection determineFieldsToShow(BibEntry entry, EntryType ent otherFields.removeAll(entryType.getDeprecatedFields()); otherFields.remove(BibEntry.KEY_FIELD); - otherFields.removeAll(Globals.prefs.getCustomTabFieldNames()); + otherFields.removeAll(customTabFieldNames); return otherFields; } } diff --git a/src/main/java/org/jabref/gui/entryeditor/RelatedArticlesTab.java b/src/main/java/org/jabref/gui/entryeditor/RelatedArticlesTab.java index 98a5ebd0bea..49d2f7d3023 100644 --- a/src/main/java/org/jabref/gui/entryeditor/RelatedArticlesTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/RelatedArticlesTab.java @@ -20,9 +20,9 @@ public class RelatedArticlesTab extends EntryEditorTab { - private final JabRefPreferences preferences; + private final EntryEditorPreferences preferences; - public RelatedArticlesTab(JabRefPreferences preferences) { + public RelatedArticlesTab(EntryEditorPreferences preferences) { setText(Localization.lang("Related articles")); setTooltip(new Tooltip(Localization.lang("Related articles"))); this.preferences = preferences; @@ -81,7 +81,7 @@ private String convertToHtml(List list) { @Override public boolean shouldShow(BibEntry entry) { - return preferences.getBoolean(JabRefPreferences.SHOW_RECOMMENDATIONS); + return preferences.shouldShowRecommendationsTab(); } @Override diff --git a/src/main/java/org/jabref/gui/entryeditor/SourceTab.java b/src/main/java/org/jabref/gui/entryeditor/SourceTab.java index 9b52b739fe8..2ad5a83d533 100644 --- a/src/main/java/org/jabref/gui/entryeditor/SourceTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/SourceTab.java @@ -24,6 +24,7 @@ import org.jabref.logic.bibtex.InvalidFieldValueException; import org.jabref.logic.bibtex.LatexFieldFormatter; import org.jabref.logic.bibtex.LatexFieldFormatterPreferences; +import org.jabref.logic.importer.ImportFormatPreferences; import org.jabref.logic.importer.ParserResult; import org.jabref.logic.importer.fileformat.BibtexParser; import org.jabref.logic.l10n.Localization; @@ -32,7 +33,6 @@ import org.jabref.model.database.BibDatabaseMode; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.InternalBibtexFields; -import org.jabref.preferences.JabRefPreferences; import de.saxsys.mvvmfx.utils.validation.ObservableRuleBasedValidator; import de.saxsys.mvvmfx.utils.validation.ValidationMessage; @@ -47,19 +47,19 @@ public class SourceTab extends EntryEditorTab { private static final Log LOGGER = LogFactory.getLog(SourceTab.class); private final LatexFieldFormatterPreferences fieldFormatterPreferences; private final BibDatabaseMode mode; - private final JabRefPreferences preferences; private UndoManager undoManager; private final ObjectProperty sourceIsValid = new SimpleObjectProperty<>(); private final ObservableRuleBasedValidator sourceValidator = new ObservableRuleBasedValidator(sourceIsValid); + private final ImportFormatPreferences importFormatPreferences; - public SourceTab(BibDatabaseContext bibDatabaseContext, CountingUndoManager undoManager, LatexFieldFormatterPreferences fieldFormatterPreferences, JabRefPreferences preferences) { + public SourceTab(BibDatabaseContext bibDatabaseContext, CountingUndoManager undoManager, LatexFieldFormatterPreferences fieldFormatterPreferences, ImportFormatPreferences importFormatPreferences) { this.mode = bibDatabaseContext.getMode(); this.setText(Localization.lang("%0 source", mode.getFormattedName())); this.setTooltip(new Tooltip(Localization.lang("Show/edit %0 source", mode.getFormattedName()))); this.setGraphic(IconTheme.JabRefIcons.SOURCE.getGraphicNode()); this.undoManager = undoManager; this.fieldFormatterPreferences = fieldFormatterPreferences; - this.preferences = preferences; + this.importFormatPreferences = importFormatPreferences; } private static String getSourceString(BibEntry entry, BibDatabaseMode type, LatexFieldFormatterPreferences fieldFormatterPreferences) throws IOException { @@ -73,7 +73,6 @@ private static String getSourceString(BibEntry entry, BibDatabaseMode type, Late private CodeArea createSourceEditor() { CodeArea codeArea = new CodeArea(); codeArea.setWrapText(true); - codeArea.lookup(".styled-text-area").setStyle("-fx-font-size: " + preferences.getFontSizeFX() + "pt;"); return codeArea; } @@ -119,7 +118,7 @@ private void storeSource(String text) { return; } - BibtexParser bibtexParser = new BibtexParser(preferences.getImportFormatPreferences()); + BibtexParser bibtexParser = new BibtexParser(importFormatPreferences); try { ParserResult parserResult = bibtexParser.parse(new StringReader(text)); BibDatabase database = parserResult.getDatabase(); @@ -166,7 +165,7 @@ private void storeSource(String text) { String newValue = field.getValue(); if (!Objects.equals(oldValue, newValue)) { // Test if the field is legally set. - new LatexFieldFormatter(preferences.getLatexFieldFormatterPreferences()) + new LatexFieldFormatter(fieldFormatterPreferences) .format(newValue, fieldName); compound.addEdit(new UndoableFieldChange(currentEntry, fieldName, oldValue, newValue)); diff --git a/src/main/java/org/jabref/gui/importer/ImportInspectionDialog.java b/src/main/java/org/jabref/gui/importer/ImportInspectionDialog.java index 85564a70dc8..6c2d81b90e2 100644 --- a/src/main/java/org/jabref/gui/importer/ImportInspectionDialog.java +++ b/src/main/java/org/jabref/gui/importer/ImportInspectionDialog.java @@ -53,6 +53,7 @@ import org.jabref.Globals; import org.jabref.JabRefExecutorService; import org.jabref.gui.BasePanel; +import org.jabref.gui.BasePanelPreferences; import org.jabref.gui.DuplicateResolverDialog; import org.jabref.gui.DuplicateResolverDialog.DuplicateResolverResult; import org.jabref.gui.EntryMarker; @@ -66,6 +67,7 @@ import org.jabref.gui.externalfiles.AutoSetLinks; import org.jabref.gui.externalfiles.DownloadExternalFile; import org.jabref.gui.externalfiletype.ExternalFileMenuItem; +import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.gui.filelist.FileListEntry; import org.jabref.gui.filelist.FileListEntryEditor; import org.jabref.gui.filelist.FileListTableModel; @@ -200,7 +202,7 @@ public ImportInspectionDialog(JabRefFrame frame, BasePanel panel, String undoNam this.undoName = undoName; this.newDatabase = newDatabase; setIconImages(IconTheme.getLogoSet()); - preview = new PreviewPanel(panel, bibDatabaseContext); + preview = new PreviewPanel(panel, bibDatabaseContext, Globals.getKeyPrefs(), Globals.prefs.getPreviewPreferences()); duplLabel.setToolTipText(Localization.lang("Possible duplicate of existing entry. Click to resolve.")); @@ -802,7 +804,7 @@ private void addSelectedEntries(NamedCompound ce, final List selected) if (newDatabase) { // Create a new BasePanel for the entries: Defaults defaults = new Defaults(Globals.prefs.getDefaultBibDatabaseMode()); - panel = new BasePanel(frame, new BibDatabaseContext(defaults)); + panel = new BasePanel(frame, BasePanelPreferences.from(Globals.prefs), new BibDatabaseContext(defaults), ExternalFileTypes.getInstance()); } boolean groupingCanceled = false; diff --git a/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java b/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java index af02bd48f03..93a2fb1a2be 100644 --- a/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java +++ b/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java @@ -21,12 +21,14 @@ import org.jabref.Globals; import org.jabref.JabRefExecutorService; import org.jabref.gui.BasePanel; +import org.jabref.gui.BasePanelPreferences; import org.jabref.gui.DialogService; import org.jabref.gui.FXDialogService; import org.jabref.gui.IconTheme; import org.jabref.gui.JabRefFrame; import org.jabref.gui.actions.MnemonicAwareAction; import org.jabref.gui.autosaveandbackup.BackupUIManager; +import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.gui.importer.ParserResultWarningDialog; import org.jabref.gui.keyboard.KeyBinding; import org.jabref.gui.shared.SharedDatabaseUIManager; @@ -270,7 +272,7 @@ private BasePanel addNewDatabase(ParserResult result, final Path file, boolean r .execute(() -> ParserResultWarningDialog.showParserResultWarningDialog(result, frame)); } - BasePanel basePanel = new BasePanel(frame, result.getDatabaseContext()); + BasePanel basePanel = new BasePanel(frame, BasePanelPreferences.from(Globals.prefs), result.getDatabaseContext(), ExternalFileTypes.getInstance()); // file is set to null inside the EventDispatcherThread SwingUtilities.invokeLater(() -> frame.addTab(basePanel, raisePanel)); diff --git a/src/main/java/org/jabref/gui/maintable/CellFactory.java b/src/main/java/org/jabref/gui/maintable/CellFactory.java index 263343eb986..72b118cfcb2 100644 --- a/src/main/java/org/jabref/gui/maintable/CellFactory.java +++ b/src/main/java/org/jabref/gui/maintable/CellFactory.java @@ -16,7 +16,7 @@ public class CellFactory { private final Map TABLE_ICONS = new HashMap<>(); - public CellFactory() { + public CellFactory(ExternalFileTypes externalFileTypes) { Node label; label = IconTheme.JabRefIcons.PDF_FILE.getGraphicNode(); //label.setToo(Localization.lang("Open") + " PDF"); @@ -50,7 +50,7 @@ public CellFactory() { //label.setToolTipText(Localization.lang("Open file")); TABLE_ICONS.put(FieldName.FILE, label); - for (ExternalFileType fileType : ExternalFileTypes.getInstance().getExternalFileTypeSelection()) { + for (ExternalFileType fileType : externalFileTypes.getExternalFileTypeSelection()) { label = fileType.getIcon().getGraphicNode(); //label.setToolTipText(Localization.lang("Open %0 file", fileType.getName())); TABLE_ICONS.put(fileType.getName(), label); diff --git a/src/main/java/org/jabref/gui/maintable/ColumnFactory.java b/src/main/java/org/jabref/gui/maintable/ColumnFactory.java index b93b5dff34c..2c50844b8b9 100644 --- a/src/main/java/org/jabref/gui/maintable/ColumnFactory.java +++ b/src/main/java/org/jabref/gui/maintable/ColumnFactory.java @@ -3,13 +3,13 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; import javafx.scene.Node; import javafx.scene.control.TableColumn; -import org.jabref.Globals; import org.jabref.gui.IconTheme; import org.jabref.gui.JabRefIcon; import org.jabref.gui.externalfiletype.ExternalFileType; @@ -21,7 +21,6 @@ import org.jabref.model.entry.FieldName; import org.jabref.model.entry.LinkedFile; import org.jabref.model.entry.specialfields.SpecialField; -import org.jabref.preferences.JabRefPreferences; import org.fxmisc.easybind.EasyBind; @@ -29,27 +28,29 @@ class ColumnFactory { private static final String STYLE_ICON = "column-icon"; + private final ColumnPreferences preferences; private final ExternalFileTypes externalFileTypes; private final BibDatabase database; private final CellFactory cellFactory; - public ColumnFactory(BibDatabase database) { - this.database = database; - externalFileTypes = ExternalFileTypes.getInstance(); - cellFactory = new CellFactory(); + public ColumnFactory(BibDatabase database, ColumnPreferences preferences, ExternalFileTypes externalFileTypes) { + this.database = Objects.requireNonNull(database); + this.preferences = Objects.requireNonNull(preferences); + this.externalFileTypes = Objects.requireNonNull(externalFileTypes); + this.cellFactory = new CellFactory(externalFileTypes); } public List> createColumns() { List> columns = new ArrayList<>(); // Add column for linked files - if (Globals.prefs.getBoolean(JabRefPreferences.FILE_COLUMN)) { + if (preferences.showFileColumn()) { columns.add(createFileColumn()); } // Add column for DOI/URL - if (Globals.prefs.getBoolean(JabRefPreferences.URL_COLUMN)) { - if (Globals.prefs.getBoolean(JabRefPreferences.PREFER_URL_DOI)) { + if (preferences.showUrlColumn()) { + if (preferences.preferDoiOverUrl()) { columns.add(createIconColumn(IconTheme.JabRefIcons.DOI, FieldName.DOI, FieldName.URL)); } else { columns.add(createIconColumn(IconTheme.JabRefIcons.WWW, FieldName.URL, FieldName.DOI)); @@ -57,44 +58,22 @@ public ColumnFactory(BibDatabase database) { } // Add column for eprints - if (Globals.prefs.getBoolean(JabRefPreferences.ARXIV_COLUMN)) { + if (preferences.showEprintColumn()) { columns.add(createIconColumn(IconTheme.JabRefIcons.WWW, FieldName.EPRINT)); } // Add columns for other file types - if (Globals.prefs.getBoolean(JabRefPreferences.EXTRA_FILE_COLUMNS)) { - List desiredColumns = Globals.prefs.getStringList(JabRefPreferences.LIST_OF_FILE_COLUMNS); - for (String desiredColumn : desiredColumns) { - columns.add(createExtraFileColumn(desiredColumn)); - } + for (String column : preferences.getExtraFileColumns()) { + columns.add(createExtraFileColumn(column)); } + // Add 'normal' bibtex fields as configured in the preferences columns.addAll(createNormalColumns()); // Add the "special" icon columns (e.g., ranking, file, ...) that are enabled in preferences - if (Globals.prefs.getBoolean(JabRefPreferences.SPECIALFIELDSENABLED)) { - if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_RANKING)) { - columns.add(createSpecialFieldColumn(SpecialField.RANKING)); - } - if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_RELEVANCE)) { - columns.add(createSpecialFieldColumn(SpecialField.RELEVANCE)); - } - if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_QUALITY)) { - columns.add(createSpecialFieldColumn(SpecialField.QUALITY)); - } - - if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_PRIORITY)) { - columns.add(createSpecialFieldColumn(SpecialField.PRIORITY)); - } - - if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_PRINTED)) { - columns.add(createSpecialFieldColumn(SpecialField.PRINTED)); - } - - if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_READ)) { - columns.add(createSpecialFieldColumn(SpecialField.READ_STATUS)); - } + for (SpecialField field : preferences.getSpecialFieldColumns()) { + columns.add(createSpecialFieldColumn((field))); } return columns; @@ -104,8 +83,7 @@ public ColumnFactory(BibDatabase database) { List> columns = new ArrayList<>(); // Read table columns from preferences - List columnSettings = Globals.prefs.getStringList(JabRefPreferences.COLUMN_NAMES); - for (String columnName : columnSettings) { + for (String columnName : preferences.getNormalColumns()) { // Stored column name will be used as header // There might be more than one field to display, e.g., "author/editor" or "date/year" - so split String[] fields = columnName.split(FieldName.FIELD_SEPARATOR); diff --git a/src/main/java/org/jabref/gui/maintable/ColumnPreferences.java b/src/main/java/org/jabref/gui/maintable/ColumnPreferences.java new file mode 100644 index 00000000000..40ad69e7453 --- /dev/null +++ b/src/main/java/org/jabref/gui/maintable/ColumnPreferences.java @@ -0,0 +1,107 @@ +package org.jabref.gui.maintable; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.jabref.model.entry.specialfields.SpecialField; +import org.jabref.preferences.JabRefPreferences; + +public class ColumnPreferences { + + private final boolean showFileColumn; + private final boolean showUrlColumn; + private final boolean preferDoiOverUrl; + private final boolean showEprintColumn; + private final List normalColumns; + private final List specialFieldColumns; + private final List extraFileColumns; + + public ColumnPreferences(boolean showFileColumn, boolean showUrlColumn, boolean preferDoiOverUrl, boolean showEprintColumn, List normalColumns, List specialFieldColumns, List extraFileColumns) { + this.showFileColumn = showFileColumn; + this.showUrlColumn = showUrlColumn; + this.preferDoiOverUrl = preferDoiOverUrl; + this.showEprintColumn = showEprintColumn; + this.normalColumns = normalColumns; + this.specialFieldColumns = specialFieldColumns; + this.extraFileColumns = extraFileColumns; + } + + public static ColumnPreferences from(JabRefPreferences preferences) { + return new ColumnPreferences( + preferences.getBoolean(JabRefPreferences.FILE_COLUMN), + preferences.getBoolean(JabRefPreferences.URL_COLUMN), + preferences.getBoolean(JabRefPreferences.PREFER_URL_DOI), + preferences.getBoolean(JabRefPreferences.ARXIV_COLUMN), + preferences.getStringList(JabRefPreferences.COLUMN_NAMES), + createSpecialFieldColumns(preferences), + createExtraFileColumns(preferences) + ); + } + + private static List createExtraFileColumns(JabRefPreferences preferences) { + if (preferences.getBoolean(JabRefPreferences.EXTRA_FILE_COLUMNS)) { + return preferences.getStringList(JabRefPreferences.LIST_OF_FILE_COLUMNS); + } else { + return Collections.emptyList(); + } + } + + private static List createSpecialFieldColumns(JabRefPreferences preferences) { + if (preferences.getBoolean(JabRefPreferences.SPECIALFIELDSENABLED)) { + List fieldsToShow = new ArrayList<>(); + if (preferences.getBoolean(JabRefPreferences.SHOWCOLUMN_RANKING)) { + fieldsToShow.add(SpecialField.RANKING); + } + if (preferences.getBoolean(JabRefPreferences.SHOWCOLUMN_RELEVANCE)) { + fieldsToShow.add(SpecialField.RELEVANCE); + } + if (preferences.getBoolean(JabRefPreferences.SHOWCOLUMN_QUALITY)) { + fieldsToShow.add(SpecialField.QUALITY); + } + + if (preferences.getBoolean(JabRefPreferences.SHOWCOLUMN_PRIORITY)) { + fieldsToShow.add(SpecialField.PRIORITY); + } + + if (preferences.getBoolean(JabRefPreferences.SHOWCOLUMN_PRINTED)) { + fieldsToShow.add(SpecialField.PRINTED); + } + + if (preferences.getBoolean(JabRefPreferences.SHOWCOLUMN_READ)) { + fieldsToShow.add(SpecialField.READ_STATUS); + } + return fieldsToShow; + } else { + return Collections.emptyList(); + } + } + + public boolean showFileColumn() { + return showFileColumn; + } + + public boolean showUrlColumn() { + return showUrlColumn; + } + + public boolean preferDoiOverUrl() { + return preferDoiOverUrl; + } + + public boolean showEprintColumn() { + return showEprintColumn; + } + + public List getExtraFileColumns() { + return extraFileColumns; + } + + public List getSpecialFieldColumns() { + return specialFieldColumns; + } + + public List getNormalColumns() { + return normalColumns; + } +} diff --git a/src/main/java/org/jabref/gui/maintable/MainTable.java b/src/main/java/org/jabref/gui/maintable/MainTable.java index ca003724cc6..dcaaaf63405 100644 --- a/src/main/java/org/jabref/gui/maintable/MainTable.java +++ b/src/main/java/org/jabref/gui/maintable/MainTable.java @@ -17,6 +17,7 @@ import org.jabref.gui.BasePanel; import org.jabref.gui.EntryMarker; import org.jabref.gui.JabRefFrame; +import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.gui.renderer.CompleteRenderer; import org.jabref.gui.renderer.GeneralRenderer; import org.jabref.gui.renderer.IncompleteRenderer; @@ -50,8 +51,8 @@ public class MainTable extends TableView { private static final Log LOGGER = LogFactory.getLog(MainTable.class); private final BasePanel panel; - private final boolean tableColorCodes; - private final boolean tableResolvedColorCodes; + //private final boolean tableColorCodes; + //private final boolean tableResolvedColorCodes; private final ScrollPane pane; // needed to activate/deactivate the listener @@ -67,22 +68,22 @@ private enum CellRendererMode { } static { - MainTable.updateRenderers(); + //MainTable.updateRenderers(); } public MainTable(MainTableDataModel model, JabRefFrame frame, - BasePanel panel, BibDatabase database) { + BasePanel panel, BibDatabase database, MainTablePreferences preferences, ExternalFileTypes externalFileTypes) { super(); this.model = model; - this.getColumns().addAll(new ColumnFactory(database).createColumns()); + this.getColumns().addAll(new ColumnFactory(database, preferences.getColumnPreferences(), externalFileTypes).createColumns()); this.setRowFactory(new ViewModelTableRowFactory() .withOnMouseClickedEvent((entry, event) -> { if (event.getClickCount() == 2) { panel.showAndEdit(entry.getEntry()); } })); - if (Globals.prefs.getBoolean(JabRefPreferences.AUTO_RESIZE_MODE)) { + if (preferences.resizeColumnsToFit()) { this.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); } this.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); @@ -99,11 +100,11 @@ public MainTable(MainTableDataModel model, JabRefFrame frame, this.pane.getStylesheets().add(MainTable.class.getResource("MainTable.css").toExternalForm()); // TODO: Color - tableColorCodes = Globals.prefs.getBoolean(JabRefPreferences.TABLE_COLOR_CODES_ON); - tableResolvedColorCodes = Globals.prefs.getBoolean(JabRefPreferences.TABLE_RESOLVED_COLOR_CODES_ON); + //tableColorCodes = Globals.prefs.getBoolean(JabRefPreferences.TABLE_COLOR_CODES_ON); + //tableResolvedColorCodes = Globals.prefs.getBoolean(JabRefPreferences.TABLE_RESOLVED_COLOR_CODES_ON); //pane.getViewport().setBackground(Globals.prefs.getColor(JabRefPreferences.TABLE_BACKGROUND)); //setGridColor(Globals.prefs.getColor(JabRefPreferences.GRID_COLOR)); - if (!Globals.prefs.getBoolean(JabRefPreferences.TABLE_SHOW_GRID)) { + if (!preferences.showGrid()) { this.setStyle("-fx-table-cell-border-color: transparent;"); } diff --git a/src/main/java/org/jabref/gui/maintable/MainTablePreferences.java b/src/main/java/org/jabref/gui/maintable/MainTablePreferences.java new file mode 100644 index 00000000000..a16aed83f92 --- /dev/null +++ b/src/main/java/org/jabref/gui/maintable/MainTablePreferences.java @@ -0,0 +1,36 @@ +package org.jabref.gui.maintable; + +import org.jabref.Globals; +import org.jabref.preferences.JabRefPreferences; + +public class MainTablePreferences { + private final boolean showGrid; + private final ColumnPreferences columnPreferences; + private final boolean resizeColumnsToFit; + + public MainTablePreferences(boolean showGrid, ColumnPreferences columnPreferences, boolean resizeColumnsToFit) { + this.showGrid = showGrid; + this.columnPreferences = columnPreferences; + this.resizeColumnsToFit = resizeColumnsToFit; + } + + public static MainTablePreferences from(JabRefPreferences preferences) { + return new MainTablePreferences( + Globals.prefs.getBoolean(JabRefPreferences.TABLE_SHOW_GRID), + ColumnPreferences.from(preferences), + Globals.prefs.getBoolean(JabRefPreferences.AUTO_RESIZE_MODE)); + } + + public ColumnPreferences getColumnPreferences() { + return columnPreferences; + } + + public boolean resizeColumnsToFit() { + + return resizeColumnsToFit; + } + + public boolean showGrid() { + return showGrid; + } +} diff --git a/src/main/java/org/jabref/gui/menus/ChangeEntryTypeMenu.java b/src/main/java/org/jabref/gui/menus/ChangeEntryTypeMenu.java index dac3baaec81..0b5b7625a24 100644 --- a/src/main/java/org/jabref/gui/menus/ChangeEntryTypeMenu.java +++ b/src/main/java/org/jabref/gui/menus/ChangeEntryTypeMenu.java @@ -15,10 +15,10 @@ import javafx.scene.control.Menu; import javafx.scene.control.SeparatorMenuItem; -import org.jabref.Globals; import org.jabref.gui.BasePanel; import org.jabref.gui.actions.ChangeTypeAction; import org.jabref.gui.keyboard.KeyBinding; +import org.jabref.gui.keyboard.KeyBindingRepository; import org.jabref.gui.undo.CountingUndoManager; import org.jabref.logic.l10n.Localization; import org.jabref.model.EntryTypes; @@ -32,15 +32,15 @@ public class ChangeEntryTypeMenu { public final Map entryShortCuts = new HashMap<>(); - public ChangeEntryTypeMenu () { - entryShortCuts.put(BibtexEntryTypes.ARTICLE.getName(), Globals.getKeyPrefs().getKey(KeyBinding.NEW_ARTICLE)); - entryShortCuts.put(BibtexEntryTypes.BOOK.getName(), Globals.getKeyPrefs().getKey(KeyBinding.NEW_BOOK)); - entryShortCuts.put(BibtexEntryTypes.PHDTHESIS.getName(), Globals.getKeyPrefs().getKey(KeyBinding.NEW_PHDTHESIS)); - entryShortCuts.put(BibtexEntryTypes.INBOOK.getName(), Globals.getKeyPrefs().getKey(KeyBinding.NEW_MASTERSTHESIS)); - entryShortCuts.put(BibtexEntryTypes.INBOOK.getName(), Globals.getKeyPrefs().getKey(KeyBinding.NEW_INBOOK)); - entryShortCuts.put(BibtexEntryTypes.PROCEEDINGS.getName(), Globals.getKeyPrefs().getKey(KeyBinding.NEW_PROCEEDINGS)); - entryShortCuts.put(BibtexEntryTypes.UNPUBLISHED.getName(), Globals.getKeyPrefs().getKey(KeyBinding.NEW_UNPUBLISHED)); - entryShortCuts.put(BibtexEntryTypes.TECHREPORT.getName(), Globals.getKeyPrefs().getKey(KeyBinding.NEW_TECHREPORT)); + public ChangeEntryTypeMenu(KeyBindingRepository keyBindings) { + entryShortCuts.put(BibtexEntryTypes.ARTICLE.getName(), keyBindings.getKey(KeyBinding.NEW_ARTICLE)); + entryShortCuts.put(BibtexEntryTypes.BOOK.getName(), keyBindings.getKey(KeyBinding.NEW_BOOK)); + entryShortCuts.put(BibtexEntryTypes.PHDTHESIS.getName(), keyBindings.getKey(KeyBinding.NEW_PHDTHESIS)); + entryShortCuts.put(BibtexEntryTypes.INBOOK.getName(), keyBindings.getKey(KeyBinding.NEW_MASTERSTHESIS)); + entryShortCuts.put(BibtexEntryTypes.INBOOK.getName(), keyBindings.getKey(KeyBinding.NEW_INBOOK)); + entryShortCuts.put(BibtexEntryTypes.PROCEEDINGS.getName(), keyBindings.getKey(KeyBinding.NEW_PROCEEDINGS)); + entryShortCuts.put(BibtexEntryTypes.UNPUBLISHED.getName(), keyBindings.getKey(KeyBinding.NEW_UNPUBLISHED)); + entryShortCuts.put(BibtexEntryTypes.TECHREPORT.getName(), keyBindings.getKey(KeyBinding.NEW_TECHREPORT)); } public JMenu getChangeEntryTypeMenu(BasePanel panel) { diff --git a/src/main/java/org/jabref/gui/menus/RightClickMenu.java b/src/main/java/org/jabref/gui/menus/RightClickMenu.java index 4903310c535..f2dc69df8db 100644 --- a/src/main/java/org/jabref/gui/menus/RightClickMenu.java +++ b/src/main/java/org/jabref/gui/menus/RightClickMenu.java @@ -53,7 +53,7 @@ public class RightClickMenu extends JPopupMenu implements PopupMenuListener { public RightClickMenu(JabRefFrame frame, BasePanel panel) { this.panel = panel; - JMenu typeMenu = new ChangeEntryTypeMenu().getChangeEntryTypeMenu(panel); + JMenu typeMenu = new ChangeEntryTypeMenu(Globals.getKeyPrefs()).getChangeEntryTypeMenu(panel); // Are multiple entries selected? boolean multiple = areMultipleEntriesSelected(); diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntries.java b/src/main/java/org/jabref/gui/mergeentries/MergeEntries.java index 82bca6c916e..e1f81c3a663 100644 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntries.java +++ b/src/main/java/org/jabref/gui/mergeentries/MergeEntries.java @@ -183,7 +183,7 @@ private void initialize() { // Setup a PreviewPanel and a Bibtex source box for the merged entry mainPanel.add(boldFontLabel(Localization.lang("Merged entry")), CELL_CONSTRAINTS.xyw(1, 6, 6)); - entryPreview = new PreviewPanel(null, null); + entryPreview = new PreviewPanel(null, null, Globals.getKeyPrefs(), Globals.prefs.getPreviewPreferences()); entryPreview.setEntry(mergedEntry); JFXPanel container = CustomJFXPanel.wrap(new Scene(entryPreview)); mainPanel.add(container, CELL_CONSTRAINTS.xyw(1, 8, 6)); diff --git a/src/main/java/org/jabref/gui/openoffice/StyleSelectDialog.java b/src/main/java/org/jabref/gui/openoffice/StyleSelectDialog.java index 1c0caa80c2d..189f27cd92a 100644 --- a/src/main/java/org/jabref/gui/openoffice/StyleSelectDialog.java +++ b/src/main/java/org/jabref/gui/openoffice/StyleSelectDialog.java @@ -139,7 +139,7 @@ private void init() { // Create a preview panel for previewing styles // Must be done before creating the table to avoid NPEs - preview = new PreviewPanel(null, null); + preview = new PreviewPanel(null, null, Globals.getKeyPrefs(), Globals.prefs.getPreviewPreferences()); // Use the test entry from the Preview settings tab in Preferences: preview.setEntry(prevEntry); diff --git a/src/main/java/org/jabref/gui/preftabs/PreviewPrefsTab.java b/src/main/java/org/jabref/gui/preftabs/PreviewPrefsTab.java index f1f36925e83..b709e206ced 100644 --- a/src/main/java/org/jabref/gui/preftabs/PreviewPrefsTab.java +++ b/src/main/java/org/jabref/gui/preftabs/PreviewPrefsTab.java @@ -121,7 +121,7 @@ private void setupLogic() { btnTest.addActionListener(event -> { try { - PreviewPanel testPane = new PreviewPanel(null, null); + PreviewPanel testPane = new PreviewPanel(null, null, Globals.getKeyPrefs(), Globals.prefs.getPreviewPreferences()); testPane.setFixedLayout(layout.getText()); testPane.setEntry(TestEntry.getTestEntry()); JFXPanel container = CustomJFXPanel.wrap(new Scene(testPane)); @@ -251,7 +251,7 @@ public void storeSettings() { // update preview for (BasePanel basePanel : JabRefGUI.getMainFrame().getBasePanelList()) { - basePanel.getPreviewPanel().updateLayout(); + basePanel.getPreviewPanel().updateLayout(Globals.prefs.getPreviewPreferences()); } } diff --git a/src/main/java/org/jabref/gui/search/SearchResultFrame.java b/src/main/java/org/jabref/gui/search/SearchResultFrame.java index 7b119820756..fb1683da614 100644 --- a/src/main/java/org/jabref/gui/search/SearchResultFrame.java +++ b/src/main/java/org/jabref/gui/search/SearchResultFrame.java @@ -128,7 +128,7 @@ private void init(String title) { searchResultFrame.setTitle(title); searchResultFrame.setIconImages(IconTheme.getLogoSet()); - preview = new PreviewPanel(null, null); + preview = new PreviewPanel(null, null, Globals.getKeyPrefs(), Globals.prefs.getPreviewPreferences()); sortedEntries = new SortedList<>(entries, new EntryComparator(false, true, FieldName.AUTHOR)); model = (DefaultEventTableModel) GlazedListsSwing.eventTableModelWithThreadProxyList(sortedEntries, diff --git a/src/main/java/org/jabref/gui/specialfields/SpecialFieldDatabaseChangeListener.java b/src/main/java/org/jabref/gui/specialfields/SpecialFieldDatabaseChangeListener.java index 4b4f0d23e79..6813f8f9183 100644 --- a/src/main/java/org/jabref/gui/specialfields/SpecialFieldDatabaseChangeListener.java +++ b/src/main/java/org/jabref/gui/specialfields/SpecialFieldDatabaseChangeListener.java @@ -1,15 +1,6 @@ package org.jabref.gui.specialfields; -import java.util.List; - -import org.jabref.Globals; -import org.jabref.gui.undo.NamedCompound; -import org.jabref.gui.undo.UndoableFieldChange; -import org.jabref.logic.l10n.Localization; -import org.jabref.logic.specialfields.SpecialFieldsUtils; -import org.jabref.model.FieldChange; import org.jabref.model.database.event.EntryAddedEvent; -import org.jabref.model.entry.BibEntry; import com.google.common.eventbus.Subscribe; @@ -26,10 +17,13 @@ public static SpecialFieldDatabaseChangeListener getInstance() { @Subscribe public void listen(EntryAddedEvent event) { + // TODO + /* if (!Globals.prefs.isKeywordSyncEnabled()) { return; } + final BibEntry entry = event.getBibEntry(); // NamedCompount code similar to SpecialFieldUpdateListener NamedCompound nc = new NamedCompound(Localization.lang("Synchronized special fields based on keywords")); @@ -40,5 +34,6 @@ public void listen(EntryAddedEvent event) { // Don't insert the compound into the undoManager, // it would be added before the component which undoes the insertion of the entry and creates heavy problems // (which prohibits the undo the deleting multiple entries) + */ } } diff --git a/src/main/java/org/jabref/migrations/FileLinksUpgradeWarning.java b/src/main/java/org/jabref/migrations/FileLinksUpgradeWarning.java index 410deea49fe..1e7c11fc8b2 100644 --- a/src/main/java/org/jabref/migrations/FileLinksUpgradeWarning.java +++ b/src/main/java/org/jabref/migrations/FileLinksUpgradeWarning.java @@ -1,6 +1,7 @@ package org.jabref.migrations; import java.util.List; +import java.util.Map; import javax.swing.JButton; import javax.swing.JCheckBox; @@ -13,7 +14,6 @@ import org.jabref.gui.BasePanel; import org.jabref.gui.DialogService; import org.jabref.gui.FXDialogService; -import org.jabref.gui.entryeditor.EntryEditorTabList; import org.jabref.gui.importer.actions.GUIPostOpenAction; import org.jabref.gui.undo.NamedCompound; import org.jabref.gui.undo.UndoableFieldChange; @@ -248,17 +248,13 @@ private void makeChanges(BasePanel panel, ParserResult pr, boolean upgradePrefs, } private boolean showsFileInGenFields() { - boolean found = false; - EntryEditorTabList tabList = Globals.prefs.getEntryEditorTabList(); - outer: for (int i = 0; i < tabList.getTabCount(); i++) { - List fields = tabList.getTabFields(i); - for (String field : fields) { + for (Map.Entry> tab : Globals.prefs.getEntryEditorTabList().entrySet()) { + for (String field : tab.getValue()) { if (field.equals(FieldName.FILE)) { - found = true; - break outer; + return true; } } } - return found; + return false; } } diff --git a/src/main/java/org/jabref/preferences/JabRefPreferences.java b/src/main/java/org/jabref/preferences/JabRefPreferences.java index 631f0b48f1a..c840405e1fe 100644 --- a/src/main/java/org/jabref/preferences/JabRefPreferences.java +++ b/src/main/java/org/jabref/preferences/JabRefPreferences.java @@ -431,7 +431,7 @@ public class JabRefPreferences implements PreferencesService { private final Preferences prefs; private GlobalBibtexKeyPattern keyPattern; // Object containing info about customized entry editor tabs. - private EntryEditorTabList tabList; + private Map> tabList; // The constructor is made private to enforce this as a singleton class: private JabRefPreferences() { @@ -1309,7 +1309,7 @@ public void purgeSeries(String prefix, int number) { } } - public EntryEditorTabList getEntryEditorTabList() { + public Map> getEntryEditorTabList() { if (tabList == null) { updateEntryEditorTabList(); } @@ -1317,7 +1317,7 @@ public EntryEditorTabList getEntryEditorTabList() { } public void updateEntryEditorTabList() { - tabList = new EntryEditorTabList(); + tabList = EntryEditorTabList.create(this); } /** diff --git a/src/main/java/org/jabref/preferences/PreviewPreferences.java b/src/main/java/org/jabref/preferences/PreviewPreferences.java index a4099ca8e54..4d7e9bb91b3 100644 --- a/src/main/java/org/jabref/preferences/PreviewPreferences.java +++ b/src/main/java/org/jabref/preferences/PreviewPreferences.java @@ -2,6 +2,8 @@ import java.util.List; +import org.jabref.Globals; +import org.jabref.logic.layout.LayoutFormatterPreferences; public class PreviewPreferences { @@ -49,6 +51,14 @@ public Builder getBuilder() { return new Builder(this); } + public String getCurrentPreviewStyle() { + return getPreviewCycle().get(getPreviewCyclePosition()); + } + + public LayoutFormatterPreferences getLayoutFormatterPreferences() { + return Globals.prefs.getLayoutFormatterPreferences(Globals.journalAbbreviationLoader); + } + public static class Builder { private List previewCycle; private int previeCyclePosition; diff --git a/src/test/java/org/jabref/gui/BasePanelTest.java b/src/test/java/org/jabref/gui/BasePanelTest.java new file mode 100644 index 00000000000..33969b7e6e8 --- /dev/null +++ b/src/test/java/org/jabref/gui/BasePanelTest.java @@ -0,0 +1,69 @@ +package org.jabref.gui; + +import javafx.scene.Scene; +import javafx.scene.control.SplitPane; +import javafx.stage.Stage; + +import org.jabref.gui.autocompleter.AutoCompletePreferences; +import org.jabref.gui.entryeditor.EntryEditorPreferences; +import org.jabref.gui.externalfiletype.ExternalFileTypes; +import org.jabref.gui.keyboard.KeyBindingRepository; +import org.jabref.gui.maintable.MainTablePreferences; +import org.jabref.model.database.BibDatabaseContext; +import org.jabref.model.entry.BibEntry; +import org.jabref.preferences.PreviewPreferences; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.testfx.api.FxRobot; +import org.testfx.framework.junit5.ApplicationExtension; +import org.testfx.framework.junit5.Start; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.RETURNS_MOCKS; +import static org.mockito.Mockito.mock; + +@ExtendWith(ApplicationExtension.class) +public class BasePanelTest { + + private BasePanel panel; + private BibDatabaseContext bibDatabaseContext; + private BasePanelPreferences preferences; + + @Start + public void onStart(Stage stage) { + JabRefFrame frame = mock(JabRefFrame.class, RETURNS_MOCKS); + ExternalFileTypes externalFileTypes = mock(ExternalFileTypes.class); + bibDatabaseContext = new BibDatabaseContext(); + preferences = new BasePanelPreferences( + mock(MainTablePreferences.class, RETURNS_MOCKS), + mock(AutoCompletePreferences.class, RETURNS_MOCKS), + mock(EntryEditorPreferences.class, RETURNS_MOCKS), + mock(KeyBindingRepository.class, RETURNS_MOCKS), + mock(PreviewPreferences.class, RETURNS_MOCKS), + 0.5 + ); + panel = new BasePanel(frame, preferences, bibDatabaseContext, externalFileTypes); + + stage.setScene(new Scene(panel)); + stage.show(); + } + + @Test + void dividerPositionIsRestoredOnReopenEntryEditor(FxRobot robot) throws Exception { + BibEntry entry = new BibEntry(); + bibDatabaseContext.getDatabase().insertEntry(entry); + + SplitPane splitPane = robot.lookup(".split-pane").query(); + + robot.interact(() -> panel.showAndEdit(entry)); + robot.interact(() -> splitPane.getDividers().get(0).setPosition(0.8)); + robot.sleep(1000); + + robot.interact(() -> panel.closeBottomPane()); + robot.sleep(1000); + robot.interact(() -> panel.showAndEdit(entry)); + + assertEquals(0.8, splitPane.getDividers().get(0).getPosition(), 0.1); + } +} diff --git a/src/test/java/org/jabref/gui/entryeditor/EntryEditorTest.java b/src/test/java/org/jabref/gui/entryeditor/EntryEditorTest.java index 2e8e4746b39..957e036ceb1 100644 --- a/src/test/java/org/jabref/gui/entryeditor/EntryEditorTest.java +++ b/src/test/java/org/jabref/gui/entryeditor/EntryEditorTest.java @@ -8,18 +8,21 @@ import org.jabref.gui.undo.CountingUndoManager; import org.jabref.logic.bibtex.LatexFieldFormatterPreferences; +import org.jabref.logic.importer.ImportFormatPreferences; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; -import org.jabref.preferences.JabRefPreferences; import org.fxmisc.richtext.CodeArea; -import org.junit.Test; -import org.mockito.Answers; -import org.testfx.framework.junit.ApplicationTest; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.testfx.api.FxRobot; +import org.testfx.framework.junit5.ApplicationExtension; +import org.testfx.framework.junit5.Start; import static org.mockito.Mockito.mock; -public class EntryEditorTest extends ApplicationTest { +@ExtendWith(ApplicationExtension.class) +public class EntryEditorTest { private Stage stage; private Scene scene; @@ -27,12 +30,11 @@ public class EntryEditorTest extends ApplicationTest { private TabPane pane; private SourceTab sourceTab; - @Override - public void start(Stage stage) throws Exception { + @Start + public void onStart(Stage stage) { area = new CodeArea(); area.appendText("some example\n text to go here\n across a couple of \n lines...."); - JabRefPreferences preferences = mock(JabRefPreferences.class, Answers.RETURNS_DEEP_STUBS); - sourceTab = new SourceTab(new BibDatabaseContext(), new CountingUndoManager(), new LatexFieldFormatterPreferences(), preferences); + sourceTab = new SourceTab(new BibDatabaseContext(), new CountingUndoManager(), new LatexFieldFormatterPreferences(), mock(ImportFormatPreferences.class)); pane = new TabPane( new Tab("main area", area), new Tab("other tab", new Label("some text")), @@ -51,22 +53,22 @@ public void start(Stage stage) throws Exception { } @Test - public void switchingFromSourceTabDoesNotThrowException() throws Exception { + void switchingFromSourceTabDoesNotThrowException(FxRobot robot) throws Exception { BibEntry entry = new BibEntry(); entry.setField("test", "testvalue"); // Update source editor - interact(() -> pane.getSelectionModel().select(2)); - interact(() -> sourceTab.bindToEntry(entry)); - clickOn(1200, 500); - interrupt(100); + robot.interact(() -> pane.getSelectionModel().select(2)); + robot.interact(() -> sourceTab.bindToEntry(entry)); + robot.clickOn(1200, 500); + robot.interrupt(100); // Switch to different tab & update entry - interact(() -> pane.getSelectionModel().select(1)); - interact(() -> stage.setWidth(600)); - interact(() -> entry.setField("test", "new value")); + robot.interact(() -> pane.getSelectionModel().select(1)); + robot.interact(() -> stage.setWidth(600)); + robot.interact(() -> entry.setField("test", "new value")); // No exception should be thrown - interrupt(100); + robot.interrupt(100); } } From 09b000b9e97a14531c21f6905e731a799a2b7759 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Tue, 2 Jan 2018 00:54:29 +0100 Subject: [PATCH 08/24] Flat design for tab header --- src/main/java/org/jabref/gui/Main.css | 71 +++++++++++++++++++ .../jabref/gui/entryeditor/EntryEditor.css | 21 ------ .../org/jabref/gui/maintable/MainTable.css | 10 +-- 3 files changed, 77 insertions(+), 25 deletions(-) diff --git a/src/main/java/org/jabref/gui/Main.css b/src/main/java/org/jabref/gui/Main.css index 95a63836304..c5b650767b6 100644 --- a/src/main/java/org/jabref/gui/Main.css +++ b/src/main/java/org/jabref/gui/Main.css @@ -48,6 +48,10 @@ */ -fx-active-background: #6A9FCD; + /* + * A dark gray for borders + */ + -fx-border: #868786; } .hyperlink { @@ -121,3 +125,70 @@ .flatButtonNoSpaceTop { -fx-padding: -0.1em 0.5em 0.5em 0.5em; } + +.tab-pane { + -fx-open-tab-animation: NONE; + -fx-close-tab-animation: NONE; +} + +.tab-pane > .tab-header-area > .headers-region > .tab { + -fx-background-insets: 0; + -fx-background-radius: 0; + -fx-background-color: -fx-accented-background; + -fx-border-color: -fx-border; + -fx-border-width: 0.5 0.5 0.5 0.5; + -fx-padding: 0.4em 0.9em 0.4em 0.9em; +} + +.tab-pane > .tab-header-area > .headers-region > .tab .tab-label { + -fx-text-fill: -fx-unimportant; +} + +.tab-pane > .tab-header-area > .headers-region > .tab:selected { + -fx-background-color: -fx-light-background; + -fx-border-color: -fx-active-background; + -fx-border-width: 3 0 0 0; +} + +.tab-pane > .tab-header-area > .headers-region > .tab:selected .tab-label { + -fx-text-fill: black; +} + +.tab-pane:focused > .tab-header-area > .headers-region > .tab:selected .focus-indicator { + -fx-border-width: 0; + -fx-border-insets: 0; + -fx-border-radius: 0; +} + +.tab-pane > .tab-header-area > .tab-header-background { + -fx-background-color: -fx-accented-background; +} + +.tab-pane > .tab-header-area > .headers-region > .tab .glyph-icon { + -glyph-size: 13px; + -fx-text-fill: -fx-unimportant; + -fx-fill: -fx-unimportant; +} + +.tab-pane > .tab-header-area > .headers-region > .tab:selected .glyph-icon { + -fx-text-fill: black; + -fx-fill: black; +} + +.tab-pane > .tab-header-area { + -fx-padding: 0.416667em 5 0.0em 0em; +} + +.table-view { + -fx-background-insets: 0; + -fx-padding: 0; +} + +.table-view:focused { + -fx-background-insets: 0; +} + +.split-pane > .split-pane-divider { + -fx-background-color: -fx-accented-background; + -fx-padding: 0 0.15ex 0 0.15ex; +} diff --git a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.css b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.css index 0e66bb6c607..34db97e415b 100644 --- a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.css +++ b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.css @@ -54,27 +54,6 @@ -fx-padding: -0.2em 0.1em 0.1em 0.1em; } -#tabbed { - -fx-open-tab-animation: NONE; - -fx-close-tab-animation: NONE; -} - -#tabbed > .tab-header-area > .tab-header-background { - -fx-background-color: #dadad8; -} - -#tabbed > .tab-header-area > .headers-region > .tab:selected { - -fx-background-color: -fx-outer-border, -fx-inner-border, -fx-light-background; -} - -#tabbed > .tab-header-area .glyph-icon { - -glyph-size: 13px; -} - -#tabbed > .tab-header-area { - -fx-padding: 0.416667em 5 0.0em 0em; -} - .editorPane .glyph-icon { -glyph-size: 16px; } diff --git a/src/main/java/org/jabref/gui/maintable/MainTable.css b/src/main/java/org/jabref/gui/maintable/MainTable.css index 651b8376d4a..1bb042ca76d 100644 --- a/src/main/java/org/jabref/gui/maintable/MainTable.css +++ b/src/main/java/org/jabref/gui/maintable/MainTable.css @@ -1,14 +1,17 @@ .table-view { - + -fx-border-width: 0; + -fx-padding: 0; + -fx-border-insets: 0; + -fx-background-color: -fx-light-background; } .table-view .column-header-background { - -fx-background-color: -fx-control-inner-background; + -fx-background-color: -fx-light-background; } .table-view .column-header, .table-view .filler { - -fx-background-color: -fx-control-inner-background; + -fx-background-color: -fx-light-background; -fx-font-weight: bold; -fx-size: 3em; -fx-border-width: 0 0 1 0; @@ -45,4 +48,3 @@ -fx-padding: 0; -fx-alignment: baseline-center; } - From d7d00a8f5d81eb54bd920eff5762d107e052f638 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Tue, 2 Jan 2018 23:04:39 +0100 Subject: [PATCH 09/24] Add dummy context menu to row --- src/main/java/org/jabref/gui/JabRefFrame.java | 2 +- .../org/jabref/gui/maintable/MainTable.java | 3 ++- .../{menus => maintable}/RightClickMenu.java | 15 ++++++++++++++- .../gui/util/ViewModelTableRowFactory.java | 19 +++++++++++++++++++ 4 files changed, 36 insertions(+), 3 deletions(-) rename src/main/java/org/jabref/gui/{menus => maintable}/RightClickMenu.java (96%) diff --git a/src/main/java/org/jabref/gui/JabRefFrame.java b/src/main/java/org/jabref/gui/JabRefFrame.java index 732c43aadbf..06c06d161e3 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -108,9 +108,9 @@ import org.jabref.gui.journals.ManageJournalsAction; import org.jabref.gui.keyboard.KeyBinding; import org.jabref.gui.keyboard.KeyBindingAction; +import org.jabref.gui.maintable.RightClickMenu; import org.jabref.gui.menus.ChangeEntryTypeMenu; import org.jabref.gui.menus.FileHistoryMenu; -import org.jabref.gui.menus.RightClickMenu; import org.jabref.gui.openoffice.OpenOfficePanel; import org.jabref.gui.openoffice.OpenOfficeSidePanel; import org.jabref.gui.preftabs.PreferencesDialog; diff --git a/src/main/java/org/jabref/gui/maintable/MainTable.java b/src/main/java/org/jabref/gui/maintable/MainTable.java index dcaaaf63405..6930debf1a5 100644 --- a/src/main/java/org/jabref/gui/maintable/MainTable.java +++ b/src/main/java/org/jabref/gui/maintable/MainTable.java @@ -82,7 +82,8 @@ public MainTable(MainTableDataModel model, JabRefFrame frame, if (event.getClickCount() == 2) { panel.showAndEdit(entry.getEntry()); } - })); + }) + .withContextMenu(RightClickMenu::create)); if (preferences.resizeColumnsToFit()) { this.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); } diff --git a/src/main/java/org/jabref/gui/menus/RightClickMenu.java b/src/main/java/org/jabref/gui/maintable/RightClickMenu.java similarity index 96% rename from src/main/java/org/jabref/gui/menus/RightClickMenu.java rename to src/main/java/org/jabref/gui/maintable/RightClickMenu.java index f2dc69df8db..88b80af064f 100644 --- a/src/main/java/org/jabref/gui/menus/RightClickMenu.java +++ b/src/main/java/org/jabref/gui/maintable/RightClickMenu.java @@ -1,4 +1,4 @@ -package org.jabref.gui.menus; +package org.jabref.gui.maintable; import java.awt.event.ActionEvent; import java.util.Arrays; @@ -16,6 +16,8 @@ import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; +import javafx.scene.control.ContextMenu; + import org.jabref.Globals; import org.jabref.gui.BasePanel; import org.jabref.gui.EntryMarker; @@ -25,6 +27,7 @@ import org.jabref.gui.copyfiles.CopyFilesAction; import org.jabref.gui.filelist.FileListTableModel; import org.jabref.gui.keyboard.KeyBinding; +import org.jabref.gui.menus.ChangeEntryTypeMenu; import org.jabref.gui.mergeentries.FetchAndMergeEntry; import org.jabref.gui.specialfields.SpecialFieldMenuAction; import org.jabref.gui.specialfields.SpecialFieldValueViewModel; @@ -318,4 +321,14 @@ public void actionPerformed(ActionEvent e) { } } + public static ContextMenu create(BibEntryTableViewModel entry) { + ContextMenu contextMenu = new ContextMenu(); + + javafx.scene.control.MenuItem copy = new javafx.scene.control.MenuItem(); + copy.setText(Localization.lang("Copy")); + copy.setGraphic(IconTheme.JabRefIcons.COPY.getGraphicNode()); + contextMenu.getItems().add(copy); + + return contextMenu; + } } diff --git a/src/main/java/org/jabref/gui/util/ViewModelTableRowFactory.java b/src/main/java/org/jabref/gui/util/ViewModelTableRowFactory.java index 4f43b5e072e..3bd35d101fb 100644 --- a/src/main/java/org/jabref/gui/util/ViewModelTableRowFactory.java +++ b/src/main/java/org/jabref/gui/util/ViewModelTableRowFactory.java @@ -1,7 +1,9 @@ package org.jabref.gui.util; import java.util.function.BiConsumer; +import java.util.function.Function; +import javafx.scene.control.ContextMenu; import javafx.scene.control.TableRow; import javafx.scene.control.TableView; import javafx.scene.control.TreeTableCell; @@ -16,12 +18,18 @@ public class ViewModelTableRowFactory implements Callback, TableRow> { private BiConsumer onMouseClickedEvent; + private Function contextMenuFactory; public ViewModelTableRowFactory withOnMouseClickedEvent(BiConsumer onMouseClickedEvent) { this.onMouseClickedEvent = onMouseClickedEvent; return this; } + public ViewModelTableRowFactory withContextMenu(Function contextMenuFactory) { + this.contextMenuFactory = contextMenuFactory; + return this; + } + @Override public TableRow call(TableView tableView) { TableRow row = new TableRow<>(); @@ -34,6 +42,17 @@ public TableRow call(TableView tableView) { }); } + if (contextMenuFactory != null) { + // We only create the context menu when really necessary + row.setOnContextMenuRequested(event -> { + if (!row.isEmpty()) { + row.setContextMenu(contextMenuFactory.apply(row.getItem())); + row.getContextMenu().show(row, event.getScreenX(), event.getScreenY()); + } + event.consume(); + }); + } + return row; } } From 7f6c9243caa63887b8499c8f5707e8f0b51a43cb Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Wed, 3 Jan 2018 20:57:03 +0100 Subject: [PATCH 10/24] Improve hover and selected row style --- src/main/java/org/jabref/gui/Main.css | 23 +++++++++++++++++++ .../java/org/jabref/gui/groups/GroupTree.css | 14 ----------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/jabref/gui/Main.css b/src/main/java/org/jabref/gui/Main.css index c5b650767b6..13c2785c77d 100644 --- a/src/main/java/org/jabref/gui/Main.css +++ b/src/main/java/org/jabref/gui/Main.css @@ -192,3 +192,26 @@ -fx-background-color: -fx-accented-background; -fx-padding: 0 0.15ex 0 0.15ex; } + +.table-row-cell:hover, +.tree-table-row-cell:hover { + -fx-background-color: lightgrey; +} + +.table-row-cell:selected, +.tree-table-row-cell:selected { + -fx-background-color: #6A9FCD; + -fx-text-fill: white; + -fx-fill: white; +} + +.tree-table-row-cell:selected > .tree-table-cell > .glyph-icon { + -fx-fill: white; + -fx-text-fill: white; +} + +.table-view > .virtual-flow > .clipped-container > .sheet > .table-row-cell .table-cell:selected, +.tree-table-view > .virtual-flow > .clipped-container > .sheet > .tree-table-row-cell .tree-table-cell:selected { + -fx-border-color: transparent; + -fx-background-insets: 0; +} diff --git a/src/main/java/org/jabref/gui/groups/GroupTree.css b/src/main/java/org/jabref/gui/groups/GroupTree.css index 22708ffeb20..ec41e9ac5a1 100644 --- a/src/main/java/org/jabref/gui/groups/GroupTree.css +++ b/src/main/java/org/jabref/gui/groups/GroupTree.css @@ -76,20 +76,6 @@ -fx-padding: 0.45em 0.2em 0.45em 0.2em; } -.tree-table-row-cell:hover { - -fx-background-color: lightgrey; -} - -.tree-table-row-cell:selected { - -fx-background-color: #6A9FCD; - -fx-text-fill: white; - -fx-fill: white; -} - -.tree-table-row-cell:selected > .tree-table-cell > .icon { - -fx-fill: white; -} - .tree-table-row-cell:selected > .tree-table-cell > .tree-disclosure-node > .arrow { -fx-background-color: white; } From dc41f2959b4597cab6c05484a52aeeebe5c21156 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Wed, 3 Jan 2018 21:05:35 +0100 Subject: [PATCH 11/24] Further improve hover and selected row style --- src/main/java/org/jabref/gui/Main.css | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/main/java/org/jabref/gui/Main.css b/src/main/java/org/jabref/gui/Main.css index 13c2785c77d..cf74e532701 100644 --- a/src/main/java/org/jabref/gui/Main.css +++ b/src/main/java/org/jabref/gui/Main.css @@ -215,3 +215,25 @@ -fx-border-color: transparent; -fx-background-insets: 0; } + +/* Selected rows */ +.list-view:focused > .virtual-flow > .clipped-container > .sheet > .list-cell:filled:selected, +.tree-view:focused > .virtual-flow > .clipped-container > .sheet > .tree-cell:filled:selected, +.table-view:focused > .virtual-flow > .clipped-container > .sheet > .table-row-cell:filled:selected, +.tree-table-view:focused > .virtual-flow > .clipped-container > .sheet > .tree-table-row-cell:filled:selected, +.table-view:focused > .virtual-flow > .clipped-container > .sheet > .table-row-cell .table-cell:selected, +.tree-table-view:focused > .virtual-flow > .clipped-container > .sheet > .tree-table-row-cell .tree-table-cell:selected { + -fx-background: -fx-selection-bar; + -fx-table-cell-border-color: transparent; +} + +/* Selected when control is not focused */ +.list-cell:filled:selected, +.tree-cell:filled:selected, +.table-row-cell:filled:selected, +.tree-table-row-cell:filled:selected, +.table-row-cell:filled > .table-cell:selected, +.tree-table-row-cell:filled > .tree-table-cell:selected { + -fx-background: -fx-selection-bar; + -fx-table-cell-border-color: transparent; +} From 38f0d15a046f742e0f556c255e95f58fffcf221a Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Thu, 4 Jan 2018 16:08:30 +0100 Subject: [PATCH 12/24] Restore column width (except when "fit to width" option is enabled) --- src/main/java/org/jabref/gui/JabRefFrame.java | 3 +- .../gui/importer/ImportInspectionDialog.java | 4 +- .../jabref/gui/maintable/ColumnFactory.java | 30 ++++--- .../gui/maintable/ColumnPreferences.java | 42 +++++++++- .../org/jabref/gui/maintable/MainTable.java | 36 -------- .../SmartConstraintedResizePolicy.java | 23 +++++ .../jabref/gui/preftabs/TableColumnsTab.java | 84 +++++++++---------- .../jabref/gui/search/SearchResultFrame.java | 8 +- .../jabref/model/entry/BibtexSingleField.java | 9 +- .../model/entry/InternalBibtexFields.java | 2 +- 10 files changed, 135 insertions(+), 106 deletions(-) create mode 100644 src/main/java/org/jabref/gui/maintable/SmartConstraintedResizePolicy.java diff --git a/src/main/java/org/jabref/gui/JabRefFrame.java b/src/main/java/org/jabref/gui/JabRefFrame.java index 70f113615be..0255e88edfd 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -1503,8 +1503,7 @@ public void setupAllTables() { // Update tables: if (bf.getDatabase() != null) { - bf.setupMainPanel(); - + DefaultTaskExecutor.runInJavaFXThread(bf::setupMainPanel); } } } diff --git a/src/main/java/org/jabref/gui/importer/ImportInspectionDialog.java b/src/main/java/org/jabref/gui/importer/ImportInspectionDialog.java index 5d70a3cf0af..d87b66da8f5 100644 --- a/src/main/java/org/jabref/gui/importer/ImportInspectionDialog.java +++ b/src/main/java/org/jabref/gui/importer/ImportInspectionDialog.java @@ -582,8 +582,8 @@ private void setWidths() { } for (int i = 0; i < INSPECTION_FIELDS.size(); i++) { - int width = InternalBibtexFields.getFieldLength(INSPECTION_FIELDS.get(i)); - glTable.getColumnModel().getColumn(i + PAD).setPreferredWidth(width); + Double width = InternalBibtexFields.getFieldLength(INSPECTION_FIELDS.get(i)); + glTable.getColumnModel().getColumn(i + PAD).setPreferredWidth(width.intValue()); } } diff --git a/src/main/java/org/jabref/gui/maintable/ColumnFactory.java b/src/main/java/org/jabref/gui/maintable/ColumnFactory.java index 2c50844b8b9..93515a85f9a 100644 --- a/src/main/java/org/jabref/gui/maintable/ColumnFactory.java +++ b/src/main/java/org/jabref/gui/maintable/ColumnFactory.java @@ -10,6 +10,7 @@ import javafx.scene.Node; import javafx.scene.control.TableColumn; +import org.jabref.gui.GUIGlobals; import org.jabref.gui.IconTheme; import org.jabref.gui.JabRefIcon; import org.jabref.gui.externalfiletype.ExternalFileType; @@ -87,7 +88,9 @@ public ColumnFactory(BibDatabase database, ColumnPreferences preferences, Extern // Stored column name will be used as header // There might be more than one field to display, e.g., "author/editor" or "date/year" - so split String[] fields = columnName.split(FieldName.FIELD_SEPARATOR); - columns.add(new StringTableColumn(columnName, Arrays.asList(fields), database)); + StringTableColumn column = new StringTableColumn(columnName, Arrays.asList(fields), database); + column.setPrefWidth(preferences.getPrefColumnWidth(columnName)); + columns.add(column); } return columns; } @@ -96,8 +99,13 @@ private TableColumn TableColumn> column = new TableColumn<>(); column.setGraphic(new SpecialFieldViewModel(specialField).getIcon().getGraphicNode()); column.getStyleClass().add(STYLE_ICON); - column.setMinWidth(30); - column.setMaxWidth(30); + if (specialField == SpecialField.RANKING) { + column.setMinWidth(GUIGlobals.WIDTH_ICON_COL_RANKING); + column.setMaxWidth(GUIGlobals.WIDTH_ICON_COL_RANKING); + } else { + column.setMinWidth(GUIGlobals.WIDTH_ICON_COL); + column.setMaxWidth(GUIGlobals.WIDTH_ICON_COL); + } column.setCellValueFactory(cellData -> cellData.getValue().getSpecialField(specialField)); column.setCellFactory( new ValueTableCellFactory>() @@ -110,8 +118,8 @@ private TableColumn> createFileColumn() TableColumn> column = new TableColumn<>(); column.setGraphic(IconTheme.JabRefIcons.FILE.getGraphicNode()); column.getStyleClass().add(STYLE_ICON); - column.setMinWidth(30); - column.setMaxWidth(30); + column.setMinWidth(GUIGlobals.WIDTH_ICON_COL); + column.setMaxWidth(GUIGlobals.WIDTH_ICON_COL); column.setCellValueFactory(cellData -> cellData.getValue().getLinkedFiles()); column.setCellFactory( new ValueTableCellFactory>() @@ -126,8 +134,8 @@ private TableColumn createIconColumn(JabRefIcon TableColumn column = new TableColumn<>(); column.setGraphic(icon.getGraphicNode()); column.getStyleClass().add(STYLE_ICON); - column.setMinWidth(30); - column.setMaxWidth(30); + column.setMinWidth(GUIGlobals.WIDTH_ICON_COL); + column.setMaxWidth(GUIGlobals.WIDTH_ICON_COL); column.setCellValueFactory(cellData -> EasyBind.monadic(cellData.getValue().getField(firstField)).orElse(cellData.getValue().getField(secondField))); column.setCellFactory( new ValueTableCellFactory() @@ -139,8 +147,8 @@ private TableColumn createIconColumn(JabRefIcon TableColumn column = new TableColumn<>(); column.setGraphic(icon.getGraphicNode()); column.getStyleClass().add(STYLE_ICON); - column.setMinWidth(30); - column.setMaxWidth(30); + column.setMinWidth(GUIGlobals.WIDTH_ICON_COL); + column.setMaxWidth(GUIGlobals.WIDTH_ICON_COL); column.setCellValueFactory(cellData -> cellData.getValue().getField(field)); column.setCellFactory( new ValueTableCellFactory() @@ -160,8 +168,8 @@ private TableColumn> createExtraFileCol .map(ExternalFileType::getIcon).orElse(IconTheme.JabRefIcons.FILE) .getGraphicNode()); column.getStyleClass().add(STYLE_ICON); - column.setMinWidth(30); - column.setMaxWidth(30); + column.setMinWidth(GUIGlobals.WIDTH_ICON_COL); + column.setMaxWidth(GUIGlobals.WIDTH_ICON_COL); column.setCellValueFactory(cellData -> cellData.getValue().getLinkedFiles()); column.setCellFactory( new ValueTableCellFactory>() diff --git a/src/main/java/org/jabref/gui/maintable/ColumnPreferences.java b/src/main/java/org/jabref/gui/maintable/ColumnPreferences.java index 40ad69e7453..e83048bc4a3 100644 --- a/src/main/java/org/jabref/gui/maintable/ColumnPreferences.java +++ b/src/main/java/org/jabref/gui/maintable/ColumnPreferences.java @@ -3,12 +3,21 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.stream.Collectors; +import org.jabref.model.entry.BibtexSingleField; import org.jabref.model.entry.specialfields.SpecialField; import org.jabref.preferences.JabRefPreferences; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + public class ColumnPreferences { + private static final Log LOGGER = LogFactory.getLog(ColumnPreferences.class); + private final boolean showFileColumn; private final boolean showUrlColumn; private final boolean preferDoiOverUrl; @@ -16,8 +25,9 @@ public class ColumnPreferences { private final List normalColumns; private final List specialFieldColumns; private final List extraFileColumns; + private final Map columnWidths; - public ColumnPreferences(boolean showFileColumn, boolean showUrlColumn, boolean preferDoiOverUrl, boolean showEprintColumn, List normalColumns, List specialFieldColumns, List extraFileColumns) { + public ColumnPreferences(boolean showFileColumn, boolean showUrlColumn, boolean preferDoiOverUrl, boolean showEprintColumn, List normalColumns, List specialFieldColumns, List extraFileColumns, Map columnWidths) { this.showFileColumn = showFileColumn; this.showUrlColumn = showUrlColumn; this.preferDoiOverUrl = preferDoiOverUrl; @@ -25,6 +35,7 @@ public ColumnPreferences(boolean showFileColumn, boolean showUrlColumn, boolean this.normalColumns = normalColumns; this.specialFieldColumns = specialFieldColumns; this.extraFileColumns = extraFileColumns; + this.columnWidths = columnWidths; } public static ColumnPreferences from(JabRefPreferences preferences) { @@ -35,10 +46,33 @@ public static ColumnPreferences from(JabRefPreferences preferences) { preferences.getBoolean(JabRefPreferences.ARXIV_COLUMN), preferences.getStringList(JabRefPreferences.COLUMN_NAMES), createSpecialFieldColumns(preferences), - createExtraFileColumns(preferences) + createExtraFileColumns(preferences), + createColumnWidths(preferences) ); } + private static Map createColumnWidths(JabRefPreferences preferences) { + List columns = preferences.getStringList(JabRefPreferences.COLUMN_NAMES); + List widths = preferences + .getStringList(JabRefPreferences.COLUMN_WIDTHS) + .stream() + .map(string -> { + try { + return Double.parseDouble(string); + } catch (NumberFormatException e) { + LOGGER.error("Exception while parsing column widths. Choosing default.", e); + return BibtexSingleField.DEFAULT_FIELD_LENGTH; + } + }) + .collect(Collectors.toList()); + + Map map = new TreeMap<>(); + for (int i = 0; i < columns.size(); i++) { + map.put(columns.get(i), widths.get(i)); + } + return map; + } + private static List createExtraFileColumns(JabRefPreferences preferences) { if (preferences.getBoolean(JabRefPreferences.EXTRA_FILE_COLUMNS)) { return preferences.getStringList(JabRefPreferences.LIST_OF_FILE_COLUMNS); @@ -104,4 +138,8 @@ public List getSpecialFieldColumns() { public List getNormalColumns() { return normalColumns; } + + public double getPrefColumnWidth(String columnName) { + return columnWidths.getOrDefault(columnName, BibtexSingleField.DEFAULT_FIELD_LENGTH); + } } diff --git a/src/main/java/org/jabref/gui/maintable/MainTable.java b/src/main/java/org/jabref/gui/maintable/MainTable.java index 6930debf1a5..a5ab554b249 100644 --- a/src/main/java/org/jabref/gui/maintable/MainTable.java +++ b/src/main/java/org/jabref/gui/maintable/MainTable.java @@ -286,42 +286,6 @@ else if (column == 0) { return renderer; } - - // TODO: Set column widths - private void setWidths() { - // Setting column widths: - int ncWidth = Globals.prefs.getInt(JabRefPreferences.NUMBER_COL_WIDTH); - List widthsFromPreferences = Globals.prefs.getStringList(JabRefPreferences.COLUMN_WIDTHS); - TableColumnModel cm = getColumnModel(); - cm.getColumn(0).setPreferredWidth(ncWidth); - for (int i = 1; i < cm.getColumnCount(); i++) { - MainTableColumn mainTableColumn = tableFormat.getTableColumn(cm.getColumn(i).getModelIndex()); - if (SpecialField.RANKING.getFieldName().equals(mainTableColumn.getColumnName())) { - cm.getColumn(i).setPreferredWidth(GUIGlobals.WIDTH_ICON_COL_RANKING); - cm.getColumn(i).setMinWidth(GUIGlobals.WIDTH_ICON_COL_RANKING); - cm.getColumn(i).setMaxWidth(GUIGlobals.WIDTH_ICON_COL_RANKING); - } else if (mainTableColumn.isIconColumn()) { - cm.getColumn(i).setPreferredWidth(GUIGlobals.WIDTH_ICON_COL); - cm.getColumn(i).setMinWidth(GUIGlobals.WIDTH_ICON_COL); - cm.getColumn(i).setMaxWidth(GUIGlobals.WIDTH_ICON_COL); - } else { - List allColumns = Globals.prefs.getStringList(JabRefPreferences.COLUMN_NAMES); - // find index of current mainTableColumn in allColumns - for (int j = 0; j < allColumns.size(); j++) { - if (allColumns.get(j).equalsIgnoreCase(mainTableColumn.getDisplayName())) { - try { - // set preferred width by using found index j in the width array - cm.getColumn(i).setPreferredWidth(Integer.parseInt(widthsFromPreferences.get(j))); - } catch (NumberFormatException e) { - LOGGER.info("Exception while setting column widths. Choosing default.", e); - cm.getColumn(i).setPreferredWidth(BibtexSingleField.DEFAULT_FIELD_LENGTH); - } - break; - } - } - } - } - } */ public BibEntry getEntryAt(int row) { diff --git a/src/main/java/org/jabref/gui/maintable/SmartConstraintedResizePolicy.java b/src/main/java/org/jabref/gui/maintable/SmartConstraintedResizePolicy.java new file mode 100644 index 00000000000..5b173dd03cb --- /dev/null +++ b/src/main/java/org/jabref/gui/maintable/SmartConstraintedResizePolicy.java @@ -0,0 +1,23 @@ +package org.jabref.gui.maintable; + +import javafx.scene.control.TableView; +import javafx.util.Callback; + +public class SmartConstraintedResizePolicy implements Callback { + private boolean isFirstRun = true; + private Callback basePolicy = TableView.CONSTRAINED_RESIZE_POLICY; + + @Override + public Boolean call(TableView.ResizeFeatures prop) { + Boolean result = basePolicy.call(prop); + + // The CONSTRAINED_RESIZE_POLICY resizes all columns to the same width + // We want to resize them to (almost) their preferred width + if (isFirstRun) { + + } + + isFirstRun = isFirstRun && !result; + return result; + } +} diff --git a/src/main/java/org/jabref/gui/preftabs/TableColumnsTab.java b/src/main/java/org/jabref/gui/preftabs/TableColumnsTab.java index 525b223b06e..627220033bc 100644 --- a/src/main/java/org/jabref/gui/preftabs/TableColumnsTab.java +++ b/src/main/java/org/jabref/gui/preftabs/TableColumnsTab.java @@ -93,47 +93,6 @@ class TableColumnsTab extends JPanel implements PrefsTab { private boolean oldWriteSpecialFields; - /*** end: special fields ***/ - - static class TableRow { - - private String name; - private int length; - - - public TableRow() { - name = ""; - length = BibtexSingleField.DEFAULT_FIELD_LENGTH; - } - - public TableRow(String name) { - this.name = name; - length = BibtexSingleField.DEFAULT_FIELD_LENGTH; - } - - public TableRow(String name, int length) { - this.name = name; - this.length = length; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public int getLength() { - return length; - } - - public void setLength(int length) { - this.length = length; - } - } - - /** * Customization of external program paths. * @@ -174,7 +133,7 @@ public Object getValueAt(int row, int column) { if (column == 0) { return rowContent.getName(); } else { - return rowContent.getLength() > 0 ? Integer.toString(rowContent.getLength()) : ""; + return rowContent.getLength() > 0 ? Double.toString(rowContent.getLength()) : ""; } } @@ -373,6 +332,45 @@ public void setValueAt(Object value, int row, int col) { add(pan, BorderLayout.CENTER); } + /*** end: special fields ***/ + + static class TableRow { + + private String name; + private double length; + + public TableRow() { + name = ""; + length = BibtexSingleField.DEFAULT_FIELD_LENGTH; + } + + public TableRow(String name) { + this.name = name; + length = BibtexSingleField.DEFAULT_FIELD_LENGTH; + } + + public TableRow(String name, int length) { + this.name = name; + this.length = length; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public double getLength() { + return length; + } + + public void setLength(int length) { + this.length = length; + } + } + @Override public void setValues() { fileColumn.setSelected(prefs.getBoolean(JabRefPreferences.FILE_COLUMN)); @@ -770,12 +768,10 @@ public void storeSettings() { // Then we make arrays List names = new ArrayList<>(tableRows.size()); List widths = new ArrayList<>(tableRows.size()); - List nWidths = new ArrayList<>(tableRows.size()); prefs.putInt(JabRefPreferences.NUMBER_COL_WIDTH, ncWidth); for (TableRow tr : tableRows) { names.add(tr.getName().toLowerCase(Locale.ROOT)); - nWidths.add(tr.getLength()); widths.add(String.valueOf(tr.getLength())); } diff --git a/src/main/java/org/jabref/gui/search/SearchResultFrame.java b/src/main/java/org/jabref/gui/search/SearchResultFrame.java index fb1683da614..a4b31d17bd5 100644 --- a/src/main/java/org/jabref/gui/search/SearchResultFrame.java +++ b/src/main/java/org/jabref/gui/search/SearchResultFrame.java @@ -362,13 +362,13 @@ private void setWidths() { cm.getColumn(i).setMaxWidth(GUIGlobals.WIDTH_ICON_COL); break; case DATABASE_COL: { - int width = InternalBibtexFields.getFieldLength(FieldName.AUTHOR); - cm.getColumn(i).setPreferredWidth(width); + Double width = InternalBibtexFields.getFieldLength(FieldName.AUTHOR); + cm.getColumn(i).setPreferredWidth(width.intValue()); break; } default: { - int width = InternalBibtexFields.getFieldLength(FIELDS[i - PAD]); - cm.getColumn(i).setPreferredWidth(width); + Double width = InternalBibtexFields.getFieldLength(FIELDS[i - PAD]); + cm.getColumn(i).setPreferredWidth(width.intValue()); break; } } diff --git a/src/main/java/org/jabref/model/entry/BibtexSingleField.java b/src/main/java/org/jabref/model/entry/BibtexSingleField.java index 5c1f8776e93..14722ee9579 100644 --- a/src/main/java/org/jabref/model/entry/BibtexSingleField.java +++ b/src/main/java/org/jabref/model/entry/BibtexSingleField.java @@ -8,7 +8,8 @@ */ public class BibtexSingleField { - public static final int DEFAULT_FIELD_LENGTH = 100; + // TODO: This constant should be moved to the gui package, probably to ColumnFactory + public static final double DEFAULT_FIELD_LENGTH = 100; private enum Flag { STANDARD, @@ -24,7 +25,7 @@ private enum Flag { // default is: not standard, public, displayable and writable private final Set flags = EnumSet.of(Flag.DISPLAYABLE, Flag.WRITEABLE); - private final int length; + private final double length; // properties contains a set of FieldProperty to e.g. tell the EntryEditor to add a specific // function to this field, to format names, or to control the integrity checks. @@ -38,7 +39,7 @@ public BibtexSingleField(String fieldName, boolean pStandard) { this(fieldName, pStandard, DEFAULT_FIELD_LENGTH); } - public BibtexSingleField(String fieldName, boolean pStandard, int pLength) { + public BibtexSingleField(String fieldName, boolean pStandard, double pLength) { name = fieldName; setFlag(pStandard, Flag.STANDARD); length = pLength; @@ -105,7 +106,7 @@ public Set getProperties() { /** * @return The maximum (expected) length of the field value; not the length of the field name */ - public int getLength() { + public double getLength() { return this.length; } diff --git a/src/main/java/org/jabref/model/entry/InternalBibtexFields.java b/src/main/java/org/jabref/model/entry/InternalBibtexFields.java index 3cf4886c36f..7b13f6f33c0 100644 --- a/src/main/java/org/jabref/model/entry/InternalBibtexFields.java +++ b/src/main/java/org/jabref/model/entry/InternalBibtexFields.java @@ -402,7 +402,7 @@ private static Optional getField(String name) { return Optional.empty(); } - public static int getFieldLength(String name) { + public static Double getFieldLength(String name) { return InternalBibtexFields.getField(name) .map(BibtexSingleField::getLength) .orElse(BibtexSingleField.DEFAULT_FIELD_LENGTH); From 7e21bc415e4be76ac7af57066ca86fe3a0d39851 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Fri, 5 Jan 2018 22:49:13 +0100 Subject: [PATCH 13/24] Update entry editor and preview --- src/main/java/org/jabref/gui/BasePanel.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/org/jabref/gui/BasePanel.java b/src/main/java/org/jabref/gui/BasePanel.java index 64cfa4ff936..2cc7f8cc676 100644 --- a/src/main/java/org/jabref/gui/BasePanel.java +++ b/src/main/java/org/jabref/gui/BasePanel.java @@ -1219,6 +1219,16 @@ private void createMainTable() { // Add the listener that binds selection to state manager (TODO: should be replaced by proper JavaFX binding as soon as table is implemented in JavaFX) mainTable.addSelectionListener(listEvent -> Globals.stateManager.setSelectedEntries(mainTable.getSelectedEntries())); + // Update entry editor and preview according to selected entries + mainTable.addSelectionListener(event -> + mainTable.getSelectedEntries().stream() + .findFirst() + .ifPresent(entry -> { + preview.setEntry(entry); + entryEditor.setEntry(entry); + }) + ); + // TODO: Register these actions globally /* String clearSearch = "clearSearch"; From 667f1c4ad59eab247fc6ffe4fc226301bf8c9b41 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Fri, 5 Jan 2018 23:54:23 +0100 Subject: [PATCH 14/24] Filter by groups and search --- src/main/java/org/jabref/gui/BasePanel.java | 13 +- .../java/org/jabref/gui/StateManager.java | 15 ++ .../org/jabref/gui/groups/GroupSidePane.java | 52 ---- .../org/jabref/gui/groups/GroupingWorker.java | 42 --- .../org/jabref/gui/maintable/MainTable.java | 14 +- .../gui/maintable/MainTableDataModel.java | 254 +++--------------- .../jabref/gui/search/GlobalSearchBar.java | 18 +- .../org/jabref/gui/search/SearchWorker.java | 48 ---- 8 files changed, 70 insertions(+), 386 deletions(-) delete mode 100644 src/main/java/org/jabref/gui/groups/GroupingWorker.java diff --git a/src/main/java/org/jabref/gui/BasePanel.java b/src/main/java/org/jabref/gui/BasePanel.java index 2cc7f8cc676..235c8c1dfbe 100644 --- a/src/main/java/org/jabref/gui/BasePanel.java +++ b/src/main/java/org/jabref/gui/BasePanel.java @@ -1209,7 +1209,6 @@ public void updateTableFont() { } private void createMainTable() { - bibDatabaseContext.getDatabase().registerListener(tableModel.getListSynchronizer()); bibDatabaseContext.getDatabase().registerListener(SpecialFieldDatabaseChangeListener.getInstance()); mainTable = new MainTable(tableModel, frame, this, bibDatabaseContext.getDatabase(), preferences.getTablePreferences(), externalFileTypes); @@ -1327,8 +1326,8 @@ public void setupMainPanel() { splitPane.setOrientation(Orientation.VERTICAL); adjustSplitter(); // restore last splitting state (before mainTable is created as creation affects the stored size of the entryEditors) - // check whether a mainTable already existed and a floatSearch was active - boolean floatSearchActive = (mainTable != null) && (this.tableModel.getSearchState() == MainTableDataModel.DisplayOption.FLOAT); + // TODO: check whether a mainTable already existed and a floatSearch was active + //boolean floatSearchActive = (mainTable != null) && (this.tableModel.getSearchState() == MainTableDataModel.DisplayOption.FLOAT); createMainTable(); @@ -1347,11 +1346,11 @@ public void setupMainPanel() { setupAutoCompletion(); - // restore floating search result + // TODO: restore floating search result // (needed if preferences have been changed which causes a recreation of the main table) - if (floatSearchActive) { - mainTable.showFloatSearch(); - } + //if (floatSearchActive) { + // mainTable.showFloatSearch(); + //} // Saves the divider position as soon as it changes // We need to keep a reference to the subscription, otherwise the binding gets garbage collected dividerPositionSubscription = EasyBind.monadic(Bindings.valueAt(splitPane.getDividers(), 0)) diff --git a/src/main/java/org/jabref/gui/StateManager.java b/src/main/java/org/jabref/gui/StateManager.java index c09a7024372..6f5f79cb41e 100644 --- a/src/main/java/org/jabref/gui/StateManager.java +++ b/src/main/java/org/jabref/gui/StateManager.java @@ -14,6 +14,7 @@ import javafx.collections.ObservableList; import javafx.collections.ObservableMap; +import org.jabref.logic.search.SearchQuery; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.model.groups.GroupTreeNode; @@ -37,6 +38,12 @@ public class StateManager { private final ObservableList selectedEntries = FXCollections.observableArrayList(); private final ObservableMap> selectedGroups = FXCollections.observableHashMap(); + private final ObjectProperty> activeSearchQuery = new SimpleObjectProperty<>(Optional.empty()); + + public ObjectProperty> activeSearchQueryProperty() { + return activeSearchQuery; + } + public StateManager() { MonadicBinding currentDatabase = EasyBind.map(activeDatabase, database -> database.orElse(null)); activeGroups.bind(Bindings.valueAt(selectedGroups, currentDatabase)); @@ -80,4 +87,12 @@ public List getEntriesInCurrentDatabase() { return OptionalUtil.flatMap(activeDatabase.get(), BibDatabaseContext::getEntries) .collect(Collectors.toList()); } + + public void clearSearchQuery() { + activeSearchQuery.setValue(Optional.empty()); + } + + public void setSearchQuery(SearchQuery searchQuery) { + activeSearchQuery.setValue(Optional.of(searchQuery)); + } } diff --git a/src/main/java/org/jabref/gui/groups/GroupSidePane.java b/src/main/java/org/jabref/gui/groups/GroupSidePane.java index 448e1dc1030..dffa6529d2f 100644 --- a/src/main/java/org/jabref/gui/groups/GroupSidePane.java +++ b/src/main/java/org/jabref/gui/groups/GroupSidePane.java @@ -1,8 +1,5 @@ package org.jabref.gui.groups; -import java.util.Collections; -import java.util.List; - import javafx.application.Platform; import javafx.embed.swing.JFXPanel; import javafx.scene.Scene; @@ -16,18 +13,9 @@ import org.jabref.gui.SidePaneManager; import org.jabref.gui.customjfx.CustomJFXPanel; import org.jabref.gui.keyboard.KeyBinding; -import org.jabref.gui.maintable.MainTableDataModel; -import org.jabref.logic.groups.DefaultGroupsFactory; import org.jabref.logic.l10n.Localization; -import org.jabref.model.entry.FieldName; -import org.jabref.model.entry.event.FieldChangedEvent; -import org.jabref.model.groups.GroupTreeNode; -import org.jabref.model.search.matchers.MatcherSet; -import org.jabref.model.search.matchers.MatcherSets; import org.jabref.preferences.JabRefPreferences; -import com.google.common.eventbus.Subscribe; - /** * The groups side pane. * This class is just a Swing wrapper around the JavaFX implementation {@link GroupTreeView}. @@ -44,18 +32,6 @@ public class GroupSidePane extends SidePaneComponent { public GroupSidePane(JabRefFrame frame, SidePaneManager manager) { super(manager, IconTheme.JabRefIcons.TOGGLE_GROUPS.getIcon(), Localization.lang("Groups")); - Globals.stateManager.activeGroupProperty() - .addListener((observable, oldValue, newValue) -> updateShownEntriesAccordingToSelectedGroups(newValue)); - - // register the panel the current active context - Globals.stateManager.activeDatabaseProperty() - .addListener((observable, oldValue, newValue) -> { - newValue.ifPresent(databaseContext -> - databaseContext.getDatabase().registerListener(this)); - oldValue.ifPresent(databaseContext -> - databaseContext.getDatabase().unregisterListener(this)); - }); - toggleAction = new ToggleAction(Localization.menuTitle("Toggle groups interface"), Localization.lang("Toggle groups interface"), Globals.getKeyPrefs().getKey(KeyBinding.TOGGLE_GROUPS_INTERFACE), @@ -75,31 +51,6 @@ public GroupSidePane(JabRefFrame frame, SidePaneManager manager) { }); } - @Subscribe - public synchronized void listen(FieldChangedEvent event) { - if (FieldName.GROUPS.equals(event.getFieldName())) { - updateShownEntriesAccordingToSelectedGroups(Globals.stateManager.activeGroupProperty()); - } - } - - private void updateShownEntriesAccordingToSelectedGroups(List selectedGroups) { - if ((selectedGroups == null) || selectedGroups.isEmpty()) { - // No selected group, show all entries - selectedGroups = Collections.singletonList(new GroupTreeNode(DefaultGroupsFactory.getAllEntriesGroup())); - } - - final MatcherSet searchRules = MatcherSets.build( - Globals.prefs.getBoolean(JabRefPreferences.GROUP_INTERSECT_SELECTIONS) ? MatcherSets.MatcherType.AND : MatcherSets.MatcherType.OR); - - for (GroupTreeNode node : selectedGroups) { - searchRules.addRule(node.getSearchMatcher()); - } - - GroupingWorker worker = new GroupingWorker(frame, panel); - worker.run(searchRules); - worker.update(); - } - @Override public void componentOpening() { Globals.prefs.putBoolean(JabRefPreferences.GROUP_SIDEPANE_VISIBLE, Boolean.TRUE); @@ -112,9 +63,6 @@ public int getRescalingWeight() { @Override public void componentClosing() { - if (panel != null) { // panel may be null if no file is open any more - panel.getMainTable().getTableModel().updateGroupingState(MainTableDataModel.DisplayOption.DISABLED); - } getToggleAction().setSelected(false); Globals.prefs.putBoolean(JabRefPreferences.GROUP_SIDEPANE_VISIBLE, Boolean.FALSE); } diff --git a/src/main/java/org/jabref/gui/groups/GroupingWorker.java b/src/main/java/org/jabref/gui/groups/GroupingWorker.java deleted file mode 100644 index 6ce158e0fba..00000000000 --- a/src/main/java/org/jabref/gui/groups/GroupingWorker.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.jabref.gui.groups; - -import org.jabref.Globals; -import org.jabref.gui.BasePanel; -import org.jabref.gui.JabRefFrame; -import org.jabref.gui.maintable.MainTableDataModel; -import org.jabref.logic.l10n.Localization; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.search.SearchMatcher; -import org.jabref.preferences.JabRefPreferences; - -class GroupingWorker { - - private final JabRefFrame frame; - private final BasePanel panel; - - public GroupingWorker(JabRefFrame frame, BasePanel panel) { - this.frame = frame; - this.panel = panel; - } - - public void run(SearchMatcher matcher) { - for (BibEntry entry : panel.getDatabase().getEntries()) { - boolean hit = matcher.isMatch(entry); - entry.setGroupHit(hit); - } - } - - public void update() { - // Show the result in the chosen way: - if (Globals.prefs.getBoolean(JabRefPreferences.GRAY_OUT_NON_HITS)) { - panel.getMainTable().getTableModel().updateGroupingState(MainTableDataModel.DisplayOption.FLOAT); - } else { - panel.getMainTable().getTableModel().updateGroupingState(MainTableDataModel.DisplayOption.FILTER); - } - panel.getMainTable().getTableModel().updateSortOrder(); - panel.getMainTable().getTableModel().updateGroupFilter(); - panel.getMainTable().scrollTo(0); - - frame.output(Localization.lang("Updated group selection") + "."); - } -} diff --git a/src/main/java/org/jabref/gui/maintable/MainTable.java b/src/main/java/org/jabref/gui/maintable/MainTable.java index a5ab554b249..350aa95c33b 100644 --- a/src/main/java/org/jabref/gui/maintable/MainTable.java +++ b/src/main/java/org/jabref/gui/maintable/MainTable.java @@ -88,7 +88,7 @@ public MainTable(MainTableDataModel model, JabRefFrame frame, this.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); } this.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); - this.setItems(model.getTableRows()); + this.setItems(model.getEntriesFiltered()); // TODO: Cannot add focus listener as it is expecting an swing component //addFocusListener(Globals.getFocusListener()); @@ -289,7 +289,7 @@ else if (column == 0) { */ public BibEntry getEntryAt(int row) { - return model.getTableRows().get(row).getEntry(); + return model.getEntriesFiltered().get(row).getEntry(); } public List getSelectedEntries() { @@ -423,7 +423,7 @@ private CellRendererMode getCellStatus(int row, int col, boolean checkResolved) */ public Optional findEntry(BibEntry entry) { - return model.getTableRows().stream() + return model.getEntriesFiltered().stream() .filter(viewModel -> viewModel.getEntry().equals(entry)) .findFirst(); } @@ -453,18 +453,12 @@ private int isMarked(int row) { private Optional getBibEntry(int row) { try { - return Optional.of(model.getTableRows().get(row).getEntry()); + return Optional.of(model.getEntriesFiltered().get(row).getEntry()); } catch (IndexOutOfBoundsException e) { return Optional.empty(); } } - public void showFloatSearch() { - this.getTableModel().updateSearchState(MainTableDataModel.DisplayOption.FLOAT); - - scrollTo(0); - } - /** * Repaints the table with the most recent font configuration */ diff --git a/src/main/java/org/jabref/gui/maintable/MainTableDataModel.java b/src/main/java/org/jabref/gui/maintable/MainTableDataModel.java index b2696d6d04f..ebb5aa92132 100644 --- a/src/main/java/org/jabref/gui/maintable/MainTableDataModel.java +++ b/src/main/java/org/jabref/gui/maintable/MainTableDataModel.java @@ -1,247 +1,67 @@ package org.jabref.gui.maintable; -import java.util.Arrays; -import java.util.Comparator; import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; +import java.util.Optional; -import javafx.collections.FXCollections; +import javafx.beans.binding.Bindings; import javafx.collections.ObservableList; +import javafx.collections.transformation.FilteredList; -import org.jabref.gui.groups.GroupMatcher; -import org.jabref.gui.search.HitOrMissComparator; -import org.jabref.gui.search.matchers.EverythingMatcher; -import org.jabref.gui.search.matchers.SearchMatcher; -import org.jabref.gui.util.comparator.IsMarkedComparator; +import org.jabref.Globals; +import org.jabref.gui.util.BindingsHelper; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; - -import ca.odell.glazedlists.BasicEventList; -import ca.odell.glazedlists.EventList; -import ca.odell.glazedlists.FilterList; -import ca.odell.glazedlists.SortedList; -import ca.odell.glazedlists.matchers.Matcher; +import org.jabref.model.groups.GroupTreeNode; +import org.jabref.model.search.matchers.MatcherSet; +import org.jabref.model.search.matchers.MatcherSets; +import org.jabref.preferences.JabRefPreferences; public class MainTableDataModel { - - private final ListSynchronizer listSynchronizer; - private final SortedList sortedForUserDefinedTableColumnSorting; - private final SortedList sortedForMarkingSearchGrouping; - private final StartStopListFilterAction filterSearchToggle; - private final StartStopListFilterAction filterGroupToggle; - private final ObservableList finalList; - private final FilterAndSortingState filterAndSortingState = new FilterAndSortingState(); + private final FilteredList entriesFiltered; public MainTableDataModel(BibDatabaseContext context) { - List entries = context.getDatabase().getEntries(); - - EventList initialEventList = new BasicEventList<>(); - initialEventList.addAll(entries); - - listSynchronizer = new ListSynchronizer(initialEventList); - - // This SortedList has a Comparator controlled by the TableComparatorChooser - // we are going to install, which responds to user sorting selections: - sortedForUserDefinedTableColumnSorting = new SortedList<>(initialEventList, null); - // This SortedList applies afterwards, and floats marked entries: - sortedForMarkingSearchGrouping = new SortedList<>(sortedForUserDefinedTableColumnSorting, null); - - FilterList groupFilterList = new FilterList<>(sortedForMarkingSearchGrouping, EverythingMatcher.INSTANCE); - filterGroupToggle = new StartStopListFilterAction(groupFilterList, GroupMatcher.INSTANCE, - EverythingMatcher.INSTANCE); - FilterList searchFilterList = new FilterList<>(groupFilterList, EverythingMatcher.INSTANCE); - filterSearchToggle = new StartStopListFilterAction(searchFilterList, SearchMatcher.INSTANCE, - EverythingMatcher.INSTANCE); - - // TODO - //finalList = searchFilterList; - finalList = FXCollections.observableArrayList(entries.stream().map(BibEntryTableViewModel::new).collect(Collectors.toList())); - } + ObservableList allEntries = context.getDatabase().getEntries(); - public void updateSortOrder() { - Comparator markingComparator = filterAndSortingState.markingState ? IsMarkedComparator.INSTANCE : null; - Comparator searchComparator = getSearchState() == DisplayOption.FLOAT ? new HitOrMissComparator(SearchMatcher.INSTANCE) : null; - Comparator groupingComparator = getGroupingState() == DisplayOption.FLOAT ? new HitOrMissComparator(GroupMatcher.INSTANCE) : null; - GenericCompositeComparator comparator = new GenericCompositeComparator( - markingComparator, - searchComparator, - groupingComparator + entriesFiltered = new FilteredList<>( + BindingsHelper.mapBacked(allEntries, BibEntryTableViewModel::new)); + entriesFiltered.predicateProperty().bind( + Bindings.createObjectBinding(() -> this::isMatched, + Globals.stateManager.activeGroupProperty(), Globals.stateManager.activeSearchQueryProperty()) ); - - sortedForMarkingSearchGrouping.getReadWriteLock().writeLock().lock(); - try { - if (sortedForMarkingSearchGrouping.getComparator() != comparator) { - sortedForMarkingSearchGrouping.setComparator(comparator); - } - } finally { - sortedForMarkingSearchGrouping.getReadWriteLock().writeLock().unlock(); - } - } - - public void updateSearchState(DisplayOption searchState) { - Objects.requireNonNull(searchState); - - // fail fast - if (filterAndSortingState.searchState == searchState) { - return; - } - - boolean updateSortOrder = false; - if (filterAndSortingState.searchState == DisplayOption.FLOAT) { - updateSortOrder = true; - } else if (filterAndSortingState.searchState == DisplayOption.FILTER) { - filterSearchToggle.stop(); - } - - if (searchState == DisplayOption.FLOAT) { - updateSortOrder = true; - } else if (searchState == DisplayOption.FILTER) { - filterSearchToggle.start(); - } - - filterAndSortingState.searchState = searchState; - if (updateSortOrder) { - updateSortOrder(); - } - } - - public void updateGroupingState(DisplayOption groupingState) { - Objects.requireNonNull(groupingState); - - // fail fast - if (filterAndSortingState.groupingState == groupingState) { - return; - } - - boolean updateSortOrder = false; - if (filterAndSortingState.groupingState == DisplayOption.FLOAT) { - updateSortOrder = true; - } else if (filterAndSortingState.groupingState == DisplayOption.FILTER) { - filterGroupToggle.stop(); - } - - if (groupingState == DisplayOption.FLOAT) { - updateSortOrder = true; - } else if (groupingState == DisplayOption.FILTER) { - filterGroupToggle.start(); - } - - filterAndSortingState.groupingState = groupingState; - if (updateSortOrder) { - updateSortOrder(); - } } - public DisplayOption getSearchState() { - return filterAndSortingState.searchState; + private boolean isMatched(BibEntryTableViewModel entry) { + return isMatchedByGroup(entry) && isMatchedBySearch(entry); } - DisplayOption getGroupingState() { - return filterAndSortingState.groupingState; + private boolean isMatchedBySearch(BibEntryTableViewModel entry) { + return Globals.stateManager.activeSearchQueryProperty().getValue() + .map(matcher -> matcher.isMatch(entry.getEntry())) + .orElse(true); } - public ListSynchronizer getListSynchronizer() { - return this.listSynchronizer; + private boolean isMatchedByGroup(BibEntryTableViewModel entry) { + return createGroupMatcher(Globals.stateManager.activeGroupProperty().getValue()) + .map(matcher -> matcher.isMatch(entry.getEntry())) + .orElse(true); } - public void updateMarkingState(boolean floatMarkedEntries) { - // fail fast - if (filterAndSortingState.markingState == floatMarkedEntries) { - return; + private Optional createGroupMatcher(List selectedGroups) { + if ((selectedGroups == null) || selectedGroups.isEmpty()) { + // No selected group, show all entries + return Optional.empty(); } - filterAndSortingState.markingState = floatMarkedEntries; - updateSortOrder(); - } - - ObservableList getTableRows() { - return finalList; - } - - /** - * Returns the List of entries sorted by a user-selected term. This is the - * sorting before marking, search etc. applies. - *

- * Note: The returned List must not be modified from the outside - * - * @return The sorted list of entries. - */ - SortedList getSortedForUserDefinedTableColumnSorting() { - return sortedForUserDefinedTableColumnSorting; - } + final MatcherSet searchRules = MatcherSets.build( + Globals.prefs.getBoolean(JabRefPreferences.GROUP_INTERSECT_SELECTIONS) ? MatcherSets.MatcherType.AND : MatcherSets.MatcherType.OR); - public void updateGroupFilter() { - if (getGroupingState() == DisplayOption.FILTER) { - filterGroupToggle.start(); - } else { - filterGroupToggle.stop(); + for (GroupTreeNode node : selectedGroups) { + searchRules.addRule(node.getSearchMatcher()); } + return Optional.of(searchRules); } - public enum DisplayOption { - FLOAT, FILTER, DISABLED - } - - static class FilterAndSortingState { - // at the beginning, everything is disabled - private DisplayOption searchState = DisplayOption.DISABLED; - private DisplayOption groupingState = DisplayOption.DISABLED; - private boolean markingState = false; + public ObservableList getEntriesFiltered() { + return entriesFiltered; } - - private static class GenericCompositeComparator implements Comparator { - - private final List> comparators; - - - @SafeVarargs - public GenericCompositeComparator(Comparator... comparators) { - this.comparators = Arrays.asList(comparators).stream().filter(Objects::nonNull).collect(Collectors.toList()); - } - - @Override - public int compare(BibEntry lhs, BibEntry rhs) { - for (Comparator comp : comparators) { - int result = comp.compare(lhs, rhs); - if (result != 0) { - return result; - } - } - return 0; - } - } - - private static class StartStopListFilterAction { - - private final Matcher active; - private final Matcher inactive; - private final FilterList list; - - private StartStopListFilterAction(FilterList list, Matcher active, Matcher inactive) { - this.list = list; - this.active = active; - this.inactive = inactive; - - list.setMatcher(inactive); - } - - public void start() { - update(active); - } - - public void stop() { - update(inactive); - } - - private void update(Matcher comparator) { - list.getReadWriteLock().writeLock().lock(); - try { - list.setMatcher(comparator); - } finally { - list.getReadWriteLock().writeLock().unlock(); - } - } - } - } diff --git a/src/main/java/org/jabref/gui/search/GlobalSearchBar.java b/src/main/java/org/jabref/gui/search/GlobalSearchBar.java index 1ea33721900..47cc5c8ee5f 100644 --- a/src/main/java/org/jabref/gui/search/GlobalSearchBar.java +++ b/src/main/java/org/jabref/gui/search/GlobalSearchBar.java @@ -42,7 +42,6 @@ import org.jabref.gui.help.HelpAction; import org.jabref.gui.keyboard.KeyBinding; import org.jabref.gui.maintable.MainTable; -import org.jabref.gui.maintable.MainTableDataModel; import org.jabref.gui.util.DefaultTaskExecutor; import org.jabref.logic.help.HelpFile; import org.jabref.logic.l10n.Localization; @@ -275,7 +274,7 @@ private void updateSearchModeButtonText() { public void endSearch() { BasePanel currentBasePanel = frame.getCurrentBasePanel(); if (currentBasePanel != null) { - clearSearch(currentBasePanel); + clearSearch(); MainTable mainTable = frame.getCurrentBasePanel().getMainTable(); //Globals.getFocusListener().setFocused(mainTable); mainTable.requestFocus(); @@ -294,16 +293,13 @@ public void focus() { searchField.selectAll(); } - private void clearSearch(BasePanel currentBasePanel) { + private void clearSearch() { currentResults.setText(""); searchField.setText(""); searchQueryHighlightObservable.reset(); openCurrentResultsInDialog.setEnabled(false); - if (currentBasePanel != null) { - currentBasePanel.getMainTable().getTableModel().updateSearchState(MainTableDataModel.DisplayOption.DISABLED); - currentBasePanel.setCurrentSearchQuery(null); - } + Globals.stateManager.clearSearchQuery(); if (dontSelectSearchBar) { dontSelectSearchBar = false; @@ -324,7 +320,7 @@ public void performSearch() { // An empty search field should cause the search to be cleared. if (searchField.getText().isEmpty()) { - clearSearch(currentBasePanel); + clearSearch(); return; } @@ -334,6 +330,9 @@ public void performSearch() { return; } + Globals.stateManager.setSearchQuery(searchQuery); + + // TODO: Remove search worker as this is doing the work twice now searchWorker = new SearchWorker(currentBasePanel, searchQuery, searchDisplayMode); searchWorker.execute(); } @@ -343,8 +342,7 @@ private void informUserAboutInvalidSearchQuery() { searchQueryHighlightObservable.reset(); - BasePanel currentBasePanel = frame.getCurrentBasePanel(); - currentBasePanel.getMainTable().getTableModel().updateSearchState(MainTableDataModel.DisplayOption.DISABLED); + Globals.stateManager.clearSearchQuery(); String illegalSearch = Localization.lang("Search failed: illegal search expression"); currentResults.setText(illegalSearch); diff --git a/src/main/java/org/jabref/gui/search/SearchWorker.java b/src/main/java/org/jabref/gui/search/SearchWorker.java index 0a67414f214..75756776a0f 100644 --- a/src/main/java/org/jabref/gui/search/SearchWorker.java +++ b/src/main/java/org/jabref/gui/search/SearchWorker.java @@ -9,8 +9,6 @@ import org.jabref.JabRefGUI; import org.jabref.gui.BasePanel; -import org.jabref.gui.BasePanelMode; -import org.jabref.gui.maintable.MainTableDataModel; import org.jabref.gui.search.rules.describer.SearchDescribers; import org.jabref.logic.search.SearchQuery; import org.jabref.model.database.BibDatabase; @@ -64,52 +62,6 @@ protected void done() { private void updateUIWithSearchResult(List matchedEntries) { GlobalSearchBar globalSearchBar = JabRefGUI.getMainFrame().getGlobalSearchBar(); - // check if still the current query - if (!globalSearchBar.isStillValidQuery(searchQuery)) { - // do not update - another search was already issued - return; - } - - // clear - for (BibEntry entry : basePanel.getDatabase().getEntries()) { - entry.setSearchHit(false); - } - // and mark - for (BibEntry entry : matchedEntries) { - entry.setSearchHit(true); - } - - basePanel.getMainTable().getTableModel().updateSearchState(MainTableDataModel.DisplayOption.DISABLED); - // Show the result in the chosen way: - switch (searchDisplayMode) { - case FLOAT: - basePanel.getMainTable().getTableModel().updateSearchState(MainTableDataModel.DisplayOption.FLOAT); - break; - case FILTER: - basePanel.getMainTable().getTableModel().updateSearchState(MainTableDataModel.DisplayOption.FILTER); - break; - default: - LOGGER.error("Following searchDisplayMode was not defined: " + searchDisplayMode); - break; - } - - // only selects the first match if the selected entries are no hits or no entry is selected - // and no editor is open (to avoid jumping around when editing an entry) - if (basePanel.getMode() != BasePanelMode.SHOWING_EDITOR && basePanel.getMode() != BasePanelMode.WILL_SHOW_EDITOR) { - List selectedEntries = basePanel.getSelectedEntries(); - boolean isHitSelected = selectedEntries.stream().anyMatch(BibEntry::isSearchHit); - if (!isHitSelected && !matchedEntries.isEmpty()) { - /*for (int i = 0; i < basePanel.getMainTable().getRowCount(); i++) { - BibEntry entry = basePanel.getMainTable().getEntryAt(i); - if (entry.isSearchHit()) { - basePanel.getMainTable().setSelected(i); - break; - } - } - */ - } - } - globalSearchBar.updateResults(matchedEntries.size(), SearchDescribers.getSearchDescriberFor(searchQuery).getDescription(), searchQuery.isGrammarBasedSearch()); From d6fe1f1557f54f6edb58d30bbe888e564e959eae Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 8 Jan 2018 13:15:12 +0100 Subject: [PATCH 15/24] Fix a few smaller bugs --- src/main/java/org/jabref/gui/BasePanel.java | 4 ++++ src/main/java/org/jabref/gui/JabRefFrame.java | 8 +++++--- .../org/jabref/gui/importer/ImportInspectionDialog.java | 3 ++- src/main/java/org/jabref/logic/util/io/FileUtil.java | 2 ++ 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jabref/gui/BasePanel.java b/src/main/java/org/jabref/gui/BasePanel.java index 235c8c1dfbe..c7d30cf880e 100644 --- a/src/main/java/org/jabref/gui/BasePanel.java +++ b/src/main/java/org/jabref/gui/BasePanel.java @@ -1726,6 +1726,10 @@ public void autoGenerateKeysBeforeSaving() { * Depending on whether a preview or an entry editor is showing, save the current divider location in the correct preference setting. */ private void saveDividerLocation(Number position) { + if (position == null) { + return; + } + if (mode == BasePanelMode.SHOWING_PREVIEW) { PreviewPreferences previewPreferences = Globals.prefs.getPreviewPreferences() .getBuilder() diff --git a/src/main/java/org/jabref/gui/JabRefFrame.java b/src/main/java/org/jabref/gui/JabRefFrame.java index 0255e88edfd..1b5da59cde9 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -1023,9 +1023,11 @@ public TabPane getTabbedPane() { } public void setTabTitle(BasePanel comp, String title, String toolTip) { - Tab tab = getTab(comp); - tab.setText(title); - tab.setTooltip(new Tooltip(toolTip)); + DefaultTaskExecutor.runInJavaFXThread(() -> { + Tab tab = getTab(comp); + tab.setText(title); + tab.setTooltip(new Tooltip(toolTip)); + }); } private void fillMenu() { diff --git a/src/main/java/org/jabref/gui/importer/ImportInspectionDialog.java b/src/main/java/org/jabref/gui/importer/ImportInspectionDialog.java index d87b66da8f5..35b524ed50c 100644 --- a/src/main/java/org/jabref/gui/importer/ImportInspectionDialog.java +++ b/src/main/java/org/jabref/gui/importer/ImportInspectionDialog.java @@ -79,6 +79,7 @@ import org.jabref.gui.undo.NamedCompound; import org.jabref.gui.undo.UndoableInsertEntry; import org.jabref.gui.undo.UndoableRemoveEntry; +import org.jabref.gui.util.DefaultTaskExecutor; import org.jabref.gui.util.comparator.IconComparator; import org.jabref.gui.util.component.CheckBoxMessage; import org.jabref.logic.bibtex.DuplicateCheck; @@ -202,7 +203,7 @@ public ImportInspectionDialog(JabRefFrame frame, BasePanel panel, String undoNam this.undoName = undoName; this.newDatabase = newDatabase; setIconImages(IconTheme.getLogoSet()); - preview = new PreviewPanel(panel, bibDatabaseContext, Globals.getKeyPrefs(), Globals.prefs.getPreviewPreferences()); + preview = DefaultTaskExecutor.runInJavaFXThread(() -> new PreviewPanel(panel, bibDatabaseContext, Globals.getKeyPrefs(), Globals.prefs.getPreviewPreferences())); duplLabel.setToolTipText(Localization.lang("Possible duplicate of existing entry. Click to resolve.")); diff --git a/src/main/java/org/jabref/logic/util/io/FileUtil.java b/src/main/java/org/jabref/logic/util/io/FileUtil.java index d5dcfa139f7..eb458547bc1 100644 --- a/src/main/java/org/jabref/logic/util/io/FileUtil.java +++ b/src/main/java/org/jabref/logic/util/io/FileUtil.java @@ -186,7 +186,9 @@ public static boolean renameFile(Path fromFile, Path toFile) { * @param toFile The target fileName * @param replaceExisting Wether to replace existing files or not * @return True if the rename was successful, false if an exception occurred + * @deprecated Use {@link #renameFileWithException(Path, Path, boolean)} instead and handle exception properly */ + @Deprecated public static boolean renameFile(Path fromFile, Path toFile, boolean replaceExisting) { try { return renameFileWithException(fromFile, toFile, replaceExisting); From 530530a42ef993009feed10077c7435348767a5a Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 8 Jan 2018 13:40:35 +0100 Subject: [PATCH 16/24] Fix keyboard shortcuts --- src/main/java/org/jabref/gui/BasePanel.java | 2 +- src/main/java/org/jabref/gui/JabRefFrame.java | 24 +++++++++++++++++++ .../jabref/gui/entryeditor/EntryEditor.java | 15 ++++++++++-- .../gui/entryeditor/FieldsEditorTab.java | 12 ---------- 4 files changed, 38 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/jabref/gui/BasePanel.java b/src/main/java/org/jabref/gui/BasePanel.java index c7d30cf880e..61a20a4826f 100644 --- a/src/main/java/org/jabref/gui/BasePanel.java +++ b/src/main/java/org/jabref/gui/BasePanel.java @@ -189,7 +189,7 @@ public class BasePanel extends StackPane implements ClipboardOwner { private StringDialog stringDialog; private SuggestionProviders suggestionProviders; - private Subscription dividerPositionSubscription; + @SuppressWarnings({"FieldCanBeLocal", "unused"}) private Subscription dividerPositionSubscription; // the query the user searches when this BasePanel is active private Optional currentSearchQuery = Optional.empty(); diff --git a/src/main/java/org/jabref/gui/JabRefFrame.java b/src/main/java/org/jabref/gui/JabRefFrame.java index 1b5da59cde9..f226cd73409 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -13,6 +13,7 @@ import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; @@ -918,6 +919,29 @@ private void initLayout() { splitPane.setDividerSize(2); splitPane.setBorder(null); JFXPanel tabbedPaneContainer = CustomJFXPanel.wrap(new Scene(tabbedPane)); + // TODO: Remove this hack as soon as toolbar is implemented in JavaFX and these events are no longer captured globally + tabbedPaneContainer.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + // We need to consume a few events that have a global listener + // Otherwise, they propagate to the JFrame (i.e. "Ctrl + A" in the entry editor still triggers the "Select all" action) + Optional keyBinding = Globals.getKeyPrefs().mapToKeyBinding(e); + if (keyBinding.isPresent()) { + switch (keyBinding.get()) { + case CUT: + case COPY: + case PASTE: + case DELETE_ENTRY: + case SELECT_ALL: + e.consume(); + break; + default: + //do nothing + } + } + } + }); + splitPane.setRightComponent(tabbedPaneContainer); splitPane.setLeftComponent(sidePaneManager.getPanel()); getContentPane().add(splitPane, BorderLayout.CENTER); diff --git a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java index 956f981b414..a6bf1dc33cd 100644 --- a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java +++ b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java @@ -20,6 +20,7 @@ import javafx.scene.layout.BorderPane; import org.jabref.gui.BasePanel; +import org.jabref.gui.GUIGlobals; import org.jabref.gui.entryeditor.fileannotationtab.FileAnnotationTab; import org.jabref.gui.help.HelpAction; import org.jabref.gui.keyboard.KeyBinding; @@ -75,6 +76,12 @@ public EntryEditor(BasePanel panel, EntryEditorPreferences preferences) { ControlHelper.loadFXMLForControl(this); getStylesheets().add(EntryEditor.class.getResource("EntryEditor.css").toExternalForm()); + if (GUIGlobals.currentFont != null) { + setStyle( + "text-area-background: " + convertToHex(GUIGlobals.validFieldBackgroundColor) + ";" + + "text-area-foreground: " + convertToHex(GUIGlobals.editorTextColor) + ";" + + "text-area-highlight: " + convertToHex(GUIGlobals.activeBackgroundColor) + ";"); + } EasyBind.subscribe(tabbed.getSelectionModel().selectedItemProperty(), tab -> { EntryEditorTab activeTab = (EntryEditorTab) tab; @@ -92,7 +99,7 @@ public EntryEditor(BasePanel panel, EntryEditorPreferences preferences) { * Set-up key bindings specific for the entry editor. */ private void setupKeyBindings() { - tabbed.addEventFilter(KeyEvent.KEY_PRESSED, event -> { + tabbed.addEventHandler(KeyEvent.KEY_PRESSED, event -> { Optional keyBinding = preferences.getKeyBindings().mapToKeyBinding(event); if (keyBinding.isPresent()) { switch (keyBinding.get()) { @@ -115,7 +122,7 @@ private void setupKeyBindings() { event.consume(); break; default: - // Pass other keys to children + // Pass other keys to parent } } }); @@ -262,4 +269,8 @@ public void setFocusToField(String fieldName) { } }); } + + private String convertToHex(java.awt.Color color) { + return String.format("#%02x%02x%02x", color.getRed(), color.getGreen(), color.getBlue()); + } } diff --git a/src/main/java/org/jabref/gui/entryeditor/FieldsEditorTab.java b/src/main/java/org/jabref/gui/entryeditor/FieldsEditorTab.java index 6ed9ce119af..80b64831e19 100644 --- a/src/main/java/org/jabref/gui/entryeditor/FieldsEditorTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/FieldsEditorTab.java @@ -23,7 +23,6 @@ import org.jabref.Globals; import org.jabref.gui.FXDialogService; -import org.jabref.gui.GUIGlobals; import org.jabref.gui.autocompleter.SuggestionProviders; import org.jabref.gui.fieldeditors.FieldEditorFX; import org.jabref.gui.fieldeditors.FieldEditors; @@ -66,10 +65,6 @@ private static void addColumn(GridPane gridPane, int columnIndex, Stream gridPane.addColumn(columnIndex, nodes.toArray(Node[]::new)); } - private String convertToHex(java.awt.Color color) { - return String.format("#%02x%02x%02x", color.getRed(), color.getGreen(), color.getBlue()); - } - private Region setupPanel(BibEntry entry, boolean compressed, SuggestionProviders suggestionProviders, UndoManager undoManager) { // The preferences might be not initialized in tests -> return empty node // TODO: Replace this ugly workaround by proper injection propagation @@ -133,13 +128,6 @@ private Region setupPanel(BibEntry entry, boolean compressed, SuggestionProvider setRegularRowLayout(gridPane, rows); } - if (GUIGlobals.currentFont != null) { - gridPane.setStyle( - "text-area-background: " + convertToHex(GUIGlobals.validFieldBackgroundColor) + ";" - + "text-area-foreground: " + convertToHex(GUIGlobals.editorTextColor) + ";" - + "text-area-highlight: " + convertToHex(GUIGlobals.activeBackgroundColor) + ";"); - } - // Warp everything in a scroll-pane ScrollPane scrollPane = new ScrollPane(); scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); From 11d4d59d951e254034ab84fc79ade8d0c169311e Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 8 Jan 2018 13:49:06 +0100 Subject: [PATCH 17/24] Fix cleanup action --- src/main/java/org/jabref/gui/BasePanel.java | 6 +++--- src/main/java/org/jabref/gui/actions/CleanupAction.java | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/jabref/gui/BasePanel.java b/src/main/java/org/jabref/gui/BasePanel.java index 61a20a4826f..1a8a6df410c 100644 --- a/src/main/java/org/jabref/gui/BasePanel.java +++ b/src/main/java/org/jabref/gui/BasePanel.java @@ -43,6 +43,7 @@ import org.jabref.JabRefExecutorService; import org.jabref.gui.actions.Actions; import org.jabref.gui.actions.BaseAction; +import org.jabref.gui.actions.CleanupAction; import org.jabref.gui.actions.CopyBibTeXKeyAndLinkAction; import org.jabref.gui.autocompleter.AutoCompletePreferences; import org.jabref.gui.autocompleter.AutoCompleteUpdater; @@ -328,8 +329,7 @@ public void output(String s) { private void setupActions() { SaveDatabaseAction saveAction = new SaveDatabaseAction(this); - // TODO - //CleanupAction cleanUpAction = new CleanupAction(this, Globals.prefs); + CleanupAction cleanUpAction = new CleanupAction(this, Globals.prefs); actions.put(Actions.UNDO, undoAction); actions.put(Actions.REDO, redoAction); @@ -479,7 +479,7 @@ public void update() { }); // The action for cleaning up entry. - //actions.put(Actions.CLEANUP, cleanUpAction); + actions.put(Actions.CLEANUP, cleanUpAction); actions.put(Actions.MERGE_ENTRIES, (BaseAction) () -> new MergeEntriesDialog(BasePanel.this)); diff --git a/src/main/java/org/jabref/gui/actions/CleanupAction.java b/src/main/java/org/jabref/gui/actions/CleanupAction.java index 89e8d94ab90..b62a01c607d 100644 --- a/src/main/java/org/jabref/gui/actions/CleanupAction.java +++ b/src/main/java/org/jabref/gui/actions/CleanupAction.java @@ -1,7 +1,6 @@ package org.jabref.gui.actions; import java.util.List; -import java.util.Objects; import javax.swing.JOptionPane; @@ -38,7 +37,7 @@ public class CleanupAction extends AbstractWorker { public CleanupAction(BasePanel panel, JabRefPreferences preferences) { this.panel = panel; this.frame = panel.frame(); - this.preferences = Objects.requireNonNull(preferences); + this.preferences = preferences; } @Override From 3a690913cd108f17dbd0b76c57f57fed3763b704 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 8 Jan 2018 13:50:26 +0100 Subject: [PATCH 18/24] Changes to entry triggers change of list of entries --- src/main/java/org/jabref/model/database/BibDatabase.java | 2 +- src/main/java/org/jabref/model/entry/BibEntry.java | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/model/database/BibDatabase.java b/src/main/java/org/jabref/model/database/BibDatabase.java index a5df29c3157..e2132648810 100644 --- a/src/main/java/org/jabref/model/database/BibDatabase.java +++ b/src/main/java/org/jabref/model/database/BibDatabase.java @@ -47,7 +47,7 @@ public class BibDatabase { /** * State attributes */ - private final ObservableList entries = FXCollections.synchronizedObservableList(FXCollections.observableArrayList()); + private final ObservableList entries = FXCollections.synchronizedObservableList(FXCollections.observableArrayList(BibEntry::getObservables)); private final Map bibtexStrings = new ConcurrentHashMap<>(); /** * this is kept in sync with the database (upon adding/removing an entry, it is updated as well) diff --git a/src/main/java/org/jabref/model/entry/BibEntry.java b/src/main/java/org/jabref/model/entry/BibEntry.java index 6e21b4ee4bc..800670be0c9 100644 --- a/src/main/java/org/jabref/model/entry/BibEntry.java +++ b/src/main/java/org/jabref/model/entry/BibEntry.java @@ -15,6 +15,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Pattern; +import javafx.beans.Observable; import javafx.beans.binding.Bindings; import javafx.beans.binding.ObjectBinding; import javafx.collections.FXCollections; @@ -854,6 +855,13 @@ public ObservableMap getFieldsObservable() { return fields; } + /** + * Returns a list of observables that represent the data of the entry. + */ + public Observable[] getObservables() { + return new Observable[]{fields}; + } + private interface GetFieldInterface { Optional getValueForField(String fieldName); From 2c7b3a7a8e329ccc06b71e9c8aa53ae83a12a62b Mon Sep 17 00:00:00 2001 From: Siedlerchr Date: Tue, 9 Jan 2018 17:57:20 +0100 Subject: [PATCH 19/24] Remove clear Search keybinding as this overlaps with Close entry editor and it is not used anylonger --- src/main/java/org/jabref/gui/keyboard/KeyBinding.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/keyboard/KeyBinding.java b/src/main/java/org/jabref/gui/keyboard/KeyBinding.java index 1a0eddd0ff9..6138ae09dd2 100644 --- a/src/main/java/org/jabref/gui/keyboard/KeyBinding.java +++ b/src/main/java/org/jabref/gui/keyboard/KeyBinding.java @@ -11,10 +11,9 @@ public enum KeyBinding { BACK("Back", Localization.lang("Back"), "alt+LEFT", KeyBindingCategory.VIEW), CHECK_INTEGRITY("Check integrity", Localization.menuTitle("Check integrity"), "ctrl+F8", KeyBindingCategory.QUALITY), CLEANUP("Cleanup", Localization.lang("Cleanup entries"), "alt+F8", KeyBindingCategory.QUALITY), - CLEAR_SEARCH("Clear search", Localization.lang("Clear search"), "ESCAPE", KeyBindingCategory.SEARCH), CLOSE_DATABASE("Close library", Localization.lang("Close library"), "ctrl+W", KeyBindingCategory.FILE), CLOSE_DIALOG("Close dialog", Localization.lang("Close dialog"), "ESCAPE", KeyBindingCategory.FILE), - CLOSE_ENTRY_EDITOR("Close entry editor", Localization.lang("Close entry editor"), "Esc", KeyBindingCategory.VIEW), + CLOSE_ENTRY_EDITOR("Close entry editor", Localization.lang("Close entry editor"), "ESCAPE", KeyBindingCategory.VIEW), COPY("Copy", Localization.lang("Copy"), "ctrl+C", KeyBindingCategory.EDIT), COPY_TITLE("Copy title", Localization.lang("Copy title"), "ctrl+shift+alt+T", KeyBindingCategory.EDIT), COPY_CITE_BIBTEX_KEY("Copy \\cite{BibTeX key}", Localization.lang("Copy \\cite{BibTeX key}"), "ctrl+K", KeyBindingCategory.EDIT), From 35d32c5b3f3761ae7360691f02ff148567c11de3 Mon Sep 17 00:00:00 2001 From: Siedlerchr Date: Tue, 9 Jan 2018 18:11:04 +0100 Subject: [PATCH 20/24] wrap showandEdit in javafx thread to make new entry actions work --- src/main/java/org/jabref/gui/BasePanel.java | 30 +++++++++++---------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/jabref/gui/BasePanel.java b/src/main/java/org/jabref/gui/BasePanel.java index 1a8a6df410c..1bae4e7cc46 100644 --- a/src/main/java/org/jabref/gui/BasePanel.java +++ b/src/main/java/org/jabref/gui/BasePanel.java @@ -1219,14 +1219,12 @@ private void createMainTable() { mainTable.addSelectionListener(listEvent -> Globals.stateManager.setSelectedEntries(mainTable.getSelectedEntries())); // Update entry editor and preview according to selected entries - mainTable.addSelectionListener(event -> - mainTable.getSelectedEntries().stream() - .findFirst() - .ifPresent(entry -> { - preview.setEntry(entry); - entryEditor.setEntry(entry); - }) - ); + mainTable.addSelectionListener(event -> mainTable.getSelectedEntries().stream() + .findFirst() + .ifPresent(entry -> { + preview.setEntry(entry); + entryEditor.setEntry(entry); + })); // TODO: Register these actions globally /* @@ -1424,13 +1422,17 @@ public EntryEditor getEntryEditor() { * @param entry The entry to edit. */ public void showAndEdit(BibEntry entry) { - showBottomPane(BasePanelMode.SHOWING_EDITOR); + DefaultTaskExecutor.runInJavaFXThread(() -> { - if (entry != getShowing()) { - entryEditor.setEntry(entry); - newEntryShowing(entry); - } - entryEditor.requestFocus(); + showBottomPane(BasePanelMode.SHOWING_EDITOR); + + if (entry != getShowing()) { + entryEditor.setEntry(entry); + newEntryShowing(entry); + } + entryEditor.requestFocus(); + + }); } private void showBottomPane(BasePanelMode newMode) { From e3515e9979bc8753abbfdb294c8d312986904d24 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Tue, 9 Jan 2018 23:51:58 +0100 Subject: [PATCH 21/24] Improve automatic sizing of columns --- .../jabref/gui/maintable/ColumnFactory.java | 24 ++--- .../org/jabref/gui/maintable/MainTable.java | 2 +- .../SmartConstrainedResizePolicy.java | 97 +++++++++++++++++++ .../SmartConstraintedResizePolicy.java | 23 ----- 4 files changed, 110 insertions(+), 36 deletions(-) create mode 100644 src/main/java/org/jabref/gui/maintable/SmartConstrainedResizePolicy.java delete mode 100644 src/main/java/org/jabref/gui/maintable/SmartConstraintedResizePolicy.java diff --git a/src/main/java/org/jabref/gui/maintable/ColumnFactory.java b/src/main/java/org/jabref/gui/maintable/ColumnFactory.java index 93515a85f9a..344e105d29d 100644 --- a/src/main/java/org/jabref/gui/maintable/ColumnFactory.java +++ b/src/main/java/org/jabref/gui/maintable/ColumnFactory.java @@ -100,11 +100,9 @@ private TableColumn column.setGraphic(new SpecialFieldViewModel(specialField).getIcon().getGraphicNode()); column.getStyleClass().add(STYLE_ICON); if (specialField == SpecialField.RANKING) { - column.setMinWidth(GUIGlobals.WIDTH_ICON_COL_RANKING); - column.setMaxWidth(GUIGlobals.WIDTH_ICON_COL_RANKING); + setExactWidth(column, GUIGlobals.WIDTH_ICON_COL_RANKING); } else { - column.setMinWidth(GUIGlobals.WIDTH_ICON_COL); - column.setMaxWidth(GUIGlobals.WIDTH_ICON_COL); + setExactWidth(column, GUIGlobals.WIDTH_ICON_COL); } column.setCellValueFactory(cellData -> cellData.getValue().getSpecialField(specialField)); column.setCellFactory( @@ -114,12 +112,17 @@ private TableColumn return column; } + private void setExactWidth(TableColumn column, int widthIconCol) { + column.setMinWidth(widthIconCol); + column.setPrefWidth(widthIconCol); + column.setMaxWidth(widthIconCol); + } + private TableColumn> createFileColumn() { TableColumn> column = new TableColumn<>(); column.setGraphic(IconTheme.JabRefIcons.FILE.getGraphicNode()); column.getStyleClass().add(STYLE_ICON); - column.setMinWidth(GUIGlobals.WIDTH_ICON_COL); - column.setMaxWidth(GUIGlobals.WIDTH_ICON_COL); + setExactWidth(column, GUIGlobals.WIDTH_ICON_COL); column.setCellValueFactory(cellData -> cellData.getValue().getLinkedFiles()); column.setCellFactory( new ValueTableCellFactory>() @@ -134,8 +137,7 @@ private TableColumn createIconColumn(JabRefIcon TableColumn column = new TableColumn<>(); column.setGraphic(icon.getGraphicNode()); column.getStyleClass().add(STYLE_ICON); - column.setMinWidth(GUIGlobals.WIDTH_ICON_COL); - column.setMaxWidth(GUIGlobals.WIDTH_ICON_COL); + setExactWidth(column, GUIGlobals.WIDTH_ICON_COL); column.setCellValueFactory(cellData -> EasyBind.monadic(cellData.getValue().getField(firstField)).orElse(cellData.getValue().getField(secondField))); column.setCellFactory( new ValueTableCellFactory() @@ -147,8 +149,7 @@ private TableColumn createIconColumn(JabRefIcon TableColumn column = new TableColumn<>(); column.setGraphic(icon.getGraphicNode()); column.getStyleClass().add(STYLE_ICON); - column.setMinWidth(GUIGlobals.WIDTH_ICON_COL); - column.setMaxWidth(GUIGlobals.WIDTH_ICON_COL); + setExactWidth(column, GUIGlobals.WIDTH_ICON_COL); column.setCellValueFactory(cellData -> cellData.getValue().getField(field)); column.setCellFactory( new ValueTableCellFactory() @@ -168,8 +169,7 @@ private TableColumn> createExtraFileCol .map(ExternalFileType::getIcon).orElse(IconTheme.JabRefIcons.FILE) .getGraphicNode()); column.getStyleClass().add(STYLE_ICON); - column.setMinWidth(GUIGlobals.WIDTH_ICON_COL); - column.setMaxWidth(GUIGlobals.WIDTH_ICON_COL); + setExactWidth(column, GUIGlobals.WIDTH_ICON_COL); column.setCellValueFactory(cellData -> cellData.getValue().getLinkedFiles()); column.setCellFactory( new ValueTableCellFactory>() diff --git a/src/main/java/org/jabref/gui/maintable/MainTable.java b/src/main/java/org/jabref/gui/maintable/MainTable.java index 350aa95c33b..ad0c14b26b4 100644 --- a/src/main/java/org/jabref/gui/maintable/MainTable.java +++ b/src/main/java/org/jabref/gui/maintable/MainTable.java @@ -85,7 +85,7 @@ public MainTable(MainTableDataModel model, JabRefFrame frame, }) .withContextMenu(RightClickMenu::create)); if (preferences.resizeColumnsToFit()) { - this.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); + this.setColumnResizePolicy(new SmartConstrainedResizePolicy()); } this.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); this.setItems(model.getEntriesFiltered()); diff --git a/src/main/java/org/jabref/gui/maintable/SmartConstrainedResizePolicy.java b/src/main/java/org/jabref/gui/maintable/SmartConstrainedResizePolicy.java new file mode 100644 index 00000000000..425a59eac5c --- /dev/null +++ b/src/main/java/org/jabref/gui/maintable/SmartConstrainedResizePolicy.java @@ -0,0 +1,97 @@ +package org.jabref.gui.maintable; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; + +import javafx.scene.control.ResizeFeaturesBase; +import javafx.scene.control.TableColumnBase; +import javafx.scene.control.TableView; +import javafx.util.Callback; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * This resize policy is almost the same as {@link TableView#CONSTRAINED_RESIZE_POLICY} + * We make sure that the width of all columns sums up to the total width of the table. + * However, in contrast to {@link TableView#CONSTRAINED_RESIZE_POLICY} we size the columns initially by their preferred width. + */ +public class SmartConstrainedResizePolicy implements Callback { + + private static final Log LOGGER = LogFactory.getLog(SmartConstrainedResizePolicy.class); + + @Override + public Boolean call(TableView.ResizeFeatures prop) { + if (prop.getColumn() == null) { + return initColumnSize(prop.getTable()); + } else { + return constrainedResize(prop); + } + } + + private Boolean initColumnSize(TableView table) { + double tableWidth = table.getWidth(); + List> visibleLeafColumns = table.getVisibleLeafColumns(); + double totalWidth = visibleLeafColumns.stream().mapToDouble(TableColumnBase::getWidth).sum(); + + if (Math.abs(totalWidth - tableWidth) > 1) { + double totalPrefWidth = visibleLeafColumns.stream().mapToDouble(TableColumnBase::getPrefWidth).sum(); + if (totalPrefWidth > 0) { + for (TableColumnBase col : visibleLeafColumns) { + double share = col.getPrefWidth() / totalPrefWidth; + double newSize = tableWidth * share; + resize(col, newSize - col.getWidth()); + } + } + } + + return false; + } + + private void resize(TableColumnBase column, double delta) { + // We have to use reflection since TableUtil is not visible to us + try { + Class clazz = Class.forName("javafx.scene.control.TableUtil"); + Method constrainedResize = clazz.getDeclaredMethod("resize", TableColumnBase.class, double.class); + constrainedResize.setAccessible(true); + constrainedResize.invoke(null, column, delta); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | ClassNotFoundException e) { + LOGGER.error("Could not invoke resize in TableUtil", e); + } + } + + private Boolean constrainedResize(TableView.ResizeFeatures prop) { + TableView table = prop.getTable(); + List> visibleLeafColumns = table.getVisibleLeafColumns(); + return constrainedResize(prop, + false, + getContentWidth(table), + visibleLeafColumns); + } + + private Boolean constrainedResize(TableView.ResizeFeatures prop, Boolean isFirstRun, Double contentWidth, List> visibleLeafColumns) { + // We have to use reflection since TableUtil is not visible to us + try { + Class clazz = Class.forName("javafx.scene.control.TableUtil"); + Method constrainedResize = clazz.getDeclaredMethod("constrainedResize", ResizeFeaturesBase.class, Boolean.TYPE, Double.TYPE, List.class); + constrainedResize.setAccessible(true); + Object returnValue = constrainedResize.invoke(null, prop, isFirstRun, contentWidth, visibleLeafColumns); + return (Boolean) returnValue; + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | ClassNotFoundException e) { + LOGGER.error("Could not invoke constrainedResize in TableUtil", e); + return false; + } + } + + private Double getContentWidth(TableView table) { + try { + Field privateStringField = TableView.class.getDeclaredField("contentWidth"); + privateStringField.setAccessible(true); + return (Double) privateStringField.get(table); + } catch (IllegalAccessException | NoSuchFieldException e) { + return 0d; + } + } +} diff --git a/src/main/java/org/jabref/gui/maintable/SmartConstraintedResizePolicy.java b/src/main/java/org/jabref/gui/maintable/SmartConstraintedResizePolicy.java deleted file mode 100644 index 5b173dd03cb..00000000000 --- a/src/main/java/org/jabref/gui/maintable/SmartConstraintedResizePolicy.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.jabref.gui.maintable; - -import javafx.scene.control.TableView; -import javafx.util.Callback; - -public class SmartConstraintedResizePolicy implements Callback { - private boolean isFirstRun = true; - private Callback basePolicy = TableView.CONSTRAINED_RESIZE_POLICY; - - @Override - public Boolean call(TableView.ResizeFeatures prop) { - Boolean result = basePolicy.call(prop); - - // The CONSTRAINED_RESIZE_POLICY resizes all columns to the same width - // We want to resize them to (almost) their preferred width - if (isFirstRun) { - - } - - isFirstRun = isFirstRun && !result; - return result; - } -} From bd2c1e3f09e7a2ddc0ea18f3e7724c51a133c485 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Wed, 10 Jan 2018 00:04:31 +0100 Subject: [PATCH 22/24] Implement feedback --- src/main/java/org/jabref/gui/maintable/MainTable.java | 2 +- .../{ColumnFactory.java => MainTableColumnFactory.java} | 9 +++------ .../org/jabref/migrations/FileLinksUpgradeWarning.java | 6 ++---- .../java/org/jabref/model/entry/BibtexSingleField.java | 2 +- 4 files changed, 7 insertions(+), 12 deletions(-) rename src/main/java/org/jabref/gui/maintable/{ColumnFactory.java => MainTableColumnFactory.java} (96%) diff --git a/src/main/java/org/jabref/gui/maintable/MainTable.java b/src/main/java/org/jabref/gui/maintable/MainTable.java index ad0c14b26b4..07e4044b26e 100644 --- a/src/main/java/org/jabref/gui/maintable/MainTable.java +++ b/src/main/java/org/jabref/gui/maintable/MainTable.java @@ -76,7 +76,7 @@ public MainTable(MainTableDataModel model, JabRefFrame frame, super(); this.model = model; - this.getColumns().addAll(new ColumnFactory(database, preferences.getColumnPreferences(), externalFileTypes).createColumns()); + this.getColumns().addAll(new MainTableColumnFactory(database, preferences.getColumnPreferences(), externalFileTypes).createColumns()); this.setRowFactory(new ViewModelTableRowFactory() .withOnMouseClickedEvent((entry, event) -> { if (event.getClickCount() == 2) { diff --git a/src/main/java/org/jabref/gui/maintable/ColumnFactory.java b/src/main/java/org/jabref/gui/maintable/MainTableColumnFactory.java similarity index 96% rename from src/main/java/org/jabref/gui/maintable/ColumnFactory.java rename to src/main/java/org/jabref/gui/maintable/MainTableColumnFactory.java index 344e105d29d..aa5c0a10b66 100644 --- a/src/main/java/org/jabref/gui/maintable/ColumnFactory.java +++ b/src/main/java/org/jabref/gui/maintable/MainTableColumnFactory.java @@ -25,7 +25,7 @@ import org.fxmisc.easybind.EasyBind; -class ColumnFactory { +class MainTableColumnFactory { private static final String STYLE_ICON = "column-icon"; @@ -34,7 +34,7 @@ class ColumnFactory { private final BibDatabase database; private final CellFactory cellFactory; - public ColumnFactory(BibDatabase database, ColumnPreferences preferences, ExternalFileTypes externalFileTypes) { + public MainTableColumnFactory(BibDatabase database, ColumnPreferences preferences, ExternalFileTypes externalFileTypes) { this.database = Objects.requireNonNull(database); this.preferences = Objects.requireNonNull(preferences); this.externalFileTypes = Objects.requireNonNull(externalFileTypes); @@ -64,10 +64,7 @@ public ColumnFactory(BibDatabase database, ColumnPreferences preferences, Extern } // Add columns for other file types - for (String column : preferences.getExtraFileColumns()) { - columns.add(createExtraFileColumn(column)); - } - + columns.addAll(preferences.getExtraFileColumns().stream().map(this::createExtraFileColumn).collect(Collectors.toList())); // Add 'normal' bibtex fields as configured in the preferences columns.addAll(createNormalColumns()); diff --git a/src/main/java/org/jabref/migrations/FileLinksUpgradeWarning.java b/src/main/java/org/jabref/migrations/FileLinksUpgradeWarning.java index 1e7c11fc8b2..552fbc36f23 100644 --- a/src/main/java/org/jabref/migrations/FileLinksUpgradeWarning.java +++ b/src/main/java/org/jabref/migrations/FileLinksUpgradeWarning.java @@ -1,7 +1,6 @@ package org.jabref.migrations; import java.util.List; -import java.util.Map; import javax.swing.JButton; import javax.swing.JCheckBox; @@ -56,7 +55,6 @@ public class FileLinksUpgradeWarning implements GUIPostOpenAction { * GUIGlobals.FILE_FIELD. * * @param database The database to modify. - * @param fields The fields to find links in. * @return A CompoundEdit specifying the undo operation for the whole operation. */ private static NamedCompound upgradePdfPsToFile(BibDatabase database) { @@ -248,8 +246,8 @@ private void makeChanges(BasePanel panel, ParserResult pr, boolean upgradePrefs, } private boolean showsFileInGenFields() { - for (Map.Entry> tab : Globals.prefs.getEntryEditorTabList().entrySet()) { - for (String field : tab.getValue()) { + for (List fields : Globals.prefs.getEntryEditorTabList().values()) { + for (String field : fields) { if (field.equals(FieldName.FILE)) { return true; } diff --git a/src/main/java/org/jabref/model/entry/BibtexSingleField.java b/src/main/java/org/jabref/model/entry/BibtexSingleField.java index 14722ee9579..fa67cefc2ef 100644 --- a/src/main/java/org/jabref/model/entry/BibtexSingleField.java +++ b/src/main/java/org/jabref/model/entry/BibtexSingleField.java @@ -8,7 +8,7 @@ */ public class BibtexSingleField { - // TODO: This constant should be moved to the gui package, probably to ColumnFactory + // TODO: This constant should be moved to the gui package, probably to MainTableColumnFactory public static final double DEFAULT_FIELD_LENGTH = 100; private enum Flag { From 8980713f22531606075a9990b9d8986bc6c266bd Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 29 Jan 2018 12:59:14 +0100 Subject: [PATCH 23/24] Bring back the context menu (#3666) * First prototype * Make old actions list an enum * Make it work! * Implement feedback --- build.gradle | 1 + src/main/java/org/jabref/gui/BasePanel.java | 28 +- .../jabref/gui/FindUnlinkedFilesDialog.java | 1 - src/main/java/org/jabref/gui/JabRefFrame.java | 37 +- .../org/jabref/gui/actions/ActionFactory.java | 45 +++ .../java/org/jabref/gui/actions/Actions.java | 150 +++---- .../org/jabref/gui/actions/ActionsFX.java | 101 +++++ .../org/jabref/gui/actions/JabRefAction.java | 25 ++ .../jabref/gui/actions/OldCommandWrapper.java | 50 +++ .../JTextAreaWithHighlighting.java | 2 +- .../jabref/gui/fieldeditors/TextField.java | 2 +- .../org/jabref/gui/maintable/MainTable.java | 5 +- .../jabref/gui/maintable/RightClickMenu.java | 372 ++++++------------ .../jabref/gui/menus/ChangeEntryTypeMenu.java | 41 +- .../gui/mergeentries/FetchAndMergeEntry.java | 7 - .../specialfields/SpecialFieldDropDown.java | 8 +- .../specialfields/SpecialFieldMenuAction.java | 27 -- .../SpecialFieldValueViewModel.java | 144 +++---- .../specialfields/SpecialFieldViewModel.java | 53 +-- .../org/jabref/gui/util/BindingsHelper.java | 9 + 20 files changed, 574 insertions(+), 534 deletions(-) create mode 100644 src/main/java/org/jabref/gui/actions/ActionFactory.java create mode 100644 src/main/java/org/jabref/gui/actions/ActionsFX.java create mode 100644 src/main/java/org/jabref/gui/actions/JabRefAction.java create mode 100644 src/main/java/org/jabref/gui/actions/OldCommandWrapper.java delete mode 100644 src/main/java/org/jabref/gui/specialfields/SpecialFieldMenuAction.java diff --git a/build.gradle b/build.gradle index d3d94ed8d22..0362677a4e9 100644 --- a/build.gradle +++ b/build.gradle @@ -128,6 +128,7 @@ dependencies { compile 'de.codecentric.centerdevice:javafxsvg:1.2.1' compile 'de.jensd:fontawesomefx-materialdesignfont:1.7.22-4' compile 'de.saxsys:mvvmfx-validation:1.7.0' + compile 'de.saxsys:mvvmfx:1.7.0' compile 'org.fxmisc.easybind:easybind:1.0.3' compile 'org.fxmisc.flowless:flowless:0.6' compile 'org.fxmisc.richtext:richtextfx:0.8.1' diff --git a/src/main/java/org/jabref/gui/BasePanel.java b/src/main/java/org/jabref/gui/BasePanel.java index 668a0046864..c62a8ed2c41 100644 --- a/src/main/java/org/jabref/gui/BasePanel.java +++ b/src/main/java/org/jabref/gui/BasePanel.java @@ -161,7 +161,7 @@ public class BasePanel extends StackPane implements ClipboardOwner { private final List previousEntries = new ArrayList<>(); private final List nextEntries = new ArrayList<>(); // Keeps track of the string dialog if it is open. - private final Map actions = new HashMap<>(); + private final Map actions = new HashMap<>(); private final SidePaneManager sidePaneManager; private final PreviewPanel preview; private final BasePanelPreferences preferences; @@ -395,7 +395,7 @@ private void setupActions() { } }); - actions.put(FindUnlinkedFilesDialog.ACTION_COMMAND, (BaseAction) () -> { + actions.put(Actions.findUnlinkedFiles, (BaseAction) () -> { final FindUnlinkedFilesDialog dialog = new FindUnlinkedFilesDialog(frame, frame, BasePanel.this); dialog.setLocationRelativeTo(frame); dialog.setVisible(true); @@ -637,26 +637,26 @@ public void update() { }); // Note that we can't put the number of entries that have been reverted into the undoText as the concrete number cannot be injected - actions.put(new SpecialFieldValueViewModel(SpecialField.RELEVANCE.getValues().get(0)).getActionName(), + actions.put(new SpecialFieldValueViewModel(SpecialField.RELEVANCE.getValues().get(0)).getCommand(), new SpecialFieldViewModel(SpecialField.RELEVANCE).getSpecialFieldAction( SpecialField.RELEVANCE.getValues().get(0), frame)); - actions.put(new SpecialFieldValueViewModel(SpecialField.QUALITY.getValues().get(0)).getActionName(), + actions.put(new SpecialFieldValueViewModel(SpecialField.QUALITY.getValues().get(0)).getCommand(), new SpecialFieldViewModel(SpecialField.QUALITY) .getSpecialFieldAction(SpecialField.QUALITY.getValues().get(0), frame)); - actions.put(new SpecialFieldValueViewModel(SpecialField.PRINTED.getValues().get(0)).getActionName(), + actions.put(new SpecialFieldValueViewModel(SpecialField.PRINTED.getValues().get(0)).getCommand(), new SpecialFieldViewModel(SpecialField.PRINTED).getSpecialFieldAction( SpecialField.PRINTED.getValues().get(0), frame)); for (SpecialFieldValue prio : SpecialField.PRIORITY.getValues()) { - actions.put(new SpecialFieldValueViewModel(prio).getActionName(), + actions.put(new SpecialFieldValueViewModel(prio).getCommand(), new SpecialFieldViewModel(SpecialField.PRIORITY).getSpecialFieldAction(prio, this.frame)); } for (SpecialFieldValue rank : SpecialField.RANKING.getValues()) { - actions.put(new SpecialFieldValueViewModel(rank).getActionName(), + actions.put(new SpecialFieldValueViewModel(rank).getCommand(), new SpecialFieldViewModel(SpecialField.RANKING).getSpecialFieldAction(rank, this.frame)); } for (SpecialFieldValue status : SpecialField.READ_STATUS.getValues()) { - actions.put(new SpecialFieldValueViewModel(status).getActionName(), + actions.put(new SpecialFieldValueViewModel(status).getCommand(), new SpecialFieldViewModel(SpecialField.READ_STATUS).getSpecialFieldAction(status, this.frame)); } @@ -998,15 +998,15 @@ private void openExternalFile() { * This method is called from JabRefFrame if a database specific action is requested by the user. Runs the command * if it is defined, or prints an error message to the standard error stream. * - * @param _command The name of the command to run. + * @param command The name of the command to run. */ - public void runCommand(final String _command) { - if (!actions.containsKey(_command)) { - LOGGER.info("No action defined for '" + _command + '\''); + public void runCommand(final Actions command) { + if (!actions.containsKey(command)) { + LOGGER.info("No action defined for '" + command + '\''); return; } - Object o = actions.get(_command); + Object o = actions.get(command); try { if (o instanceof BaseAction) { ((BaseAction) o).action(); @@ -1211,7 +1211,7 @@ public void updateTableFont() { private void createMainTable() { bibDatabaseContext.getDatabase().registerListener(SpecialFieldDatabaseChangeListener.getInstance()); - mainTable = new MainTable(tableModel, frame, this, bibDatabaseContext.getDatabase(), preferences.getTablePreferences(), externalFileTypes); + mainTable = new MainTable(tableModel, frame, this, bibDatabaseContext.getDatabase(), preferences.getTablePreferences(), externalFileTypes, Globals.getKeyPrefs()); mainTable.updateFont(); diff --git a/src/main/java/org/jabref/gui/FindUnlinkedFilesDialog.java b/src/main/java/org/jabref/gui/FindUnlinkedFilesDialog.java index 3bc4e339797..fbeb4ead8be 100644 --- a/src/main/java/org/jabref/gui/FindUnlinkedFilesDialog.java +++ b/src/main/java/org/jabref/gui/FindUnlinkedFilesDialog.java @@ -93,7 +93,6 @@ public class FindUnlinkedFilesDialog extends JabRefDialog { /** * Keys to be used for referencing this Action. */ - public static final String ACTION_COMMAND = "findUnlinkedFiles"; public static final String ACTION_MENU_TITLE = Localization.menuTitle("Find unlinked files..."); public static final String ACTION_SHORT_DESCRIPTION = Localization diff --git a/src/main/java/org/jabref/gui/JabRefFrame.java b/src/main/java/org/jabref/gui/JabRefFrame.java index f226cd73409..6b1b2f37cb5 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -109,7 +109,6 @@ import org.jabref.gui.journals.ManageJournalsAction; import org.jabref.gui.keyboard.KeyBinding; import org.jabref.gui.keyboard.KeyBindingAction; -import org.jabref.gui.maintable.RightClickMenu; import org.jabref.gui.menus.ChangeEntryTypeMenu; import org.jabref.gui.menus.FileHistoryMenu; import org.jabref.gui.openoffice.OpenOfficePanel; @@ -274,17 +273,17 @@ public class JabRefFrame extends JFrame implements OutputPrinter { Globals.getKeyPrefs().getKey(KeyBinding.UNMARK_ENTRIES), IconTheme.JabRefIcons.UNMARK_ENTRIES.getIcon()); private final AbstractAction unmarkAll = new GeneralAction(Actions.UNMARK_ALL, Localization.menuTitle("Unmark all")); private final AbstractAction toggleRelevance = new GeneralAction( - new SpecialFieldValueViewModel(SpecialField.RELEVANCE.getValues().get(0)).getActionName(), + new SpecialFieldValueViewModel(SpecialField.RELEVANCE.getValues().get(0)).getCommand(), new SpecialFieldValueViewModel(SpecialField.RELEVANCE.getValues().get(0)).getMenuString(), new SpecialFieldValueViewModel(SpecialField.RELEVANCE.getValues().get(0)).getToolTipText(), IconTheme.JabRefIcons.RELEVANCE.getIcon()); private final AbstractAction toggleQualityAssured = new GeneralAction( - new SpecialFieldValueViewModel(SpecialField.QUALITY.getValues().get(0)).getActionName(), + new SpecialFieldValueViewModel(SpecialField.QUALITY.getValues().get(0)).getCommand(), new SpecialFieldValueViewModel(SpecialField.QUALITY.getValues().get(0)).getMenuString(), new SpecialFieldValueViewModel(SpecialField.QUALITY.getValues().get(0)).getToolTipText(), IconTheme.JabRefIcons.QUALITY_ASSURED.getIcon()); private final AbstractAction togglePrinted = new GeneralAction( - new SpecialFieldValueViewModel(SpecialField.PRINTED.getValues().get(0)).getActionName(), + new SpecialFieldValueViewModel(SpecialField.PRINTED.getValues().get(0)).getCommand(), new SpecialFieldValueViewModel(SpecialField.PRINTED.getValues().get(0)).getMenuString(), new SpecialFieldValueViewModel(SpecialField.PRINTED.getValues().get(0)).getToolTipText(), IconTheme.JabRefIcons.PRINTED.getIcon()); @@ -427,7 +426,7 @@ public void actionPerformed(ActionEvent e) { private final ManageKeywordsAction manageKeywords = new ManageKeywordsAction(this); private final JMenu lookupIdentifiers = JabRefFrame.subMenu(Localization.menuTitle("Look up document identifier...")); private final GeneralAction findUnlinkedFiles = new GeneralAction( - FindUnlinkedFilesDialog.ACTION_COMMAND, + Actions.findUnlinkedFiles, FindUnlinkedFilesDialog.ACTION_MENU_TITLE, FindUnlinkedFilesDialog.ACTION_SHORT_DESCRIPTION, Globals.getKeyPrefs().getKey(KeyBinding.FIND_UNLINKED_FILES) ); @@ -1131,7 +1130,7 @@ private void fillMenu() { boolean menuitem = false; if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_RANKING)) { rankSubMenu = new JMenu(); - RightClickMenu.populateSpecialFieldMenu(rankSubMenu, SpecialField.RANKING, this); + // TODO RightClickMenu.createSpecialFieldMenu(rankSubMenu, SpecialField.RANKING, this); edit.add(rankSubMenu); menuitem = true; } @@ -1145,7 +1144,7 @@ private void fillMenu() { } if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_PRIORITY)) { rankSubMenu = new JMenu(); - RightClickMenu.populateSpecialFieldMenu(rankSubMenu, SpecialField.PRIORITY, this); + // TODO RightClickMenu.createSpecialFieldMenu(rankSubMenu, SpecialField.PRIORITY, this); edit.add(rankSubMenu); menuitem = true; } @@ -1155,7 +1154,7 @@ private void fillMenu() { } if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_READ)) { rankSubMenu = new JMenu(); - RightClickMenu.populateSpecialFieldMenu(rankSubMenu, SpecialField.READ_STATUS, this); + // TODO RightClickMenu.createSpecialFieldMenu(rankSubMenu, SpecialField.READ_STATUS, this); edit.add(rankSubMenu); menuitem = true; } @@ -2033,27 +2032,27 @@ public void actionPerformed(ActionEvent evt) { private class GeneralAction extends MnemonicAwareAction { - private final String command; + private final Actions command; - public GeneralAction(String command, String text) { + public GeneralAction(Actions command, String text) { this.command = command; putValue(Action.NAME, text); } - public GeneralAction(String command, String text, String description) { + public GeneralAction(Actions command, String text, String description) { this.command = command; putValue(Action.NAME, text); putValue(Action.SHORT_DESCRIPTION, description); } - public GeneralAction(String command, String text, Icon icon) { + public GeneralAction(Actions command, String text, Icon icon) { super(icon); this.command = command; putValue(Action.NAME, text); } - public GeneralAction(String command, String text, String description, Icon icon) { + public GeneralAction(Actions command, String text, String description, Icon icon) { super(icon); this.command = command; @@ -2061,20 +2060,20 @@ public GeneralAction(String command, String text, String description, Icon icon) putValue(Action.SHORT_DESCRIPTION, description); } - public GeneralAction(String command, String text, KeyStroke key) { + public GeneralAction(Actions command, String text, KeyStroke key) { this.command = command; putValue(Action.NAME, text); putValue(Action.ACCELERATOR_KEY, key); } - public GeneralAction(String command, String text, String description, KeyStroke key) { + public GeneralAction(Actions command, String text, String description, KeyStroke key) { this.command = command; putValue(Action.NAME, text); putValue(Action.SHORT_DESCRIPTION, description); putValue(Action.ACCELERATOR_KEY, key); } - public GeneralAction(String command, String text, String description, KeyStroke key, Icon icon) { + public GeneralAction(Actions command, String text, String description, KeyStroke key, Icon icon) { super(icon); this.command = command; @@ -2158,9 +2157,9 @@ public void actionPerformed(ActionEvent e) { */ private class EditAction extends MnemonicAwareAction { - private final String command; + private final Actions command; - public EditAction(String command, String menuTitle, String description, KeyStroke key, Icon icon) { + public EditAction(Actions command, String menuTitle, String description, KeyStroke key, Icon icon) { super(icon); this.command = command; putValue(Action.NAME, menuTitle); @@ -2174,7 +2173,7 @@ public EditAction(String command, String menuTitle, String description, KeyStrok JComponent source = Globals.getFocusListener().getFocused(); Action action = source.getActionMap().get(command); if (action != null) { - action.actionPerformed(new ActionEvent(source, 0, command)); + action.actionPerformed(new ActionEvent(source, 0, command.name())); } } } diff --git a/src/main/java/org/jabref/gui/actions/ActionFactory.java b/src/main/java/org/jabref/gui/actions/ActionFactory.java new file mode 100644 index 00000000000..e8374353d20 --- /dev/null +++ b/src/main/java/org/jabref/gui/actions/ActionFactory.java @@ -0,0 +1,45 @@ +package org.jabref.gui.actions; + +import java.util.Objects; + +import javafx.scene.control.Menu; +import javafx.scene.control.MenuItem; + +import org.jabref.gui.keyboard.KeyBindingRepository; + +import de.saxsys.mvvmfx.utils.commands.Command; +import org.controlsfx.control.action.ActionUtils; + +/** + * Helper class to create and style controls according to an {@link ActionsFX}. + */ +public class ActionFactory { + + private KeyBindingRepository keyBindingRepository; + + public ActionFactory(KeyBindingRepository keyBindingRepository) { + this.keyBindingRepository = Objects.requireNonNull(keyBindingRepository); + } + + public MenuItem configureMenuItem(ActionsFX action, Command command, MenuItem menuItem) { + return ActionUtils.configureMenuItem(new JabRefAction(action, command, keyBindingRepository), menuItem); + } + + public MenuItem createMenuItem(ActionsFX action, Command command) { + MenuItem menuItem = ActionUtils.createMenuItem(new JabRefAction(action, command, keyBindingRepository)); + + // For some reason the graphic is not set correctly, so let's fix this + menuItem.graphicProperty().unbind(); + action.getIcon().ifPresent(icon -> menuItem.setGraphic(icon.getGraphicNode())); + return menuItem; + } + + public Menu createMenu(ActionsFX action) { + Menu menu = ActionUtils.createMenu(new JabRefAction(action, keyBindingRepository)); + + // For some reason the graphic is not set correctly, so let's fix this + menu.graphicProperty().unbind(); + action.getIcon().ifPresent(icon -> menu.setGraphic(icon.getGraphicNode())); + return menu; + } +} diff --git a/src/main/java/org/jabref/gui/actions/Actions.java b/src/main/java/org/jabref/gui/actions/Actions.java index 8f93cd76970..b987cba8220 100644 --- a/src/main/java/org/jabref/gui/actions/Actions.java +++ b/src/main/java/org/jabref/gui/actions/Actions.java @@ -3,73 +3,87 @@ /** * Global String constants for GUI actions */ -public class Actions { +public enum Actions { - public static final String ABBREVIATE_ISO = "abbreviateIso"; - public static final String ABBREVIATE_MEDLINE = "abbreviateMedline"; - public static final String ADD_FILE_LINK = "addFileLink"; - public static final String ADD_TO_GROUP = "addToGroup"; - public static final String AUTO_SET_FILE = "autoSetFile"; - public static final String BACK = "back"; - public static final String CLEANUP = "Cleanup"; - public static final String COPY = "copy"; - public static final String COPY_CITATION_ASCII_DOC = "copyCitaitonAsciidoc"; - public static final String COPY_CITATION_XSLFO = "copyCitaitonFo"; - public static final String COPY_CITATION_HTML = "copyCitaitonHtml"; - public static final String COPY_CITATION_RTF = "copyCitaitonRtf"; - public static final String COPY_CITATION_TEXT = "copyCitaitonText"; - public static final String COPY_KEY = "copyKey"; - public static final String COPY_CITE_KEY = "copyCiteKey"; - public static final String COPY_KEY_AND_TITLE = "copyKeyAndTitle"; - public static final String COPY_KEY_AND_LINK = "copyKeyAndLink"; - public static final String COPY_TITLE = "copyTitle"; - public static final String CUT = "cut"; - public static final String DELETE = "delete"; - public static final String DOWNLOAD_FULL_TEXT = "downloadFullText"; - public static final String DUPLI_CHECK = "dupliCheck"; - public static final String EDIT = "edit"; - public static final String EDIT_PREAMBLE = "editPreamble"; - public static final String EDIT_STRINGS = "editStrings"; - public static final String EXPORT_TO_CLIPBOARD = "exportToClipboard"; - public static final String FOCUS_TABLE = "focusTable"; - public static final String FORWARD = "forward"; - public static final String MAKE_KEY = "makeKey"; - public static final String MANAGE_SELECTORS = "manageSelectors"; - public static final String MARK_ENTRIES = "markEntries"; - public static final String MERGE_DATABASE = "mergeDatabase"; - public static final String MERGE_ENTRIES = "mergeEntries"; - public static final String MERGE_WITH_FETCHED_ENTRY = "mergeWithFetchedEntry"; - public static final String NEXT_PREVIEW_STYLE = "nextPreviewStyle"; - public static final String MOVE_TO_GROUP = "moveToGroup"; - public static final String OPEN_CONSOLE = "openConsole"; - public static final String OPEN_EXTERNAL_FILE = "openExternalFile"; - public static final String OPEN_FOLDER = "openFolder"; - public static final String OPEN_URL = "openUrl"; - public static final String PASTE = "paste"; - public static final String PLAIN_TEXT_IMPORT = "plainTextImport"; - public static final String PREVIOUS_PREVIEW_STYLE = "previousPreviewStyle"; - public static final String PULL_CHANGES_FROM_SHARED_DATABASE = "pullChangesFromSharedDatabase"; - public static final String REDO = "redo"; - public static final String REMOVE_FROM_GROUP = "removeFromGroup"; - public static final String REPLACE_ALL = "replaceAll"; - public static final String RESOLVE_DUPLICATE_KEYS = "resolveDuplicateKeys"; - public static final String SAVE = "save"; - public static final String SAVE_AS = "saveAs"; - public static final String SAVE_SELECTED_AS = "saveSelectedAs"; - public static final String SAVE_SELECTED_AS_PLAIN = "saveSelectedAsPlain"; - public static final String SEARCH = "search"; - 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_GROUPS = "toggleGroups"; - public static final String TOGGLE_PREVIEW = "togglePreview"; - public static final String UNABBREVIATE = "unabbreviate"; - public static final String UNDO = "undo"; - public static final String UNMARK_ALL = "unmarkAll"; - public static final String UNMARK_ENTRIES = "unmarkEntries"; - public static final String WRITE_XMP = "writeXMP"; - public static final String PRINT_PREVIEW = "printPreview"; - - private Actions() { - } + ABBREVIATE_ISO, + ABBREVIATE_MEDLINE, + ADD_FILE_LINK, + ADD_TO_GROUP, + AUTO_SET_FILE, + BACK, + CLEANUP, + COPY, + COPY_CITATION_ASCII_DOC, + COPY_CITATION_XSLFO, + COPY_CITATION_HTML, + COPY_CITATION_RTF, + COPY_CITATION_TEXT, + COPY_KEY, + COPY_CITE_KEY, + COPY_KEY_AND_TITLE, + COPY_KEY_AND_LINK, + COPY_TITLE, + CUT, + DELETE, + DOWNLOAD_FULL_TEXT, + DUPLI_CHECK, + EDIT, + EDIT_PREAMBLE, + EDIT_STRINGS, + EXPORT_TO_CLIPBOARD, + FOCUS_TABLE, + FORWARD, + MAKE_KEY, + MANAGE_SELECTORS, + MARK_ENTRIES, + MERGE_DATABASE, + MERGE_ENTRIES, + MERGE_WITH_FETCHED_ENTRY, + NEXT_PREVIEW_STYLE, + MOVE_TO_GROUP, + OPEN_CONSOLE, + OPEN_EXTERNAL_FILE, + OPEN_FOLDER, + OPEN_URL, + PASTE, + PLAIN_TEXT_IMPORT, + PREVIOUS_PREVIEW_STYLE, + PULL_CHANGES_FROM_SHARED_DATABASE, + REDO, + REMOVE_FROM_GROUP, + REPLACE_ALL, + RESOLVE_DUPLICATE_KEYS, + SAVE, + SAVE_AS, + SAVE_SELECTED_AS, + SAVE_SELECTED_AS_PLAIN, + SEARCH, + GLOBAL_SEARCH, + SELECT_ALL, + SEND_AS_EMAIL, + TOGGLE_GROUPS, + TOGGLE_PREVIEW, + UNABBREVIATE, + UNDO, + UNMARK_ALL, + UNMARK_ENTRIES, + WRITE_XMP, + PRINT_PREVIEW, + togglePrinted, + clearPriority, + setPriority1, + setPriority2, + setPriority3, + toggleQualityAssured, + clearRank, + setRank1, + setRank2, + setRank3, + setRank4, + setRank5, + clearReadStatus, + setReadStatusToRead, + setReadStatusToSkimmed, + toggleRelevance, + findUnlinkedFiles } diff --git a/src/main/java/org/jabref/gui/actions/ActionsFX.java b/src/main/java/org/jabref/gui/actions/ActionsFX.java new file mode 100644 index 00000000000..64c6276f1b0 --- /dev/null +++ b/src/main/java/org/jabref/gui/actions/ActionsFX.java @@ -0,0 +1,101 @@ +package org.jabref.gui.actions; + +import java.util.Optional; + +import org.jabref.gui.IconTheme; +import org.jabref.gui.keyboard.KeyBinding; +import org.jabref.logic.l10n.Localization; + +public enum ActionsFX { + + COPY_MORE(Localization.lang("Copy") + "..."), + COPY_TITLE(Localization.lang("Copy title"), KeyBinding.COPY_TITLE), + COPY_KEY(Localization.lang("Copy BibTeX key"), KeyBinding.COPY_BIBTEX_KEY), + COPY_CITE_KEY(Localization.lang("Copy \\cite{BibTeX key}"), KeyBinding.COPY_CITE_BIBTEX_KEY), + COPY_KEY_AND_TITLE(Localization.lang("Copy BibTeX key and title"), KeyBinding.COPY_BIBTEX_KEY_AND_TITLE), + COPY_KEY_AND_LINK(Localization.lang("Copy BibTeX key and link"), KeyBinding.COPY_BIBTEX_KEY_AND_LINK), + COPY_CITATION_HTML(Localization.menuTitle("Copy citation") + " (HTML)", KeyBinding.COPY_PREVIEW), + COPY_CITATION_MORE(Localization.menuTitle("Copy citation") + "..."), + COPY_CITATION_TEXT("Text"), + COPY_CITATION_RTF("RTF"), + COPY_CITATION_ASCII_DOC("AsciiDoc"), + COPY_CITATION_XSLFO("XSL-FO"), + COPY_CITATION_PREVIEW(Localization.lang("Copy preview"), KeyBinding.COPY_PREVIEW), + EXPORT_TO_CLIPBOARD(Localization.lang("Export to clipboard"), IconTheme.JabRefIcons.EXPORT_TO_CLIPBOARD), + COPY(Localization.lang("Copy"), IconTheme.JabRefIcons.COPY, KeyBinding.COPY), + PASTE(Localization.lang("Paste"), IconTheme.JabRefIcons.PASTE, KeyBinding.PASTE), + CUT(Localization.lang("Cut"), IconTheme.JabRefIcons.CUT, KeyBinding.CUT), + DELETE(Localization.lang("Delete"), IconTheme.JabRefIcons.DELETE_ENTRY, KeyBinding.DELETE_ENTRY), + SEND_AS_EMAIL(Localization.lang("Send as email"), IconTheme.JabRefIcons.EMAIL), + OPEN_FOLDER(Localization.lang("Open folder"), KeyBinding.OPEN_FOLDER), + OPEN_EXTERNAL_FILE(Localization.lang("Open file"), IconTheme.JabRefIcons.FILE, KeyBinding.OPEN_FILE), + OPEN_URL(Localization.lang("Open URL or DOI"), IconTheme.JabRefIcons.WWW, KeyBinding.OPEN_URL_OR_DOI), + MERGE_WITH_FETCHED_ENTRY(Localization.lang("Get BibTeX data from %0", "DOI/ISBN/...")), + ADD_FILE_LINK(Localization.lang("Attach file"), IconTheme.JabRefIcons.ATTACH_FILE), + MERGE_ENTRIES(Localization.lang("Merge entries") + "...", IconTheme.JabRefIcons.MERGE_ENTRIES), + ADD_TO_GROUP(Localization.lang("Add to group")), + REMOVE_FROM_GROUP(Localization.lang("Remove from group")), + MOVE_TO_GROUP(Localization.lang("Move to group")), + PRIORITY(Localization.lang("Priority"), IconTheme.JabRefIcons.PRIORITY), + CLEAR_PRIORITY(Localization.lang("Clear priority")), + PRIORITY_HIGH(Localization.lang("Set priority to high"), IconTheme.JabRefIcons.PRIORITY_HIGH), + PRIORITY_MEDIUM(Localization.lang("Set priority to medium"), IconTheme.JabRefIcons.PRIORITY_MEDIUM), + PRIORITY_LOW(Localization.lang("Set priority to low"), IconTheme.JabRefIcons.PRIORITY_LOW), + QUALITY(Localization.lang("Quality"), IconTheme.JabRefIcons.QUALITY), + QUALITY_ASSURED(Localization.lang("Toggle quality assured"), IconTheme.JabRefIcons.QUALITY_ASSURED), + RANKING(Localization.lang("Rank"), IconTheme.JabRefIcons.RANKING), + CLEAR_RANK(Localization.lang("Clear rank")), + RANK_1("", IconTheme.JabRefIcons.RANK1), + RANK_2("", IconTheme.JabRefIcons.RANK2), + RANK_3("", IconTheme.JabRefIcons.RANK3), + RANK_4("", IconTheme.JabRefIcons.RANK4), + RANK_5("", IconTheme.JabRefIcons.RANK5), + PRINTED(Localization.lang("Printed"), IconTheme.JabRefIcons.PRINTED), + TOGGLE_PRINTED(Localization.lang("Toggle print status"), IconTheme.JabRefIcons.PRINTED), + READ_STATUS(Localization.lang("Read status"), IconTheme.JabRefIcons.READ_STATUS), + CLEAR_READ_STATUS(Localization.lang("Clear read status")), + READ(Localization.lang("Set read status to read"), IconTheme.JabRefIcons.READ_STATUS_READ), + SKIMMED(Localization.lang("Set read status to skimmed"), IconTheme.JabRefIcons.READ_STATUS_SKIMMED), + RELEVANCE(Localization.lang("Relevance"), IconTheme.JabRefIcons.RELEVANCE), + RELEVANT(Localization.lang("Toggle relevance"), IconTheme.JabRefIcons.RELEVANCE); + + private final String text; + private final Optional icon; + private final Optional keyBinding; + + ActionsFX(String text) { + this.text = text; + this.icon = Optional.empty(); + this.keyBinding = Optional.empty(); + } + + ActionsFX(String text, IconTheme.JabRefIcons icon) { + this.text = text; + this.icon = Optional.of(icon); + this.keyBinding = Optional.empty(); + } + + ActionsFX(String text, IconTheme.JabRefIcons icon, KeyBinding keyBinding) { + this.text = text; + this.icon = Optional.of(icon); + this.keyBinding = Optional.of(keyBinding); + } + + ActionsFX(String text, KeyBinding keyBinding) { + this.text = text; + this.keyBinding = Optional.of(keyBinding); + this.icon = Optional.empty(); + } + + public Optional getIcon() { + return icon; + } + + public Optional getKeyBinding() { + return keyBinding; + } + + public String getText() { + return text; + } +} diff --git a/src/main/java/org/jabref/gui/actions/JabRefAction.java b/src/main/java/org/jabref/gui/actions/JabRefAction.java new file mode 100644 index 00000000000..dd99c18044b --- /dev/null +++ b/src/main/java/org/jabref/gui/actions/JabRefAction.java @@ -0,0 +1,25 @@ +package org.jabref.gui.actions; + +import org.jabref.gui.keyboard.KeyBindingRepository; + +import de.saxsys.mvvmfx.utils.commands.Command; +import org.controlsfx.control.action.Action; + +/** + * Wrapper around one of our actions from {@link ActionsFX} to convert them to controlsfx {@link Action}. + */ +class JabRefAction extends Action { + + public JabRefAction(ActionsFX action, KeyBindingRepository keyBindingRepository) { + super(action.getText()); + action.getIcon() + .ifPresent(icon -> setGraphic(icon.getGraphicNode())); + action.getKeyBinding() + .ifPresent(keyBinding -> setAccelerator(keyBindingRepository.getKeyCombination(keyBinding))); + } + + public JabRefAction(ActionsFX action, Command command, KeyBindingRepository keyBindingRepository) { + this(action, keyBindingRepository); + setEventHandler(event -> command.execute()); + } +} diff --git a/src/main/java/org/jabref/gui/actions/OldCommandWrapper.java b/src/main/java/org/jabref/gui/actions/OldCommandWrapper.java new file mode 100644 index 00000000000..1fa7ac6774a --- /dev/null +++ b/src/main/java/org/jabref/gui/actions/OldCommandWrapper.java @@ -0,0 +1,50 @@ +package org.jabref.gui.actions; + +import javafx.beans.property.ReadOnlyDoubleProperty; + +import org.jabref.gui.BasePanel; +import org.jabref.gui.util.BindingsHelper; + +import de.saxsys.mvvmfx.utils.commands.CommandBase; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * This wraps the old Swing commands so that they fit into the new infrastructure. + * In the long term, this class should be removed. + */ +public class OldCommandWrapper extends CommandBase { + + private static final Log LOGGER = LogFactory.getLog(OldCommandWrapper.class); + + private final Actions command; + private final BasePanel panel; + + public OldCommandWrapper(Actions command, BasePanel panel) { + this.command = command; + this.panel = panel; + } + + @Override + public void execute() { + try { + panel.runCommand(command); + } catch (Throwable ex) { + LOGGER.debug("Cannot execute command " + command + ".", ex); + } + } + + @Override + public double getProgress() { + return 0; + } + + @Override + public ReadOnlyDoubleProperty progressProperty() { + return null; + } + + public void setExecutable(boolean executable) { + this.executable.bind(BindingsHelper.constantOf(executable)); + } +} diff --git a/src/main/java/org/jabref/gui/fieldeditors/JTextAreaWithHighlighting.java b/src/main/java/org/jabref/gui/fieldeditors/JTextAreaWithHighlighting.java index f633b142e4b..909fa05778d 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/JTextAreaWithHighlighting.java +++ b/src/main/java/org/jabref/gui/fieldeditors/JTextAreaWithHighlighting.java @@ -85,7 +85,7 @@ public void actionPerformed(ActionEvent evt) { getInputMap().put(Globals.getKeyPrefs().getKey(org.jabref.gui.keyboard.KeyBinding.UNDO), "Undo"); // Create a redo action and add it to the text component - getActionMap().put("Redo", new AbstractAction(Actions.REDO) { + getActionMap().put("Redo", new AbstractAction(Actions.REDO.name()) { @Override public void actionPerformed(ActionEvent evt) { diff --git a/src/main/java/org/jabref/gui/fieldeditors/TextField.java b/src/main/java/org/jabref/gui/fieldeditors/TextField.java index 6a240db224d..ba89717e38f 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/TextField.java +++ b/src/main/java/org/jabref/gui/fieldeditors/TextField.java @@ -163,7 +163,7 @@ public void actionPerformed(ActionEvent evt) { getInputMap().put(Globals.getKeyPrefs().getKey(org.jabref.gui.keyboard.KeyBinding.UNDO), "Undo"); // Create a redo action and add it to the text component - getActionMap().put("Redo", new AbstractAction(Actions.REDO) { + getActionMap().put("Redo", new AbstractAction(Actions.REDO.name()) { @Override public void actionPerformed(ActionEvent evt) { diff --git a/src/main/java/org/jabref/gui/maintable/MainTable.java b/src/main/java/org/jabref/gui/maintable/MainTable.java index 07e4044b26e..63ef218c6ca 100644 --- a/src/main/java/org/jabref/gui/maintable/MainTable.java +++ b/src/main/java/org/jabref/gui/maintable/MainTable.java @@ -18,6 +18,7 @@ import org.jabref.gui.EntryMarker; import org.jabref.gui.JabRefFrame; import org.jabref.gui.externalfiletype.ExternalFileTypes; +import org.jabref.gui.keyboard.KeyBindingRepository; import org.jabref.gui.renderer.CompleteRenderer; import org.jabref.gui.renderer.GeneralRenderer; import org.jabref.gui.renderer.IncompleteRenderer; @@ -72,7 +73,7 @@ private enum CellRendererMode { } public MainTable(MainTableDataModel model, JabRefFrame frame, - BasePanel panel, BibDatabase database, MainTablePreferences preferences, ExternalFileTypes externalFileTypes) { + BasePanel panel, BibDatabase database, MainTablePreferences preferences, ExternalFileTypes externalFileTypes, KeyBindingRepository keyBindingRepository) { super(); this.model = model; @@ -83,7 +84,7 @@ public MainTable(MainTableDataModel model, JabRefFrame frame, panel.showAndEdit(entry.getEntry()); } }) - .withContextMenu(RightClickMenu::create)); + .withContextMenu(entry1 -> RightClickMenu.create(entry1, keyBindingRepository, panel, Globals.getKeyPrefs()))); if (preferences.resizeColumnsToFit()) { this.setColumnResizePolicy(new SmartConstrainedResizePolicy()); } diff --git a/src/main/java/org/jabref/gui/maintable/RightClickMenu.java b/src/main/java/org/jabref/gui/maintable/RightClickMenu.java index 88b80af064f..ce7e20d7b7d 100644 --- a/src/main/java/org/jabref/gui/maintable/RightClickMenu.java +++ b/src/main/java/org/jabref/gui/maintable/RightClickMenu.java @@ -1,40 +1,26 @@ package org.jabref.gui.maintable; -import java.awt.event.ActionEvent; -import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.Optional; - -import javax.swing.AbstractAction; -import javax.swing.Action; -import javax.swing.Icon; -import javax.swing.JLabel; -import javax.swing.JMenu; -import javax.swing.JMenuItem; -import javax.swing.JPopupMenu; -import javax.swing.event.PopupMenuEvent; -import javax.swing.event.PopupMenuListener; import javafx.scene.control.ContextMenu; +import javafx.scene.control.Menu; +import javafx.scene.control.MenuItem; +import javafx.scene.control.SeparatorMenuItem; import org.jabref.Globals; import org.jabref.gui.BasePanel; -import org.jabref.gui.EntryMarker; -import org.jabref.gui.IconTheme; -import org.jabref.gui.JabRefFrame; +import org.jabref.gui.actions.ActionFactory; import org.jabref.gui.actions.Actions; -import org.jabref.gui.copyfiles.CopyFilesAction; -import org.jabref.gui.filelist.FileListTableModel; -import org.jabref.gui.keyboard.KeyBinding; +import org.jabref.gui.actions.ActionsFX; +import org.jabref.gui.actions.OldCommandWrapper; +import org.jabref.gui.keyboard.KeyBindingRepository; import org.jabref.gui.menus.ChangeEntryTypeMenu; import org.jabref.gui.mergeentries.FetchAndMergeEntry; -import org.jabref.gui.specialfields.SpecialFieldMenuAction; import org.jabref.gui.specialfields.SpecialFieldValueViewModel; import org.jabref.gui.specialfields.SpecialFieldViewModel; -import org.jabref.gui.worker.MarkEntriesAction; import org.jabref.logic.citationstyle.CitationStyle; -import org.jabref.logic.l10n.Localization; +import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.FieldName; import org.jabref.model.entry.specialfields.SpecialField; @@ -45,290 +31,184 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -public class RightClickMenu extends JPopupMenu implements PopupMenuListener { +public class RightClickMenu { private static final Log LOGGER = LogFactory.getLog(RightClickMenu.class); - private final BasePanel panel; - private final JMenuItem groupAdd; - private final JMenuItem groupRemove; - private final JMenuItem groupMoveTo; - - - public RightClickMenu(JabRefFrame frame, BasePanel panel) { - this.panel = panel; - JMenu typeMenu = new ChangeEntryTypeMenu(Globals.getKeyPrefs()).getChangeEntryTypeMenu(panel); - // Are multiple entries selected? - boolean multiple = areMultipleEntriesSelected(); - - // If only one entry is selected, get a reference to it for adapting the menu. - BibEntry be = null; - if (panel.getMainTable().getSelectedEntries().size() == 1) { - be = panel.getMainTable().getSelectedEntries().get(0); - } - - addPopupMenuListener(this); - - JMenu copySpecialMenu = new JMenu(Localization.lang("Copy") + "..."); - copySpecialMenu.add(new GeneralAction(Actions.COPY_TITLE, Localization.lang("Copy title"), KeyBinding.COPY_TITLE)); - copySpecialMenu.add(new GeneralAction(Actions.COPY_KEY, Localization.lang("Copy BibTeX key"), KeyBinding.COPY_BIBTEX_KEY)); - copySpecialMenu.add(new GeneralAction(Actions.COPY_CITE_KEY, Localization.lang("Copy \\cite{BibTeX key}"), KeyBinding.COPY_CITE_BIBTEX_KEY)); - copySpecialMenu.add(new GeneralAction(Actions.COPY_KEY_AND_TITLE, Localization.lang("Copy BibTeX key and title"), KeyBinding.COPY_BIBTEX_KEY_AND_TITLE)); - copySpecialMenu.add(new GeneralAction(Actions.COPY_KEY_AND_LINK, Localization.lang("Copy BibTeX key and link"), KeyBinding.COPY_BIBTEX_KEY_AND_LINK)); - - // the submenu will behave dependent on what style is currently selected (citation/preview) - PreviewPreferences previewPreferences = Globals.prefs.getPreviewPreferences(); - String style = previewPreferences.getPreviewCycle().get(previewPreferences.getPreviewCyclePosition()); - if (CitationStyle.isCitationStyleFile(style)) { - copySpecialMenu.add(new GeneralAction(Actions.COPY_CITATION_HTML, Localization.menuTitle("Copy citation") + " (HTML)", KeyBinding.COPY_PREVIEW)); - JMenu copyCitationMenu = new JMenu(Localization.menuTitle("Copy citation") + "..."); - copyCitationMenu.add(new GeneralAction(Actions.COPY_CITATION_TEXT, "Text")); - copyCitationMenu.add(new GeneralAction(Actions.COPY_CITATION_RTF, "RTF")); - copyCitationMenu.add(new GeneralAction(Actions.COPY_CITATION_ASCII_DOC, "AsciiDoc")); - copyCitationMenu.add(new GeneralAction(Actions.COPY_CITATION_XSLFO, "XSL-FO")); - copySpecialMenu.add(copyCitationMenu); - } else { - copySpecialMenu.add(new GeneralAction(Actions.COPY_CITATION_HTML, Localization.lang("Copy preview"), KeyBinding.COPY_PREVIEW)); - } - - copySpecialMenu.add(new GeneralAction(Actions.EXPORT_TO_CLIPBOARD, Localization.lang("Export to clipboard"), - IconTheme.JabRefIcons.EXPORT_TO_CLIPBOARD.getSmallIcon())); + public static ContextMenu create(BibEntryTableViewModel entry, KeyBindingRepository keyBindingRepository, BasePanel panel, KeyBindingRepository keyBindings) { + ContextMenu contextMenu = new ContextMenu(); + ActionFactory factory = new ActionFactory(keyBindingRepository); - add(new GeneralAction(Actions.COPY, Localization.lang("Copy"), IconTheme.JabRefIcons.COPY.getSmallIcon(), KeyBinding.COPY)); - add(copySpecialMenu); - add(new GeneralAction(Actions.PASTE, Localization.lang("Paste"), IconTheme.JabRefIcons.PASTE.getSmallIcon(), KeyBinding.PASTE)); - add(new GeneralAction(Actions.CUT, Localization.lang("Cut"), IconTheme.JabRefIcons.CUT.getSmallIcon(), KeyBinding.CUT)); - add(new GeneralAction(Actions.DELETE, Localization.lang("Delete"), IconTheme.JabRefIcons.DELETE_ENTRY.getSmallIcon(), KeyBinding.DELETE_ENTRY)); - GeneralAction printPreviewAction = new GeneralAction(Actions.PRINT_PREVIEW, Localization.lang("Print entry preview"), IconTheme.JabRefIcons.PRINTED.getSmallIcon()); - printPreviewAction.setEnabled(!multiple); - add(printPreviewAction); + contextMenu.getItems().add(factory.createMenuItem(ActionsFX.COPY, new OldCommandWrapper(Actions.COPY, panel))); + contextMenu.getItems().add(createCopySubMenu(panel, factory)); + contextMenu.getItems().add(factory.createMenuItem(ActionsFX.PASTE, new OldCommandWrapper(Actions.PASTE, panel))); + contextMenu.getItems().add(factory.createMenuItem(ActionsFX.CUT, new OldCommandWrapper(Actions.CUT, panel))); + contextMenu.getItems().add(factory.createMenuItem(ActionsFX.DELETE, new OldCommandWrapper(Actions.DELETE, panel))); - addSeparator(); + contextMenu.getItems().add(new SeparatorMenuItem()); - add(new GeneralAction(Actions.SEND_AS_EMAIL, Localization.lang("Send as email"), IconTheme.JabRefIcons.EMAIL.getSmallIcon())); - addSeparator(); - add(new CopyFilesAction()); + contextMenu.getItems().add(factory.createMenuItem(ActionsFX.SEND_AS_EMAIL, new OldCommandWrapper(Actions.SEND_AS_EMAIL, panel))); - JMenu markSpecific = JabRefFrame.subMenu(Localization.menuTitle("Mark specific color")); - markSpecific.setIcon(IconTheme.JabRefIcons.MARK_ENTRIES.getSmallIcon()); - for (int i = 0; i < EntryMarker.MAX_MARKING_LEVEL; i++) { - markSpecific.add(new MarkEntriesAction(frame, i).getMenuItem()); - } - - if (multiple) { - add(new GeneralAction(Actions.MARK_ENTRIES, Localization.lang("Mark entries"), IconTheme.JabRefIcons.MARK_ENTRIES.getSmallIcon(), KeyBinding.MARK_ENTRIES)); - add(markSpecific); - add(new GeneralAction(Actions.UNMARK_ENTRIES, Localization.lang("Unmark entries"), IconTheme.JabRefIcons.UNMARK_ENTRIES.getSmallIcon(), KeyBinding.UNMARK_ENTRIES)); - } else if (be != null) { - Optional marked = be.getField(FieldName.MARKED_INTERNAL); - // We have to check for "" too as the marked field may be empty - if ((!marked.isPresent()) || marked.get().isEmpty()) { - add(new GeneralAction(Actions.MARK_ENTRIES, Localization.lang("Mark entry"), IconTheme.JabRefIcons.MARK_ENTRIES.getSmallIcon(), KeyBinding.MARK_ENTRIES)); - add(markSpecific); - } else { - add(markSpecific); - add(new GeneralAction(Actions.UNMARK_ENTRIES, Localization.lang("Unmark entry"), IconTheme.JabRefIcons.UNMARK_ENTRIES.getSmallIcon(), KeyBinding.UNMARK_ENTRIES)); - } - } + contextMenu.getItems().add(new SeparatorMenuItem()); if (Globals.prefs.getBoolean(JabRefPreferences.SPECIALFIELDSENABLED)) { if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_RANKING)) { - JMenu rankingMenu = new JMenu(); - RightClickMenu.populateSpecialFieldMenu(rankingMenu, SpecialField.RANKING, frame); - add(rankingMenu); + contextMenu.getItems().add(createSpecialFieldMenu(SpecialField.RANKING, factory, panel)); } - // TODO: multiple handling for relevance and quality-assurance - // if multiple values are selected ("if (multiple)"), two options (set / clear) should be offered - // if one value is selected either set or clear should be offered if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_RELEVANCE)) { - add(new SpecialFieldMenuAction(new SpecialFieldValueViewModel(SpecialField.RELEVANCE.getValues().get(0)), frame)); + contextMenu.getItems().add(getSpecialFieldSingleItem(SpecialField.RELEVANCE, factory, panel)); } + if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_QUALITY)) { - add(new SpecialFieldMenuAction(new SpecialFieldValueViewModel(SpecialField.QUALITY.getValues().get(0)), frame)); + contextMenu.getItems().add(getSpecialFieldSingleItem(SpecialField.QUALITY, factory, panel)); } + if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_PRINTED)) { - add(new SpecialFieldMenuAction(new SpecialFieldValueViewModel(SpecialField.PRINTED.getValues().get(0)), frame)); + contextMenu.getItems().add(getSpecialFieldSingleItem(SpecialField.PRINTED, factory, panel)); } if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_PRIORITY)) { - JMenu priorityMenu = new JMenu(); - RightClickMenu.populateSpecialFieldMenu(priorityMenu, SpecialField.PRIORITY, frame); - add(priorityMenu); + Menu priorityMenu = createSpecialFieldMenu(SpecialField.PRIORITY, factory, panel); + contextMenu.getItems().add(priorityMenu); } if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_READ)) { - JMenu readStatusMenu = new JMenu(); - RightClickMenu.populateSpecialFieldMenu(readStatusMenu, SpecialField.READ_STATUS, frame); - add(readStatusMenu); + Menu readStatusMenu = createSpecialFieldMenu(SpecialField.READ_STATUS, factory, panel); + contextMenu.getItems().add(readStatusMenu); } - } - addSeparator(); - - GeneralAction openFolderAction = new GeneralAction(Actions.OPEN_FOLDER, Localization.lang("Open folder"), - KeyBinding.OPEN_FOLDER); - openFolderAction.setEnabled(isFieldSetForSelectedEntry(FieldName.FILE)); - add(openFolderAction); - - GeneralAction openFileAction = new GeneralAction(Actions.OPEN_EXTERNAL_FILE, Localization.lang("Open file"), - getFileIconForSelectedEntry(), KeyBinding.OPEN_FILE); - openFileAction.setEnabled(isFieldSetForSelectedEntry(FieldName.FILE)); - add(openFileAction); + contextMenu.getItems().add(new SeparatorMenuItem()); - GeneralAction openUrlAction = new GeneralAction(Actions.OPEN_URL, Localization.lang("Open URL or DOI"), - IconTheme.JabRefIcons.WWW.getSmallIcon(), KeyBinding.OPEN_URL_OR_DOI); - openUrlAction.setEnabled(isFieldSetForSelectedEntry(FieldName.URL) || isFieldSetForSelectedEntry(FieldName.DOI)); - add(openUrlAction); + contextMenu.getItems().add(factory.createMenuItem(ActionsFX.OPEN_FOLDER, getOpenFolderCommand(panel))); + contextMenu.getItems().add(factory.createMenuItem(ActionsFX.OPEN_EXTERNAL_FILE, getOpenExternalFileCommand(panel))); + contextMenu.getItems().add(factory.createMenuItem(ActionsFX.OPEN_URL, getOpenUrlCommand(panel))); - addSeparator(); + contextMenu.getItems().add(new SeparatorMenuItem()); - add(typeMenu); + contextMenu.getItems().add(new ChangeEntryTypeMenu(keyBindings).getChangeEntryTypeMenu(entry.getEntry(), panel.getBibDatabaseContext(), panel.getUndoManager())); + contextMenu.getItems().add(factory.createMenuItem(ActionsFX.MERGE_WITH_FETCHED_ENTRY, getFetchEntryData(panel))); + contextMenu.getItems().add(factory.createMenuItem(ActionsFX.ADD_FILE_LINK, getAddFileLinkCommand(panel))); + contextMenu.getItems().add(factory.createMenuItem(ActionsFX.MERGE_ENTRIES, mergeEntries(panel))); - GeneralAction mergeFetchedEntryAction = new GeneralAction(Actions.MERGE_WITH_FETCHED_ENTRY, - Localization.lang("Get BibTeX data from %0", FetchAndMergeEntry.getDisplayNameOfSupportedFields())); - mergeFetchedEntryAction.setEnabled(isAnyFieldSetForSelectedEntry(FetchAndMergeEntry.SUPPORTED_FIELDS)); - add(mergeFetchedEntryAction); + contextMenu.getItems().add(new SeparatorMenuItem()); - add(frame.getMassSetField()); + contextMenu.getItems().add(factory.createMenuItem(ActionsFX.ADD_TO_GROUP, addToGroup(panel))); + contextMenu.getItems().add(factory.createMenuItem(ActionsFX.REMOVE_FROM_GROUP, removeFromGroup(panel))); + contextMenu.getItems().add(factory.createMenuItem(ActionsFX.MOVE_TO_GROUP, moveToGroup(panel))); - GeneralAction attachFileAction = new GeneralAction(Actions.ADD_FILE_LINK, Localization.lang("Attach file"), - IconTheme.JabRefIcons.ATTACH_FILE.getSmallIcon()); - attachFileAction.setEnabled(!multiple); - add(attachFileAction); - - add(frame.getManageKeywords()); - - GeneralAction mergeEntriesAction = new GeneralAction(Actions.MERGE_ENTRIES, - Localization.lang("Merge entries") + "...", IconTheme.JabRefIcons.MERGE_ENTRIES.getSmallIcon()); - mergeEntriesAction.setEnabled(areExactlyTwoEntriesSelected()); - add(mergeEntriesAction); - - addSeparator(); // for "add/move/remove to/from group" entries (appended here) - - groupAdd = new JMenuItem(new GeneralAction(Actions.ADD_TO_GROUP, Localization.lang("Add to group"))); - add(groupAdd); - groupRemove = new JMenuItem(new GeneralAction(Actions.REMOVE_FROM_GROUP, Localization.lang("Remove from group"))); - add(groupRemove); - - groupMoveTo = add(new GeneralAction(Actions.MOVE_TO_GROUP, Localization.lang("Move to group"))); - add(groupMoveTo); - - // create disabledIcons for all menu entries - frame.createDisabledIconsForMenuEntries(this); + return contextMenu; } - /** - * Remove all types from the menu. - * Then cycle through all available values, and add them. - */ - public static void populateSpecialFieldMenu(JMenu menu, SpecialField field, JabRefFrame frame) { - SpecialFieldViewModel viewModel = new SpecialFieldViewModel(field); - menu.setText(viewModel.getLocalization()); - menu.setIcon(viewModel.getRepresentingIcon()); - for (SpecialFieldValue val : field.getValues()) { - menu.add(new SpecialFieldMenuAction(new SpecialFieldValueViewModel(val), frame)); - } + private static OldCommandWrapper moveToGroup(BasePanel panel) { + OldCommandWrapper command = new OldCommandWrapper(Actions.MOVE_TO_GROUP, panel); + command.setExecutable(areGroupsPresent(panel.getBibDatabaseContext())); + return command; } - private boolean areMultipleEntriesSelected() { - return panel.getMainTable().getSelectedEntries().size() > 1; + private static OldCommandWrapper removeFromGroup(BasePanel panel) { + OldCommandWrapper command = new OldCommandWrapper(Actions.REMOVE_FROM_GROUP, panel); + command.setExecutable(areGroupsPresent(panel.getBibDatabaseContext())); + return command; } - private boolean areExactlyTwoEntriesSelected() { - return panel.getMainTable().getSelectedEntries().size() == 2; + private static OldCommandWrapper addToGroup(BasePanel panel) { + OldCommandWrapper command = new OldCommandWrapper(Actions.ADD_TO_GROUP, panel); + command.setExecutable(areGroupsPresent(panel.getBibDatabaseContext())); + return command; } - /** - * Set the dynamic contents of "Add to group ..." submenu. - */ - @Override - public void popupMenuWillBecomeVisible(PopupMenuEvent e) { - boolean groupsPresent = panel.getBibDatabaseContext().getMetaData().getGroups().isPresent(); - groupAdd.setEnabled(groupsPresent); - groupRemove.setEnabled(groupsPresent); - groupMoveTo.setEnabled(groupsPresent); + private static OldCommandWrapper mergeEntries(BasePanel panel) { + OldCommandWrapper command = new OldCommandWrapper(Actions.MERGE_ENTRIES, panel); + command.setExecutable(panel.getMainTable().getSelectedEntries().size() == 2); + return command; } - @Override - public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { - // Nothing to do + private static OldCommandWrapper getAddFileLinkCommand(BasePanel panel) { + OldCommandWrapper command = new OldCommandWrapper(Actions.ADD_FILE_LINK, panel); + command.setExecutable(panel.getMainTable().getSelectedEntries().size() == 1); + return command; } - @Override - public void popupMenuCanceled(PopupMenuEvent e) { - // nothing to do + private static OldCommandWrapper getFetchEntryData(BasePanel panel) { + OldCommandWrapper command = new OldCommandWrapper(Actions.MERGE_WITH_FETCHED_ENTRY, panel); + command.setExecutable(isAnyFieldSetForSelectedEntry(FetchAndMergeEntry.SUPPORTED_FIELDS, panel)); + return command; } - private boolean isFieldSetForSelectedEntry(String fieldname) { - return isAnyFieldSetForSelectedEntry(Arrays.asList(fieldname)); + private static OldCommandWrapper getOpenUrlCommand(BasePanel panel) { + OldCommandWrapper command = new OldCommandWrapper(Actions.OPEN_URL, panel); + command.setExecutable(isFieldSetForSelectedEntry(FieldName.URL, panel) || isFieldSetForSelectedEntry(FieldName.DOI, panel)); + return command; } - private boolean isAnyFieldSetForSelectedEntry(List fieldnames) { - if (panel.getMainTable().getSelectedEntries().size() == 1) { - BibEntry entry = panel.getMainTable().getSelectedEntries().get(0); - return !Collections.disjoint(fieldnames, entry.getFieldNames()); - } - return false; + private static OldCommandWrapper getOpenExternalFileCommand(BasePanel panel) { + OldCommandWrapper command = new OldCommandWrapper(Actions.OPEN_EXTERNAL_FILE, panel); + command.setExecutable(isFieldSetForSelectedEntry(FieldName.FILE, panel)); + return command; } - private Icon getFileIconForSelectedEntry() { - if (panel.getMainTable().getSelectedEntries().size() == 1) { - BibEntry entry = panel.getMainTable().getSelectedEntries().get(0); - if (entry.hasField(FieldName.FILE)) { - JLabel label = FileListTableModel.getFirstLabel(entry.getField(FieldName.FILE).get()); - if (label != null) { - return label.getIcon(); - } - } - } - return IconTheme.JabRefIcons.FILE.getSmallIcon(); + private static OldCommandWrapper getOpenFolderCommand(BasePanel panel) { + OldCommandWrapper command = new OldCommandWrapper(Actions.OPEN_FOLDER, panel); + command.setExecutable(isFieldSetForSelectedEntry(FieldName.FILE, panel)); + return command; } - class GeneralAction extends AbstractAction { - - private final String command; - - public GeneralAction(String command, String name) { - super(name); - this.command = command; - } + private static MenuItem getSpecialFieldSingleItem(SpecialField field, ActionFactory factory, BasePanel panel) { + SpecialFieldValueViewModel specialField = new SpecialFieldValueViewModel(field.getValues().get(0)); + return factory.createMenuItem(specialField.getAction(), new OldCommandWrapper(specialField.getCommand(), panel)); + } - public GeneralAction(String command, String name, Icon icon) { - super(name, icon); - this.command = command; - } + private static Menu createCopySubMenu(BasePanel panel, ActionFactory factory) { + Menu copySpecialMenu = factory.createMenu(ActionsFX.COPY_MORE); + copySpecialMenu.getItems().add(factory.createMenuItem(ActionsFX.COPY_TITLE, new OldCommandWrapper(Actions.COPY_TITLE, panel))); + copySpecialMenu.getItems().add(factory.createMenuItem(ActionsFX.COPY_KEY, new OldCommandWrapper(Actions.COPY_KEY, panel))); + copySpecialMenu.getItems().add(factory.createMenuItem(ActionsFX.COPY_CITE_KEY, new OldCommandWrapper(Actions.COPY_CITE_KEY, panel))); + copySpecialMenu.getItems().add(factory.createMenuItem(ActionsFX.COPY_KEY_AND_TITLE, new OldCommandWrapper(Actions.COPY_KEY_AND_TITLE, panel))); + copySpecialMenu.getItems().add(factory.createMenuItem(ActionsFX.COPY_KEY_AND_LINK, new OldCommandWrapper(Actions.COPY_KEY_AND_LINK, panel))); - public GeneralAction(String command, String name, KeyBinding key) { - super(name); - this.command = command; - putValue(Action.ACCELERATOR_KEY, Globals.getKeyPrefs().getKey(key)); + // the submenu will behave dependent on what style is currently selected (citation/preview) + PreviewPreferences previewPreferences = Globals.prefs.getPreviewPreferences(); + String style = previewPreferences.getPreviewCycle().get(previewPreferences.getPreviewCyclePosition()); + if (CitationStyle.isCitationStyleFile(style)) { + copySpecialMenu.getItems().add(factory.createMenuItem(ActionsFX.COPY_CITATION_HTML, new OldCommandWrapper(Actions.COPY_CITATION_HTML, panel))); + Menu copyCitationMenu = factory.createMenu(ActionsFX.COPY_CITATION_MORE); + copyCitationMenu.getItems().add(factory.createMenuItem(ActionsFX.COPY_CITATION_TEXT, new OldCommandWrapper(Actions.COPY_CITATION_TEXT, panel))); + copyCitationMenu.getItems().add(factory.createMenuItem(ActionsFX.COPY_CITATION_RTF, new OldCommandWrapper(Actions.COPY_CITATION_RTF, panel))); + copyCitationMenu.getItems().add(factory.createMenuItem(ActionsFX.COPY_CITATION_ASCII_DOC, new OldCommandWrapper(Actions.COPY_CITATION_ASCII_DOC, panel))); + copyCitationMenu.getItems().add(factory.createMenuItem(ActionsFX.COPY_CITATION_XSLFO, new OldCommandWrapper(Actions.COPY_CITATION_XSLFO, panel))); + copySpecialMenu.getItems().add(copyCitationMenu); + } else { + copySpecialMenu.getItems().add(factory.createMenuItem(ActionsFX.COPY_CITATION_PREVIEW, new OldCommandWrapper(Actions.COPY_CITATION_HTML, panel))); } - public GeneralAction(String command, String name, Icon icon, KeyBinding key) { - super(name, icon); - this.command = command; - putValue(Action.ACCELERATOR_KEY, Globals.getKeyPrefs().getKey(key)); - } + copySpecialMenu.getItems().add(factory.createMenuItem(ActionsFX.EXPORT_TO_CLIPBOARD, new OldCommandWrapper(Actions.EXPORT_TO_CLIPBOARD, panel))); + return copySpecialMenu; + } - @Override - public void actionPerformed(ActionEvent e) { - try { - panel.runCommand(command); - } catch (Throwable ex) { - LOGGER.debug("Cannot execute command " + command + ".", ex); - } + private static Menu createSpecialFieldMenu(SpecialField field, ActionFactory factory, BasePanel panel) { + SpecialFieldViewModel viewModel = new SpecialFieldViewModel(field); + Menu menu = factory.createMenu(viewModel.getAction()); + for (SpecialFieldValue val : field.getValues()) { + SpecialFieldValueViewModel specialField = new SpecialFieldValueViewModel(val); + menu.getItems().add(factory.createMenuItem(specialField.getAction(), new OldCommandWrapper(specialField.getCommand(), panel))); } + return menu; } - public static ContextMenu create(BibEntryTableViewModel entry) { - ContextMenu contextMenu = new ContextMenu(); + private static boolean areGroupsPresent(BibDatabaseContext database) { + return database.getMetaData().getGroups().isPresent(); + } - javafx.scene.control.MenuItem copy = new javafx.scene.control.MenuItem(); - copy.setText(Localization.lang("Copy")); - copy.setGraphic(IconTheme.JabRefIcons.COPY.getGraphicNode()); - contextMenu.getItems().add(copy); + private static boolean isFieldSetForSelectedEntry(String field, BasePanel panel) { + return isAnyFieldSetForSelectedEntry(Collections.singletonList(field), panel); + } - return contextMenu; + private static boolean isAnyFieldSetForSelectedEntry(List fields, BasePanel panel) { + if (panel.getMainTable().getSelectedEntries().size() == 1) { + BibEntry entry = panel.getMainTable().getSelectedEntries().get(0); + return !Collections.disjoint(fields, entry.getFieldNames()); + } + return false; } } diff --git a/src/main/java/org/jabref/gui/menus/ChangeEntryTypeMenu.java b/src/main/java/org/jabref/gui/menus/ChangeEntryTypeMenu.java index 0b5b7625a24..d8b62b42b00 100644 --- a/src/main/java/org/jabref/gui/menus/ChangeEntryTypeMenu.java +++ b/src/main/java/org/jabref/gui/menus/ChangeEntryTypeMenu.java @@ -11,8 +11,10 @@ import javax.swing.KeyStroke; import javax.swing.undo.UndoManager; +import javafx.collections.ObservableList; import javafx.scene.control.ContextMenu; import javafx.scene.control.Menu; +import javafx.scene.control.MenuItem; import javafx.scene.control.SeparatorMenuItem; import org.jabref.gui.BasePanel; @@ -51,47 +53,54 @@ public JMenu getChangeEntryTypeMenu(BasePanel panel) { public ContextMenu getChangeEntryTypePopupMenu(BibEntry entry, BibDatabaseContext bibDatabaseContext, CountingUndoManager undoManager) { ContextMenu menu = new ContextMenu(); + populateComplete(menu.getItems(), entry, bibDatabaseContext, undoManager); + return menu; + } + + public Menu getChangeEntryTypeMenu(BibEntry entry, BibDatabaseContext bibDatabaseContext, CountingUndoManager undoManager) { + Menu menu = new Menu(); + menu.setText(Localization.lang("Change entry type")); + populateComplete(menu.getItems(), entry, bibDatabaseContext, undoManager); + return menu; + } + private void populateComplete(ObservableList items, BibEntry entry, BibDatabaseContext bibDatabaseContext, CountingUndoManager undoManager) { if (bibDatabaseContext.isBiblatexMode()) { // Default BibLaTeX - populate(menu, EntryTypes.getAllValues(BibDatabaseMode.BIBLATEX), entry, undoManager); + populate(items, EntryTypes.getAllValues(BibDatabaseMode.BIBLATEX), entry, undoManager); // Custom types - populateSubMenu(menu, Localization.lang("Custom"), EntryTypes.getAllCustomTypes(BibDatabaseMode.BIBLATEX), entry, undoManager); + populateSubMenu(items, Localization.lang("Custom"), EntryTypes.getAllCustomTypes(BibDatabaseMode.BIBLATEX), entry, undoManager); } else { // Default BibTeX - populateSubMenu(menu, Localization.BIBTEX, BibtexEntryTypes.ALL, entry, undoManager); - menu.getItems().remove(0); // Remove separator + populateSubMenu(items, Localization.BIBTEX, BibtexEntryTypes.ALL, entry, undoManager); + items.remove(0); // Remove separator // IEEETran - populateSubMenu(menu, "IEEETran", IEEETranEntryTypes.ALL, entry, undoManager); + populateSubMenu(items, "IEEETran", IEEETranEntryTypes.ALL, entry, undoManager); // Custom types - populateSubMenu(menu, Localization.lang("Custom"), EntryTypes.getAllCustomTypes(BibDatabaseMode.BIBTEX), entry, undoManager); + populateSubMenu(items, Localization.lang("Custom"), EntryTypes.getAllCustomTypes(BibDatabaseMode.BIBTEX), entry, undoManager); } - - return menu; } - private void populateSubMenu(ContextMenu menu, String text, List entryTypes, BibEntry entry, CountingUndoManager undoManager) { + private void populateSubMenu(ObservableList items, String text, List entryTypes, BibEntry entry, CountingUndoManager undoManager) { if (!entryTypes.isEmpty()) { - menu.getItems().add(new SeparatorMenuItem()); + items.add(new SeparatorMenuItem()); Menu custom = new Menu(text); populate(custom, entryTypes, entry, undoManager); - menu.getItems().add(custom); + items.add(custom); } } - private void populate(ContextMenu menu, Collection types, BibEntry entry, UndoManager undoManager) { + private void populate(ObservableList items, Collection types, BibEntry entry, UndoManager undoManager) { for (EntryType type : types) { - menu.getItems().add(ChangeTypeAction.as(type, entry, undoManager)); + items.add(ChangeTypeAction.as(type, entry, undoManager)); } } private void populate(Menu menu, Collection types, BibEntry entry, UndoManager undoManager) { - for (EntryType type : types) { - menu.getItems().add(ChangeTypeAction.as(type, entry, undoManager)); - } + populate(menu.getItems(), types, entry, undoManager); } /** diff --git a/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java b/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java index 2dcda823439..add51e29eb4 100644 --- a/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java +++ b/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java @@ -2,7 +2,6 @@ import java.util.Arrays; import java.util.List; -import java.util.stream.Collectors; import org.jabref.JabRefGUI; import org.jabref.gui.BasePanel; @@ -50,10 +49,4 @@ public FetchAndMergeEntry(BibEntry entry, BasePanel panel, List fields) } } } - - public static String getDisplayNameOfSupportedFields() { - return FieldName.orFields(SUPPORTED_FIELDS.stream() - .map(FieldName::getDisplayName) - .collect(Collectors.toList())); - } } diff --git a/src/main/java/org/jabref/gui/specialfields/SpecialFieldDropDown.java b/src/main/java/org/jabref/gui/specialfields/SpecialFieldDropDown.java index 7e3245571fc..bf854ef6f8d 100644 --- a/src/main/java/org/jabref/gui/specialfields/SpecialFieldDropDown.java +++ b/src/main/java/org/jabref/gui/specialfields/SpecialFieldDropDown.java @@ -11,6 +11,7 @@ import org.jabref.gui.BasePanel; import org.jabref.gui.JabRefFrame; +import org.jabref.gui.actions.Actions; import org.jabref.logic.util.OS; import org.jabref.model.entry.specialfields.SpecialField; import org.jabref.model.entry.specialfields.SpecialFieldValue; @@ -66,7 +67,7 @@ public void actionPerformed(ActionEvent e) { JMenuItem item = new JMenuItem(viewModel.getSpecialFieldValueIcon()); item.setText(viewModel.getMenuString()); item.setToolTipText(viewModel.getToolTipText()); - item.addActionListener(new PopupitemActionListener(frame.getCurrentBasePanel(), new SpecialFieldValueViewModel(val).getActionName())); + item.addActionListener(new PopupitemActionListener(frame.getCurrentBasePanel(), new SpecialFieldValueViewModel(val).getCommand())); item.setMargin(new Insets(0, 0, 0, 0)); popup.add(item); } @@ -77,10 +78,9 @@ public void actionPerformed(ActionEvent e) { private class PopupitemActionListener implements ActionListener { private final BasePanel panel; - private final String actionName; + private final Actions actionName; - - public PopupitemActionListener(BasePanel panel, String actionName) { + public PopupitemActionListener(BasePanel panel, Actions actionName) { this.panel = panel; this.actionName = actionName; } diff --git a/src/main/java/org/jabref/gui/specialfields/SpecialFieldMenuAction.java b/src/main/java/org/jabref/gui/specialfields/SpecialFieldMenuAction.java deleted file mode 100644 index f845fc0d971..00000000000 --- a/src/main/java/org/jabref/gui/specialfields/SpecialFieldMenuAction.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.jabref.gui.specialfields; - -import java.awt.event.ActionEvent; - -import javax.swing.AbstractAction; - -import org.jabref.gui.JabRefFrame; - -public class SpecialFieldMenuAction extends AbstractAction { - - private final JabRefFrame frame; - private final String actionName; - - - public SpecialFieldMenuAction(SpecialFieldValueViewModel val, JabRefFrame frame) { - super(val.getMenuString(), val.getSpecialFieldValueIcon()); - this.frame = frame; - this.actionName = val.getActionName(); - } - - @Override - public void actionPerformed(ActionEvent evt) { - if (frame.getCurrentBasePanel() != null) { - frame.getCurrentBasePanel().runCommand(actionName); - } - } -} diff --git a/src/main/java/org/jabref/gui/specialfields/SpecialFieldValueViewModel.java b/src/main/java/org/jabref/gui/specialfields/SpecialFieldValueViewModel.java index 54b6166d949..0273b9f59a4 100644 --- a/src/main/java/org/jabref/gui/specialfields/SpecialFieldValueViewModel.java +++ b/src/main/java/org/jabref/gui/specialfields/SpecialFieldValueViewModel.java @@ -5,8 +5,9 @@ import javax.swing.Icon; import javax.swing.JLabel; -import org.jabref.gui.IconTheme; import org.jabref.gui.JabRefIcon; +import org.jabref.gui.actions.Actions; +import org.jabref.gui.actions.ActionsFX; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.specialfields.SpecialFieldValue; @@ -30,42 +31,7 @@ public Icon getSpecialFieldValueIcon() { } public JabRefIcon getIcon() { - switch (value) { - case PRINTED: - return IconTheme.JabRefIcons.PRINTED; - case CLEAR_PRIORITY: - return null; - case PRIORITY_HIGH: - return IconTheme.JabRefIcons.PRIORITY_HIGH; - case PRIORITY_MEDIUM: - return IconTheme.JabRefIcons.PRIORITY_MEDIUM; - case PRIORITY_LOW: - return IconTheme.JabRefIcons.PRIORITY_LOW; - case QUALITY_ASSURED: - return IconTheme.JabRefIcons.QUALITY_ASSURED; - case CLEAR_RANK: - return null; - case RANK_1: - return IconTheme.JabRefIcons.RANK1; - case RANK_2: - return IconTheme.JabRefIcons.RANK2; - case RANK_3: - return IconTheme.JabRefIcons.RANK3; - case RANK_4: - return IconTheme.JabRefIcons.RANK4; - case RANK_5: - return IconTheme.JabRefIcons.RANK5; - case CLEAR_READ_STATUS: - return null; - case READ: - return IconTheme.JabRefIcons.READ_STATUS_READ; - case SKIMMED: - return IconTheme.JabRefIcons.READ_STATUS_SKIMMED; - case RELEVANT: - return IconTheme.JabRefIcons.RELEVANCE; - default: - throw new IllegalArgumentException("There is no icon mapping for special field value " + value); - } + return getAction().getIcon().orElse(null); } public JLabel createSpecialFieldValueLabel() { @@ -75,38 +41,42 @@ public JLabel createSpecialFieldValueLabel() { } public String getMenuString() { + return getAction().getText(); + } + + public String getToolTipText() { switch (value) { case PRINTED: return Localization.lang("Toggle print status"); case CLEAR_PRIORITY: - return Localization.lang("Clear priority"); + return Localization.lang("No priority information"); case PRIORITY_HIGH: - return Localization.lang("Set priority to high"); + return Localization.lang("Priority high"); case PRIORITY_MEDIUM: - return Localization.lang("Set priority to medium"); + return Localization.lang("Priority medium"); case PRIORITY_LOW: - return Localization.lang("Set priority to low"); + return Localization.lang("Priority low"); case QUALITY_ASSURED: return Localization.lang("Toggle quality assured"); case CLEAR_RANK: - return Localization.lang("Clear rank"); + return Localization.lang("No rank information"); case RANK_1: - return ""; + return Localization.lang("One star"); case RANK_2: - return ""; + return Localization.lang("Two stars"); case RANK_3: - return ""; + return Localization.lang("Three stars"); case RANK_4: - return ""; + return Localization.lang("Four stars"); case RANK_5: - return ""; + return Localization.lang("Five stars"); case CLEAR_READ_STATUS: - return Localization.lang("Clear read status"); + return Localization.lang("No read status information"); case READ: - return Localization.lang("Set read status to read"); + return Localization.lang("Read status read"); case SKIMMED: - return Localization.lang("Set read status to skimmed"); + return Localization.lang("Read status skimmed"); case RELEVANT: return Localization.lang("Toggle relevance"); default: @@ -114,83 +84,81 @@ public String getMenuString() { } } - public String getToolTipText() { - + public Actions getCommand() { switch (value) { case PRINTED: - return Localization.lang("Toggle print status"); + return Actions.togglePrinted; case CLEAR_PRIORITY: - return Localization.lang("No priority information"); + return Actions.clearPriority; case PRIORITY_HIGH: - return Localization.lang("Priority high"); + return Actions.setPriority1; case PRIORITY_MEDIUM: - return Localization.lang("Priority medium"); + return Actions.setPriority2; case PRIORITY_LOW: - return Localization.lang("Priority low"); + return Actions.setPriority3; case QUALITY_ASSURED: - return Localization.lang("Toggle quality assured"); + return Actions.toggleQualityAssured; case CLEAR_RANK: - return Localization.lang("No rank information"); + return Actions.clearRank; case RANK_1: - return Localization.lang("One star"); + return Actions.setRank1; case RANK_2: - return Localization.lang("Two stars"); + return Actions.setRank2; case RANK_3: - return Localization.lang("Three stars"); + return Actions.setRank3; case RANK_4: - return Localization.lang("Four stars"); + return Actions.setRank4; case RANK_5: - return Localization.lang("Five stars"); + return Actions.setRank5; case CLEAR_READ_STATUS: - return Localization.lang("No read status information"); + return Actions.clearReadStatus; case READ: - return Localization.lang("Read status read"); + return Actions.setReadStatusToRead; case SKIMMED: - return Localization.lang("Read status skimmed"); + return Actions.setReadStatusToSkimmed; case RELEVANT: - return Localization.lang("Toggle relevance"); + return Actions.toggleRelevance; default: - throw new IllegalArgumentException("There is no tooltip localization for special field value " + value); + throw new IllegalArgumentException("There is no action name for special field value " + value); } } - public String getActionName() { - + public ActionsFX getAction() { switch (value) { case PRINTED: - return "togglePrinted"; + return ActionsFX.TOGGLE_PRINTED; case CLEAR_PRIORITY: - return "clearPriority"; + return ActionsFX.CLEAR_PRIORITY; case PRIORITY_HIGH: - return "setPriority1"; + return ActionsFX.PRIORITY_HIGH; case PRIORITY_MEDIUM: - return "setPriority2"; + return ActionsFX.PRIORITY_MEDIUM; case PRIORITY_LOW: - return "setPriority3"; + return ActionsFX.PRIORITY_LOW; case QUALITY_ASSURED: - return "toggleQualityAssured"; + return ActionsFX.QUALITY_ASSURED; case CLEAR_RANK: - return "clearRank"; + return ActionsFX.CLEAR_RANK; case RANK_1: - return "setRank1"; + return ActionsFX.RANK_1; case RANK_2: - return "setRank2"; + return ActionsFX.RANK_2; case RANK_3: - return "setRank3"; + return ActionsFX.RANK_3; case RANK_4: - return "setRank4"; + return ActionsFX.RANK_4; case RANK_5: - return "setRank5"; + return ActionsFX.RANK_5; case CLEAR_READ_STATUS: - return "clearReadStatus"; + return ActionsFX.CLEAR_READ_STATUS; case READ: - return "setReadStatusToRead"; + return ActionsFX.READ; case SKIMMED: - return "setReadStatusToSkimmed"; + return ActionsFX.SKIMMED; case RELEVANT: - return "toggleRelevance"; + return ActionsFX.RELEVANT; default: - throw new IllegalArgumentException("There is no action name for special field value " + value); + throw new IllegalArgumentException("There is no tooltip localization for special field value " + value); } } } diff --git a/src/main/java/org/jabref/gui/specialfields/SpecialFieldViewModel.java b/src/main/java/org/jabref/gui/specialfields/SpecialFieldViewModel.java index a372ba71417..2df8d05be52 100644 --- a/src/main/java/org/jabref/gui/specialfields/SpecialFieldViewModel.java +++ b/src/main/java/org/jabref/gui/specialfields/SpecialFieldViewModel.java @@ -7,7 +7,7 @@ import org.jabref.gui.IconTheme; import org.jabref.gui.JabRefFrame; import org.jabref.gui.JabRefIcon; -import org.jabref.logic.l10n.Localization; +import org.jabref.gui.actions.ActionsFX; import org.jabref.model.entry.specialfields.SpecialField; import org.jabref.model.entry.specialfields.SpecialFieldValue; @@ -29,60 +29,33 @@ public SpecialFieldAction getSpecialFieldAction(SpecialFieldValue value, JabRefF } public Icon getRepresentingIcon() { - switch (field) { - case PRINTED: - return IconTheme.JabRefIcons.PRINTED.getSmallIcon(); - case PRIORITY: - return IconTheme.JabRefIcons.PRIORITY.getSmallIcon(); - case QUALITY: - return IconTheme.JabRefIcons.QUALITY.getSmallIcon(); - case RANKING: - return IconTheme.JabRefIcons.RANKING.getIcon(); - case READ_STATUS: - return IconTheme.JabRefIcons.READ_STATUS.getSmallIcon(); - case RELEVANCE: - return IconTheme.JabRefIcons.RELEVANCE.getSmallIcon(); - default: - throw new IllegalArgumentException("There is no icon mapping for special field " + field); - } + return getAction().getIcon().map(IconTheme.JabRefIcons::getSmallIcon).orElse(null); } public JabRefIcon getIcon() { - switch (field) { - case PRINTED: - return IconTheme.JabRefIcons.PRINTED; - case PRIORITY: - return IconTheme.JabRefIcons.PRIORITY; - case QUALITY: - return IconTheme.JabRefIcons.QUALITY; - case RANKING: - return IconTheme.JabRefIcons.RANKING; - case READ_STATUS: - return IconTheme.JabRefIcons.READ_STATUS; - case RELEVANCE: - return IconTheme.JabRefIcons.RELEVANCE; - default: - throw new IllegalArgumentException("There is no icon mapping for special field " + field); - } + return getAction().getIcon().orElse(null); } public String getLocalization() { + return getAction().getText(); + } + + public ActionsFX getAction() { switch (field) { case PRINTED: - return Localization.lang("Printed"); + return ActionsFX.PRINTED; case PRIORITY: - return Localization.lang("Priority"); + return ActionsFX.PRIORITY; case QUALITY: - return Localization.lang("Quality"); + return ActionsFX.QUALITY; case RANKING: - return Localization.lang("Rank"); + return ActionsFX.RANKING; case READ_STATUS: - return Localization.lang("Read status"); + return ActionsFX.READ_STATUS; case RELEVANCE: - return Localization.lang("Relevance"); + return ActionsFX.RELEVANCE; default: throw new IllegalArgumentException("There is no icon mapping for special field " + field); } } - } diff --git a/src/main/java/org/jabref/gui/util/BindingsHelper.java b/src/main/java/org/jabref/gui/util/BindingsHelper.java index 022205e9314..3b344e30469 100644 --- a/src/main/java/org/jabref/gui/util/BindingsHelper.java +++ b/src/main/java/org/jabref/gui/util/BindingsHelper.java @@ -165,6 +165,15 @@ public static void bindContentBidirectional(ObservableMap proper updateB); } + public static ObservableValue constantOf(boolean value) { + return new BooleanBinding() { + @Override + protected boolean computeValue() { + return value; + } + }; + } + private static class BidirectionalBinding { private final ObservableValue propertyA; From fbc57073f6e2c5ed8387ef880121269fde27472a Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 29 Jan 2018 13:07:52 +0100 Subject: [PATCH 24/24] Reimplement special field and file columns (#3647) * Show special field icons properly in main table * Make icons functional * Fix NPE * Handle file icon click --- src/main/java/org/jabref/gui/BasePanel.java | 17 +-- src/main/java/org/jabref/gui/IconTheme.java | 5 +- .../gui/InternalMaterialDesignIcon.java | 40 +++--- src/main/java/org/jabref/gui/JabRefFrame.java | 6 + .../org/jabref/gui/desktop/JabRefDesktop.java | 20 +-- .../fieldeditors/AbstractEditorViewModel.java | 2 +- .../gui/fieldeditors/LinkedFileViewModel.java | 26 +++- .../gui/fieldeditors/LinkedFilesEditor.java | 2 +- .../org/jabref/gui/maintable/CellFactory.java | 16 ++- .../org/jabref/gui/maintable/MainTable.css | 28 ++++ .../org/jabref/gui/maintable/MainTable.java | 6 +- .../gui/maintable/MainTableColumnFactory.java | 122 +++++++++++++++--- .../jabref/gui/maintable/RightClickMenu.java | 2 +- .../gui/specialfields/SpecialFieldAction.java | 2 +- .../specialfields/SpecialFieldDropDown.java | 2 +- .../SpecialFieldValueViewModel.java | 16 +-- .../specialfields/SpecialFieldViewModel.java | 42 +++++- .../java/org/jabref/gui/util/ColorUtil.java | 28 ++++ .../util/OptionalValueTableCellFactory.java | 41 ++++++ .../gui/util/ValueTableCellFactory.java | 87 ++++++++++--- .../specialfields/SpecialFieldsUtils.java | 6 +- .../specialfields/SpecialFieldValue.java | 33 +++++ .../jabref/preferences/JabRefPreferences.java | 8 +- src/test/resources/testbib/complex.bib | 102 +++++++-------- 24 files changed, 492 insertions(+), 167 deletions(-) create mode 100644 src/main/java/org/jabref/gui/util/ColorUtil.java create mode 100644 src/main/java/org/jabref/gui/util/OptionalValueTableCellFactory.java diff --git a/src/main/java/org/jabref/gui/BasePanel.java b/src/main/java/org/jabref/gui/BasePanel.java index c62a8ed2c41..a67c65147ac 100644 --- a/src/main/java/org/jabref/gui/BasePanel.java +++ b/src/main/java/org/jabref/gui/BasePanel.java @@ -157,7 +157,7 @@ public class BasePanel extends StackPane implements ClipboardOwner { // The undo manager. private final UndoAction undoAction = new UndoAction(); private final RedoAction redoAction = new RedoAction(); - private final CountingUndoManager undoManager = new CountingUndoManager(); + private final CountingUndoManager undoManager; private final List previousEntries = new ArrayList<>(); private final List nextEntries = new ArrayList<>(); // Keeps track of the string dialog if it is open. @@ -202,6 +202,7 @@ public BasePanel(JabRefFrame frame, BasePanelPreferences preferences, BibDatabas this.frame = Objects.requireNonNull(frame); this.bibDatabaseContext = Objects.requireNonNull(bibDatabaseContext); this.externalFileTypes = Objects.requireNonNull(externalFileTypes); + this.undoManager = frame.getUndoManager(); bibDatabaseContext.getDatabase().registerListener(this); bibDatabaseContext.getMetaData().registerListener(this); @@ -638,26 +639,26 @@ public void update() { // Note that we can't put the number of entries that have been reverted into the undoText as the concrete number cannot be injected actions.put(new SpecialFieldValueViewModel(SpecialField.RELEVANCE.getValues().get(0)).getCommand(), - new SpecialFieldViewModel(SpecialField.RELEVANCE).getSpecialFieldAction( + new SpecialFieldViewModel(SpecialField.RELEVANCE, undoManager).getSpecialFieldAction( SpecialField.RELEVANCE.getValues().get(0), frame)); actions.put(new SpecialFieldValueViewModel(SpecialField.QUALITY.getValues().get(0)).getCommand(), - new SpecialFieldViewModel(SpecialField.QUALITY) + new SpecialFieldViewModel(SpecialField.QUALITY, undoManager) .getSpecialFieldAction(SpecialField.QUALITY.getValues().get(0), frame)); actions.put(new SpecialFieldValueViewModel(SpecialField.PRINTED.getValues().get(0)).getCommand(), - new SpecialFieldViewModel(SpecialField.PRINTED).getSpecialFieldAction( + new SpecialFieldViewModel(SpecialField.PRINTED, undoManager).getSpecialFieldAction( SpecialField.PRINTED.getValues().get(0), frame)); for (SpecialFieldValue prio : SpecialField.PRIORITY.getValues()) { actions.put(new SpecialFieldValueViewModel(prio).getCommand(), - new SpecialFieldViewModel(SpecialField.PRIORITY).getSpecialFieldAction(prio, this.frame)); + new SpecialFieldViewModel(SpecialField.PRIORITY, undoManager).getSpecialFieldAction(prio, this.frame)); } for (SpecialFieldValue rank : SpecialField.RANKING.getValues()) { actions.put(new SpecialFieldValueViewModel(rank).getCommand(), - new SpecialFieldViewModel(SpecialField.RANKING).getSpecialFieldAction(rank, this.frame)); + new SpecialFieldViewModel(SpecialField.RANKING, undoManager).getSpecialFieldAction(rank, this.frame)); } for (SpecialFieldValue status : SpecialField.READ_STATUS.getValues()) { actions.put(new SpecialFieldValueViewModel(status).getCommand(), - new SpecialFieldViewModel(SpecialField.READ_STATUS).getSpecialFieldAction(status, this.frame)); + new SpecialFieldViewModel(SpecialField.READ_STATUS, undoManager).getSpecialFieldAction(status, this.frame)); } actions.put(Actions.TOGGLE_PREVIEW, (BaseAction) () -> { @@ -1211,7 +1212,7 @@ public void updateTableFont() { private void createMainTable() { bibDatabaseContext.getDatabase().registerListener(SpecialFieldDatabaseChangeListener.getInstance()); - mainTable = new MainTable(tableModel, frame, this, bibDatabaseContext.getDatabase(), preferences.getTablePreferences(), externalFileTypes, Globals.getKeyPrefs()); + mainTable = new MainTable(tableModel, frame, this, bibDatabaseContext, preferences.getTablePreferences(), externalFileTypes, Globals.getKeyPrefs()); mainTable.updateFont(); diff --git a/src/main/java/org/jabref/gui/IconTheme.java b/src/main/java/org/jabref/gui/IconTheme.java index da228780bd5..49de563c05f 100644 --- a/src/main/java/org/jabref/gui/IconTheme.java +++ b/src/main/java/org/jabref/gui/IconTheme.java @@ -27,6 +27,7 @@ import javafx.scene.image.Image; import javafx.scene.image.ImageView; +import org.jabref.gui.util.ColorUtil; import org.jabref.logic.groups.DefaultGroupsFactory; import org.jabref.preferences.JabRefPreferences; @@ -71,7 +72,7 @@ private static InputStream getMaterialDesignIconsStream() { } 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); + return ColorUtil.toFX(DEFAULT_COLOR); } /** @@ -277,7 +278,7 @@ public enum JabRefIcons implements JabRefIcon { private final JabRefIcon icon; JabRefIcons(MaterialDesignIcon... icons) { - this(IconTheme.DEFAULT_COLOR, icons); + icon = new InternalMaterialDesignIcon(icons); } JabRefIcons(Color color, MaterialDesignIcon... icons) { diff --git a/src/main/java/org/jabref/gui/InternalMaterialDesignIcon.java b/src/main/java/org/jabref/gui/InternalMaterialDesignIcon.java index d8d9f44e338..e568773f91f 100644 --- a/src/main/java/org/jabref/gui/InternalMaterialDesignIcon.java +++ b/src/main/java/org/jabref/gui/InternalMaterialDesignIcon.java @@ -2,13 +2,16 @@ import java.util.Arrays; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; import javax.swing.Icon; import javafx.scene.Node; import javafx.scene.paint.Color; +import javafx.scene.text.Text; +import org.jabref.gui.util.ColorUtil; import org.jabref.preferences.JabRefPreferences; import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon; @@ -16,11 +19,11 @@ public class InternalMaterialDesignIcon implements JabRefIcon { private final List icons; - private final Color color; + private Optional color; private final String unicode; public InternalMaterialDesignIcon(java.awt.Color color, MaterialDesignIcon... icons) { - this(toFX(color), Arrays.asList(icons)); + this(ColorUtil.toFX(color), Arrays.asList(icons)); } public InternalMaterialDesignIcon(Color color, MaterialDesignIcon... icons) { @@ -28,45 +31,40 @@ public InternalMaterialDesignIcon(Color color, MaterialDesignIcon... icons) { } InternalMaterialDesignIcon(Color color, List icons) { - this.icons = icons; - this.color = color; - this.unicode = icons.stream().map(MaterialDesignIcon::unicode).collect(Collectors.joining()); + this(icons); + this.color = Optional.of(color); } - public static java.awt.Color toAWT(Color color) { - return new java.awt.Color((float) color.getRed(), - (float) color.getGreen(), - (float) color.getBlue(), - (float) color.getOpacity()); + public InternalMaterialDesignIcon(MaterialDesignIcon... icons) { + this(Arrays.asList(icons)); } - public static Color toFX(java.awt.Color awtColor) { - int r = awtColor.getRed(); - int g = awtColor.getGreen(); - int b = awtColor.getBlue(); - int a = awtColor.getAlpha(); - double opacity = a / 255.0; - return javafx.scene.paint.Color.rgb(r, g, b, opacity); + public InternalMaterialDesignIcon(List icons) { + this.icons = icons; + this.unicode = icons.stream().map(MaterialDesignIcon::unicode).collect(Collectors.joining()); + this.color = Optional.empty(); } @Override public Icon getIcon() { - return new IconTheme.FontBasedIcon(this.unicode, toAWT(this.color)); + return new IconTheme.FontBasedIcon(this.unicode, ColorUtil.toAWT(this.color.orElse(IconTheme.getDefaultColor()))); } @Override public Icon getSmallIcon() { - return new IconTheme.FontBasedIcon(this.unicode, toAWT(this.color), JabRefPreferences.getInstance().getInt(JabRefPreferences.ICON_SIZE_SMALL)); + return new IconTheme.FontBasedIcon(this.unicode, ColorUtil.toAWT(this.color.orElse(IconTheme.getDefaultColor())), JabRefPreferences.getInstance().getInt(JabRefPreferences.ICON_SIZE_SMALL)); } @Override public Node getGraphicNode() { - return MaterialDesignIconFactory.get().createIcon(this.icons.get(0)); + Text icon = MaterialDesignIconFactory.get().createIcon(icons.get(0)); + color.ifPresent(color -> icon.setStyle(icon.getStyle() + String.format("-fx-fill: %s;", ColorUtil.toRGBCode(color)))); + return icon; } @Override public JabRefIcon disabled() { - return new InternalMaterialDesignIcon(toFX(IconTheme.DEFAULT_DISABLED_COLOR), icons); + return new InternalMaterialDesignIcon(ColorUtil.toFX(IconTheme.DEFAULT_DISABLED_COLOR), icons); } public String getCode() { diff --git a/src/main/java/org/jabref/gui/JabRefFrame.java b/src/main/java/org/jabref/gui/JabRefFrame.java index 6b1b2f37cb5..b138bf0a0b5 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -120,6 +120,7 @@ import org.jabref.gui.search.GlobalSearchBar; import org.jabref.gui.specialfields.SpecialFieldDropDown; import org.jabref.gui.specialfields.SpecialFieldValueViewModel; +import org.jabref.gui.undo.CountingUndoManager; import org.jabref.gui.util.DefaultTaskExecutor; import org.jabref.gui.util.WindowLocation; import org.jabref.gui.worker.MarkEntriesAction; @@ -467,6 +468,7 @@ public void actionPerformed(ActionEvent e) { private OpenOfficePanel openOfficePanel; private GroupSidePane groupSidePane; private JMenu newSpec; + private final CountingUndoManager undoManager = new CountingUndoManager(); public JabRefFrame() { init(); @@ -1972,6 +1974,10 @@ public GlobalSearchBar getGlobalSearchBar() { return globalSearchBar; } + public CountingUndoManager getUndoManager() { + return undoManager; + } + private static class MyGlassPane extends JPanel { public MyGlassPane() { addKeyListener(new KeyAdapter() { diff --git a/src/main/java/org/jabref/gui/desktop/JabRefDesktop.java b/src/main/java/org/jabref/gui/desktop/JabRefDesktop.java index a362446b26f..d5ad147d0a6 100644 --- a/src/main/java/org/jabref/gui/desktop/JabRefDesktop.java +++ b/src/main/java/org/jabref/gui/desktop/JabRefDesktop.java @@ -132,26 +132,16 @@ private static void openDoi(String doi) throws IOException { */ public static boolean openExternalFileAnyFormat(final BibDatabaseContext databaseContext, String link, final Optional type) throws IOException { - boolean httpLink = false; if (REMOTE_LINK_PATTERN.matcher(link.toLowerCase(Locale.ROOT)).matches()) { - httpLink = true; - } - - // For other platforms we'll try to find the file type: - Path file = null; - if (!httpLink) { - Optional tmp = FileHelper.expandFilename(databaseContext, link, - Globals.prefs.getFileDirectoryPreferences()); - if (tmp.isPresent()) { - file = tmp.get(); - } + openExternalFilePlatformIndependent(type, link); + return true; } - // Check if we have arrived at a file type, and either an http link or an existing file: - if (httpLink || ((file != null) && Files.exists(file) && (type.isPresent()))) { + Optional file = FileHelper.expandFilename(databaseContext, link, Globals.prefs.getFileDirectoryPreferences()); + if (file.isPresent() && Files.exists(file.get()) && (type.isPresent())) { // Open the file: - String filePath = httpLink ? link : file.toString(); + String filePath = file.get().toString(); openExternalFilePlatformIndependent(type, filePath); return true; } else { diff --git a/src/main/java/org/jabref/gui/fieldeditors/AbstractEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/AbstractEditorViewModel.java index f249aa1c37a..e88226ac0ba 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/AbstractEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/AbstractEditorViewModel.java @@ -64,7 +64,7 @@ public void bindToEntry(BibEntry entry) { if (newValue != null) { String oldValue = entry.getField(fieldName).orElse(null); entry.setField(fieldName, newValue); - UndoManager undoManager = JabRefGUI.getMainFrame().getCurrentBasePanel().getUndoManager(); + UndoManager undoManager = JabRefGUI.getMainFrame().getUndoManager(); undoManager.addEdit(new UndoableFieldChange(entry, fieldName, oldValue, newValue)); } }); diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java index 6612a752c20..ac995be2994 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java @@ -24,6 +24,8 @@ import org.jabref.gui.AbstractViewModel; import org.jabref.gui.DialogService; import org.jabref.gui.FXDialogService; +import org.jabref.gui.IconTheme; +import org.jabref.gui.JabRefIcon; import org.jabref.gui.desktop.JabRefDesktop; import org.jabref.gui.externalfiletype.ExternalFileType; import org.jabref.gui.externalfiletype.ExternalFileTypes; @@ -38,9 +40,8 @@ import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.LinkedFile; +import org.jabref.model.strings.StringUtil; -import de.jensd.fx.glyphs.GlyphIcons; -import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -100,6 +101,14 @@ public String getDescription() { return linkedFile.getDescription(); } + public String getDescriptionAndLink() { + if (StringUtil.isBlank(linkedFile.getDescription())) { + return linkedFile.getLink(); + } else { + return linkedFile.getDescription() + " (" + linkedFile.getLink() + ")"; + } + } + public Optional findIn(List directories) { return linkedFile.findIn(directories); } @@ -108,8 +117,8 @@ public Optional findIn(List directories) { * TODO: Be a bit smarter and try to infer correct icon, for example using {@link * org.jabref.gui.externalfiletype.ExternalFileTypes#getExternalFileTypeByName(String)} */ - public GlyphIcons getTypeIcon() { - return MaterialDesignIcon.FILE_PDF; + public JabRefIcon getTypeIcon() { + return IconTheme.JabRefIcons.PDF_FILE; } public void markAsAutomaticallyFound() { @@ -131,9 +140,14 @@ public Observable[] getObservables() { public void open() { try { Optional type = ExternalFileTypes.getInstance().fromLinkedFile(linkedFile, true); - JabRefDesktop.openExternalFileAnyFormat(databaseContext, linkedFile.getLink(), type); + boolean successful = JabRefDesktop.openExternalFileAnyFormat(databaseContext, linkedFile.getLink(), type); + if (!successful) { + dialogService.showErrorDialogAndWait( + Localization.lang("File not found"), + Localization.lang("Could not find file '%0'.", linkedFile.getLink())); + } } catch (IOException e) { - LOGGER.warn("Cannot open selected file.", e); + dialogService.showErrorDialogAndWait(Localization.lang("Error opening file '%0'.", getLink()), e); } } diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditor.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditor.java index 306bb3b148c..b01af694d40 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditor.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditor.java @@ -148,7 +148,7 @@ private void handleOnDragDropped(LinkedFileViewModel originalItem, DragEvent eve } private static Node createFileDisplay(LinkedFileViewModel linkedFile) { - Text icon = MaterialDesignIconFactory.get().createIcon(linkedFile.getTypeIcon()); + Node icon = linkedFile.getTypeIcon().getGraphicNode(); icon.setOnMouseClicked(event -> linkedFile.open()); Text link = new Text(linkedFile.getLink()); Text desc = new Text(linkedFile.getDescription()); diff --git a/src/main/java/org/jabref/gui/maintable/CellFactory.java b/src/main/java/org/jabref/gui/maintable/CellFactory.java index 72b118cfcb2..f3ab65dbf5d 100644 --- a/src/main/java/org/jabref/gui/maintable/CellFactory.java +++ b/src/main/java/org/jabref/gui/maintable/CellFactory.java @@ -3,6 +3,8 @@ import java.util.HashMap; import java.util.Map; +import javax.swing.undo.UndoManager; + import javafx.scene.Node; import org.jabref.gui.IconTheme; @@ -16,7 +18,7 @@ public class CellFactory { private final Map TABLE_ICONS = new HashMap<>(); - public CellFactory(ExternalFileTypes externalFileTypes) { + public CellFactory(ExternalFileTypes externalFileTypes, UndoManager undoManager) { Node label; label = IconTheme.JabRefIcons.PDF_FILE.getGraphicNode(); //label.setToo(Localization.lang("Open") + " PDF"); @@ -56,36 +58,36 @@ public CellFactory(ExternalFileTypes externalFileTypes) { TABLE_ICONS.put(fileType.getName(), label); } - SpecialFieldViewModel relevanceViewModel = new SpecialFieldViewModel(SpecialField.RELEVANCE); + SpecialFieldViewModel relevanceViewModel = new SpecialFieldViewModel(SpecialField.RELEVANCE, undoManager); label = relevanceViewModel.getIcon().getGraphicNode(); //label.setToolTipText(relevanceViewModel.getLocalization()); TABLE_ICONS.put(SpecialField.RELEVANCE.getFieldName(), label); - SpecialFieldViewModel qualityViewModel = new SpecialFieldViewModel(SpecialField.QUALITY); + SpecialFieldViewModel qualityViewModel = new SpecialFieldViewModel(SpecialField.QUALITY, undoManager); label = qualityViewModel.getIcon().getGraphicNode(); //label.setToolTipText(qualityViewModel.getLocalization()); TABLE_ICONS.put(SpecialField.QUALITY.getFieldName(), label); // Ranking item in the menu uses one star - SpecialFieldViewModel rankViewModel = new SpecialFieldViewModel(SpecialField.RANKING); + SpecialFieldViewModel rankViewModel = new SpecialFieldViewModel(SpecialField.RANKING, undoManager); label = rankViewModel.getIcon().getGraphicNode(); //label.setToolTipText(rankViewModel.getLocalization()); TABLE_ICONS.put(SpecialField.RANKING.getFieldName(), label); // Priority icon used for the menu - SpecialFieldViewModel priorityViewModel = new SpecialFieldViewModel(SpecialField.PRIORITY); + SpecialFieldViewModel priorityViewModel = new SpecialFieldViewModel(SpecialField.PRIORITY, undoManager); label = priorityViewModel.getIcon().getGraphicNode(); //label.setToolTipText(priorityViewModel.getLocalization()); TABLE_ICONS.put(SpecialField.PRIORITY.getFieldName(), label); // Read icon used for menu - SpecialFieldViewModel readViewModel = new SpecialFieldViewModel(SpecialField.READ_STATUS); + SpecialFieldViewModel readViewModel = new SpecialFieldViewModel(SpecialField.READ_STATUS, undoManager); label = readViewModel.getIcon().getGraphicNode(); //label.setToolTipText(readViewModel.getLocalization()); TABLE_ICONS.put(SpecialField.READ_STATUS.getFieldName(), label); // Print icon used for menu - SpecialFieldViewModel printedViewModel = new SpecialFieldViewModel(SpecialField.PRINTED); + SpecialFieldViewModel printedViewModel = new SpecialFieldViewModel(SpecialField.PRINTED, undoManager); label = printedViewModel.getIcon().getGraphicNode(); //label.setToolTipText(printedViewModel.getLocalization()); TABLE_ICONS.put(SpecialField.PRINTED.getFieldName(), label); diff --git a/src/main/java/org/jabref/gui/maintable/MainTable.css b/src/main/java/org/jabref/gui/maintable/MainTable.css index 1bb042ca76d..00b26481afe 100644 --- a/src/main/java/org/jabref/gui/maintable/MainTable.css +++ b/src/main/java/org/jabref/gui/maintable/MainTable.css @@ -48,3 +48,31 @@ -fx-padding: 0; -fx-alignment: baseline-center; } + +.empty-special-field { + visibility: hidden; +} + +.table-row-cell:hover .empty-special-field { + visibility: visible; + -fx-fill: -fx-unimportant; +} + +.rating > .container { + -fx-spacing: 2; +} + +.rating > .container > .button { + -fx-pref-width: 10; + -fx-pref-height: 10; + -fx-background-size: cover; + -fx-padding: 0; +} + +.rating > .container > .button.strong { + +} + +.rating > .container > .button:hover { + -fx-effect: dropshadow(three-pass-box, rgba(0, 0, 0, 0.6), 8, 0.0, 0, 0); +} diff --git a/src/main/java/org/jabref/gui/maintable/MainTable.java b/src/main/java/org/jabref/gui/maintable/MainTable.java index 63ef218c6ca..4731efc8eb3 100644 --- a/src/main/java/org/jabref/gui/maintable/MainTable.java +++ b/src/main/java/org/jabref/gui/maintable/MainTable.java @@ -24,7 +24,7 @@ import org.jabref.gui.renderer.IncompleteRenderer; import org.jabref.gui.util.ViewModelTableRowFactory; import org.jabref.logic.TypedBibEntry; -import org.jabref.model.database.BibDatabase; +import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.preferences.JabRefPreferences; @@ -73,11 +73,11 @@ private enum CellRendererMode { } public MainTable(MainTableDataModel model, JabRefFrame frame, - BasePanel panel, BibDatabase database, MainTablePreferences preferences, ExternalFileTypes externalFileTypes, KeyBindingRepository keyBindingRepository) { + BasePanel panel, BibDatabaseContext database, MainTablePreferences preferences, ExternalFileTypes externalFileTypes, KeyBindingRepository keyBindingRepository) { super(); this.model = model; - this.getColumns().addAll(new MainTableColumnFactory(database, preferences.getColumnPreferences(), externalFileTypes).createColumns()); + this.getColumns().addAll(new MainTableColumnFactory(database, preferences.getColumnPreferences(), externalFileTypes, panel.getUndoManager()).createColumns()); this.setRowFactory(new ViewModelTableRowFactory() .withOnMouseClickedEvent((entry, event) -> { if (event.getClickCount() == 2) { diff --git a/src/main/java/org/jabref/gui/maintable/MainTableColumnFactory.java b/src/main/java/org/jabref/gui/maintable/MainTableColumnFactory.java index aa5c0a10b66..435e9e7fc89 100644 --- a/src/main/java/org/jabref/gui/maintable/MainTableColumnFactory.java +++ b/src/main/java/org/jabref/gui/maintable/MainTableColumnFactory.java @@ -7,22 +7,33 @@ import java.util.Optional; import java.util.stream.Collectors; +import javax.swing.undo.UndoManager; + import javafx.scene.Node; +import javafx.scene.control.ContextMenu; +import javafx.scene.control.MenuItem; import javafx.scene.control.TableColumn; +import javafx.scene.input.MouseButton; +import org.jabref.Globals; import org.jabref.gui.GUIGlobals; import org.jabref.gui.IconTheme; import org.jabref.gui.JabRefIcon; import org.jabref.gui.externalfiletype.ExternalFileType; import org.jabref.gui.externalfiletype.ExternalFileTypes; +import org.jabref.gui.fieldeditors.LinkedFileViewModel; import org.jabref.gui.specialfields.SpecialFieldValueViewModel; import org.jabref.gui.specialfields.SpecialFieldViewModel; +import org.jabref.gui.util.OptionalValueTableCellFactory; import org.jabref.gui.util.ValueTableCellFactory; -import org.jabref.model.database.BibDatabase; +import org.jabref.model.database.BibDatabaseContext; +import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.FieldName; import org.jabref.model.entry.LinkedFile; import org.jabref.model.entry.specialfields.SpecialField; +import org.jabref.model.entry.specialfields.SpecialFieldValue; +import org.controlsfx.control.Rating; import org.fxmisc.easybind.EasyBind; class MainTableColumnFactory { @@ -31,14 +42,16 @@ class MainTableColumnFactory { private final ColumnPreferences preferences; private final ExternalFileTypes externalFileTypes; - private final BibDatabase database; + private final BibDatabaseContext database; private final CellFactory cellFactory; + private final UndoManager undoManager; - public MainTableColumnFactory(BibDatabase database, ColumnPreferences preferences, ExternalFileTypes externalFileTypes) { + public MainTableColumnFactory(BibDatabaseContext database, ColumnPreferences preferences, ExternalFileTypes externalFileTypes, UndoManager undoManager) { this.database = Objects.requireNonNull(database); this.preferences = Objects.requireNonNull(preferences); this.externalFileTypes = Objects.requireNonNull(externalFileTypes); - this.cellFactory = new CellFactory(externalFileTypes); + this.cellFactory = new CellFactory(externalFileTypes, undoManager); + this.undoManager = undoManager; } public List> createColumns() { @@ -85,7 +98,7 @@ public MainTableColumnFactory(BibDatabase database, ColumnPreferences preference // Stored column name will be used as header // There might be more than one field to display, e.g., "author/editor" or "date/year" - so split String[] fields = columnName.split(FieldName.FIELD_SEPARATOR); - StringTableColumn column = new StringTableColumn(columnName, Arrays.asList(fields), database); + StringTableColumn column = new StringTableColumn(columnName, Arrays.asList(fields), database.getDatabase()); column.setPrefWidth(preferences.getPrefColumnWidth(columnName)); columns.add(column); } @@ -94,21 +107,70 @@ public MainTableColumnFactory(BibDatabase database, ColumnPreferences preference private TableColumn> createSpecialFieldColumn(SpecialField specialField) { TableColumn> column = new TableColumn<>(); - column.setGraphic(new SpecialFieldViewModel(specialField).getIcon().getGraphicNode()); + SpecialFieldViewModel specialFieldViewModel = new SpecialFieldViewModel(specialField, undoManager); + column.setGraphic(specialFieldViewModel.getIcon().getGraphicNode()); column.getStyleClass().add(STYLE_ICON); if (specialField == SpecialField.RANKING) { setExactWidth(column, GUIGlobals.WIDTH_ICON_COL_RANKING); + new OptionalValueTableCellFactory() + .withGraphicIfPresent(this::createRating) + .install(column); } else { setExactWidth(column, GUIGlobals.WIDTH_ICON_COL); + + if (specialField.isSingleValueField()) { + new OptionalValueTableCellFactory() + .withGraphic((entry, value) -> createSpecialFieldIcon(value, specialFieldViewModel)) + .withOnMouseClickedEvent((entry, value) -> event -> { + if (event.getButton() == MouseButton.PRIMARY) { + specialFieldViewModel.toggle(entry.getEntry()); + } + }) + .install(column); + } else { + new OptionalValueTableCellFactory() + .withGraphic((entry, value) -> createSpecialFieldIcon(value, specialFieldViewModel)) + .withMenu((entry, value) -> createSpecialFieldMenu(entry.getEntry(), specialFieldViewModel)) + .install(column); + } } column.setCellValueFactory(cellData -> cellData.getValue().getSpecialField(specialField)); - column.setCellFactory( - new ValueTableCellFactory>() - .withGraphic(param -> param.map(specialFieldValue -> specialFieldValue.getIcon().getGraphicNode()).orElse(null))); return column; } + private Rating createRating(BibEntryTableViewModel entry, SpecialFieldValueViewModel value) { + Rating ranking = new Rating(); + ranking.setRating(value.getValue().toRating()); + EasyBind.subscribe(ranking.ratingProperty(), rating -> + new SpecialFieldViewModel(SpecialField.RANKING, undoManager).setSpecialFieldValue(entry.getEntry(), SpecialFieldValue.getRating(rating.intValue())) + ); + return ranking; + } + + private ContextMenu createSpecialFieldMenu(BibEntry entry, SpecialFieldViewModel specialField) { + ContextMenu contextMenu = new ContextMenu(); + + for (SpecialFieldValueViewModel value : specialField.getValues()) { + MenuItem menuItem = new MenuItem(value.getMenuString(), value.getIcon().map(JabRefIcon::getGraphicNode).orElse(null)); + menuItem.setOnAction(event -> specialField.setSpecialFieldValue(entry, value.getValue())); + contextMenu.getItems().add(menuItem); + } + + return contextMenu; + } + + private Node createSpecialFieldIcon(Optional fieldValue, SpecialFieldViewModel specialField) { + return fieldValue + .flatMap(SpecialFieldValueViewModel::getIcon) + .map(JabRefIcon::getGraphicNode) + .orElseGet(() -> { + Node node = specialField.getEmptyIcon().getGraphicNode(); + node.getStyleClass().add("empty-special-field"); + return node; + }); + } + private void setExactWidth(TableColumn column, int widthIconCol) { column.setMinWidth(widthIconCol); column.setPrefWidth(widthIconCol); @@ -121,12 +183,38 @@ private TableColumn> createFileColumn() column.getStyleClass().add(STYLE_ICON); setExactWidth(column, GUIGlobals.WIDTH_ICON_COL); column.setCellValueFactory(cellData -> cellData.getValue().getLinkedFiles()); - column.setCellFactory( new ValueTableCellFactory>() - .withGraphic(this::createFileIcon)); + .withGraphic(this::createFileIcon) + .withMenu(this::createFileMenu) + .withOnMouseClickedEvent((entry, linkedFiles) -> event -> { + if (event.getButton() == MouseButton.PRIMARY && linkedFiles.size() == 1) { + // Only one linked file -> open directly + LinkedFileViewModel linkedFileViewModel = new LinkedFileViewModel(linkedFiles.get(0), entry.getEntry(), database, Globals.TASK_EXECUTOR); + linkedFileViewModel.open(); + } + }) + .install(column); return column; } + private ContextMenu createFileMenu(BibEntryTableViewModel entry, List linkedFiles) { + if (linkedFiles.size() <= 1) { + return null; + } + + ContextMenu contextMenu = new ContextMenu(); + + for (LinkedFile linkedFile : linkedFiles) { + LinkedFileViewModel linkedFileViewModel = new LinkedFileViewModel(linkedFile, entry.getEntry(), database, Globals.TASK_EXECUTOR); + + MenuItem menuItem = new MenuItem(linkedFileViewModel.getDescriptionAndLink(), linkedFileViewModel.getTypeIcon().getGraphicNode()); + menuItem.setOnAction(event -> linkedFileViewModel.open()); + contextMenu.getItems().add(menuItem); + } + + return contextMenu; + } + /** * Creates a column which shows an icon instead of the textual content */ @@ -136,9 +224,9 @@ private TableColumn createIconColumn(JabRefIcon column.getStyleClass().add(STYLE_ICON); setExactWidth(column, GUIGlobals.WIDTH_ICON_COL); column.setCellValueFactory(cellData -> EasyBind.monadic(cellData.getValue().getField(firstField)).orElse(cellData.getValue().getField(secondField))); - column.setCellFactory( new ValueTableCellFactory() - .withGraphic(cellFactory::getTableIcon)); + .withGraphic(cellFactory::getTableIcon) + .install(column); return column; } @@ -148,9 +236,9 @@ private TableColumn createIconColumn(JabRefIcon column.getStyleClass().add(STYLE_ICON); setExactWidth(column, GUIGlobals.WIDTH_ICON_COL); column.setCellValueFactory(cellData -> cellData.getValue().getField(field)); - column.setCellFactory( new ValueTableCellFactory() - .withGraphic(cellFactory::getTableIcon)); + .withGraphic(cellFactory::getTableIcon) + .install(column); return column; } @@ -168,9 +256,9 @@ private TableColumn> createExtraFileCol column.getStyleClass().add(STYLE_ICON); setExactWidth(column, GUIGlobals.WIDTH_ICON_COL); column.setCellValueFactory(cellData -> cellData.getValue().getLinkedFiles()); - column.setCellFactory( new ValueTableCellFactory>() - .withGraphic(linkedFiles -> createFileIcon(linkedFiles.stream().filter(linkedFile -> linkedFile.getFileType().equalsIgnoreCase(externalFileTypeName)).collect(Collectors.toList())))); + .withGraphic(linkedFiles -> createFileIcon(linkedFiles.stream().filter(linkedFile -> linkedFile.getFileType().equalsIgnoreCase(externalFileTypeName)).collect(Collectors.toList()))) + .install(column); return column; } diff --git a/src/main/java/org/jabref/gui/maintable/RightClickMenu.java b/src/main/java/org/jabref/gui/maintable/RightClickMenu.java index ce7e20d7b7d..5e817414d5d 100644 --- a/src/main/java/org/jabref/gui/maintable/RightClickMenu.java +++ b/src/main/java/org/jabref/gui/maintable/RightClickMenu.java @@ -187,7 +187,7 @@ private static Menu createCopySubMenu(BasePanel panel, ActionFactory factory) { } private static Menu createSpecialFieldMenu(SpecialField field, ActionFactory factory, BasePanel panel) { - SpecialFieldViewModel viewModel = new SpecialFieldViewModel(field); + viewModel = new SpecialFieldViewModel(field); Menu menu = factory.createMenu(viewModel.getAction()); for (SpecialFieldValue val : field.getValues()) { SpecialFieldValueViewModel specialField = new SpecialFieldValueViewModel(val); diff --git a/src/main/java/org/jabref/gui/specialfields/SpecialFieldAction.java b/src/main/java/org/jabref/gui/specialfields/SpecialFieldAction.java index bed9b589bc7..ea0f6b6c8d0 100644 --- a/src/main/java/org/jabref/gui/specialfields/SpecialFieldAction.java +++ b/src/main/java/org/jabref/gui/specialfields/SpecialFieldAction.java @@ -83,7 +83,7 @@ public void action() { private String getTextDone(SpecialField field, String... params) { Objects.requireNonNull(params); - SpecialFieldViewModel viewModel = new SpecialFieldViewModel(field); + SpecialFieldViewModel viewModel = new SpecialFieldViewModel(field, frame.getCurrentBasePanel().getUndoManager()); if (field.isSingleValueField() && (params.length == 1) && (params[0] != null)) { // Single value fields can be toggled only diff --git a/src/main/java/org/jabref/gui/specialfields/SpecialFieldDropDown.java b/src/main/java/org/jabref/gui/specialfields/SpecialFieldDropDown.java index bf854ef6f8d..95979a18e66 100644 --- a/src/main/java/org/jabref/gui/specialfields/SpecialFieldDropDown.java +++ b/src/main/java/org/jabref/gui/specialfields/SpecialFieldDropDown.java @@ -23,7 +23,7 @@ private SpecialFieldDropDown() { public static JButton generateSpecialFieldButtonWithDropDown(SpecialField field, JabRefFrame frame) { Dimension buttonDim = new Dimension(23, 23); - SpecialFieldViewModel viewModel = new SpecialFieldViewModel(field); + SpecialFieldViewModel viewModel = new SpecialFieldViewModel(field, frame.getUndoManager()); JButton button = new JButton(viewModel.getRepresentingIcon()); button.setToolTipText(viewModel.getLocalization()); button.setPreferredSize(buttonDim); diff --git a/src/main/java/org/jabref/gui/specialfields/SpecialFieldValueViewModel.java b/src/main/java/org/jabref/gui/specialfields/SpecialFieldValueViewModel.java index 0273b9f59a4..7813c0e89a8 100644 --- a/src/main/java/org/jabref/gui/specialfields/SpecialFieldValueViewModel.java +++ b/src/main/java/org/jabref/gui/specialfields/SpecialFieldValueViewModel.java @@ -1,6 +1,7 @@ package org.jabref.gui.specialfields; import java.util.Objects; +import java.util.Optional; import javax.swing.Icon; import javax.swing.JLabel; @@ -13,6 +14,10 @@ public class SpecialFieldValueViewModel { + public SpecialFieldValue getValue() { + return value; + } + private final SpecialFieldValue value; public SpecialFieldValueViewModel(SpecialFieldValue value) { @@ -22,16 +27,11 @@ public SpecialFieldValueViewModel(SpecialFieldValue value) { } public Icon getSpecialFieldValueIcon() { - JabRefIcon icon = getIcon(); - if (icon == null) { - return null; - } else { - return icon.getSmallIcon(); - } + return getIcon().map(JabRefIcon::getSmallIcon).orElse(null); } - public JabRefIcon getIcon() { - return getAction().getIcon().orElse(null); + public Optional getIcon() { + return getAction().getIcon(); } public JLabel createSpecialFieldValueLabel() { diff --git a/src/main/java/org/jabref/gui/specialfields/SpecialFieldViewModel.java b/src/main/java/org/jabref/gui/specialfields/SpecialFieldViewModel.java index 2df8d05be52..0f620e21154 100644 --- a/src/main/java/org/jabref/gui/specialfields/SpecialFieldViewModel.java +++ b/src/main/java/org/jabref/gui/specialfields/SpecialFieldViewModel.java @@ -1,23 +1,38 @@ package org.jabref.gui.specialfields; +import java.util.List; import java.util.Objects; +import java.util.stream.Collectors; import javax.swing.Icon; +import javax.swing.undo.UndoManager; +import org.jabref.Globals; import org.jabref.gui.IconTheme; import org.jabref.gui.JabRefFrame; import org.jabref.gui.JabRefIcon; import org.jabref.gui.actions.ActionsFX; +import org.jabref.gui.undo.UndoableFieldChange; +import org.jabref.logic.l10n.Localization; +import org.jabref.logic.specialfields.SpecialFieldsUtils; +import org.jabref.model.FieldChange; +import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.specialfields.SpecialField; import org.jabref.model.entry.specialfields.SpecialFieldValue; public class SpecialFieldViewModel { + private UndoManager undoManager; + + public SpecialFieldViewModel(SpecialField field, UndoManager undoManager) { + this.field = Objects.requireNonNull(field); + this.undoManager = Objects.requireNonNull(undoManager); + } + private final SpecialField field; - public SpecialFieldViewModel(SpecialField field) { - Objects.requireNonNull(field); - this.field = field; + public SpecialField getField() { + return field; } public SpecialFieldAction getSpecialFieldAction(SpecialFieldValue value, JabRefFrame frame) { @@ -58,4 +73,25 @@ public ActionsFX getAction() { throw new IllegalArgumentException("There is no icon mapping for special field " + field); } } + + public JabRefIcon getEmptyIcon() { + return getIcon(); + } + + public List getValues() { + return field.getValues().stream() + .map(SpecialFieldValueViewModel::new) + .collect(Collectors.toList()); + } + + public void setSpecialFieldValue(BibEntry be, SpecialFieldValue value) { + List changes = SpecialFieldsUtils.updateField(getField(), value.getFieldValue().orElse(null), be, getField().isSingleValueField(), Globals.prefs.isKeywordSyncEnabled(), Globals.prefs.getKeywordDelimiter()); + for (FieldChange change : changes) { + undoManager.addEdit(new UndoableFieldChange(change)); + } + } + + public void toggle(BibEntry entry) { + setSpecialFieldValue(entry, getField().getValues().get(0)); + } } diff --git a/src/main/java/org/jabref/gui/util/ColorUtil.java b/src/main/java/org/jabref/gui/util/ColorUtil.java new file mode 100644 index 00000000000..3b713ded83c --- /dev/null +++ b/src/main/java/org/jabref/gui/util/ColorUtil.java @@ -0,0 +1,28 @@ +package org.jabref.gui.util; + +import javafx.scene.paint.Color; + +public class ColorUtil { + public static java.awt.Color toAWT(Color color) { + return new java.awt.Color((float) color.getRed(), + (float) color.getGreen(), + (float) color.getBlue(), + (float) color.getOpacity()); + } + + public static Color toFX(java.awt.Color awtColor) { + int r = awtColor.getRed(); + int g = awtColor.getGreen(); + int b = awtColor.getBlue(); + int a = awtColor.getAlpha(); + double opacity = a / 255.0; + return Color.rgb(r, g, b, opacity); + } + + public static String toRGBCode(Color color) { + return String.format("#%02X%02X%02X", + (int) (color.getRed() * 255), + (int) (color.getGreen() * 255), + (int) (color.getBlue() * 255)); + } +} diff --git a/src/main/java/org/jabref/gui/util/OptionalValueTableCellFactory.java b/src/main/java/org/jabref/gui/util/OptionalValueTableCellFactory.java new file mode 100644 index 00000000000..2232561583b --- /dev/null +++ b/src/main/java/org/jabref/gui/util/OptionalValueTableCellFactory.java @@ -0,0 +1,41 @@ +package org.jabref.gui.util; + +import java.util.Optional; +import java.util.function.BiFunction; + +import javafx.scene.Node; +import javafx.scene.control.TableCell; + +/** + * Constructs a {@link TableCell} based on an optional value of the cell and a bunch of specified converter methods. + * + * @param view model of table row + * @param cell value + */ +public class OptionalValueTableCellFactory extends ValueTableCellFactory> { + + private BiFunction toGraphicIfPresent; + private Node defaultGraphic; + + public OptionalValueTableCellFactory withGraphicIfPresent(BiFunction toGraphicIfPresent) { + this.toGraphicIfPresent = toGraphicIfPresent; + setToGraphic(); + return this; + } + + public OptionalValueTableCellFactory withDefaultGraphic(Node defaultGraphic) { + this.defaultGraphic = defaultGraphic; + setToGraphic(); + return this; + } + + private void setToGraphic() { + withGraphic((rowItem, item) -> { + if (item.isPresent() && toGraphicIfPresent != null) { + return toGraphicIfPresent.apply(rowItem, item.get()); + } else { + return defaultGraphic; + } + }); + } +} diff --git a/src/main/java/org/jabref/gui/util/ValueTableCellFactory.java b/src/main/java/org/jabref/gui/util/ValueTableCellFactory.java index 2d4892086de..82468f56578 100644 --- a/src/main/java/org/jabref/gui/util/ValueTableCellFactory.java +++ b/src/main/java/org/jabref/gui/util/ValueTableCellFactory.java @@ -1,10 +1,16 @@ package org.jabref.gui.util; +import java.util.function.BiFunction; +import java.util.function.Function; + import javafx.event.EventHandler; import javafx.scene.Node; +import javafx.scene.control.ContextMenu; import javafx.scene.control.TableCell; import javafx.scene.control.TableColumn; +import javafx.scene.control.TableRow; import javafx.scene.control.Tooltip; +import javafx.scene.input.MouseButton; import javafx.scene.input.MouseEvent; import javafx.util.Callback; @@ -18,32 +24,53 @@ */ public class ValueTableCellFactory implements Callback, TableCell> { - private Callback toText; - private Callback toGraphic; - private Callback> toOnMouseClickedEvent; - private Callback toTooltip; + private Function toText; + private BiFunction toGraphic; + private BiFunction> toOnMouseClickedEvent; + private Function toTooltip; + private Function contextMenuFactory; + private BiFunction menuFactory; - public ValueTableCellFactory withText(Callback toText) { + public ValueTableCellFactory withText(Function toText) { this.toText = toText; return this; } - public ValueTableCellFactory withGraphic(Callback toGraphic) { + public ValueTableCellFactory withGraphic(Function toGraphic) { + this.toGraphic = (rowItem, value) -> toGraphic.apply(value); + return this; + } + + public ValueTableCellFactory withGraphic(BiFunction toGraphic) { this.toGraphic = toGraphic; return this; } - public ValueTableCellFactory withTooltip(Callback toTooltip) { + public ValueTableCellFactory withTooltip(Function toTooltip) { this.toTooltip = toTooltip; return this; } - public ValueTableCellFactory withOnMouseClickedEvent( - Callback> toOnMouseClickedEvent) { + public ValueTableCellFactory withOnMouseClickedEvent(BiFunction> toOnMouseClickedEvent) { this.toOnMouseClickedEvent = toOnMouseClickedEvent; return this; } + public ValueTableCellFactory withOnMouseClickedEvent(Function> toOnMouseClickedEvent) { + this.toOnMouseClickedEvent = (rowItem, value) -> toOnMouseClickedEvent.apply(value); + return this; + } + + public ValueTableCellFactory withContextMenu(Function contextMenuFactory) { + this.contextMenuFactory = contextMenuFactory; + return this; + } + + public ValueTableCellFactory withMenu(BiFunction menuFactory) { + this.menuFactory = menuFactory; + return this; + } + @Override public TableCell call(TableColumn param) { @@ -53,29 +80,59 @@ public TableCell call(TableColumn param) { protected void updateItem(T item, boolean empty) { super.updateItem(item, empty); - if (empty || (item == null)) { + if (empty || (item == null) || (getTableRow() == null) || (getTableRow().getItem() == null)) { setText(null); setGraphic(null); setOnMouseClicked(null); setTooltip(null); } else { + S rowItem = ((TableRow) getTableRow()).getItem(); + if (toText != null) { - setText(toText.call(item)); + setText(toText.apply(item)); } if (toGraphic != null) { - setGraphic(toGraphic.call(item)); + setGraphic(toGraphic.apply(rowItem, item)); } if (toTooltip != null) { - String tooltipText = toTooltip.call(item); + String tooltipText = toTooltip.apply(item); if (StringUtil.isNotBlank(tooltipText)) { setTooltip(new Tooltip(tooltipText)); } } - if (toOnMouseClickedEvent != null) { - setOnMouseClicked(toOnMouseClickedEvent.call(item)); + + if (contextMenuFactory != null) { + // We only create the context menu when really necessary + setOnContextMenuRequested(event -> { + if (!isEmpty()) { + setContextMenu(contextMenuFactory.apply(item)); + getContextMenu().show(this, event.getScreenX(), event.getScreenY()); + } + event.consume(); + }); } + + setOnMouseClicked(event -> { + if (toOnMouseClickedEvent != null) { + toOnMouseClickedEvent.apply(rowItem, item).handle(event); + } + + if (menuFactory != null && !event.isConsumed()) { + if (event.getButton() == MouseButton.PRIMARY) { + ContextMenu menu = menuFactory.apply(rowItem, item); + if (menu != null) { + menu.show(this, event.getScreenX(), event.getScreenY()); + event.consume(); + } + } + } + }); } } }; } + + public void install(TableColumn column) { + column.setCellFactory(this); + } } diff --git a/src/main/java/org/jabref/logic/specialfields/SpecialFieldsUtils.java b/src/main/java/org/jabref/logic/specialfields/SpecialFieldsUtils.java index 084239efe0d..0152f2fed86 100644 --- a/src/main/java/org/jabref/logic/specialfields/SpecialFieldsUtils.java +++ b/src/main/java/org/jabref/logic/specialfields/SpecialFieldsUtils.java @@ -32,7 +32,7 @@ public static List updateField(SpecialField field, String value, Bi List fieldChanges = new ArrayList<>(); UpdateField.updateField(entry, field.getFieldName(), value, nullFieldIfValueIsTheSame) - .ifPresent(fieldChange -> fieldChanges.add(fieldChange)); + .ifPresent(fieldChanges::add); // we cannot use "value" here as updateField has side effects: "nullFieldIfValueIsTheSame" nulls the field if value is the same if (isKeywordSyncEnabled) { fieldChanges.addAll(SpecialFieldsUtils.exportFieldToKeywords(field, entry, keywordDelimiter)); @@ -79,9 +79,7 @@ private static List importKeywordsForField(KeywordList keywordList, } UpdateField.updateNonDisplayableField(entry, field.getFieldName(), newValue.map(Keyword::toString).orElse(null)) - .ifPresent(fieldChange -> { - fieldChanges.add(fieldChange); - }); + .ifPresent(fieldChanges::add); return fieldChanges; } diff --git a/src/main/java/org/jabref/model/entry/specialfields/SpecialFieldValue.java b/src/main/java/org/jabref/model/entry/specialfields/SpecialFieldValue.java index 742b707bd36..7176b39a6ce 100644 --- a/src/main/java/org/jabref/model/entry/specialfields/SpecialFieldValue.java +++ b/src/main/java/org/jabref/model/entry/specialfields/SpecialFieldValue.java @@ -34,6 +34,23 @@ public enum SpecialFieldValue { this.keyword = Optional.ofNullable(keyword).map(Keyword::new); } + public static SpecialFieldValue getRating(int ranking) { + switch (ranking) { + case 1: + return RANK_1; + case 2: + return RANK_2; + case 3: + return RANK_3; + case 4: + return RANK_4; + case 5: + return RANK_5; + default: + throw new UnsupportedOperationException(ranking + "is not a valid ranking"); + } + } + public Optional getKeyword() { return keyword; } @@ -42,4 +59,20 @@ public Optional getFieldValue() { return keyword.map(Keyword::toString); } + public int toRating() { + switch (this) { + case RANK_1: + return 1; + case RANK_2: + return 2; + case RANK_3: + return 3; + case RANK_4: + return 4; + case RANK_5: + return 5; + default: + throw new UnsupportedOperationException(this + "is not a valid ranking"); + } + } } diff --git a/src/main/java/org/jabref/preferences/JabRefPreferences.java b/src/main/java/org/jabref/preferences/JabRefPreferences.java index fa1fdcc2425..80422e2a647 100644 --- a/src/main/java/org/jabref/preferences/JabRefPreferences.java +++ b/src/main/java/org/jabref/preferences/JabRefPreferences.java @@ -632,7 +632,7 @@ private JabRefPreferences() { defaults.put(FIELD_EDITOR_TEXT_COLOR, "0:0:0"); // default icon colors - defaults.put(ICON_ENABLED_COLOR, "79:95:143"); + defaults.put(ICON_ENABLED_COLOR, "0:0:0"); defaults.put(ICON_DISABLED_COLOR, "200:200:200"); defaults.put(INCOMPLETE_ENTRY_BACKGROUND, "250:175:175"); @@ -1292,7 +1292,11 @@ private Object getObject(String key) { try { return this.getBoolean(key); } catch (ClassCastException e2) { - return this.getInt(key); + try { + return this.getInt(key); + } catch (ClassCastException e3) { + return this.getDouble(key); + } } } } diff --git a/src/test/resources/testbib/complex.bib b/src/test/resources/testbib/complex.bib index dd64afe4e54..84a8899d40f 100644 --- a/src/test/resources/testbib/complex.bib +++ b/src/test/resources/testbib/complex.bib @@ -18,20 +18,20 @@ @PhdThesis{deBraga2001 school = {Department of Zoology, University of Toronto}, } -@ARTICLE{1102917, - author = {E. Bardram}, - title = {The trouble with login: on usability and computer security in ubiquitous - computing}, - journal = {Personal Ubiquitous Comput.}, - year = {2005}, - volume = {9}, - pages = {357--367}, - number = {6}, - address = {London, UK}, +@Article{1102917, + author = {E. Bardram}, + title = {The trouble with login: on usability and computer security in ubiquitous computing}, + journal = {Personal Ubiquitous Comput.}, + year = {2005}, + volume = {9}, + number = {6}, + pages = {357--367}, + issn = {1617-4909}, + doi = {http://dx.doi.org/10.1007/s00779-005-0347-6}, + address = {London, UK}, bdsk-url-1 = {http://dx.doi.org/10.1007/s00779-005-0347-6}, - doi = {http://dx.doi.org/10.1007/s00779-005-0347-6}, - issn = {1617-4909}, - publisher = {Springer-Verlag} + priority = {prio1}, + publisher = {Springer-Verlag}, } @InProceedings{1137631, @@ -65,20 +65,19 @@ @INPROCEEDINGS{1132768 location = {Montreal, Canada} } -@INPROCEEDINGS{1137628, - author = {Danilo Bruschi and Bart De Win and Mattia Monga}, - title = {Introduction to software engineering for secure systems: SESS06 -- - secure by design}, - booktitle = {SESS '06: Proceedings of the 2006 international workshop on Software - engineering for secure systems}, - year = {2006}, - pages = {1--2}, - address = {New York, NY, USA}, - publisher = {ACM}, +@InProceedings{1137628, + author = {Danilo Bruschi and Bart De Win and Mattia Monga}, + title = {Introduction to software engineering for secure systems: SESS06 -- secure by design}, + booktitle = {SESS '06: Proceedings of the 2006 international workshop on Software engineering for secure systems}, + year = {2006}, + publisher = {ACM}, + location = {Shanghai, China}, + isbn = {1-59593-411-1}, + pages = {1--2}, + doi = {http://doi.acm.org/10.1145/1137627.1137628}, + address = {New York, NY, USA}, bdsk-url-1 = {http://doi.acm.org/10.1145/1137627.1137628}, - doi = {http://doi.acm.org/10.1145/1137627.1137628}, - isbn = {1-59593-411-1}, - location = {Shanghai, China} + readstatus = {read}, } @ARTICLE{1373163, @@ -96,20 +95,20 @@ @ARTICLE{1373163 publisher = {IEEE Educational Activities Department} } -@ARTICLE{820136, - author = {Tony Clear}, - title = {Design and usability in security systems: daily life as a context - of use?}, - journal = {SIGCSE Bull.}, - year = {2002}, - volume = {34}, - pages = {13--14}, - number = {4}, - address = {New York, NY, USA}, +@Article{820136, + author = {Tony Clear}, + title = {Design and usability in security systems: daily life as a context of use?}, + journal = {SIGCSE Bull.}, + year = {2002}, + volume = {34}, + number = {4}, + pages = {13--14}, + issn = {0097-8418}, + doi = {http://doi.acm.org/10.1145/820127.820136}, + address = {New York, NY, USA}, bdsk-url-1 = {http://doi.acm.org/10.1145/820127.820136}, - doi = {http://doi.acm.org/10.1145/820127.820136}, - issn = {0097-8418}, - publisher = {ACM} + publisher = {ACM}, + readstatus = {skimmed}, } @BOOK{1098730, @@ -150,19 +149,20 @@ @InProceedings{1233448 groups = {StaticGroup}, } -@ARTICLE{10250999, - author = {von Hippel, Eric and Reagle, Jr., Joseph M. and Sherry, John F., Jr. and van den Huevel, Jr., Johan A}, - title = {Article with complex Authornames}, - journal = {IEEE Security and Privacy}, - year = {2004}, - volume = {2}, - pages = {25--31}, - number = {5}, - address = {Piscataway, NJ, USA}, +@Article{10250999, + author = {von Hippel, Eric and Reagle, Jr., Joseph M. and Sherry, John F., Jr. and van den Huevel, Jr., Johan A}, + title = {Article with complex Authornames}, + journal = {IEEE Security and Privacy}, + year = {2004}, + volume = {2}, + number = {5}, + pages = {25--31}, + issn = {1540-7993}, + doi = {http://dx.doi.org/10.1109/MSP.2004.81}, + address = {Piscataway, NJ, USA}, bdsk-url-1 = {http://dx.doi.org/10.1109/MSP.2004.81}, - doi = {http://dx.doi.org/10.1109/MSP.2004.81}, - issn = {1540-7993}, - publisher = {IEEE Educational Activities Department} + priority = {prio2}, + publisher = {IEEE Educational Activities Department}, } @InProceedings{1314293,