diff --git a/CHANGELOG.md b/CHANGELOG.md index 560b2236e0a..be3982fb06c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,7 +52,8 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - We added the ability to add field names from the Preferences Dialog [#4546](https://github.com/JabRef/jabref/issues/4546) - We added the ability change the column widths directly in the main table. [#4546](https://github.com/JabRef/jabref/issues/4546) - We added the ability to execute default action in dialog by using with Ctrl + Enter combination [#4496](https://github.com/JabRef/jabref/issues/4496) - +- We grouped and reordered the Main Menu (File, Edit, Library, Quality, Tools, and View tabs & icons). [#4666](https://github.com/JabRef/jabref/issues/4666) [#4667](https://github.com/JabRef/jabref/issues/4667) [#4668](https://github.com/JabRef/jabref/issues/4668) [#4669](https://github.com/JabRef/jabref/issues/4669) [#4670](https://github.com/JabRef/jabref/issues/4670) [#4671](https://github.com/JabRef/jabref/issues/4671) [#4672](https://github.com/JabRef/jabref/issues/4672) [#4673](https://github.com/JabRef/jabref/issues/4673) +- We added additional modifiers (capitalize, titlecase and sentencecase) to the Bibtex key generator. [#1506](https://github.com/JabRef/jabref/issues/1506) diff --git a/build.gradle b/build.gradle index ea5d8e813b2..d08efe7b1a2 100644 --- a/build.gradle +++ b/build.gradle @@ -167,7 +167,7 @@ dependencies { testRuntime 'org.apache.logging.log4j:log4j-core:2.11.1' testRuntime 'org.apache.logging.log4j:log4j-jul:2.11.2' - testCompile 'org.mockito:mockito-core:2.24.5' + testCompile 'org.mockito:mockito-core:2.25.0' testCompile 'com.github.tomakehurst:wiremock:2.21.0' testCompile 'org.assertj:assertj-swing-junit:3.9.2' testCompile 'org.reflections:reflections:0.9.11' diff --git a/src/main/java/org/jabref/gui/Base.css b/src/main/java/org/jabref/gui/Base.css index ab4097899cc..e9c36458ba8 100644 --- a/src/main/java/org/jabref/gui/Base.css +++ b/src/main/java/org/jabref/gui/Base.css @@ -818,8 +818,8 @@ .separator:horizontal .line { -fx-border-color: -jr-separator; - -fx-border-width: 0; - -fx-border-insets: 1 0 0 0; + -fx-border-width: 0.3; + -fx-border-insets: 1 15 0 20; } .separator:vertical .line { diff --git a/src/main/java/org/jabref/gui/DefaultInjector.java b/src/main/java/org/jabref/gui/DefaultInjector.java index e94e6fe8697..4f18a03b9e6 100644 --- a/src/main/java/org/jabref/gui/DefaultInjector.java +++ b/src/main/java/org/jabref/gui/DefaultInjector.java @@ -6,6 +6,7 @@ import org.jabref.gui.keyboard.KeyBindingRepository; import org.jabref.gui.util.TaskExecutor; import org.jabref.logic.journals.JournalAbbreviationLoader; +import org.jabref.logic.protectedterms.ProtectedTermsLoader; import org.jabref.model.util.FileUpdateMonitor; import org.jabref.preferences.PreferencesService; @@ -38,6 +39,8 @@ private static Object createDependency(Class clazz) { return Globals.stateManager; } else if (clazz == FileUpdateMonitor.class) { return Globals.getFileUpdateMonitor(); + } else if (clazz == ProtectedTermsLoader.class) { + return Globals.protectedTermsLoader; } else if (clazz == ClipBoardManager.class) { return Globals.clipboardManager; } else { diff --git a/src/main/java/org/jabref/gui/JabRefFrame.java b/src/main/java/org/jabref/gui/JabRefFrame.java index 8346fe58e7f..2e41bbc7e64 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -58,7 +58,6 @@ import org.jabref.gui.actions.BibtexKeyPatternAction; import org.jabref.gui.actions.ConnectToSharedDatabaseCommand; import org.jabref.gui.actions.CopyFilesAction; -import org.jabref.gui.actions.CustomizeEntryAction; import org.jabref.gui.actions.CustomizeKeyBindingAction; import org.jabref.gui.actions.DatabasePropertiesAction; import org.jabref.gui.actions.EditExternalFileTypesAction; @@ -68,8 +67,6 @@ import org.jabref.gui.actions.ManageCustomExportsAction; import org.jabref.gui.actions.ManageCustomImportsAction; import org.jabref.gui.actions.ManageJournalsAction; -import org.jabref.gui.actions.ManageKeywordsAction; -import org.jabref.gui.actions.ManageProtectedTermsAction; import org.jabref.gui.actions.NewDatabaseAction; import org.jabref.gui.actions.NewEntryAction; import org.jabref.gui.actions.NewEntryFromPlainTextAction; @@ -83,6 +80,7 @@ import org.jabref.gui.actions.SimpleCommand; import org.jabref.gui.actions.StandardActions; import org.jabref.gui.dialogs.AutosaveUIManager; +import org.jabref.gui.edit.ManageKeywordsAction; import org.jabref.gui.edit.MassSetFieldsAction; import org.jabref.gui.exporter.ExportCommand; import org.jabref.gui.exporter.ExportToClipboardAction; @@ -101,6 +99,7 @@ import org.jabref.gui.mergeentries.MergeEntriesAction; import org.jabref.gui.metadata.BibtexStringEditorAction; import org.jabref.gui.metadata.PreambleEditor; +import org.jabref.gui.protectedterms.ManageProtectedTermsAction; import org.jabref.gui.push.PushToApplicationButton; import org.jabref.gui.push.PushToApplications; import org.jabref.gui.search.GlobalSearchBar; @@ -126,7 +125,6 @@ import org.jabref.model.database.shared.DatabaseLocation; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.BiblatexEntryTypes; -import org.jabref.model.entry.BibtexEntryTypes; import org.jabref.model.entry.FieldName; import org.jabref.model.entry.specialfields.SpecialField; import org.jabref.preferences.JabRefPreferences; @@ -735,35 +733,35 @@ private MenuBar createMenu() { Menu help = new Menu(Localization.lang("Help")); file.getItems().addAll( - factory.createMenuItem(StandardActions.NEW_LIBRARY_BIBTEX, new NewDatabaseAction(this, BibDatabaseMode.BIBTEX)), - factory.createMenuItem(StandardActions.NEW_LIBRARY_BIBLATEX, new NewDatabaseAction(this, BibDatabaseMode.BIBLATEX)), + factory.createSubMenu(StandardActions.NEW_LIBRARY, + factory.createMenuItem(StandardActions.NEW_LIBRARY_BIBTEX, new NewDatabaseAction(this, BibDatabaseMode.BIBTEX)), + factory.createMenuItem(StandardActions.NEW_LIBRARY_BIBLATEX, new NewDatabaseAction(this, BibDatabaseMode.BIBLATEX))), + factory.createMenuItem(StandardActions.OPEN_LIBRARY, getOpenDatabaseAction()), + fileHistory, factory.createMenuItem(StandardActions.SAVE_LIBRARY, new OldDatabaseCommandWrapper(Actions.SAVE, this, Globals.stateManager)), factory.createMenuItem(StandardActions.SAVE_LIBRARY_AS, new OldDatabaseCommandWrapper(Actions.SAVE_AS, this, Globals.stateManager)), factory.createMenuItem(StandardActions.SAVE_ALL, new SaveAllAction(this)), - factory.createSubMenu(StandardActions.IMPORT_EXPORT, + new SeparatorMenuItem(), + + factory.createSubMenu(StandardActions.IMPORT, factory.createMenuItem(StandardActions.MERGE_DATABASE, new OldDatabaseCommandWrapper(Actions.MERGE_DATABASE, this, Globals.stateManager)), // TODO: merge with import factory.createMenuItem(StandardActions.IMPORT_INTO_CURRENT_LIBRARY, new ImportCommand(this, false)), - factory.createMenuItem(StandardActions.IMPORT_INTO_NEW_LIBRARY, new ImportCommand(this, true)), + factory.createMenuItem(StandardActions.IMPORT_INTO_NEW_LIBRARY, new ImportCommand(this, true))), + + factory.createSubMenu(StandardActions.EXPORT, factory.createMenuItem(StandardActions.EXPORT_ALL, new ExportCommand(this, false, Globals.prefs)), factory.createMenuItem(StandardActions.EXPORT_SELECTED, new ExportCommand(this, true, Globals.prefs)), factory.createMenuItem(StandardActions.SAVE_SELECTED_AS_PLAIN_BIBTEX, new OldDatabaseCommandWrapper(Actions.SAVE_SELECTED_AS_PLAIN, this, Globals.stateManager))), - new SeparatorMenuItem(), - factory.createMenuItem(StandardActions.CONNECT_TO_SHARED_DB, new ConnectToSharedDatabaseCommand(this)), factory.createMenuItem(StandardActions.PULL_CHANGES_FROM_SHARED_DB, new OldDatabaseCommandWrapper(Actions.PULL_CHANGES_FROM_SHARED_DATABASE, this, Globals.stateManager)), new SeparatorMenuItem(), - fileHistory, - - new SeparatorMenuItem(), - factory.createMenuItem(StandardActions.CLOSE_LIBRARY, new CloseDatabaseAction()), factory.createMenuItem(StandardActions.QUIT, new CloseAction()) - ); edit.getItems().addAll( @@ -788,10 +786,7 @@ private MenuBar createMenu() { new SeparatorMenuItem(), - factory.createMenuItem(StandardActions.SEND_AS_EMAIL, new OldDatabaseCommandWrapper(Actions.SEND_AS_EMAIL, this, Globals.stateManager)), - - new SeparatorMenuItem() - + factory.createMenuItem(StandardActions.MANAGE_KEYWORDS, new ManageKeywordsAction(this)) ); if (Globals.prefs.getBoolean(JabRefPreferences.SPECIALFIELDSENABLED)) { @@ -831,28 +826,17 @@ private MenuBar createMenu() { } } - edit.getItems().addAll( - factory.createMenuItem(StandardActions.MANAGE_KEYWORDS, new ManageKeywordsAction(this)), - factory.createMenuItem(StandardActions.REPLACE_ALL, new OldDatabaseCommandWrapper(Actions.REPLACE_ALL, this, Globals.stateManager)), - factory.createMenuItem(StandardActions.MASS_SET_FIELDS, new MassSetFieldsAction(this)) - - ); - library.getItems().addAll( - factory.createMenuItem(StandardActions.NEW_ARTICLE, new NewEntryAction(this, BibtexEntryTypes.ARTICLE, dialogService, Globals.prefs)), factory.createMenuItem(StandardActions.NEW_ENTRY, new NewEntryAction(this, dialogService, Globals.prefs)), factory.createMenuItem(StandardActions.NEW_ENTRY_FROM_PLAINTEX, new NewEntryFromPlainTextAction(this, Globals.prefs.getUpdateFieldPreferences(), dialogService, Globals.prefs)), - - new SeparatorMenuItem(), - factory.createMenuItem(StandardActions.DELETE_ENTRY, new OldDatabaseCommandWrapper(Actions.DELETE, this, Globals.stateManager)), new SeparatorMenuItem(), factory.createMenuItem(StandardActions.LIBRARY_PROPERTIES, new DatabasePropertiesAction(this)), factory.createMenuItem(StandardActions.EDIT_PREAMBLE, new PreambleEditor(this)), - factory.createMenuItem(StandardActions.EDIT_STRINGS, new BibtexStringEditorAction(this)) - + factory.createMenuItem(StandardActions.EDIT_STRINGS, new BibtexStringEditorAction(this)), + factory.createMenuItem(StandardActions.MASS_SET_FIELDS, new MassSetFieldsAction(this)) ); Menu lookupIdentifiers = factory.createSubMenu(StandardActions.LOOKUP_DOC_IDENTIFIER); @@ -865,67 +849,66 @@ private MenuBar createMenu() { quality.getItems().addAll( factory.createMenuItem(StandardActions.FIND_DUPLICATES, new DuplicateSearch(this, dialogService)), factory.createMenuItem(StandardActions.MERGE_ENTRIES, new MergeEntriesAction(this)), - - new SeparatorMenuItem(), - factory.createMenuItem(StandardActions.CHECK_INTEGRITY, new IntegrityCheckAction(this)), factory.createMenuItem(StandardActions.CLEANUP_ENTRIES, new OldDatabaseCommandWrapper(Actions.CLEANUP, this, Globals.stateManager)), - factory.createMenuItem(StandardActions.GENERATE_CITE_KEYS, new OldDatabaseCommandWrapper(Actions.MAKE_KEY, this, Globals.stateManager)), - - new SeparatorMenuItem(), - - factory.createMenuItem(StandardActions.SET_FILE_LINKS, new AutoLinkFilesAction()), - factory.createMenuItem(StandardActions.FIND_UNLINKED_FILES, new FindUnlinkedFilesAction(this)), - lookupIdentifiers, - factory.createMenuItem(StandardActions.DOWNLOAD_FULL_TEXT, new OldDatabaseCommandWrapper(Actions.DOWNLOAD_FULL_TEXT, this, Globals.stateManager)) - ); - - SidePaneComponent webSearch = sidePaneManager.getComponent(SidePaneType.WEB_SEARCH); - SidePaneComponent groups = sidePaneManager.getComponent(SidePaneType.GROUPS); - SidePaneComponent openOffice = sidePaneManager.getComponent(SidePaneType.OPEN_OFFICE); - - view.getItems().addAll( - factory.createMenuItem(webSearch.getToggleAction(), webSearch.getToggleCommand()), - factory.createMenuItem(groups.getToggleAction(), groups.getToggleCommand()), - factory.createMenuItem(StandardActions.TOGGLE_PREVIEW, new OldDatabaseCommandWrapper(Actions.TOGGLE_PREVIEW, this, Globals.stateManager)), - factory.createMenuItem(StandardActions.EDIT_ENTRY, new OldDatabaseCommandWrapper(Actions.EDIT, this, Globals.stateManager)), - factory.createMenuItem(StandardActions.SHOW_PDV_VIEWER, new ShowDocumentViewerAction()), new SeparatorMenuItem(), - factory.createMenuItem(StandardActions.SELECT_ALL, new OldDatabaseCommandWrapper(Actions.SELECT_ALL, this, Globals.stateManager)), - - new SeparatorMenuItem(), - - factory.createMenuItem(StandardActions.NEXT_PREVIEW_STYLE, new OldDatabaseCommandWrapper(Actions.NEXT_PREVIEW_STYLE, this, Globals.stateManager)), - factory.createMenuItem(StandardActions.PREVIOUS_PREVIEW_STYLE, new OldDatabaseCommandWrapper(Actions.PREVIOUS_PREVIEW_STYLE, this, Globals.stateManager)) + factory.createMenuItem(StandardActions.SET_FILE_LINKS, new AutoLinkFilesAction()) ); PushToApplicationButton pushToExternal = new PushToApplicationButton(this, pushApplications.getApplications()); tools.getItems().addAll( factory.createMenuItem(StandardActions.NEW_SUB_LIBRARY_FROM_AUX, new NewSubLibraryAction(this)), + factory.createMenuItem(StandardActions.FIND_UNLINKED_FILES, new FindUnlinkedFilesAction(this)), factory.createMenuItem(StandardActions.WRITE_XMP, new OldDatabaseCommandWrapper(Actions.WRITE_XMP, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.COPY_LINKED_FILES, new CopyFilesAction(this)), new SeparatorMenuItem(), - factory.createMenuItem(openOffice.getToggleAction(), openOffice.getToggleCommand()), - factory.createMenuItem(pushToExternal.getMenuAction(), pushToExternal), + lookupIdentifiers, + factory.createMenuItem(StandardActions.DOWNLOAD_FULL_TEXT, new OldDatabaseCommandWrapper(Actions.DOWNLOAD_FULL_TEXT, this, Globals.stateManager)), new SeparatorMenuItem(), - factory.createMenuItem(StandardActions.OPEN_FOLDER, new OldDatabaseCommandWrapper(Actions.OPEN_FOLDER, this, Globals.stateManager)), - factory.createMenuItem(StandardActions.OPEN_FILE, new OldDatabaseCommandWrapper(Actions.OPEN_EXTERNAL_FILE, this, Globals.stateManager)), - factory.createMenuItem(StandardActions.OPEN_URL, new OldDatabaseCommandWrapper(Actions.OPEN_URL, this, Globals.stateManager)), - factory.createMenuItem(StandardActions.OPEN_CONSOLE, new OldDatabaseCommandWrapper(Actions.OPEN_CONSOLE, this, Globals.stateManager)), - factory.createMenuItem(StandardActions.COPY_LINKED_FILES, new CopyFilesAction(this)), + factory.createMenuItem(StandardActions.GENERATE_CITE_KEYS, new OldDatabaseCommandWrapper(Actions.MAKE_KEY, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.REPLACE_ALL, new OldDatabaseCommandWrapper(Actions.REPLACE_ALL, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.SEND_AS_EMAIL, new OldDatabaseCommandWrapper(Actions.SEND_AS_EMAIL, this, Globals.stateManager)), + factory.createMenuItem(pushToExternal.getMenuAction(), pushToExternal), - new SeparatorMenuItem(), + factory.createSubMenu(StandardActions.ABBREVIATE, + factory.createMenuItem(StandardActions.ABBREVIATE_ISO, new OldDatabaseCommandWrapper(Actions.ABBREVIATE_ISO, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.ABBREVIATE_MEDLINE, new OldDatabaseCommandWrapper(Actions.ABBREVIATE_MEDLINE, this, Globals.stateManager))), - factory.createMenuItem(StandardActions.ABBREVIATE_ISO, new OldDatabaseCommandWrapper(Actions.ABBREVIATE_ISO, this, Globals.stateManager)), - factory.createMenuItem(StandardActions.ABBREVIATE_MEDLINE, new OldDatabaseCommandWrapper(Actions.ABBREVIATE_MEDLINE, this, Globals.stateManager)), factory.createMenuItem(StandardActions.UNABBREVIATE, new OldDatabaseCommandWrapper(Actions.UNABBREVIATE, this, Globals.stateManager)) ); + SidePaneComponent webSearch = sidePaneManager.getComponent(SidePaneType.WEB_SEARCH); + SidePaneComponent groups = sidePaneManager.getComponent(SidePaneType.GROUPS); + SidePaneComponent openOffice = sidePaneManager.getComponent(SidePaneType.OPEN_OFFICE); + + view.getItems().add(new SeparatorMenuItem()); + view.setOnShowing(event -> { + view.getItems().clear(); + view.getItems().addAll( + factory.createCheckMenuItem(webSearch.getToggleAction(), webSearch.getToggleCommand(), sidePaneManager.isComponentVisible(SidePaneType.WEB_SEARCH)), + factory.createCheckMenuItem(groups.getToggleAction(), groups.getToggleCommand(), sidePaneManager.isComponentVisible(SidePaneType.GROUPS)), + factory.createCheckMenuItem(openOffice.getToggleAction(), openOffice.getToggleCommand(), sidePaneManager.isComponentVisible(SidePaneType.OPEN_OFFICE)), + + new SeparatorMenuItem(), + + factory.createCheckMenuItem(StandardActions.TOGGLE_PREVIEW, new OldDatabaseCommandWrapper(Actions.TOGGLE_PREVIEW, this, Globals.stateManager), Globals.prefs.getPreviewPreferences().isPreviewPanelEnabled()), + factory.createMenuItem(StandardActions.NEXT_PREVIEW_STYLE, new OldDatabaseCommandWrapper(Actions.NEXT_PREVIEW_STYLE, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.PREVIOUS_PREVIEW_STYLE, new OldDatabaseCommandWrapper(Actions.PREVIOUS_PREVIEW_STYLE, this, Globals.stateManager)), + + new SeparatorMenuItem(), + + factory.createMenuItem(StandardActions.SHOW_PDF_VIEWER, new ShowDocumentViewerAction()), + factory.createMenuItem(StandardActions.EDIT_ENTRY, new OldDatabaseCommandWrapper(Actions.EDIT, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.OPEN_CONSOLE, new OldDatabaseCommandWrapper(Actions.OPEN_CONSOLE, this, Globals.stateManager)) + ); + }); + options.getItems().addAll( factory.createMenuItem(StandardActions.SHOW_PREFS, new ShowPreferencesAction(this, Globals.TASK_EXECUTOR)), @@ -937,13 +920,15 @@ private MenuBar createMenu() { factory.createMenuItem(StandardActions.MANAGE_EXTERNAL_FILETYPES, new EditExternalFileTypesAction()), factory.createMenuItem(StandardActions.MANAGE_JOURNALS, new ManageJournalsAction()), factory.createMenuItem(StandardActions.CUSTOMIZE_KEYBINDING, new CustomizeKeyBindingAction()), - factory.createMenuItem(StandardActions.MANAGE_PROTECTED_TERMS, new ManageProtectedTermsAction(this, Globals.protectedTermsLoader)), + factory.createMenuItem(StandardActions.MANAGE_PROTECTED_TERMS, new ManageProtectedTermsAction()), new SeparatorMenuItem(), factory.createMenuItem(StandardActions.MANAGE_CONTENT_SELECTORS, new ManageContentSelectorAction(this)), - factory.createMenuItem(StandardActions.CUSTOMIZE_ENTRY_TYPES, new CustomizeEntryAction(this)), - factory.createMenuItem(StandardActions.MANAGE_CITE_KEY_PATTERNS, new BibtexKeyPatternAction(this))); + // TODO: Reenable customize entry types feature (https://github.com/JabRef/jabref/issues/4719) + //factory.createMenuItem(StandardActions.CUSTOMIZE_ENTRY_TYPES, new CustomizeEntryAction(this)), + factory.createMenuItem(StandardActions.MANAGE_CITE_KEY_PATTERNS, new BibtexKeyPatternAction(this)) + ); help.getItems().addAll( factory.createMenuItem(StandardActions.HELP, HelpAction.getMainHelpPageCommand()), @@ -975,6 +960,7 @@ private MenuBar createMenu() { ), factory.createMenuItem(StandardActions.ABOUT, new AboutAction()) ); + //@formatter:on MenuBar menu = new MenuBar(); menu.getStyleClass().add("mainMenu"); diff --git a/src/main/java/org/jabref/gui/WrapLayout.java b/src/main/java/org/jabref/gui/WrapLayout.java deleted file mode 100644 index 999c7abd3f0..00000000000 --- a/src/main/java/org/jabref/gui/WrapLayout.java +++ /dev/null @@ -1,175 +0,0 @@ -package org.jabref.gui; - -import java.awt.Component; -import java.awt.Container; -import java.awt.Dimension; -import java.awt.FlowLayout; -import java.awt.Insets; - -import javax.swing.JScrollPane; -import javax.swing.SwingUtilities; - -/** - * FlowLayout subclass that fully supports wrapping of components. - */ -public class WrapLayout extends FlowLayout { - /** - * Constructs a new WrapLayout with a left - * alignment and a default 5-unit horizontal and vertical gap. - */ - public WrapLayout() { - super(); - } - - /** - * Constructs a new FlowLayout with the specified - * alignment and a default 5-unit horizontal and vertical gap. - * The value of the alignment argument must be one of - * WrapLayout, WrapLayout, - * or WrapLayout. - * @param align the alignment value - */ - public WrapLayout(int align) { - super(align); - } - - /** - * Creates a new flow layout manager with the indicated alignment - * and the indicated horizontal and vertical gaps. - *

- * The value of the alignment argument must be one of - * WrapLayout, WrapLayout, - * or WrapLayout. - * @param align the alignment value - * @param hgap the horizontal gap between components - * @param vgap the vertical gap between components - */ - public WrapLayout(int align, int hgap, int vgap) { - super(align, hgap, vgap); - } - - /** - * Returns the preferred dimensions for this layout given the - * visible components in the specified target container. - * @param target the component which needs to be laid out - * @return the preferred dimensions to lay out the - * subcomponents of the specified container - */ - @Override - public Dimension preferredLayoutSize(Container target) { - return layoutSize(target, true); - } - - /** - * Returns the minimum dimensions needed to layout the visible - * components contained in the specified target container. - * @param target the component which needs to be laid out - * @return the minimum dimensions to lay out the - * subcomponents of the specified container - */ - @Override - public Dimension minimumLayoutSize(Container target) { - Dimension minimum = layoutSize(target, false); - minimum.width -= (getHgap() + 1); - return minimum; - } - - /** - * Returns the minimum or preferred dimension needed to layout the target - * container. - * - * @param target target to get layout size for - * @param preferred should preferred size be calculated - * @return the dimension to layout the target container - */ - private Dimension layoutSize(Container target, boolean preferred) { - synchronized (target.getTreeLock()) { - // Each row must fit with the width allocated to the container. - // When the container width = 0, the preferred width of the container - // has not yet been calculated so lets ask for the maximum. - - int targetWidth = target.getSize().width; - - if (targetWidth == 0) { - targetWidth = Integer.MAX_VALUE; - } - - int hgap = getHgap(); - int vgap = getVgap(); - Insets insets = target.getInsets(); - int horizontalInsetsAndGap = insets.left + insets.right + (hgap * 2); - int maxWidth = targetWidth - horizontalInsetsAndGap; - - // Fit components into the allowed width - - Dimension dim = new Dimension(0, 0); - int rowWidth = 0; - int rowHeight = 0; - - int nmembers = target.getComponentCount(); - - for (int i = 0; i < nmembers; i++) { - Component m = target.getComponent(i); - - if (m.isVisible()) { - Dimension d = preferred ? m.getPreferredSize() : m.getMinimumSize(); - - if (d != null) { - // Can't add the component to current row. Start a new row. - - if ((rowWidth + d.width) > maxWidth) { - addRow(dim, rowWidth, rowHeight); - rowWidth = 0; - rowHeight = 0; - } - - // Add a horizontal gap for all components after the first - - if (rowWidth != 0) { - rowWidth += hgap; - } - - rowWidth += d.width; - rowHeight = Math.max(rowHeight, d.height); - } - } - } - - addRow(dim, rowWidth, rowHeight); - - dim.width += horizontalInsetsAndGap; - dim.height += insets.top + insets.bottom + (vgap * 2); - - // When using a scroll pane or the DecoratedLookAndFeel we need to - // make sure the preferred size is less than the size of the - // target container so shrinking the container size works - // correctly. Removing the horizontal gap is an easy way to do this. - - Container scrollPane = SwingUtilities.getAncestorOfClass(JScrollPane.class, target); - - if (scrollPane != null) { - dim.width -= (hgap + 1); - } - - return dim; - } - } - - /* - * A new row has been completed. Use the dimensions of this row - * to update the preferred size for the container. - * - * @param dim update the width and height when appropriate - * @param rowWidth the width of the row to add - * @param rowHeight the height of the row to add - */ - private void addRow(Dimension dim, int rowWidth, int rowHeight) { - dim.width = Math.max(dim.width, rowWidth); - - if (dim.height > 0) { - dim.height += getVgap(); - } - - dim.height += rowHeight; - } -} diff --git a/src/main/java/org/jabref/gui/actions/ActionFactory.java b/src/main/java/org/jabref/gui/actions/ActionFactory.java index 51c77f1f8d2..69c5531db65 100644 --- a/src/main/java/org/jabref/gui/actions/ActionFactory.java +++ b/src/main/java/org/jabref/gui/actions/ActionFactory.java @@ -5,6 +5,7 @@ import javafx.scene.Node; import javafx.scene.control.Button; import javafx.scene.control.ButtonBase; +import javafx.scene.control.CheckMenuItem; import javafx.scene.control.Menu; import javafx.scene.control.MenuItem; @@ -43,6 +44,14 @@ public MenuItem createMenuItem(Action action, Command command) { return menuItem; } + public CheckMenuItem createCheckMenuItem(Action action, Command command, boolean selected) { + CheckMenuItem checkMenuItem = ActionUtils.createCheckMenuItem(new JabRefAction(action, command, keyBindingRepository)); + checkMenuItem.setSelected(selected); + setGraphic(checkMenuItem, action); + + return checkMenuItem; + } + public Menu createMenu(Action action) { Menu menu = ActionUtils.createMenu(new JabRefAction(action, keyBindingRepository)); diff --git a/src/main/java/org/jabref/gui/actions/ManageKeywordsAction.java b/src/main/java/org/jabref/gui/actions/ManageKeywordsAction.java deleted file mode 100644 index 0af7a02f91c..00000000000 --- a/src/main/java/org/jabref/gui/actions/ManageKeywordsAction.java +++ /dev/null @@ -1,356 +0,0 @@ -package org.jabref.gui.actions; - -import java.awt.BorderLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; -import java.util.Enumeration; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.stream.Collectors; - -import javax.swing.AbstractAction; -import javax.swing.Action; -import javax.swing.ActionMap; -import javax.swing.BorderFactory; -import javax.swing.ButtonGroup; -import javax.swing.DefaultListModel; -import javax.swing.InputMap; -import javax.swing.JButton; -import javax.swing.JComponent; -import javax.swing.JDialog; -import javax.swing.JFrame; -import javax.swing.JList; -import javax.swing.JRadioButton; -import javax.swing.JScrollPane; -import javax.swing.JTextField; - -import org.jabref.Globals; -import org.jabref.gui.BasePanel; -import org.jabref.gui.JabRefFrame; -import org.jabref.gui.keyboard.KeyBinding; -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.entry.BibEntry; -import org.jabref.model.entry.Keyword; -import org.jabref.model.entry.KeywordList; -import org.jabref.model.strings.StringUtil; - -import com.jgoodies.forms.builder.ButtonBarBuilder; -import com.jgoodies.forms.builder.FormBuilder; -import com.jgoodies.forms.layout.FormLayout; - -/** - * An Action for launching keyword managing dialog - * - */ -public class ManageKeywordsAction extends SimpleCommand { - - private final JabRefFrame frame; - private final KeywordList sortedKeywordsOfAllEntriesBeforeUpdateByUser = new KeywordList(); - private JDialog diag; - private DefaultListModel keywordListModel; - private JRadioButton intersectKeywords; - private JRadioButton mergeKeywords; - private boolean canceled; - - - public ManageKeywordsAction(JabRefFrame frame) { - this.frame = frame; - } - - private void createDialog() { - if (diag != null) { - return; - } - // keyword to add - JTextField keyword = new JTextField(); - - keywordListModel = new DefaultListModel<>(); - JList keywordList = new JList<>(keywordListModel); - keywordList.setVisibleRowCount(8); - JScrollPane kPane = new JScrollPane(keywordList); - - diag = new JDialog((JFrame) null, Localization.lang("Manage keywords"), true); - - JButton ok = new JButton(Localization.lang("OK")); - JButton cancel = new JButton(Localization.lang("Cancel")); - JButton add = new JButton(Localization.lang("Add")); - JButton remove = new JButton(Localization.lang("Remove")); - JButton replace = new JButton(Localization.lang("Replace")); - JButton join = new JButton(Localization.lang("Join")); - - join.setToolTipText(Localization.lang("Joins selected keywords and deletes selected keywords.")); - - keywordList.setVisibleRowCount(10); - - intersectKeywords = new JRadioButton(Localization.lang("Display keywords appearing in ALL entries")); - mergeKeywords = new JRadioButton(Localization.lang("Display keywords appearing in ANY entry")); - ButtonGroup group = new ButtonGroup(); - group.add(intersectKeywords); - group.add(mergeKeywords); - ActionListener stateChanged = e -> fillKeyWordList(); - intersectKeywords.addActionListener(stateChanged); - mergeKeywords.addActionListener(stateChanged); - intersectKeywords.setSelected(true); - - FormBuilder builder = FormBuilder.create().layout(new FormLayout("fill:200dlu:grow, pref, fill:pref", - "pref, 2dlu, pref, 1dlu, pref, 2dlu, fill:100dlu:grow, 4dlu, pref, 4dlu, pref, ")); - - builder.addSeparator(Localization.lang("Keywords of selected entries")).xyw(1, 1, 3); - builder.add(intersectKeywords).xyw(1, 3, 3); - builder.add(mergeKeywords).xyw(1, 5, 3); - builder.add(kPane).xywh(1, 7, 1, 3); - builder.add(join).xy(2,9); - builder.add(replace).xy(3, 9); - builder.add(keyword).xy(1, 11); - builder.add(add).xy(2, 11); - builder.add(remove).xy(3, 11); - - ButtonBarBuilder bb = new ButtonBarBuilder(); - bb.addGlue(); - bb.addButton(ok); - bb.addButton(cancel); - bb.addGlue(); - builder.getPanel().setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); - bb.getPanel().setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); - - ok.addActionListener(e -> { - canceled = false; - diag.dispose(); - }); - - Action cancelAction = new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - canceled = true; - diag.dispose(); - } - }; - cancel.addActionListener(cancelAction); - - final ActionListener addActionListener = arg0 -> addButtonActionListener(keyword); - - add.addActionListener(addActionListener); - - final ActionListener removeActionListener = arg0 -> { - // keywordList.getSelectedIndices(); does not work, therefore we operate on the values - List values = keywordList.getSelectedValuesList(); - - for (Keyword val : values) { - keywordListModel.removeElement(val); - } - }; - - remove.addActionListener(removeActionListener); - - final ActionListener joinActionListener = arg0 -> { - List values = keywordList.getSelectedValuesList(); - String joinedKeyword = values.stream().map(currentKeyword -> currentKeyword.get()).collect(Collectors.joining(" ")); - this.addKeywordToKeywordListModel(joinedKeyword); - - for (Keyword val : values) { - this.keywordListModel.removeElement(val); - } - }; - - join.addActionListener(joinActionListener); - - final ActionListener replaceActionListener = arg0 -> { - List values = keywordList.getSelectedValuesList(); - - for (Keyword val : values) { - keywordListModel.removeElement(val); - } - addButtonActionListener(keyword); - }; - - replace.addActionListener(replaceActionListener); - - //enable a user to press Delete to delete a keyword - keywordList.addKeyListener(new KeyAdapter() { - - @Override - public void keyPressed(KeyEvent arg0) { - if (arg0.getKeyCode() == KeyEvent.VK_DELETE) { - removeActionListener.actionPerformed(null); - } - } - }); - - //enable a user to press Enter to add a keyword - keyword.addKeyListener(new KeyAdapter() { - - @Override - public void keyPressed(KeyEvent e) { - if (e.getKeyCode() == KeyEvent.VK_ENTER) { - addActionListener.actionPerformed(null); - } - } - }); - - // Key bindings: - ActionMap am = builder.getPanel().getActionMap(); - InputMap im = builder.getPanel().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); - im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE), "close"); - am.put("close", cancelAction); - - diag.getContentPane().add(builder.getPanel(), BorderLayout.CENTER); - diag.getContentPane().add(bb.getPanel(), BorderLayout.SOUTH); - } - - private void addButtonActionListener(JTextField keywordTextField) { - if (StringUtil.isBlank(keywordTextField.getText())) { - return; // nothing to add - } - addKeywordToKeywordListModel(keywordTextField.getText()); - keywordTextField.setText(null); - keywordTextField.requestFocusInWindow(); - - } - - /** - * Adds given keyword to the keyword list model - */ - private void addKeywordToKeywordListModel(String keyword) { - String keywordToAdd = Objects.requireNonNull(keyword).trim(); - Keyword newKeyword = new Keyword(keywordToAdd); - if (keywordListModel.isEmpty()) { - keywordListModel.addElement(newKeyword); - } else { - int idx = 0; - Keyword element = keywordListModel.getElementAt(idx); - while ((idx < keywordListModel.size()) && (element.compareTo(newKeyword) < 0)) { - idx++; - } - if (idx == keywordListModel.size()) { - // list is empty or word is greater than last word in list - keywordListModel.addElement(newKeyword); - } else if (element.compareTo(newKeyword) == 0) { - // nothing to do, word already in table - } else { - keywordListModel.add(idx, newKeyword); - } - } - } - - @Override - public void execute() { - BasePanel bp = frame.getCurrentBasePanel(); - if (bp == null) { - return; - } - if (bp.getSelectedEntries().isEmpty()) { - bp.output(Localization.lang("Select at least one entry to manage keywords.")); - return; - } - - // Lazy creation of the dialog: - createDialog(); - - canceled = true; - - fillKeyWordList(); - - diag.pack(); - diag.setVisible(true); - if (canceled) { - return; - } - - KeywordList keywordsToAdd = new KeywordList(); - KeywordList userSelectedKeywords = new KeywordList(); - // build keywordsToAdd and userSelectedKeywords in parallel - for (Enumeration keywords = keywordListModel.elements(); keywords.hasMoreElements();) { - Keyword keyword = keywords.nextElement(); - userSelectedKeywords.add(keyword); - if (!sortedKeywordsOfAllEntriesBeforeUpdateByUser.contains(keyword)) { - keywordsToAdd.add(keyword); - } - } - - KeywordList keywordsToRemove = new KeywordList(); - for (Keyword kword : sortedKeywordsOfAllEntriesBeforeUpdateByUser) { - if (!userSelectedKeywords.contains(kword)) { - keywordsToRemove.add(kword); - } - } - - if (keywordsToAdd.isEmpty() && keywordsToRemove.isEmpty()) { - // nothing to be done if nothing is new and nothing is obsolete - return; - } - - if (Globals.prefs.isKeywordSyncEnabled() && !keywordsToAdd.isEmpty()) { - SpecialFieldsUtils.synchronizeSpecialFields(keywordsToAdd, keywordsToRemove); - } - - NamedCompound ce = updateKeywords(bp.getSelectedEntries(), keywordsToAdd, keywordsToRemove); - bp.getUndoManager().addEdit(ce); - bp.markBaseChanged(); - } - - private NamedCompound updateKeywords(List entries, KeywordList keywordsToAdd, - KeywordList keywordsToRemove) { - NamedCompound ce = new NamedCompound(Localization.lang("Update keywords")); - for (BibEntry entry : entries) { - KeywordList keywords = entry.getKeywords(Globals.prefs.getKeywordDelimiter()); - - // update keywords - keywords.removeAll(keywordsToRemove); - keywords.addAll(keywordsToAdd); - - // put keywords back - Optional change = entry.putKeywords(keywords, Globals.prefs.getKeywordDelimiter()); - if (change.isPresent()) { - ce.addEdit(new UndoableFieldChange(change.get())); - } - - if (Globals.prefs.isKeywordSyncEnabled()) { - SpecialFieldsUtils.syncSpecialFieldsFromKeywords(entry, Globals.prefs.getKeywordDelimiter()); - } - } - ce.end(); - return ce; - } - - private void fillKeyWordList() { - BasePanel bp = frame.getCurrentBasePanel(); - List entries = bp.getSelectedEntries(); - - // fill dialog with values - keywordListModel.clear(); - sortedKeywordsOfAllEntriesBeforeUpdateByUser.clear(); - - if (mergeKeywords.isSelected()) { - for (BibEntry entry : entries) { - KeywordList separatedKeywords = entry.getKeywords(Globals.prefs.getKeywordDelimiter()); - sortedKeywordsOfAllEntriesBeforeUpdateByUser.addAll(separatedKeywords); - } - } else { - assert intersectKeywords.isSelected(); - - // all keywords from first entry have to be added - BibEntry firstEntry = entries.get(0); - KeywordList separatedKeywords = firstEntry.getKeywords(Globals.prefs.getKeywordDelimiter()); - sortedKeywordsOfAllEntriesBeforeUpdateByUser.addAll(separatedKeywords); - - // for the remaining entries, intersection has to be used - // this approach ensures that one empty keyword list leads to an empty set of common keywords - for (int i = 1; i < entries.size(); i++) { - BibEntry entry = entries.get(i); - separatedKeywords = entry.getKeywords(Globals.prefs.getKeywordDelimiter()); - sortedKeywordsOfAllEntriesBeforeUpdateByUser.retainAll(separatedKeywords); - } - } - for (Keyword keyword : sortedKeywordsOfAllEntriesBeforeUpdateByUser) { - keywordListModel.addElement(keyword); - } - } - -} diff --git a/src/main/java/org/jabref/gui/actions/ManageProtectedTermsAction.java b/src/main/java/org/jabref/gui/actions/ManageProtectedTermsAction.java deleted file mode 100644 index c4f05f955cf..00000000000 --- a/src/main/java/org/jabref/gui/actions/ManageProtectedTermsAction.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.jabref.gui.actions; - -import org.jabref.gui.JabRefFrame; -import org.jabref.gui.protectedterms.ProtectedTermsDialog; -import org.jabref.logic.protectedterms.ProtectedTermsLoader; - -public class ManageProtectedTermsAction extends SimpleCommand { - - private final JabRefFrame jabRefFrame; - private final ProtectedTermsLoader termsLoader; - - public ManageProtectedTermsAction(JabRefFrame jabRefFrame, ProtectedTermsLoader termsLoader) { - this.jabRefFrame = jabRefFrame; - this.termsLoader = termsLoader; - } - @Override - public void execute() { - ProtectedTermsDialog protectTermsDialog = new ProtectedTermsDialog(jabRefFrame); - protectTermsDialog.setVisible(true); - - } - -} diff --git a/src/main/java/org/jabref/gui/actions/StandardActions.java b/src/main/java/org/jabref/gui/actions/StandardActions.java index 69321ed5766..b3b10e3aeaa 100644 --- a/src/main/java/org/jabref/gui/actions/StandardActions.java +++ b/src/main/java/org/jabref/gui/actions/StandardActions.java @@ -60,10 +60,12 @@ public enum StandardActions implements Action { 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), - NEW_LIBRARY_BIBTEX(Localization.lang("New %0 library", BibDatabaseMode.BIBTEX.getFormattedName()), IconTheme.JabRefIcons.NEW), - NEW_LIBRARY_BIBLATEX(Localization.lang("New %0 library", BibDatabaseMode.BIBLATEX.getFormattedName()), IconTheme.JabRefIcons.NEW), + NEW_LIBRARY(Localization.lang("New library"), IconTheme.JabRefIcons.NEW), + NEW_LIBRARY_BIBTEX(Localization.lang("New %0 library", BibDatabaseMode.BIBTEX.getFormattedName())), + NEW_LIBRARY_BIBLATEX(Localization.lang("New %0 library", BibDatabaseMode.BIBLATEX.getFormattedName())), OPEN_LIBRARY(Localization.lang("Open library"), IconTheme.JabRefIcons.OPEN, KeyBinding.OPEN_DATABASE), - IMPORT_EXPORT(Localization.lang("Import & Export"), IconTheme.JabRefIcons.IMPORT_EXPORT), + IMPORT(Localization.lang("Import"), IconTheme.JabRefIcons.IMPORT), + EXPORT(Localization.lang("Export"), IconTheme.JabRefIcons.EXPORT), MERGE_DATABASE(Localization.lang("Append library"), Localization.lang("Append contents from a BibTeX library into the currently viewed library")), SAVE_LIBRARY(Localization.lang("Save library"), IconTheme.JabRefIcons.SAVE, KeyBinding.SAVE_DATABASE), SAVE_LIBRARY_AS(Localization.lang("Save library as..."), KeyBinding.SAVE_DATABASE_AS), @@ -71,19 +73,19 @@ public enum StandardActions implements Action { SAVE_ALL(Localization.lang("Save all"), Localization.lang("Save all open libraries"), IconTheme.JabRefIcons.SAVE_ALL, KeyBinding.SAVE_ALL), IMPORT_INTO_NEW_LIBRARY(Localization.lang("Import into new library"), KeyBinding.IMPORT_INTO_NEW_DATABASE), IMPORT_INTO_CURRENT_LIBRARY(Localization.lang("Import into current library"), KeyBinding.IMPORT_INTO_CURRENT_DATABASE), - EXPORT_ALL(Localization.lang("Export")), + EXPORT_ALL(Localization.lang("Export all entries")), EXPORT_SELECTED(Localization.lang("Export selected entries")), - CONNECT_TO_SHARED_DB(Localization.lang("Connect to shared database")), - PULL_CHANGES_FROM_SHARED_DB(Localization.lang("Pull changes from shared database"), IconTheme.JabRefIcons.PULL, KeyBinding.PULL_CHANGES_FROM_SHARED_DATABASE), + CONNECT_TO_SHARED_DB(Localization.lang("Connect to shared database"), IconTheme.JabRefIcons.CONNECT_DB), + PULL_CHANGES_FROM_SHARED_DB(Localization.lang("Pull changes from shared database"), KeyBinding.PULL_CHANGES_FROM_SHARED_DATABASE), CLOSE_LIBRARY(Localization.lang("Close library"), Localization.lang("Close the current library"), IconTheme.JabRefIcons.CLOSE, KeyBinding.CLOSE_DATABASE), QUIT(Localization.lang("Quit"), Localization.lang("Quit JabRef"), IconTheme.JabRefIcons.CLOSE_JABREF, KeyBinding.QUIT_JABREF), UNDO(Localization.lang("Undo"), IconTheme.JabRefIcons.UNDO, KeyBinding.UNDO), REDO(Localization.lang("Redo"), IconTheme.JabRefIcons.REDO, KeyBinding.REDO), - REPLACE_ALL(Localization.lang("Replace string"), KeyBinding.REPLACE_STRING), + REPLACE_ALL(Localization.lang("Find and replace"), KeyBinding.REPLACE_STRING), MANAGE_KEYWORDS(Localization.lang("Manage keywords")), - MASS_SET_FIELDS(Localization.lang("Set/clear/append/rename fields")), - TOGGLE_GROUPS(Localization.lang("Toggle groups interface"), IconTheme.JabRefIcons.TOGGLE_GROUPS, KeyBinding.TOGGLE_GROUPS_INTERFACE), - TOOGLE_OO(Localization.lang("OpenOffice/LibreOffice connection"), IconTheme.JabRefIcons.FILE_OPENOFFICE, KeyBinding.OPEN_OPEN_OFFICE_LIBRE_OFFICE_CONNECTION), + MASS_SET_FIELDS(Localization.lang("Manage field names & content")), + TOGGLE_GROUPS(Localization.lang("Groups interface"), IconTheme.JabRefIcons.TOGGLE_GROUPS, KeyBinding.TOGGLE_GROUPS_INTERFACE), + TOOGLE_OO(Localization.lang("OpenOffice/LibreOffice"), IconTheme.JabRefIcons.FILE_OPENOFFICE, KeyBinding.OPEN_OPEN_OFFICE_LIBRE_OFFICE_CONNECTION), TOGGLE_WEB_SEARCH(Localization.lang("Web search"), Localization.lang("Toggle web search interface"), IconTheme.JabRefIcons.WWW, KeyBinding.WEB_SEARCH), NEW_SUB_LIBRARY_FROM_AUX(Localization.lang("New sublibrary based on AUX file") + "...", Localization.lang("New BibTeX sublibrary") + Localization.lang("This feature generates a new library based on which entries are needed in an existing LaTeX document."), IconTheme.JabRefIcons.NEW), @@ -92,8 +94,9 @@ public enum StandardActions implements Action { OPEN_FILE(Localization.lang("Open file"), Localization.lang("Open file"), IconTheme.JabRefIcons.FILE, KeyBinding.OPEN_FILE), OPEN_CONSOLE(Localization.lang("Open terminal here"), Localization.lang("Open terminal here"), IconTheme.JabRefIcons.CONSOLE, KeyBinding.OPEN_CONSOLE), COPY_LINKED_FILES(Localization.lang("Copy linked files to folder...")), - ABBREVIATE_ISO(Localization.lang("Abbreviate journal names (ISO)"), Localization.lang("Abbreviate journal names of the selected entries (ISO abbreviation)"), KeyBinding.ABBREVIATE), - ABBREVIATE_MEDLINE(Localization.lang("Abbreviate journal names (MEDLINE)"), Localization.lang("Abbreviate journal names of the selected entries (MEDLINE abbreviation)")), + ABBREVIATE(Localization.lang("Abbreviate journal names")), + ABBREVIATE_ISO("ISO", Localization.lang("Abbreviate journal names of the selected entries (ISO abbreviation)"), KeyBinding.ABBREVIATE), + ABBREVIATE_MEDLINE("MEDLINE", Localization.lang("Abbreviate journal names of the selected entries (MEDLINE abbreviation)")), UNABBREVIATE(Localization.lang("Unabbreviate journal names"), Localization.lang("Unabbreviate journal names of the selected entries"), KeyBinding.UNABBREVIATE), MANAGE_CUSTOM_EXPORTS(Localization.lang("Manage custom exports")), @@ -109,11 +112,11 @@ public enum StandardActions implements Action { MANAGE_CONTENT_SELECTORS(Localization.lang("Manage content selectors"), IconTheme.JabRefIcons.PREFERENCES), MANAGE_CITE_KEY_PATTERNS(Localization.lang("BibTeX key patterns")), - TOGGLE_PREVIEW(Localization.lang("Toggle entry preview"), IconTheme.JabRefIcons.TOGGLE_ENTRY_PREVIEW, KeyBinding.TOGGLE_ENTRY_PREVIEW), - EDIT_ENTRY(Localization.lang("Edit entry"), IconTheme.JabRefIcons.EDIT_ENTRY, KeyBinding.EDIT_ENTRY), - SHOW_PDV_VIEWER(Localization.lang("Show document viewer"), IconTheme.JabRefIcons.PDF_FILE), - NEXT_PREVIEW_STYLE(Localization.lang("Next preview layout"), KeyBinding.NEXT_PREVIEW_LAYOUT), - PREVIOUS_PREVIEW_STYLE(Localization.lang("Previous preview layout"), KeyBinding.PREVIOUS_PREVIEW_LAYOUT), + EDIT_ENTRY(Localization.lang("Open entry editor"), IconTheme.JabRefIcons.EDIT_ENTRY, KeyBinding.EDIT_ENTRY), + SHOW_PDF_VIEWER(Localization.lang("Open document viewer"), IconTheme.JabRefIcons.PDF_FILE), + TOGGLE_PREVIEW(Localization.lang("Entry preview"), IconTheme.JabRefIcons.TOGGLE_ENTRY_PREVIEW, KeyBinding.TOGGLE_ENTRY_PREVIEW), + NEXT_PREVIEW_STYLE(Localization.lang("Next citation style"), KeyBinding.NEXT_PREVIEW_LAYOUT), + PREVIOUS_PREVIEW_STYLE(Localization.lang("Previous citation style"), KeyBinding.PREVIOUS_PREVIEW_LAYOUT), SELECT_ALL(Localization.lang("Select all"), KeyBinding.SELECT_ALL), NEW_ENTRY(Localization.lang("New entry"), IconTheme.JabRefIcons.ADD_ENTRY, KeyBinding.NEW_ENTRY), @@ -121,21 +124,21 @@ public enum StandardActions implements Action { NEW_ENTRY_FROM_PLAINTEX(Localization.lang("New entry from plain text"), KeyBinding.NEW_FROM_PLAIN_TEXT), LIBRARY_PROPERTIES(Localization.lang("Library properties")), EDIT_PREAMBLE(Localization.lang("Edit preamble")), - EDIT_STRINGS(Localization.lang("Edit strings"), IconTheme.JabRefIcons.EDIT_STRINGS, KeyBinding.EDIT_STRINGS), + EDIT_STRINGS(Localization.lang("Edit string constants"), IconTheme.JabRefIcons.EDIT_STRINGS, KeyBinding.EDIT_STRINGS), FIND_DUPLICATES(Localization.lang("Find duplicates"), IconTheme.JabRefIcons.FIND_DUPLICATES), MERGE_ENTRIES(Localization.lang("Merge entries"), IconTheme.JabRefIcons.MERGE_ENTRIES), RESOLVE_DUPLICATE_KEYS(Localization.lang("Resolve duplicate BibTeX keys"), Localization.lang("Find and remove duplicate BibTeX keys"), KeyBinding.RESOLVE_DUPLICATE_BIBTEX_KEYS), CHECK_INTEGRITY(Localization.lang("Check integrity"), KeyBinding.CHECK_INTEGRITY), - FIND_UNLINKED_FILES(Localization.lang("Find unlinked files"), Localization.lang("Searches for unlinked PDF files on the file system"), KeyBinding.FIND_UNLINKED_FILES), + FIND_UNLINKED_FILES(Localization.lang("Search for unlinked local files"), IconTheme.JabRefIcons.SEARCH, KeyBinding.FIND_UNLINKED_FILES), AUTO_LINK_FILES(Localization.lang("Automatically set file links"), IconTheme.JabRefIcons.AUTO_FILE_LINK, KeyBinding.AUTOMATICALLY_LINK_FILES), - LOOKUP_DOC_IDENTIFIER(Localization.lang("Look up document identifier")), - LOOKUP_FULLTEXT(Localization.lang("Look up full text documents"), KeyBinding.DOWNLOAD_FULL_TEXT), + LOOKUP_DOC_IDENTIFIER(Localization.lang("Search document identifier online")), + LOOKUP_FULLTEXT(Localization.lang("Search full text documents online"), IconTheme.JabRefIcons.FILE_SEARCH, KeyBinding.DOWNLOAD_FULL_TEXT), GENERATE_CITE_KEY(Localization.lang("Generate BibTeX key"), IconTheme.JabRefIcons.MAKE_KEY, KeyBinding.AUTOGENERATE_BIBTEX_KEYS), - GENERATE_CITE_KEYS(Localization.lang("Autogenerate BibTeX keys"), IconTheme.JabRefIcons.MAKE_KEY, KeyBinding.AUTOGENERATE_BIBTEX_KEYS), - DOWNLOAD_FULL_TEXT(Localization.lang("Look up full text documents"), KeyBinding.DOWNLOAD_FULL_TEXT), + GENERATE_CITE_KEYS(Localization.lang("Generate BibTeX keys"), IconTheme.JabRefIcons.MAKE_KEY, KeyBinding.AUTOGENERATE_BIBTEX_KEYS), + DOWNLOAD_FULL_TEXT(Localization.lang("Search full text documents online"), IconTheme.JabRefIcons.FILE_SEARCH, KeyBinding.DOWNLOAD_FULL_TEXT), CLEANUP_ENTRIES(Localization.lang("Cleanup entries"), IconTheme.JabRefIcons.CLEANUP_ENTRIES, KeyBinding.CLEANUP), - SET_FILE_LINKS(Localization.lang("Automatically set file links"), IconTheme.JabRefIcons.AUTO_FILE_LINK, KeyBinding.AUTOMATICALLY_LINK_FILES), + SET_FILE_LINKS(Localization.lang("Automatically set file links"), KeyBinding.AUTOMATICALLY_LINK_FILES), HELP(Localization.lang("Online help"), IconTheme.JabRefIcons.HELP, KeyBinding.HELP), WEB_MENU(Localization.lang("JabRef resources")), diff --git a/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java b/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java index 994452e5efa..e3796c623ee 100644 --- a/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java +++ b/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java @@ -15,6 +15,8 @@ import org.jabref.Globals; import org.jabref.gui.BasePanel; +import org.jabref.gui.actions.ActionFactory; +import org.jabref.gui.actions.StandardActions; import org.jabref.gui.help.HelpAction; import org.jabref.logic.help.HelpFile; import org.jabref.logic.l10n.Localization; @@ -34,7 +36,6 @@ public class BibtexKeyPatternPanel extends Pane { // default pattern protected final TextField defaultPat = new TextField(); - private final HelpAction help; private final int COLUMNS = 2; @@ -45,7 +46,6 @@ public class BibtexKeyPatternPanel extends Pane { public BibtexKeyPatternPanel(BasePanel panel) { this.panel = panel; - help = new HelpAction(Localization.lang("Help on key patterns"), HelpFile.BIBTEX_KEY_PATTERN); gridPane.setHgap(10); gridPane.setVgap(5); buildGUI(); @@ -93,7 +93,7 @@ private void buildGUI() { textFields.put(type.getName().toLowerCase(Locale.ROOT), textField); - if (columnIndex == COLUMNS - 1) { + if (columnIndex == (COLUMNS - 1)) { columnIndex = 0; rowIndex++; } else { @@ -103,9 +103,9 @@ private void buildGUI() { rowIndex++; - Button help1 = new Button("?"); - help1.setOnAction(e -> new HelpAction(Localization.lang("Help on key patterns"), HelpFile.BIBTEX_KEY_PATTERN).getHelpButton().doClick()); - gridPane.add(help1, 1, rowIndex); + ActionFactory factory = new ActionFactory(Globals.prefs.getKeyBindingRepository()); + Button help = factory.createIconButton(StandardActions.HELP, new HelpAction(Localization.lang("Help on key patterns"), HelpFile.BIBTEX_KEY_PATTERN).getCommand()); + gridPane.add(help, 1, rowIndex); Button btnDefaultAll1 = new Button(Localization.lang("Reset all")); btnDefaultAll1.setOnAction(e -> { @@ -118,7 +118,6 @@ private void buildGUI() { gridPane.add(btnDefaultAll1, 2, rowIndex); } - /** * fill the given LabelPattern by values generated from the text fields */ @@ -140,8 +139,7 @@ private void fillPatternUsingPanelData(AbstractBibtexKeyPattern keypatterns) { protected GlobalBibtexKeyPattern getKeyPatternAsGlobalBibtexKeyPattern() { GlobalBibtexKeyPattern res = GlobalBibtexKeyPattern.fromPattern( - JabRefPreferences.getInstance().get(JabRefPreferences.DEFAULT_BIBTEX_KEY_PATTERN) - ); + JabRefPreferences.getInstance().get(JabRefPreferences.DEFAULT_BIBTEX_KEY_PATTERN)); fillPatternUsingPanelData(res); return res; } @@ -162,7 +160,7 @@ public void setValues(AbstractBibtexKeyPattern keyPattern) { setValue(entry.getValue(), entry.getKey(), keyPattern); } - if (keyPattern.getDefaultValue() == null || keyPattern.getDefaultValue().isEmpty()) { + if ((keyPattern.getDefaultValue() == null) || keyPattern.getDefaultValue().isEmpty()) { defaultPat.setText(""); } else { defaultPat.setText(keyPattern.getDefaultValue().get(0)); diff --git a/src/main/java/org/jabref/gui/actions/CustomizeEntryAction.java b/src/main/java/org/jabref/gui/customentrytypes/CustomizeEntryAction.java similarity index 54% rename from src/main/java/org/jabref/gui/actions/CustomizeEntryAction.java rename to src/main/java/org/jabref/gui/customentrytypes/CustomizeEntryAction.java index b8ea7ee567b..3fb6a635a53 100644 --- a/src/main/java/org/jabref/gui/actions/CustomizeEntryAction.java +++ b/src/main/java/org/jabref/gui/customentrytypes/CustomizeEntryAction.java @@ -1,9 +1,7 @@ -package org.jabref.gui.actions; - -import javax.swing.JDialog; +package org.jabref.gui.customentrytypes; import org.jabref.gui.JabRefFrame; -import org.jabref.gui.customentrytypes.EntryTypeCustomizationDialog; +import org.jabref.gui.actions.SimpleCommand; public class CustomizeEntryAction extends SimpleCommand { @@ -15,7 +13,7 @@ public CustomizeEntryAction(JabRefFrame frame) { @Override public void execute() { - JDialog dialog = new EntryTypeCustomizationDialog(frame); - dialog.setVisible(true); + EntryTypeCustomizationDialog dialog = new EntryTypeCustomizationDialog(); + dialog.showAndWait(); } } diff --git a/src/main/java/org/jabref/gui/customentrytypes/EntryTypeCustomizationDialog.java b/src/main/java/org/jabref/gui/customentrytypes/EntryTypeCustomizationDialog.java index 0361f3013a1..cf0439125d1 100644 --- a/src/main/java/org/jabref/gui/customentrytypes/EntryTypeCustomizationDialog.java +++ b/src/main/java/org/jabref/gui/customentrytypes/EntryTypeCustomizationDialog.java @@ -1,56 +1,11 @@ package org.jabref.gui.customentrytypes; -import java.awt.BorderLayout; -import java.awt.Container; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.GridLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -import javax.swing.AbstractAction; -import javax.swing.ActionMap; -import javax.swing.BorderFactory; -import javax.swing.InputMap; -import javax.swing.JButton; -import javax.swing.JComponent; -import javax.swing.JList; -import javax.swing.JPanel; -import javax.swing.ListSelectionModel; -import javax.swing.event.ListDataEvent; -import javax.swing.event.ListDataListener; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; - -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.logic.l10n.Localization; -import org.jabref.model.EntryTypes; -import org.jabref.model.database.BibDatabaseMode; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.CustomEntryType; -import org.jabref.model.entry.EntryType; -import org.jabref.model.entry.InternalBibtexFields; -import org.jabref.model.strings.StringUtil; - -import com.jgoodies.forms.builder.ButtonBarBuilder; - -public class EntryTypeCustomizationDialog extends JabRefDialog implements ListSelectionListener { +import org.jabref.gui.util.BaseDialog; +public class EntryTypeCustomizationDialog extends BaseDialog { + + // TODO: Re-implement customize entry types feature (https://github.com/JabRef/jabref/issues/4719) + /* protected GridBagLayout gbl = new GridBagLayout(); protected GridBagConstraints con = new GridBagConstraints(); protected JButton delete; @@ -70,9 +25,6 @@ public class EntryTypeCustomizationDialog extends JabRefDialog implements ListSe private boolean biblatexMode; private BibDatabaseMode bibDatabaseMode; - /** - * Creates a new instance of EntryTypeCustomizationDialog - */ public EntryTypeCustomizationDialog(JabRefFrame frame) { super(Localization.lang("Customize entry types"), false, EntryTypeCustomizationDialog.class); @@ -419,6 +371,7 @@ private void record() { changed.add(lastSelected); typeComp.enable(lastSelected, true); } - } + + */ } diff --git a/src/main/java/org/jabref/gui/edit/ManageKeywordsAction.java b/src/main/java/org/jabref/gui/edit/ManageKeywordsAction.java new file mode 100644 index 00000000000..333e206cd02 --- /dev/null +++ b/src/main/java/org/jabref/gui/edit/ManageKeywordsAction.java @@ -0,0 +1,34 @@ +package org.jabref.gui.edit; + +import org.jabref.gui.BasePanel; +import org.jabref.gui.JabRefFrame; +import org.jabref.gui.actions.SimpleCommand; +import org.jabref.logic.l10n.Localization; + +/** + * An Action for launching keyword managing dialog + * + */ +public class ManageKeywordsAction extends SimpleCommand { + + private final JabRefFrame frame; + + public ManageKeywordsAction(JabRefFrame frame) { + this.frame = frame; + } + + @Override + public void execute() { + BasePanel basePanel = frame.getCurrentBasePanel(); + if (basePanel == null) { + return; + } + if (basePanel.getSelectedEntries().isEmpty()) { + basePanel.output(Localization.lang("Select at least one entry to manage keywords.")); + return; + } + + ManageKeywordsDialog dialog = new ManageKeywordsDialog(basePanel.getSelectedEntries()); + dialog.showAndWait(); + } +} diff --git a/src/main/java/org/jabref/gui/edit/ManageKeywordsDialog.fxml b/src/main/java/org/jabref/gui/edit/ManageKeywordsDialog.fxml new file mode 100644 index 00000000000..609c6655bb9 --- /dev/null +++ b/src/main/java/org/jabref/gui/edit/ManageKeywordsDialog.fxml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/org/jabref/gui/edit/ManageKeywordsDialog.java b/src/main/java/org/jabref/gui/edit/ManageKeywordsDialog.java new file mode 100644 index 00000000000..2b1201fd24e --- /dev/null +++ b/src/main/java/org/jabref/gui/edit/ManageKeywordsDialog.java @@ -0,0 +1,83 @@ +package org.jabref.gui.edit; + +import java.util.List; + +import javax.inject.Inject; + +import javafx.fxml.FXML; +import javafx.scene.control.ButtonType; +import javafx.scene.control.TableColumn; +import javafx.scene.control.TableView; +import javafx.scene.control.ToggleGroup; +import javafx.scene.control.cell.TextFieldTableCell; + +import org.jabref.gui.icon.IconTheme; +import org.jabref.gui.util.BaseDialog; +import org.jabref.gui.util.BindingsHelper; +import org.jabref.gui.util.ValueTableCellFactory; +import org.jabref.logic.l10n.Localization; +import org.jabref.model.entry.BibEntry; +import org.jabref.preferences.PreferencesService; + +import com.airhacks.afterburner.views.ViewLoader; +import org.fxmisc.easybind.EasyBind; + +public class ManageKeywordsDialog extends BaseDialog { + private final List entries; + @FXML private TableColumn keywordsTableMainColumn; + @FXML private TableColumn keywordsTableEditColumn; + @FXML private TableColumn keywordsTableDeleteColumn; + @FXML private TableView keywordsTable; + @FXML private ToggleGroup displayType; + @Inject private PreferencesService preferences; + private ManageKeywordsViewModel viewModel; + + public ManageKeywordsDialog(List entries) { + this.entries = entries; + this.setTitle(Localization.lang("Manage keywords")); + + ViewLoader.view(this) + .load() + .setAsDialogPane(this); + + setResultConverter(button -> { + if (button == ButtonType.APPLY) { + viewModel.saveChanges(); + } + return null; + }); + } + + @FXML + public void initialize() { + viewModel = new ManageKeywordsViewModel(preferences, entries); + + viewModel.displayTypeProperty().bind( + EasyBind.map(displayType.selectedToggleProperty(), toggle -> { + if (toggle != null) { + return (ManageKeywordsDisplayType) toggle.getUserData(); + } else { + return ManageKeywordsDisplayType.CONTAINED_IN_ALL_ENTRIES; + } + }) + ); + + keywordsTable.setItems(viewModel.getKeywords()); + keywordsTableMainColumn.setCellValueFactory(data -> BindingsHelper.constantOf(data.getValue())); + keywordsTableMainColumn.setOnEditCommit(event -> { + // Poor mans reverse databinding (necessary because we use a constant value above) + viewModel.getKeywords().set(event.getTablePosition().getRow(), event.getNewValue()); + }); + keywordsTableMainColumn.setCellFactory(TextFieldTableCell.forTableColumn()); + keywordsTableEditColumn.setCellValueFactory(data -> BindingsHelper.constantOf(true)); + keywordsTableDeleteColumn.setCellValueFactory(data -> BindingsHelper.constantOf(true)); + new ValueTableCellFactory() + .withGraphic(none -> IconTheme.JabRefIcons.EDIT.getGraphicNode()) + .withOnMouseClickedEvent(none -> event -> keywordsTable.edit(keywordsTable.getFocusModel().getFocusedIndex(), keywordsTableMainColumn)) + .install(keywordsTableEditColumn); + new ValueTableCellFactory() + .withGraphic(none -> IconTheme.JabRefIcons.REMOVE.getGraphicNode()) + .withOnMouseClickedEvent((keyword, none) -> event -> viewModel.removeKeyword(keyword)) + .install(keywordsTableDeleteColumn); + } +} diff --git a/src/main/java/org/jabref/gui/edit/ManageKeywordsDisplayType.java b/src/main/java/org/jabref/gui/edit/ManageKeywordsDisplayType.java new file mode 100644 index 00000000000..0af51af0734 --- /dev/null +++ b/src/main/java/org/jabref/gui/edit/ManageKeywordsDisplayType.java @@ -0,0 +1,6 @@ +package org.jabref.gui.edit; + +public enum ManageKeywordsDisplayType { + CONTAINED_IN_ALL_ENTRIES, + CONTAINED_IN_ANY_ENTRY, +} diff --git a/src/main/java/org/jabref/gui/edit/ManageKeywordsViewModel.java b/src/main/java/org/jabref/gui/edit/ManageKeywordsViewModel.java new file mode 100644 index 00000000000..c071e652033 --- /dev/null +++ b/src/main/java/org/jabref/gui/edit/ManageKeywordsViewModel.java @@ -0,0 +1,139 @@ +package org.jabref.gui.edit; + +import java.util.List; +import java.util.Optional; + +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; + +import 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.entry.BibEntry; +import org.jabref.model.entry.Keyword; +import org.jabref.model.entry.KeywordList; +import org.jabref.preferences.PreferencesService; + +import org.fxmisc.easybind.EasyBind; + +public class ManageKeywordsViewModel { + + private final List entries; + private final KeywordList sortedKeywordsOfAllEntriesBeforeUpdateByUser = new KeywordList(); + private final PreferencesService preferences; + private final ObjectProperty displayType = new SimpleObjectProperty<>(ManageKeywordsDisplayType.CONTAINED_IN_ALL_ENTRIES); + private final ObservableList keywords; + + public ManageKeywordsViewModel(PreferencesService preferences, List entries) { + this.preferences = preferences; + this.entries = entries; + this.keywords = FXCollections.observableArrayList(); + + EasyBind.subscribe(displayType, this::fillKeywordsList); + } + + public ManageKeywordsDisplayType getDisplayType() { + return displayType.get(); + } + + public ObjectProperty displayTypeProperty() { + return displayType; + } + + private void fillKeywordsList(ManageKeywordsDisplayType type) { + keywords.clear(); + sortedKeywordsOfAllEntriesBeforeUpdateByUser.clear(); + + if (type == ManageKeywordsDisplayType.CONTAINED_IN_ALL_ENTRIES) { + for (BibEntry entry : entries) { + KeywordList separatedKeywords = entry.getKeywords(preferences.getKeywordDelimiter()); + sortedKeywordsOfAllEntriesBeforeUpdateByUser.addAll(separatedKeywords); + } + } else if (type == ManageKeywordsDisplayType.CONTAINED_IN_ANY_ENTRY) { + + // all keywords from first entry have to be added + BibEntry firstEntry = entries.get(0); + KeywordList separatedKeywords = firstEntry.getKeywords(preferences.getKeywordDelimiter()); + sortedKeywordsOfAllEntriesBeforeUpdateByUser.addAll(separatedKeywords); + + // for the remaining entries, intersection has to be used + // this approach ensures that one empty keyword list leads to an empty set of common keywords + for (BibEntry entry : entries) { + separatedKeywords = entry.getKeywords(preferences.getKeywordDelimiter()); + sortedKeywordsOfAllEntriesBeforeUpdateByUser.retainAll(separatedKeywords); + } + } else { + throw new IllegalStateException("DisplayType " + type + " not handled"); + } + for (Keyword keyword : sortedKeywordsOfAllEntriesBeforeUpdateByUser) { + keywords.add(keyword.get()); + } + } + + public ObservableList getKeywords() { + return keywords; + } + + public void removeKeyword(String keyword) { + keywords.remove(keyword); + } + + public void saveChanges() { + KeywordList keywordsToAdd = new KeywordList(); + KeywordList userSelectedKeywords = new KeywordList(); + // build keywordsToAdd and userSelectedKeywords in parallel + for (String keyword : keywords) { + userSelectedKeywords.add(keyword); + if (!sortedKeywordsOfAllEntriesBeforeUpdateByUser.contains(keyword)) { + keywordsToAdd.add(keyword); + } + } + + KeywordList keywordsToRemove = new KeywordList(); + for (Keyword kword : sortedKeywordsOfAllEntriesBeforeUpdateByUser) { + if (!userSelectedKeywords.contains(kword)) { + keywordsToRemove.add(kword); + } + } + + if (keywordsToAdd.isEmpty() && keywordsToRemove.isEmpty()) { + // nothing to be done if nothing is new and nothing is obsolete + return; + } + + if (preferences.isKeywordSyncEnabled() && !keywordsToAdd.isEmpty()) { + SpecialFieldsUtils.synchronizeSpecialFields(keywordsToAdd, keywordsToRemove); + } + + NamedCompound ce = updateKeywords(entries, keywordsToAdd, keywordsToRemove); + //TODO: bp.getUndoManager().addEdit(ce); + } + + private NamedCompound updateKeywords(List entries, KeywordList keywordsToAdd, + KeywordList keywordsToRemove) { + NamedCompound ce = new NamedCompound(Localization.lang("Update keywords")); + for (BibEntry entry : entries) { + KeywordList keywords = entry.getKeywords(preferences.getKeywordDelimiter()); + + // update keywords + keywords.removeAll(keywordsToRemove); + keywords.addAll(keywordsToAdd); + + // put keywords back + Optional change = entry.putKeywords(keywords, preferences.getKeywordDelimiter()); + if (change.isPresent()) { + ce.addEdit(new UndoableFieldChange(change.get())); + } + + if (preferences.isKeywordSyncEnabled()) { + SpecialFieldsUtils.syncSpecialFieldsFromKeywords(entry, preferences.getKeywordDelimiter()); + } + } + ce.end(); + return ce; + } +} diff --git a/src/main/java/org/jabref/gui/fieldeditors/contextmenu/ProtectedTermsMenu.java b/src/main/java/org/jabref/gui/fieldeditors/contextmenu/ProtectedTermsMenu.java index 4af7fec8023..85bd758232d 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/contextmenu/ProtectedTermsMenu.java +++ b/src/main/java/org/jabref/gui/fieldeditors/contextmenu/ProtectedTermsMenu.java @@ -3,16 +3,12 @@ import java.util.List; import java.util.stream.Collectors; -import javax.swing.SwingUtilities; - import javafx.scene.control.Menu; import javafx.scene.control.MenuItem; import javafx.scene.control.SeparatorMenuItem; import javafx.scene.control.TextInputControl; import org.jabref.Globals; -import org.jabref.JabRefGUI; -import org.jabref.gui.protectedterms.NewProtectedTermsFileDialog; import org.jabref.logic.formatter.casechanger.ProtectTermsFormatter; import org.jabref.logic.l10n.Localization; import org.jabref.logic.protectedterms.ProtectedTermsList; @@ -65,21 +61,5 @@ private void updateFiles() { externalFiles.getItems().add(fileItem); } externalFiles.getItems().add(new SeparatorMenuItem()); - MenuItem addToNewFileItem = new MenuItem(Localization.lang("New") + "..."); - addToNewFileItem.setOnAction(event -> { - NewProtectedTermsFileDialog dialog = new NewProtectedTermsFileDialog(JabRefGUI.getMainFrame().getDialogService(), - loader); - - SwingUtilities.invokeLater(() -> { - dialog.setVisible(true); - - if (dialog.isOKPressed()) { - // Update preferences with new list - Globals.prefs.setProtectedTermsPreferences(loader); - this.updateFiles(); - } - }); - }); - externalFiles.getItems().add(addToNewFileItem); } } diff --git a/src/main/java/org/jabref/gui/help/HelpAction.java b/src/main/java/org/jabref/gui/help/HelpAction.java index ab7ae84e027..e8d410de343 100644 --- a/src/main/java/org/jabref/gui/help/HelpAction.java +++ b/src/main/java/org/jabref/gui/help/HelpAction.java @@ -1,11 +1,7 @@ package org.jabref.gui.help; -import java.awt.Color; -import java.awt.Cursor; import java.awt.Dimension; import java.awt.event.ActionEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; import java.util.HashSet; import java.util.Set; import java.util.stream.Collectors; @@ -14,7 +10,6 @@ import javax.swing.Action; import javax.swing.Icon; import javax.swing.JButton; -import javax.swing.JLabel; import javax.swing.KeyStroke; import org.jabref.Globals; @@ -91,20 +86,6 @@ public void setHelpFile(HelpFile urlPart) { this.helpPage = urlPart; } - public JLabel getHelpLabel(String labelText) { - JLabel helpLabel = new JLabel("" + labelText + ""); - helpLabel.setForeground(Color.BLUE); - helpLabel.setCursor(new Cursor(Cursor.HAND_CURSOR)); - helpLabel.addMouseListener(new MouseAdapter() { - - @Override - public void mouseClicked(MouseEvent e) { - openHelpPage(helpPage); - } - }); - return helpLabel; - } - @Override public void actionPerformed(ActionEvent e) { openHelpPage(helpPage); diff --git a/src/main/java/org/jabref/gui/icon/IconTheme.java b/src/main/java/org/jabref/gui/icon/IconTheme.java index 5c0510f862a..49cfe8ba53a 100644 --- a/src/main/java/org/jabref/gui/icon/IconTheme.java +++ b/src/main/java/org/jabref/gui/icon/IconTheme.java @@ -205,6 +205,7 @@ public enum JabRefIcons implements JabRefIcon { REFRESH(MaterialDesignIcon.REFRESH), DELETE_ENTRY(MaterialDesignIcon.DELETE), SEARCH(MaterialDesignIcon.MAGNIFY), + FILE_SEARCH(MaterialDesignIcon.FILE_FIND), ADVANCED_SEARCH(Color.CYAN, MaterialDesignIcon.MAGNIFY), PREFERENCES(MaterialDesignIcon.SETTINGS), HELP(MaterialDesignIcon.HELP_CIRCLE), @@ -238,7 +239,7 @@ public enum JabRefIcons implements JabRefIcon { AUTO_FILE_LINK(MaterialDesignIcon.FILE_FIND) /*css: file-find */, QUALITY_ASSURED(MaterialDesignIcon.CERTIFICATE), /*css: certificate */ QUALITY(MaterialDesignIcon.CERTIFICATE),/*css: certificate */ - OPEN(MaterialDesignIcon.FOLDER) /*css: folder */, + OPEN(MaterialDesignIcon.FOLDER_OUTLINE) /*css: folder-outline */, ADD_ROW(MaterialDesignIcon.SERVER_PLUS) /* css: server-plus*/, REMOVE_ROW(MaterialDesignIcon.SERVER_MINUS) /*css: server-minus */, PICTURE(MaterialDesignIcon.FILE_IMAGE) /*css: file-image */, @@ -276,7 +277,7 @@ public enum JabRefIcons implements JabRefIcon { APPLICATION_WINEDT(JabRefMaterialDesignIcon.WINEDT), KEY_BINDINGS(MaterialDesignIcon.KEYBOARD), /*css: keyboard */ FIND_DUPLICATES(MaterialDesignIcon.CODE_EQUAL), /*css: code-equal */ - PULL(MaterialDesignIcon.SOURCE_PULL), /*source-pull*/ + CONNECT_DB(MaterialDesignIcon.CLOUD_UPLOAD), /*cloud-upload*/ SUCCESS(MaterialDesignIcon.CHECK_CIRCLE), WARNING(MaterialDesignIcon.ALERT), ERROR(MaterialDesignIcon.ALERT_CIRCLE), @@ -293,7 +294,8 @@ public enum JabRefIcons implements JabRefIcon { DEFAULT_GROUP_ICON_COLORED(MaterialDesignIcon.PLAY), DEFAULT_GROUP_ICON(MaterialDesignIcon.LABEL_OUTLINE), ALL_ENTRIES_GROUP_ICON(DefaultGroupsFactory.ALL_ENTRIES_GROUP_DEFAULT_ICON), - IMPORT_EXPORT(MaterialDesignIcon.SWAP_VERTICAL), + IMPORT(MaterialDesignIcon.CALL_RECEIVED), + EXPORT(MaterialDesignIcon.CALL_MADE), PREVIOUS_LEFT(MaterialDesignIcon.CHEVRON_LEFT), PREVIOUS_UP(MaterialDesignIcon.CHEVRON_UP), NEXT_RIGHT(MaterialDesignIcon.CHEVRON_RIGHT), 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 9a87333b386..67bd022cbc0 100644 --- a/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java +++ b/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java @@ -35,7 +35,6 @@ import org.jabref.logic.shared.exception.InvalidDBMSConnectionPropertiesException; import org.jabref.logic.shared.exception.NotASharedDatabaseException; import org.jabref.logic.util.StandardFileType; -import org.jabref.migrations.FileLinksUpgradeWarning; import org.jabref.model.database.BibDatabase; import org.jabref.model.database.shared.DatabaseNotSupportedException; import org.jabref.preferences.JabRefPreferences; @@ -53,9 +52,6 @@ public class OpenDatabaseAction extends SimpleCommand { // Migrations: // Warning for migrating the Review into the Comment field new MergeReviewIntoCommentAction(), - // External file handling system in version 2.3: - new FileLinksUpgradeWarning(), - // Check for new custom entry types loaded from the BIB file: new CheckForNewEntryTypesAction() ); diff --git a/src/main/java/org/jabref/gui/journals/JournalAbbreviationsUtil.java b/src/main/java/org/jabref/gui/journals/JournalAbbreviationsUtil.java deleted file mode 100644 index 86a284cd78f..00000000000 --- a/src/main/java/org/jabref/gui/journals/JournalAbbreviationsUtil.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.jabref.gui.journals; - -import java.util.Collection; - -import javax.swing.table.DefaultTableModel; -import javax.swing.table.TableModel; - -import org.jabref.logic.journals.Abbreviation; -import org.jabref.logic.l10n.Localization; - -public class JournalAbbreviationsUtil { - - private JournalAbbreviationsUtil() { - } - - public static TableModel getTableModel(Collection abbreviations) { - Object[][] cells = new Object[abbreviations.size()][2]; - int row = 0; - for (Abbreviation abbreviation : abbreviations) { - cells[row][0] = abbreviation.getName(); - cells[row][1] = abbreviation.getIsoAbbreviation(); - row++; - } - - return new DefaultTableModel(cells, new Object[] {Localization.lang("Full name"), - Localization.lang("Abbreviation")}) { - - @Override - public boolean isCellEditable(int row1, int column) { - return false; - } - }; - } -} diff --git a/src/main/java/org/jabref/gui/preferences/AdvancedTab.java b/src/main/java/org/jabref/gui/preferences/AdvancedTab.java index 3fcd0516ce5..4a8dbf0a075 100644 --- a/src/main/java/org/jabref/gui/preferences/AdvancedTab.java +++ b/src/main/java/org/jabref/gui/preferences/AdvancedTab.java @@ -15,6 +15,8 @@ import org.jabref.Globals; import org.jabref.gui.DialogService; +import org.jabref.gui.actions.ActionFactory; +import org.jabref.gui.actions.StandardActions; import org.jabref.gui.help.HelpAction; import org.jabref.gui.remote.JabRefMessageHandler; import org.jabref.gui.util.DefaultTaskExecutor; @@ -76,9 +78,11 @@ public AdvancedTab(DialogService dialogService, JabRefPreferences prefs) { HBox p = new HBox(); p.getChildren().add(useRemoteServer); p.getChildren().add(remoteServerPort); - Button helpButton = new Button("?"); - helpButton.setOnAction(event -> new HelpAction(HelpFile.REMOTE).getHelpButton().doClick()); - p.getChildren().add(helpButton); + + ActionFactory factory = new ActionFactory(preferences.getKeyBindingRepository()); + Button help = factory.createIconButton(StandardActions.HELP, new HelpAction(HelpFile.REMOTE).getCommand()); + help.setMaxWidth(Double.MAX_VALUE); + p.getChildren().add(help); builder.add(p, 2, 9); builder.add(new Label(""), 1, 10); diff --git a/src/main/java/org/jabref/gui/preferences/ExternalTab.java b/src/main/java/org/jabref/gui/preferences/ExternalTab.java index 782a14fa11d..0328eaf4e1b 100644 --- a/src/main/java/org/jabref/gui/preferences/ExternalTab.java +++ b/src/main/java/org/jabref/gui/preferences/ExternalTab.java @@ -1,13 +1,6 @@ package org.jabref.gui.preferences; -import java.awt.BorderLayout; - -import javax.swing.JFileChooser; -import javax.swing.JPanel; - -import javafx.embed.swing.JFXPanel; import javafx.scene.Node; -import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.CheckBox; import javafx.scene.control.Label; @@ -17,18 +10,19 @@ import javafx.scene.layout.GridPane; import org.jabref.Globals; +import org.jabref.gui.DialogService; import org.jabref.gui.JabRefFrame; -import org.jabref.gui.customjfx.CustomJFXPanel; import org.jabref.gui.externalfiletype.ExternalFileTypeEditor; import org.jabref.gui.push.PushToApplication; import org.jabref.gui.push.PushToApplicationSettings; import org.jabref.gui.push.PushToApplicationSettingsDialog; import org.jabref.gui.push.PushToApplications; +import org.jabref.gui.util.FileDialogConfiguration; import org.jabref.logic.l10n.Localization; import org.jabref.logic.util.OS; import org.jabref.preferences.JabRefPreferences; -class ExternalTab extends JPanel implements PrefsTab { +class ExternalTab implements PrefsTab { private final JabRefPreferences prefs; private final TextField emailSubject; @@ -45,12 +39,15 @@ class ExternalTab extends JPanel implements PrefsTab { private final TextField adobeAcrobatReaderPath; private final TextField sumatraReaderPath; private final GridPane builder = new GridPane(); + private final DialogService dialogService; + private final FileDialogConfiguration fileDialogConfiguration = new FileDialogConfiguration.Builder().build(); public ExternalTab(JabRefFrame frame, PreferencesDialog prefsDiag, JabRefPreferences prefs) { this.prefs = prefs; + dialogService = frame.getDialogService(); Button editFileTypes = new Button(Localization.lang("Manage external file types")); citeCommand = new TextField(); - editFileTypes.setOnAction(e->ExternalFileTypeEditor.getAction()); + editFileTypes.setOnAction(e -> ExternalFileTypeEditor.getAction()); defaultConsole = new RadioButton(Localization.lang("Use default terminal emulator")); executeConsole = new RadioButton(Localization.lang("Execute command") + ":"); consoleCommand = new TextField(); @@ -73,25 +70,25 @@ public ExternalTab(JabRefFrame frame, PreferencesDialog prefsDiag, JabRefPrefere final ToggleGroup consoleGroup = new ToggleGroup(); defaultConsole.setToggleGroup(consoleGroup); executeConsole.setToggleGroup(consoleGroup); - consoleOptionPanel.add(defaultConsole, 1, 1); - consoleOptionPanel.add(executeConsole, 1, 2); - consoleOptionPanel.add(consoleCommand, 2, 2); - consoleOptionPanel.add(browseButton, 3, 2); - consoleOptionPanel.add(commandDescription, 2, 3); + consoleOptionPanel.add(defaultConsole, 1, 1); + consoleOptionPanel.add(executeConsole, 1, 2); + consoleOptionPanel.add(consoleCommand, 2, 2); + consoleOptionPanel.add(browseButton, 3, 2); + consoleOptionPanel.add(commandDescription, 2, 3); GridPane pdfOptionPanel = new GridPane(); final ToggleGroup pdfReaderGroup = new ToggleGroup(); - pdfOptionPanel.add(adobeAcrobatReader, 1, 1); - pdfOptionPanel.add(adobeAcrobatReaderPath, 2, 1); + pdfOptionPanel.add(adobeAcrobatReader, 1, 1); + pdfOptionPanel.add(adobeAcrobatReaderPath, 2, 1); adobeAcrobatReader.setToggleGroup(pdfReaderGroup); - pdfOptionPanel.add(browseAdobeAcrobatReader, 3, 1); + pdfOptionPanel.add(browseAdobeAcrobatReader, 3, 1); if (OS.WINDOWS) { browseSumatraReader.setOnAction(e -> showSumatraChooser()); - pdfOptionPanel.add(sumatraReader, 1, 2); + pdfOptionPanel.add(sumatraReader, 1, 2); sumatraReader.setToggleGroup(pdfReaderGroup); - pdfOptionPanel.add(sumatraReaderPath, 2, 2); - pdfOptionPanel.add(browseSumatraReader, 3, 2); + pdfOptionPanel.add(sumatraReaderPath, 2, 2); + pdfOptionPanel.add(browseSumatraReader, 3, 2); } Label sendingOfEmails = new Label(Localization.lang("Sending of emails")); @@ -132,14 +129,13 @@ public ExternalTab(JabRefFrame frame, PreferencesDialog prefsDiag, JabRefPrefere Label openPdf = new Label(Localization.lang("Open PDF")); openPdf.getStyleClass().add("sectionHeader"); - builder.add(openPdf, 1, 12); + builder.add(openPdf, 1, 12); builder.add(pdfOptionPanel, 1, 13); - JFXPanel panel = CustomJFXPanel.wrap(new Scene(builder)); - setLayout(new BorderLayout()); - add(panel, BorderLayout.CENTER); + } + @Override public Node getBuilder() { return builder; } @@ -149,10 +145,10 @@ private void addSettingsButton(final PushToApplication application, GridPane pan Button button = new Button(Localization.lang("Settings for %0", application.getApplicationName())); button.setPrefSize(150, 20); button.setOnAction(e -> PushToApplicationSettingsDialog.showSettingsDialog(null, settings, index)); - if (index % 2 == 0) { - panel.add(button, 1, index / 2 + 1); + if ((index % 2) == 0) { + panel.add(button, 1, (index / 2) + 1); } else { - panel.add(button, 2, index / 2 + 1); + panel.add(button, 2, (index / 2) + 1); } } @@ -213,27 +209,15 @@ private void updateExecuteConsoleButtonAndFieldEnabledState() { } private void showConsoleChooser() { - JFileChooser consoleChooser = new JFileChooser(); - int answer = consoleChooser.showOpenDialog(ExternalTab.this); - if (answer == JFileChooser.APPROVE_OPTION) { - consoleCommand.setText(consoleChooser.getSelectedFile().getAbsolutePath()); - } + dialogService.showFileOpenDialog(fileDialogConfiguration).ifPresent(file -> consoleCommand.setText(file.toAbsolutePath().toString())); } private void showAdobeChooser() { - JFileChooser adobeChooser = new JFileChooser(); - int answer = adobeChooser.showOpenDialog(ExternalTab.this); - if (answer == JFileChooser.APPROVE_OPTION) { - adobeAcrobatReaderPath.setText(adobeChooser.getSelectedFile().getAbsolutePath()); - } + dialogService.showFileOpenDialog(fileDialogConfiguration).ifPresent(file -> adobeAcrobatReaderPath.setText(file.toAbsolutePath().toString())); } private void showSumatraChooser() { - JFileChooser adobeChooser = new JFileChooser(); - int answer = adobeChooser.showOpenDialog(ExternalTab.this); - if (answer == JFileChooser.APPROVE_OPTION) { - sumatraReaderPath.setText(adobeChooser.getSelectedFile().getAbsolutePath()); - } + dialogService.showFileOpenDialog(fileDialogConfiguration).ifPresent(file -> sumatraReaderPath.setText(file.toAbsolutePath().toString())); } private void readerSelected() { diff --git a/src/main/java/org/jabref/gui/preferences/FileTab.java b/src/main/java/org/jabref/gui/preferences/FileTab.java index 55e599e67ae..3bbc387f130 100644 --- a/src/main/java/org/jabref/gui/preferences/FileTab.java +++ b/src/main/java/org/jabref/gui/preferences/FileTab.java @@ -211,7 +211,7 @@ public void storeSettings() { } String newline; - switch (newlineSeparator.getPromptText()) { + switch (newlineSeparator.getValue()) { case "CR": newline = "\r"; break; diff --git a/src/main/java/org/jabref/gui/protectedterms/ManageProtectedTermsAction.java b/src/main/java/org/jabref/gui/protectedterms/ManageProtectedTermsAction.java new file mode 100644 index 00000000000..34f4ff3f116 --- /dev/null +++ b/src/main/java/org/jabref/gui/protectedterms/ManageProtectedTermsAction.java @@ -0,0 +1,12 @@ +package org.jabref.gui.protectedterms; + +import org.jabref.gui.actions.SimpleCommand; + +public class ManageProtectedTermsAction extends SimpleCommand { + + @Override + public void execute() { + ManageProtectedTermsDialog protectTermsDialog = new ManageProtectedTermsDialog(); + protectTermsDialog.showAndWait(); + } +} diff --git a/src/main/java/org/jabref/gui/protectedterms/ManageProtectedTermsDialog.fxml b/src/main/java/org/jabref/gui/protectedterms/ManageProtectedTermsDialog.fxml new file mode 100644 index 00000000000..0b23bc0ccaf --- /dev/null +++ b/src/main/java/org/jabref/gui/protectedterms/ManageProtectedTermsDialog.fxml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +