fields;
private final EntryEditor parent;
private final Map editors = new LinkedHashMap<>();
- private final FocusListener fieldListener = new EntryEditorTabFocusListener(this);
private final String tabTitle;
private final JabRefFrame frame;
private final BasePanel basePanel;
@@ -256,15 +247,11 @@ private String getPrompt(String field) {
return "";
}
- private BibEntry getEntry() {
- return entry;
- }
-
public void setEntry(BibEntry entry) {
try {
updating = true;
for (FieldEditorFX editor : editors.values()) {
- DefaultTaskExecutor.runInJavaFXThread(() -> editor.bindToEntry(entry));
+ editor.bindToEntry(entry);
}
this.entry = entry;
} finally {
@@ -272,41 +259,11 @@ public void setEntry(BibEntry entry) {
}
}
- private boolean isFieldModified(FieldEditor fieldEditor) {
- String text = fieldEditor.getText().trim();
-
- if (text.isEmpty()) {
- return getEntry().hasField(fieldEditor.getFieldName());
- } else {
- return !Optional.of(text).equals(getEntry().getField(fieldEditor.getFieldName()));
- }
- }
-
- public void markIfModified(FieldEditor fieldEditor) {
- // Only mark as changed if not already is and the field was indeed modified
- if (!updating && !basePanel.isModified() && isFieldModified(fieldEditor)) {
- markBaseChanged();
- }
- }
-
- private void markBaseChanged() {
- basePanel.markBaseChanged();
- }
-
/**
* Only sets the activeField variable but does not focus it.
*
* If you want to focus it call {@link #focus()} afterwards.
*/
- // TODO: Reenable or delete this
- //public void setActive(FieldEditor fieldEditor) {
- // activeField = fieldEditor;
- //}
-
- //public FieldEditor getActive() {
- // return activeField;
- //}
-
public void setActive(String fieldName) {
if (editors.containsKey(fieldName)) {
activeField = editors.get(fieldName);
@@ -323,13 +280,6 @@ public void focus() {
}
}
- /**
- * Reset all fields from the data in the BibEntry.
- */
- public void updateAll() {
- setEntry(getEntry());
- }
-
public boolean updateField(String field, String content) {
if (!editors.containsKey(field)) {
return false;
@@ -358,15 +308,6 @@ public boolean updateField(String field, String content) {
return true;
}
- public void setEnabled(boolean enabled) {
- /*
- // TODO: Reenable this
- for (FieldEditor editor : editors.values()) {
- editor.setEnabled(enabled);
- }
- */
- }
-
public Component getPane() {
return panel;
}
@@ -402,40 +343,4 @@ private void setupKeyBindings(final InputMap inputMap, final ActionMap actionMap
inputMap.put(Globals.getKeyPrefs().getKey(KeyBinding.PREVIOUS_TAB), "prevtab");
actionMap.put("prevtab", this.frame.prevTab);
}
-
- /**
- * Set up key bindings and focus listener for the FieldEditor.
- *
- * @param component
- */
- private void setupJTextComponent(final JComponent component, final AutoCompleteListener autoCompleteListener) {
-
- // Here we add focus listeners to the component. The funny code is because we need
- // to guarantee that the AutoCompleteListener - if used - is called before fieldListener
- // on a focus lost event. The AutoCompleteListener is responsible for removing any
- // current suggestion when focus is lost, and this must be done before fieldListener
- // stores the current edit. Swing doesn't guarantee the order of execution of event
- // listeners, so we handle this by only adding the AutoCompleteListener and telling
- // it to call fieldListener afterwards. If no AutoCompleteListener is used, we
- // add the fieldListener normally.
- if (autoCompleteListener == null) {
- component.addFocusListener(fieldListener);
- } else {
- component.addKeyListener(autoCompleteListener);
- component.addFocusListener(autoCompleteListener);
- autoCompleteListener.setNextFocusListener(fieldListener);
- }
-
- setupKeyBindings(component.getInputMap(JComponent.WHEN_FOCUSED), component.getActionMap());
-
- Set keys = new HashSet<>(
- component.getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS));
- keys.clear();
- keys.add(AWTKeyStroke.getAWTKeyStroke("pressed TAB"));
- component.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, keys);
- keys = new HashSet<>(component.getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS));
- keys.clear();
- keys.add(KeyStroke.getKeyStroke("shift pressed TAB"));
- component.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, keys);
- }
}
diff --git a/src/main/java/org/jabref/gui/entryeditor/EntryEditorTabFocusListener.java b/src/main/java/org/jabref/gui/entryeditor/EntryEditorTabFocusListener.java
deleted file mode 100644
index c0b0bcfe299..00000000000
--- a/src/main/java/org/jabref/gui/entryeditor/EntryEditorTabFocusListener.java
+++ /dev/null
@@ -1,103 +0,0 @@
-package org.jabref.gui.entryeditor;
-
-import java.awt.Component;
-import java.awt.Rectangle;
-import java.awt.event.FocusEvent;
-import java.awt.event.FocusListener;
-
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.event.DocumentEvent;
-import javax.swing.event.DocumentListener;
-import javax.swing.text.JTextComponent;
-
-import org.jabref.gui.fieldeditors.FieldEditor;
-
-
-/**
- * Focus listener that fires the storeFieldAction when a TextArea loses focus.
- */
-class EntryEditorTabFocusListener implements FocusListener {
-
- /**
- * The EntryEditorTab this FocusListener is currently tied to
- */
- private final EntryEditorTab entryEditorTab;
- /** The component this DocumentListener is currently tied to */
- private JTextComponent textComponent;
- /** The listener which gets tied to each TextComponent (and removed) */
- private DocumentListener documentListener;
-
-
- public EntryEditorTabFocusListener(final EntryEditorTab entryEditorTab) {
- this.entryEditorTab = entryEditorTab;
- }
-
- @Override
- public void focusGained(FocusEvent event) {
- synchronized (this) {
- if (textComponent != null) {
- textComponent.getDocument().removeDocumentListener(documentListener);
- textComponent = null;
- documentListener = null;
- }
-
- if (event.getSource() instanceof JTextComponent) {
- textComponent = (JTextComponent) event.getSource();
- documentListener = new DocumentListener() {
- private void fire() {
- if (textComponent.isFocusOwner()) {
- entryEditorTab.markIfModified((FieldEditor) textComponent);
- }
- }
-
- @Override
- public void changedUpdate(DocumentEvent e) {
- fire();
- }
-
- @Override
- public void insertUpdate(DocumentEvent e) {
- fire();
- }
-
- @Override
- public void removeUpdate(DocumentEvent e) {
- fire();
- }
- };
- textComponent.getDocument().addDocumentListener(documentListener);
-
- // Makes the vertical scroll panel view follow the focus
- Component component = textComponent.getParent().getParent();
- if (component instanceof JScrollPane) {
- JScrollPane scrollPane = (JScrollPane) component;
- Component scrollPaneParent = scrollPane.getParent();
- if (scrollPaneParent instanceof JPanel) {
- JPanel panel = (JPanel) scrollPaneParent;
- Rectangle bounds = scrollPane.getBounds();
- panel.scrollRectToVisible(bounds);
- }
- }
-
- }
- }
- // TODO: Reenable this
- //entryEditorTab.setActive((FieldEditor) event.getSource());
- }
-
- @Override
- public void focusLost(FocusEvent event) {
- synchronized (this) {
- if (textComponent != null) {
- textComponent.getDocument().removeDocumentListener(documentListener);
- textComponent = null;
- documentListener = null;
- }
- }
- if (!event.isTemporary()) {
- entryEditorTab.getParent().updateField(event.getSource());
- }
- }
-
-}
diff --git a/src/main/java/org/jabref/gui/errorconsole/ErrorConsoleViewModel.java b/src/main/java/org/jabref/gui/errorconsole/ErrorConsoleViewModel.java
index 596a7f9eac2..2cc348f9e76 100644
--- a/src/main/java/org/jabref/gui/errorconsole/ErrorConsoleViewModel.java
+++ b/src/main/java/org/jabref/gui/errorconsole/ErrorConsoleViewModel.java
@@ -16,7 +16,6 @@
import org.jabref.gui.AbstractViewModel;
import org.jabref.gui.ClipBoardManager;
import org.jabref.gui.DialogService;
-import org.jabref.gui.MappedList;
import org.jabref.gui.desktop.JabRefDesktop;
import org.jabref.logic.l10n.Localization;
import org.jabref.logic.logging.LogMessages;
@@ -27,6 +26,7 @@
import org.apache.commons.logging.LogFactory;
import org.apache.http.client.utils.URIBuilder;
import org.apache.logging.log4j.core.LogEvent;
+import org.fxmisc.easybind.EasyBind;
public class ErrorConsoleViewModel extends AbstractViewModel {
private static final Log LOGGER = LogFactory.getLog(ErrorConsoleViewModel.class);
@@ -42,7 +42,7 @@ public ErrorConsoleViewModel(DialogService dialogService, ClipBoardManager clipB
this.dialogService = Objects.requireNonNull(dialogService);
this.clipBoardManager = Objects.requireNonNull(clipBoardManager);
this.buildInfo = Objects.requireNonNull(buildInfo);
- ObservableList eventViewModels = new MappedList<>(LogMessages.getInstance().getMessages(), LogEventViewModel::new);
+ ObservableList eventViewModels = EasyBind.map(LogMessages.getInstance().getMessages(), LogEventViewModel::new);
allMessagesData = new ReadOnlyListWrapper<>(eventViewModels);
}
diff --git a/src/main/java/org/jabref/gui/groups/DroppingMouseLocation.java b/src/main/java/org/jabref/gui/groups/DroppingMouseLocation.java
new file mode 100644
index 00000000000..e946facdcf7
--- /dev/null
+++ b/src/main/java/org/jabref/gui/groups/DroppingMouseLocation.java
@@ -0,0 +1,10 @@
+package org.jabref.gui.groups;
+
+/**
+ * The mouse location within the cell when the dropping gesture occurs.
+ */
+enum DroppingMouseLocation {
+ BOTTOM,
+ CENTER,
+ TOP
+}
diff --git a/src/main/java/org/jabref/gui/groups/GroupNodeViewModel.java b/src/main/java/org/jabref/gui/groups/GroupNodeViewModel.java
index a73496975cb..4e1b85993a2 100644
--- a/src/main/java/org/jabref/gui/groups/GroupNodeViewModel.java
+++ b/src/main/java/org/jabref/gui/groups/GroupNodeViewModel.java
@@ -67,7 +67,7 @@ public GroupNodeViewModel(BibDatabaseContext databaseContext, StateManager state
.sorted((group1, group2) -> group1.getDisplayName().compareToIgnoreCase(group2.getDisplayName()))
.collect(Collectors.toCollection(FXCollections::observableArrayList));
} else {
- children = EasyBind.map(groupNode.getChildren(), this::toViewModel);
+ children = BindingsHelper.mapBacked(groupNode.getChildren(), this::toViewModel);
}
hasChildren = new SimpleBooleanProperty();
hasChildren.bind(Bindings.isNotEmpty(children));
@@ -254,6 +254,51 @@ public void moveTo(GroupNodeViewModel target) {
//panel.getUndoManager().addEdit(new UndoableMoveGroup(this.groupsRoot, moveChange));
//panel.markBaseChanged();
//frame.output(Localization.lang("Moved group \"%0\".", node.getNode().getGroup().getName()));
+ }
+
+ public void moveTo(GroupTreeNode target, int targetIndex) {
+ getGroupNode().moveTo(target, targetIndex);
+ }
+
+ public Optional getParent() {
+ return groupNode.getParent();
+ }
+
+ public void draggedOn(GroupNodeViewModel target, DroppingMouseLocation mouseLocation) {
+ Optional targetParent = target.getParent();
+ if (targetParent.isPresent()) {
+ int targetIndex = target.getPositionInParent();
+
+ // In case we want to move an item in the same parent
+ // and the item is moved down, we need to adjust the target index
+ if (targetParent.equals(getParent())) {
+ int sourceIndex = this.getPositionInParent();
+ if (sourceIndex < targetIndex) {
+ targetIndex--;
+ }
+ }
+
+ // Different actions depending on where the user releases the drop in the target row
+ // Bottom + top -> insert source row before / after this row
+ // Center -> add as child
+ switch (mouseLocation) {
+ case BOTTOM:
+ this.moveTo(targetParent.get(), targetIndex + 1);
+ break;
+ case CENTER:
+ this.moveTo(target);
+ break;
+ case TOP:
+ this.moveTo(targetParent.get(), targetIndex);
+ break;
+ }
+ } else {
+ // No parent = root -> just add
+ this.moveTo(target);
+ }
+ }
+ private int getPositionInParent() {
+ return groupNode.getPositionInParent();
}
}
diff --git a/src/main/java/org/jabref/gui/groups/GroupSelector.java b/src/main/java/org/jabref/gui/groups/GroupSelector.java
deleted file mode 100644
index c5ff928e176..00000000000
--- a/src/main/java/org/jabref/gui/groups/GroupSelector.java
+++ /dev/null
@@ -1,637 +0,0 @@
-package org.jabref.gui.groups;
-
-import java.awt.BorderLayout;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.awt.event.ActionEvent;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.Optional;
-
-import javax.swing.AbstractAction;
-import javax.swing.BorderFactory;
-import javax.swing.ButtonGroup;
-import javax.swing.JButton;
-import javax.swing.JCheckBoxMenuItem;
-import javax.swing.JMenu;
-import javax.swing.JPanel;
-import javax.swing.JPopupMenu;
-import javax.swing.JRadioButtonMenuItem;
-import javax.swing.JScrollPane;
-import javax.swing.ScrollPaneConstants;
-import javax.swing.SwingUtilities;
-import javax.swing.event.PopupMenuEvent;
-import javax.swing.event.PopupMenuListener;
-import javax.swing.event.TreeSelectionEvent;
-import javax.swing.event.TreeSelectionListener;
-import javax.swing.tree.DefaultTreeModel;
-import javax.swing.tree.TreePath;
-import javax.swing.undo.AbstractUndoableEdit;
-import javax.swing.undo.CompoundEdit;
-
-import javafx.application.Platform;
-import javafx.embed.swing.JFXPanel;
-import javafx.scene.Scene;
-import javafx.scene.layout.StackPane;
-
-import org.jabref.Globals;
-import org.jabref.gui.BasePanel;
-import org.jabref.gui.IconTheme;
-import org.jabref.gui.JabRefFrame;
-import org.jabref.gui.SidePaneComponent;
-import org.jabref.gui.SidePaneManager;
-import org.jabref.gui.help.HelpAction;
-import org.jabref.gui.keyboard.KeyBinding;
-import org.jabref.gui.maintable.MainTableDataModel;
-import org.jabref.logic.groups.DefaultGroupsFactory;
-import org.jabref.logic.help.HelpFile;
-import org.jabref.logic.l10n.Localization;
-import org.jabref.model.entry.BibEntry;
-import org.jabref.model.groups.AllEntriesGroup;
-import org.jabref.model.groups.GroupTreeNode;
-import org.jabref.model.groups.event.GroupUpdatedEvent;
-import org.jabref.model.metadata.MetaData;
-import org.jabref.model.search.SearchMatcher;
-import org.jabref.preferences.JabRefPreferences;
-
-import com.google.common.eventbus.Subscribe;
-
-/**
- * The whole UI component holding the groups tree and the buttons
- */
-public class GroupSelector extends SidePaneComponent implements TreeSelectionListener {
-
- protected final JabRefFrame frame;
- private final GroupsTree groupsTree;
- private final JPopupMenu groupsContextMenu = new JPopupMenu();
- private final JPopupMenu settings = new JPopupMenu();
- private final JRadioButtonMenuItem andCb = new JRadioButtonMenuItem(Localization.lang("Intersection"), true);
- private final JRadioButtonMenuItem floatCb = new JRadioButtonMenuItem(Localization.lang("Float"), true);
- private final JCheckBoxMenuItem invCb = new JCheckBoxMenuItem(Localization.lang("Inverted"), false);
- private final JCheckBoxMenuItem autoAssignGroup = new JCheckBoxMenuItem(
- Localization.lang("Automatically assign new entry to selected groups"));
- private final JMenu sortSubmenu = new JMenu(Localization.lang("Sort alphabetically"));
- private final NodeAction sortDirectSubgroupsPopupAction = new SortDirectSubgroupsAction();
- private final NodeAction sortAllSubgroupsPopupAction = new SortAllSubgroupsAction();
- private final ToggleAction toggleAction;
- private DefaultTreeModel groupsTreeModel;
- private GroupTreeNodeViewModel groupsRoot;
-
- /**
- * The first element for each group defines which field to use for the quicksearch. The next two define the name and
- * regexp for the group.
- */
- public GroupSelector(JabRefFrame frame, SidePaneManager manager) {
- super(manager, IconTheme.JabRefIcon.TOGGLE_GROUPS.getIcon(), Localization.lang("Groups"));
-
- Globals.stateManager.activeGroupProperty()
- .addListener((observable, oldValue, newValue) -> updateShownEntriesAccordingToSelectedGroups(newValue));
-
- toggleAction = new ToggleAction(Localization.menuTitle("Toggle groups interface"),
- Localization.lang("Toggle groups interface"),
- Globals.getKeyPrefs().getKey(KeyBinding.TOGGLE_GROUPS_INTERFACE),
- IconTheme.JabRefIcon.TOGGLE_GROUPS);
-
- this.frame = frame;
-
- floatCb.addChangeListener(
- event -> Globals.prefs.putBoolean(JabRefPreferences.GROUP_FLOAT_SELECTIONS, floatCb.isSelected()));
- andCb.addChangeListener(
- event -> Globals.prefs.putBoolean(JabRefPreferences.GROUP_INTERSECT_SELECTIONS, andCb.isSelected()));
- invCb.addChangeListener(
- event -> Globals.prefs.putBoolean(JabRefPreferences.GROUP_INVERT_SELECTIONS, invCb.isSelected()));
-
- JRadioButtonMenuItem highlCb = new JRadioButtonMenuItem(Localization.lang("Highlight"), false);
- if (Globals.prefs.getBoolean(JabRefPreferences.GROUP_FLOAT_SELECTIONS)) {
-
- floatCb.setSelected(true);
- highlCb.setSelected(false);
- } else {
- highlCb.setSelected(true);
- floatCb.setSelected(false);
- }
- JRadioButtonMenuItem orCb = new JRadioButtonMenuItem(Localization.lang("Union"), false);
- if (Globals.prefs.getBoolean(JabRefPreferences.GROUP_INTERSECT_SELECTIONS)) {
- andCb.setSelected(true);
- orCb.setSelected(false);
- } else {
- orCb.setSelected(true);
- andCb.setSelected(false);
- }
-
- autoAssignGroup.addChangeListener(
- event -> Globals.prefs.putBoolean(JabRefPreferences.AUTO_ASSIGN_GROUP, autoAssignGroup.isSelected()));
-
- invCb.setSelected(Globals.prefs.getBoolean(JabRefPreferences.GROUP_INVERT_SELECTIONS));
- autoAssignGroup.setSelected(Globals.prefs.getBoolean(JabRefPreferences.AUTO_ASSIGN_GROUP));
-
- JButton openSettings = new JButton(IconTheme.JabRefIcon.PREFERENCES.getSmallIcon());
- settings.add(andCb);
- settings.add(orCb);
- settings.addSeparator();
- settings.add(invCb);
- settings.addSeparator();
- settings.add(autoAssignGroup);
- openSettings.addActionListener(e -> {
- if (!settings.isVisible()) {
- JButton src = (JButton) e.getSource();
- autoAssignGroup.setSelected(Globals.prefs.getBoolean(JabRefPreferences.AUTO_ASSIGN_GROUP));
- settings.show(src, 0, openSettings.getHeight());
- }
- });
-
- JButton helpButton = new HelpAction(Localization.lang("Help on groups"), HelpFile.GROUP)
- .getHelpButton();
- Insets butIns = new Insets(0, 0, 0, 0);
- helpButton.setMargin(butIns);
- openSettings.setMargin(butIns);
- andCb.addActionListener(e -> valueChanged(null));
- orCb.addActionListener(e -> valueChanged(null));
- invCb.addActionListener(e -> valueChanged(null));
- floatCb.addActionListener(e -> valueChanged(null));
- highlCb.addActionListener(e -> valueChanged(null));
- andCb.setToolTipText(Localization.lang("Display only entries belonging to all selected groups."));
- orCb.setToolTipText(Localization.lang("Display all entries belonging to one or more of the selected groups."));
- openSettings.setToolTipText(Localization.lang("Settings"));
- invCb.setToolTipText("" + Localization.lang("Show entries not in group selection") + "");
- floatCb.setToolTipText(Localization.lang("Move entries in group selection to the top"));
- highlCb.setToolTipText(Localization.lang("Gray out entries not in group selection"));
- ButtonGroup bgr = new ButtonGroup();
- bgr.add(andCb);
- bgr.add(orCb);
- ButtonGroup visMode = new ButtonGroup();
- visMode.add(floatCb);
- visMode.add(highlCb);
-
- JPanel rootPanel = new JPanel();
- GridBagLayout gbl = new GridBagLayout();
- rootPanel.setLayout(gbl);
-
- GridBagConstraints con = new GridBagConstraints();
- con.fill = GridBagConstraints.BOTH;
- con.weightx = 1;
- con.gridwidth = 1;
- con.gridy = 0;
-
- con.gridx = 0;
-
- con.gridx = 1;
-
- con.gridx = 2;
- gbl.setConstraints(openSettings, con);
- rootPanel.add(openSettings);
-
- con.gridx = 3;
- con.gridwidth = GridBagConstraints.REMAINDER;
- gbl.setConstraints(helpButton, con);
- rootPanel.add(helpButton);
-
- groupsTree = new GroupsTree(this);
- groupsTree.addTreeSelectionListener(this);
-
- JScrollPane groupsTreePane = new JScrollPane(groupsTree, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
- ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
- groupsTreePane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
- groupsTreePane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
- con.gridwidth = GridBagConstraints.REMAINDER;
- con.weighty = 1;
- con.gridx = 0;
- con.gridwidth = 4;
- con.gridy = 1;
- gbl.setConstraints(groupsTreePane, con);
- rootPanel.add(groupsTreePane);
-
- add(rootPanel, BorderLayout.CENTER);
- groupsTree.setBorder(BorderFactory.createEmptyBorder(5, 10, 0, 0));
- this.setTitle(Localization.lang("Groups"));
- definePopup();
-
- setGroups(GroupTreeNode.fromGroup(DefaultGroupsFactory.getAllEntriesGroup()));
-
- JFXPanel groupsPane = new JFXPanel();
- add(groupsPane);
- // Execute on JavaFX Application Thread
- Platform.runLater(() -> {
- StackPane root = new StackPane();
- root.getChildren().addAll(new GroupTreeView().getView());
- Scene scene = new Scene(root);
- groupsPane.setScene(scene);
- });
- }
-
- private void definePopup() {
- // These key bindings are just to have the shortcuts displayed
- // in the popup menu. The actual keystroke processing is in
- // BasePanel (entryTable.addKeyListener(...)).
- groupsContextMenu.addSeparator();
- sortSubmenu.add(sortDirectSubgroupsPopupAction);
- sortSubmenu.add(sortAllSubgroupsPopupAction);
- groupsContextMenu.add(sortSubmenu);
- groupsContextMenu.addSeparator();
- groupsTree.addMouseListener(new MouseAdapter() {
-
- @Override
- public void mousePressed(MouseEvent e) {
- if (e.isPopupTrigger()) {
- showPopup(e);
- }
- }
-
- @Override
- public void mouseReleased(MouseEvent e) {
- if (e.isPopupTrigger()) {
- showPopup(e);
- }
- }
-
- @Override
- public void mouseClicked(MouseEvent e) {
- TreePath path = groupsTree.getPathForLocation(e.getPoint().x, e.getPoint().y);
- if (path == null) {
- return;
- }
- GroupTreeNodeViewModel node = (GroupTreeNodeViewModel) path.getLastPathComponent();
- // the root node is "AllEntries" and cannot be edited
- if (node.getNode().isRoot()) {
- return;
- }
- if ((e.getClickCount() == 2) && (e.getButton() == MouseEvent.BUTTON1)) { // edit
- //editGroupAction.actionPerformed(null); // dummy event
- }
- }
- });
- // be sure to remove a possible border highlight when the popup menu
- // disappears
- groupsContextMenu.addPopupMenuListener(new PopupMenuListener() {
-
- @Override
- public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
- // nothing to do
- }
-
- @Override
- public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
- groupsTree.setHighlightBorderCell(null);
- }
-
- @Override
- public void popupMenuCanceled(PopupMenuEvent e) {
- groupsTree.setHighlightBorderCell(null);
- }
- });
- }
-
- private void showPopup(MouseEvent e) {
- final TreePath path = groupsTree.getPathForLocation(e.getPoint().x, e.getPoint().y);
- sortSubmenu.setEnabled(path != null);
- if (path != null) { // some path dependent enabling/disabling
- GroupTreeNodeViewModel node = (GroupTreeNodeViewModel) path.getLastPathComponent();
- sortDirectSubgroupsPopupAction.setNode(node);
- sortAllSubgroupsPopupAction.setNode(node);
- groupsTree.setHighlightBorderCell(node);
- if (node.canBeEdited()) {
- //editGroupPopupAction.setEnabled(false);
- //addGroupPopupAction.setEnabled(false);
- //removeGroupAndSubgroupsPopupAction.setEnabled(false);
- //removeGroupKeepSubgroupsPopupAction.setEnabled(false);
- } else {
- //editGroupPopupAction.setEnabled(true);
- //addGroupPopupAction.setEnabled(true);
- //addGroupPopupAction.setNode(node);
- //removeGroupAndSubgroupsPopupAction.setEnabled(true);
- //removeGroupKeepSubgroupsPopupAction.setEnabled(true);
- }
- sortSubmenu.setEnabled(!node.isLeaf());
- //removeSubgroupsPopupAction.setEnabled(!node.isLeaf());
- // add/remove entries to/from group
- List selection = frame.getCurrentBasePanel().getSelectedEntries();
- if (!selection.isEmpty()) {
- if (node.canAddEntries(selection)) {
- //addToGroup.setEnabled(true);
- }
- if (node.canRemoveEntries(selection)) {
- //removeFromGroup.setEnabled(true);
- }
- }
- } else {
- sortDirectSubgroupsPopupAction.setNode(null);
- sortAllSubgroupsPopupAction.setNode(null);
- }
- groupsContextMenu.show(groupsTree, e.getPoint().x, e.getPoint().y);
- }
-
- @Override
- public void valueChanged(TreeSelectionEvent e) {
- if (panel == null) {
- return; // ignore this event (happens for example if the file was closed)
- }
- /*
- if (getLeafsOfSelection().stream().allMatch(GroupTreeNodeViewModel::isAllEntriesGroup)) {
- panel.getMainTable().getTableModel().updateGroupingState(MainTableDataModel.DisplayOption.DISABLED);
- if (showOverlappingGroups.isSelected()) {
- groupsTree.setOverlappingGroups(Collections.emptyList());
- }
- frame.output(Localization.lang("Displaying no groups") + ".");
- return;
- }
- */
- updateShownEntriesAccordingToSelectedGroups();
- }
-
- private void updateShownEntriesAccordingToSelectedGroups() {
- updateShownEntriesAccordingToSelectedGroups(Globals.stateManager.activeGroupProperty().get());
- /*final MatcherSet searchRules = MatcherSets
- .build(andCb.isSelected() ? MatcherSets.MatcherType.AND : MatcherSets.MatcherType.OR);
-
- for (GroupTreeNodeViewModel node : getLeafsOfSelection()) {
- SearchMatcher searchRule = node.getNode().getSearchMatcher();
- searchRules.addRule(searchRule);
- }
- SearchMatcher searchRule = invCb.isSelected() ? new NotMatcher(searchRules) : searchRules;
- GroupingWorker worker = new GroupingWorker(searchRule);
- worker.getWorker().run();
- worker.getCallBack().update();
- */
- }
-
- private void updateShownEntriesAccordingToSelectedGroups(Optional selectedGroup) {
- if (!selectedGroup.isPresent()) {
- // No selected group, nothing to do
- return;
- }
- SearchMatcher searchRule = selectedGroup.get().getSearchMatcher();
- GroupingWorker worker = new GroupingWorker(searchRule);
- worker.run();
- worker.update();
- }
-
- private GroupTreeNodeViewModel getFirstSelectedNode() {
- TreePath path = groupsTree.getSelectionPath();
- if (path != null) {
- return (GroupTreeNodeViewModel) path.getLastPathComponent();
- }
- return null;
- }
-
- /**
- * Revalidate the groups tree (e.g. after the data stored in the model has been changed) and maintain the current
- * selection and expansion state.
- */
- public void revalidateGroups() {
- if (SwingUtilities.isEventDispatchThread()) {
- revalidateGroups(null);
- } else {
- SwingUtilities.invokeLater(() -> revalidateGroups(null));
- }
- }
-
- /**
- * Revalidate the groups tree (e.g. after the data stored in the model has been changed) and maintain the current
- * selection and expansion state.
- *
- * @param node If this is non-null, the view is scrolled to make it visible.
- */
- private void revalidateGroups(GroupTreeNodeViewModel node) {
- revalidateGroups(groupsTree.getSelectionPaths(), getExpandedPaths(), node);
- }
-
- /**
- * Revalidate the groups tree (e.g. after the data stored in the model has been changed) and set the specified
- * selection and expansion state.
- *
- * @param node If this is non-null, the view is scrolled to make it visible.
- */
- private void revalidateGroups(TreePath[] selectionPaths, Enumeration expandedNodes,
- GroupTreeNodeViewModel node) {
- groupsTree.clearSelection();
- if (selectionPaths != null) {
- groupsTree.setSelectionPaths(selectionPaths);
- }
- // tree is completely collapsed here
- if (expandedNodes != null) {
- while (expandedNodes.hasMoreElements()) {
- groupsTree.expandPath(expandedNodes.nextElement());
- }
- }
- groupsTree.revalidate();
- if (node != null) {
- groupsTree.scrollPathToVisible(node.getTreePath());
- }
- }
-
- @Override
- public void componentOpening() {
- valueChanged(null);
- Globals.prefs.putBoolean(JabRefPreferences.GROUP_SIDEPANE_VISIBLE, Boolean.TRUE);
- }
-
- @Override
- public int getRescalingWeight() {
- return 1;
- }
-
- @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);
- }
-
- private void setGroups(GroupTreeNode groupsRoot) {
- // We ignore the set group since this is handled via JavaFX
- this.groupsRoot = new GroupTreeNodeViewModel(new GroupTreeNode(DefaultGroupsFactory.getAllEntriesGroup()));
- //this.groupsRoot = new GroupTreeNodeViewModel(groupsRoot);
- groupsTreeModel = new DefaultTreeModel(this.groupsRoot);
- this.groupsRoot.subscribeToDescendantChanged(groupsTreeModel::nodeStructureChanged);
- groupsTree.setModel(groupsTreeModel);
- }
-
- /**
- * Adds the specified node as a child of the current root. The group contained in newGroups must not be of
- * type AllEntriesGroup, since every tree has exactly one AllEntriesGroup (its root). The newGroups are
- * inserted directly, i.e. they are not deepCopy()'d.
- */
- public void addGroups(GroupTreeNode newGroups, CompoundEdit ce) {
- // TODO: This shouldn't be a method of GroupSelector
-
- // paranoia: ensure that there are never two instances of AllEntriesGroup
- if (newGroups.getGroup() instanceof AllEntriesGroup) {
- return; // this should be impossible anyway
- }
- newGroups.moveTo(groupsRoot.getNode());
- UndoableAddOrRemoveGroup undo = new UndoableAddOrRemoveGroup(groupsRoot,
- new GroupTreeNodeViewModel(newGroups), UndoableAddOrRemoveGroup.ADD_NODE);
- ce.addEdit(undo);
- }
-
- public TreePath getSelectionPath() {
- return groupsTree.getSelectionPath();
- }
-
- public void concludeAssignment(AbstractUndoableEdit undo, GroupTreeNode node, int assignedEntries) {
- if (undo == null) {
- frame.output(Localization.lang("The group \"%0\" already contains the selection.",
- node.getGroup().getName()));
- return;
- }
- panel.getUndoManager().addEdit(undo);
- panel.markBaseChanged();
- panel.updateEntryEditorIfShowing();
- final String groupName = node.getGroup().getName();
- if (assignedEntries == 1) {
- frame.output(Localization.lang("Assigned 1 entry to group \"%0\".", groupName));
- } else {
- frame.output(Localization.lang("Assigned %0 entries to group \"%1\".", String.valueOf(assignedEntries),
- groupName));
- }
- }
-
- private GroupTreeNodeViewModel getGroupTreeRoot() {
- return groupsRoot;
- }
-
- private Enumeration getExpandedPaths() {
- return groupsTree.getExpandedDescendants(groupsRoot.getTreePath());
- }
-
- /**
- * panel may be null to indicate that no file is currently open.
- */
- @Override
- public void setActiveBasePanel(BasePanel panel) {
- super.setActiveBasePanel(panel);
- if (panel == null) { // hide groups
- frame.getSidePaneManager().hide(GroupSelector.class);
- return;
- }
- MetaData metaData = panel.getBibDatabaseContext().getMetaData();
- if (metaData.getGroups().isPresent()) {
- setGroups(metaData.getGroups().get());
- } else {
- GroupTreeNode newGroupsRoot = GroupTreeNode
- .fromGroup(DefaultGroupsFactory.getAllEntriesGroup());
- metaData.setGroups(newGroupsRoot);
- setGroups(newGroupsRoot);
- }
-
- metaData.registerListener(this);
-
- synchronized (getTreeLock()) {
- validateTree();
- }
- }
-
- public GroupsTree getGroupsTree() {
- return this.groupsTree;
- }
-
- @Subscribe
- public void listen(GroupUpdatedEvent updateEvent) {
- setGroups(updateEvent.getMetaData().getGroups().orElse(null));
- }
-
- @Override
- public void grabFocus() {
- groupsTree.grabFocus();
- }
-
- @Override
- public ToggleAction getToggleAction() {
- return toggleAction;
- }
-
- class GroupingWorker {
-
- private final SearchMatcher matcher;
-
- public GroupingWorker(SearchMatcher matcher) {
- this.matcher = matcher;
- }
-
- public void run() {
- 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") + ".");
- }
- }
-
- private abstract class NodeAction extends AbstractAction {
-
- private GroupTreeNodeViewModel node;
-
- public NodeAction(String s) {
- super(s);
- }
-
- public void setNode(GroupTreeNodeViewModel node) {
- this.node = node;
- }
-
- /**
- * Returns the node to use in this action. If a node has been set explicitly (via setNode), it is returned.
- * Otherwise, the first node in the current selection is returned. If all this fails, null is returned.
- */
- public GroupTreeNodeViewModel getNodeToUse() {
- if (node != null) {
- return node;
- }
- return getFirstSelectedNode();
- }
- }
-
- private class SortDirectSubgroupsAction extends NodeAction {
-
- public SortDirectSubgroupsAction() {
- super(Localization.lang("Immediate subgroups"));
- }
-
- @Override
- public void actionPerformed(ActionEvent ae) {
- final GroupTreeNodeViewModel node = getNodeToUse();
- final UndoableModifySubtree undo = new UndoableModifySubtree(getGroupTreeRoot(), node,
- Localization.lang("sort subgroups"));
- groupsTree.sort(node, false);
- panel.getUndoManager().addEdit(undo);
- panel.markBaseChanged();
- frame.output(Localization.lang("Sorted immediate subgroups."));
- }
- }
-
- private class SortAllSubgroupsAction extends NodeAction {
-
- public SortAllSubgroupsAction() {
- super(Localization.lang("All subgroups (recursively)"));
- }
-
- @Override
- public void actionPerformed(ActionEvent ae) {
- final GroupTreeNodeViewModel node = getNodeToUse();
- final UndoableModifySubtree undo = new UndoableModifySubtree(getGroupTreeRoot(), node,
- Localization.lang("sort subgroups"));
- groupsTree.sort(node, true);
- panel.getUndoManager().addEdit(undo);
- panel.markBaseChanged();
- frame.output(Localization.lang("Sorted all subgroups recursively."));
- }
- }
-}
diff --git a/src/main/java/org/jabref/gui/groups/GroupSidePane.java b/src/main/java/org/jabref/gui/groups/GroupSidePane.java
new file mode 100644
index 00000000000..6123a99920d
--- /dev/null
+++ b/src/main/java/org/jabref/gui/groups/GroupSidePane.java
@@ -0,0 +1,122 @@
+package org.jabref.gui.groups;
+
+import java.util.List;
+
+import javafx.application.Platform;
+import javafx.embed.swing.JFXPanel;
+import javafx.scene.Scene;
+import javafx.scene.layout.StackPane;
+
+import org.jabref.Globals;
+import org.jabref.gui.BasePanel;
+import org.jabref.gui.IconTheme;
+import org.jabref.gui.JabRefFrame;
+import org.jabref.gui.SidePaneComponent;
+import org.jabref.gui.SidePaneManager;
+import org.jabref.gui.keyboard.KeyBinding;
+import org.jabref.gui.maintable.MainTableDataModel;
+import org.jabref.logic.l10n.Localization;
+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;
+
+/**
+ * The groups side pane.
+ * This class is just a Swing wrapper around the JavaFX implementation {@link GroupTreeView}.
+ */
+public class GroupSidePane extends SidePaneComponent {
+
+ protected final JabRefFrame frame;
+ private final ToggleAction toggleAction;
+
+ /**
+ * The first element for each group defines which field to use for the quicksearch. The next two define the name and
+ * regexp for the group.
+ */
+ public GroupSidePane(JabRefFrame frame, SidePaneManager manager) {
+ super(manager, IconTheme.JabRefIcon.TOGGLE_GROUPS.getIcon(), Localization.lang("Groups"));
+
+ Globals.stateManager.activeGroupProperty()
+ .addListener((observable, oldValue, newValue) -> updateShownEntriesAccordingToSelectedGroups(newValue));
+
+ toggleAction = new ToggleAction(Localization.menuTitle("Toggle groups interface"),
+ Localization.lang("Toggle groups interface"),
+ Globals.getKeyPrefs().getKey(KeyBinding.TOGGLE_GROUPS_INTERFACE),
+ IconTheme.JabRefIcon.TOGGLE_GROUPS);
+
+ this.frame = frame;
+
+ this.setTitle(Localization.lang("Groups"));
+
+ JFXPanel groupsPane = new JFXPanel();
+ add(groupsPane);
+ // Execute on JavaFX Application Thread
+ Platform.runLater(() -> {
+ StackPane root = new StackPane();
+ root.getChildren().addAll(new GroupTreeView().getView());
+ Scene scene = new Scene(root);
+ groupsPane.setScene(scene);
+ });
+ }
+
+ private void updateShownEntriesAccordingToSelectedGroups(List selectedGroups) {
+ if (selectedGroups == null || selectedGroups.isEmpty()) {
+ // No selected group, nothing to do
+ return;
+ }
+
+ 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);
+ }
+
+ @Override
+ public int getRescalingWeight() {
+ return 1;
+ }
+
+ @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);
+ }
+
+ @Override
+ public void setActiveBasePanel(BasePanel panel) {
+ super.setActiveBasePanel(panel);
+ if (panel == null) { // hide groups
+ frame.getSidePaneManager().hide(GroupSidePane.class);
+ return;
+ }
+
+ synchronized (getTreeLock()) {
+ validateTree();
+ }
+ }
+
+ @Override
+ public void grabFocus() {
+
+ }
+
+ @Override
+ public ToggleAction getToggleAction() {
+ return toggleAction;
+ }
+}
diff --git a/src/main/java/org/jabref/gui/groups/GroupTree.css b/src/main/java/org/jabref/gui/groups/GroupTree.css
index d0d7859dbfc..7a46b16a4bb 100644
--- a/src/main/java/org/jabref/gui/groups/GroupTree.css
+++ b/src/main/java/org/jabref/gui/groups/GroupTree.css
@@ -34,6 +34,24 @@
-fx-font-size: 12px;
}
+.tree-table-row-cell:dragOver-bottom {
+ -fx-border-color: #eea82f;
+ -fx-border-width: 0 0 2 0;
+ -fx-padding: 0 0 -2 0;
+}
+
+.tree-table-row-cell:dragOver-center {
+ -fx-border-color: #eea82f;
+ -fx-border-width: 2 2 2 2;
+ -fx-padding: -2 -2 -2 -2;
+}
+
+.tree-table-row-cell:dragOver-top {
+ -fx-border-color: #eea82f;
+ -fx-border-width: 2 0 0 0;
+ -fx-padding: -2 0 0 0;
+}
+
.tree-table-row-cell:sub > .tree-table-cell {
-fx-padding: 0.20em 0em 0.20em 0em;
}
diff --git a/src/main/java/org/jabref/gui/groups/GroupTree.fxml b/src/main/java/org/jabref/gui/groups/GroupTree.fxml
index 322ae5140d8..1d994c8f11c 100644
--- a/src/main/java/org/jabref/gui/groups/GroupTree.fxml
+++ b/src/main/java/org/jabref/gui/groups/GroupTree.fxml
@@ -14,8 +14,8 @@
-
-
+
diff --git a/src/main/java/org/jabref/gui/groups/GroupTreeController.java b/src/main/java/org/jabref/gui/groups/GroupTreeController.java
index 471f2c1a2f2..1d1d58c2534 100644
--- a/src/main/java/org/jabref/gui/groups/GroupTreeController.java
+++ b/src/main/java/org/jabref/gui/groups/GroupTreeController.java
@@ -2,17 +2,22 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.util.List;
import java.util.Optional;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
import javax.inject.Inject;
import javafx.beans.property.ObjectProperty;
+import javafx.collections.ObservableList;
import javafx.css.PseudoClass;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Control;
import javafx.scene.control.MenuItem;
+import javafx.scene.control.SelectionMode;
import javafx.scene.control.SeparatorMenuItem;
import javafx.scene.control.TextField;
import javafx.scene.control.TreeItem;
@@ -20,6 +25,7 @@
import javafx.scene.control.TreeTableRow;
import javafx.scene.control.TreeTableView;
import javafx.scene.input.ClipboardContent;
+import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.StackPane;
@@ -55,15 +61,37 @@ public class GroupTreeController extends AbstractController
@Inject private DialogService dialogService;
@Inject private TaskExecutor taskExecutor;
+ private static void removePseudoClasses(TreeTableRow row, PseudoClass... pseudoClasses) {
+ for (PseudoClass pseudoClass : pseudoClasses) {
+ row.pseudoClassStateChanged(pseudoClass, false);
+ }
+ }
+
@FXML
public void initialize() {
viewModel = new GroupTreeViewModel(stateManager, dialogService, taskExecutor);
+ // Set-up groups tree
+ groupTree.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
+
// Set-up bindings
- groupTree.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> viewModel
- .selectedGroupProperty().setValue(newValue != null ? newValue.getValue() : null));
- viewModel.selectedGroupProperty().addListener((observable, oldValue, newValue) -> getTreeItemByValue(newValue)
- .ifPresent(treeItem -> groupTree.getSelectionModel().select(treeItem)));
+ Consumer> updateSelectedGroups =
+ (newSelectedGroups) -> newSelectedGroups.forEach(this::selectNode);
+ Consumer>> updateViewModel =
+ (newSelectedGroups) -> {
+ if (newSelectedGroups == null) {
+ viewModel.selectedGroupsProperty().clear();
+ } else {
+ viewModel.selectedGroupsProperty().setAll(newSelectedGroups.stream().map(TreeItem::getValue).collect(Collectors.toList()));
+ }
+ };
+ BindingsHelper.bindContentBidirectional(
+ groupTree.getSelectionModel().getSelectedItems(),
+ viewModel.selectedGroupsProperty(),
+ updateSelectedGroups,
+ updateViewModel
+ );
+
viewModel.filterTextProperty().bind(searchField.textProperty());
groupTree.rootProperty().bind(
@@ -120,6 +148,11 @@ public void initialize() {
// Set pseudo-classes to indicate if row is root or sub-item ( > 1 deep)
PseudoClass rootPseudoClass = PseudoClass.getPseudoClass("root");
PseudoClass subElementPseudoClass = PseudoClass.getPseudoClass("sub");
+
+ // Pseudo-classes for drag and drop
+ PseudoClass dragOverBottom = PseudoClass.getPseudoClass("dragOver-bottom");
+ PseudoClass dragOverCenter = PseudoClass.getPseudoClass("dragOver-center");
+ PseudoClass dragOverTop = PseudoClass.getPseudoClass("dragOver-top");
groupTree.setRowFactory(treeTable -> {
TreeTableRow row = new TreeTableRow<>();
row.treeItemProperty().addListener((ov, oldTreeItem, newTreeItem) -> {
@@ -162,9 +195,25 @@ public void initialize() {
Dragboard dragboard = event.getDragboard();
if ((event.getGestureSource() != row) && row.getItem().acceptableDrop(dragboard)) {
event.acceptTransferModes(TransferMode.MOVE, TransferMode.LINK);
+
+ removePseudoClasses(row, dragOverBottom, dragOverCenter, dragOverTop);
+ switch (getDroppingMouseLocation(row, event)) {
+ case BOTTOM:
+ row.pseudoClassStateChanged(dragOverBottom, true);
+ break;
+ case CENTER:
+ row.pseudoClassStateChanged(dragOverCenter, true);
+ break;
+ case TOP:
+ row.pseudoClassStateChanged(dragOverTop, true);
+ break;
+ }
}
event.consume();
});
+ row.setOnDragExited(event -> {
+ removePseudoClasses(row, dragOverBottom, dragOverCenter, dragOverTop);
+ });
row.setOnDragDropped(event -> {
Dragboard dragboard = event.getDragboard();
@@ -174,7 +223,7 @@ public void initialize() {
Optional source = viewModel.rootGroupProperty().get()
.getChildByPath(pathToSource);
if (source.isPresent()) {
- source.get().moveTo(row.getItem());
+ source.get().draggedOn(row.getItem(), getDroppingMouseLocation(row, event));
success = true;
}
}
@@ -196,6 +245,11 @@ public void initialize() {
setupClearButtonField(searchField);
}
+ private void selectNode(GroupNodeViewModel value) {
+ getTreeItemByValue(value)
+ .ifPresent(treeItem -> groupTree.getSelectionModel().select(treeItem));
+ }
+
private Optional> getTreeItemByValue(GroupNodeViewModel value) {
return getTreeItemByValue(groupTree.getRoot(), value);
}
@@ -253,6 +307,22 @@ private ContextMenu createContextMenuForGroup(GroupNodeViewModel group) {
menu.getItems().add(new SeparatorMenuItem());
menu.getItems().add(sortAlphabetically);
+ // TODO: Disable some actions under certain conditions
+ //if (group.canBeEdited()) {
+ //editGroupPopupAction.setEnabled(false);
+ //addGroupPopupAction.setEnabled(false);
+ //removeGroupAndSubgroupsPopupAction.setEnabled(false);
+ //removeGroupKeepSubgroupsPopupAction.setEnabled(false);
+ //} else {
+ //editGroupPopupAction.setEnabled(true);
+ //addGroupPopupAction.setEnabled(true);
+ //addGroupPopupAction.setNode(node);
+ //removeGroupAndSubgroupsPopupAction.setEnabled(true);
+ //removeGroupKeepSubgroupsPopupAction.setEnabled(true);
+ //}
+ //sortSubmenu.setEnabled(!node.isLeaf());
+ //removeSubgroupsPopupAction.setEnabled(!node.isLeaf());
+
return menu;
}
@@ -273,4 +343,17 @@ private void setupClearButtonField(CustomTextField customTextField) {
LOGGER.error("Failed to decorate text field with clear button", ex);
}
}
+
+ /**
+ * Determines where the mouse is in the given row.
+ */
+ private DroppingMouseLocation getDroppingMouseLocation(TreeTableRow row, DragEvent event) {
+ if ((row.getHeight() * 0.25) > event.getY()) {
+ return DroppingMouseLocation.TOP;
+ } else if ((row.getHeight() * 0.75) < event.getY()) {
+ return DroppingMouseLocation.BOTTOM;
+ } else {
+ return DroppingMouseLocation.CENTER;
+ }
+ }
}
diff --git a/src/main/java/org/jabref/gui/groups/GroupTreeViewModel.java b/src/main/java/org/jabref/gui/groups/GroupTreeViewModel.java
index adab6abb7dd..c505280e705 100644
--- a/src/main/java/org/jabref/gui/groups/GroupTreeViewModel.java
+++ b/src/main/java/org/jabref/gui/groups/GroupTreeViewModel.java
@@ -5,15 +5,20 @@
import java.util.Objects;
import java.util.Optional;
import java.util.function.Predicate;
+import java.util.stream.Collectors;
import javax.swing.SwingUtilities;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
+import javafx.beans.property.ListProperty;
import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleListProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
import org.jabref.gui.AbstractViewModel;
import org.jabref.gui.DialogService;
@@ -30,16 +35,16 @@
public class GroupTreeViewModel extends AbstractViewModel {
private final ObjectProperty rootGroup = new SimpleObjectProperty<>();
- private final ObjectProperty selectedGroup = new SimpleObjectProperty<>();
+ private final ListProperty selectedGroups = new SimpleListProperty<>(FXCollections.observableArrayList());
private final StateManager stateManager;
private final DialogService dialogService;
private final TaskExecutor taskExecutor;
private final ObjectProperty> filterPredicate = new SimpleObjectProperty<>();
private final StringProperty filterText = new SimpleStringProperty();
- private Optional currentDatabase;
private final Comparator compAlphabetIgnoreCase = (GroupTreeNode v1, GroupTreeNode v2) -> v1
.getName()
.compareToIgnoreCase(v2.getName());
+ private Optional currentDatabase;
public GroupTreeViewModel(StateManager stateManager, DialogService dialogService, TaskExecutor taskExecutor) {
this.stateManager = Objects.requireNonNull(stateManager);
@@ -49,7 +54,7 @@ public GroupTreeViewModel(StateManager stateManager, DialogService dialogService
// Register listener
stateManager.activeDatabaseProperty()
.addListener((observable, oldValue, newValue) -> onActiveDatabaseChanged(newValue));
- selectedGroup.addListener((observable, oldValue, newValue) -> onSelectedGroupChanged(newValue));
+ selectedGroups.addListener((observable, oldValue, newValue) -> onSelectedGroupChanged(newValue));
// Set-up bindings
filterPredicate
@@ -63,8 +68,8 @@ public ObjectProperty rootGroupProperty() {
return rootGroup;
}
- public ObjectProperty selectedGroupProperty() {
- return selectedGroup;
+ public ListProperty selectedGroupsProperty() {
+ return selectedGroups;
}
public ObjectProperty> filterPredicateProperty() {
@@ -79,7 +84,7 @@ public StringProperty filterTextProperty() {
* Gets invoked if the user selects a different group.
* We need to notify the {@link StateManager} about this change so that the main table gets updated.
*/
- private void onSelectedGroupChanged(GroupNodeViewModel newValue) {
+ private void onSelectedGroupChanged(ObservableList newValue) {
if (!currentDatabase.equals(stateManager.activeDatabaseProperty().getValue())) {
// Switch of database occurred -> do nothing
return;
@@ -87,9 +92,9 @@ private void onSelectedGroupChanged(GroupNodeViewModel newValue) {
currentDatabase.ifPresent(database -> {
if (newValue == null) {
- stateManager.clearSelectedGroup(database);
+ stateManager.clearSelectedGroups(database);
} else {
- stateManager.setSelectedGroup(database, newValue.getGroupNode());
+ stateManager.setSelectedGroups(database, newValue.stream().map(GroupNodeViewModel::getGroupNode).collect(Collectors.toList()));
}
});
}
@@ -114,9 +119,10 @@ private void onActiveDatabaseChanged(Optional newDatabase) {
.orElse(GroupNodeViewModel.getAllEntriesGroup(newDatabase.get(), stateManager, taskExecutor));
rootGroup.setValue(newRoot);
- stateManager.getSelectedGroup(newDatabase.get()).ifPresent(
- selectedGroup -> this.selectedGroup.setValue(
- new GroupNodeViewModel(newDatabase.get(), stateManager, taskExecutor, selectedGroup)));
+ this.selectedGroups.setAll(
+ stateManager.getSelectedGroup(newDatabase.get()).stream()
+ .map(selectedGroup -> new GroupNodeViewModel(newDatabase.get(), stateManager, taskExecutor, selectedGroup))
+ .collect(Collectors.toList()));
}
currentDatabase = newDatabase;
@@ -251,6 +257,21 @@ public void addSelectedEntries(GroupNodeViewModel group) {
// NamedCompound undoAll = new NamedCompound(Localization.lang("change assignment of entries"));
// if (!undoAdd.isEmpty()) { undo.addEdit(UndoableChangeEntriesOfGroup.getUndoableEdit(node, undoAdd)); }
// panel.getUndoManager().addEdit(undoAll);
+
+ // TODO Display massages
+ //if (undo == null) {
+ // frame.output(Localization.lang("The group \"%0\" already contains the selection.",
+ // node.getGroup().getName()));
+ // return;
+ //}
+ // panel.getUndoManager().addEdit(undo);
+ // final String groupName = node.getGroup().getName();
+ // if (assignedEntries == 1) {
+ // frame.output(Localization.lang("Assigned 1 entry to group \"%0\".", groupName));
+ // } else {
+ // frame.output(Localization.lang("Assigned %0 entries to group \"%1\".", String.valueOf(assignedEntries),
+ // groupName));
+ //}
}
public void removeSelectedEntries(GroupNodeViewModel group) {
diff --git a/src/main/java/org/jabref/gui/groups/GroupingWorker.java b/src/main/java/org/jabref/gui/groups/GroupingWorker.java
new file mode 100644
index 00000000000..6ce158e0fba
--- /dev/null
+++ b/src/main/java/org/jabref/gui/groups/GroupingWorker.java
@@ -0,0 +1,42 @@
+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/groups/GroupsTree.java b/src/main/java/org/jabref/gui/groups/GroupsTree.java
deleted file mode 100644
index e95ea812bc5..00000000000
--- a/src/main/java/org/jabref/gui/groups/GroupsTree.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package org.jabref.gui.groups;
-
-import javax.swing.JTree;
-import javax.swing.ToolTipManager;
-import javax.swing.tree.TreeSelectionModel;
-
-public class GroupsTree extends JTree {
-
- private final GroupTreeCellRenderer localCellRenderer = new GroupTreeCellRenderer();
-
- /**
- * @param groupSelector the parent UI component
- */
- public GroupsTree(GroupSelector groupSelector) {
- setCellRenderer(localCellRenderer);
- setFocusable(false);
- setToggleClickCount(0);
- ToolTipManager.sharedInstance().registerComponent(this);
- setShowsRootHandles(false);
- getSelectionModel().setSelectionMode(
- TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
- this.setFocusable(true);
-
- }
-
- /** Highlights the specified cell or disables highlight if cell == null */
- public void setHighlightBorderCell(GroupTreeNodeViewModel node) {
- localCellRenderer.setHighlightBorderCell(node);
- repaint();
- }
-
- /** Sort immediate children of the specified node alphabetically. */
- public void sort(GroupTreeNodeViewModel node, boolean recursive) {
- node.sortChildrenByName(recursive);
- }
-}
diff --git a/src/main/java/org/jabref/gui/groups/UndoableModifyGroup.java b/src/main/java/org/jabref/gui/groups/UndoableModifyGroup.java
index 91802ff907b..c4b67ddc683 100644
--- a/src/main/java/org/jabref/gui/groups/UndoableModifyGroup.java
+++ b/src/main/java/org/jabref/gui/groups/UndoableModifyGroup.java
@@ -9,7 +9,7 @@
class UndoableModifyGroup extends AbstractUndoableJabRefEdit {
- private final GroupSelector groupSelector;
+ private final GroupSidePane groupSidePane;
private final AbstractGroup m_oldGroupBackup;
private final AbstractGroup m_newGroupBackup;
private final GroupTreeNode m_groupsRootHandle;
@@ -23,9 +23,9 @@ class UndoableModifyGroup extends AbstractUndoableJabRefEdit {
* The new group to replace the one currently stored in node
* .
*/
- public UndoableModifyGroup(GroupSelector gs, GroupTreeNodeViewModel groupsRoot,
- GroupTreeNodeViewModel node, AbstractGroup newGroup) {
- groupSelector = gs;
+ public UndoableModifyGroup(GroupSidePane gs, GroupTreeNodeViewModel groupsRoot,
+ GroupTreeNodeViewModel node, AbstractGroup newGroup) {
+ groupSidePane = gs;
m_oldGroupBackup = node.getNode().getGroup().deepCopy();
m_newGroupBackup = newGroup.deepCopy();
m_pathToNode = node.getNode().getIndexedPathFromRoot();
@@ -43,7 +43,6 @@ public void undo() {
//TODO: NULL
m_groupsRootHandle.getDescendant(m_pathToNode).get().setGroup(
m_oldGroupBackup.deepCopy());
- groupSelector.revalidateGroups();
}
@Override
@@ -51,6 +50,5 @@ public void redo() {
super.redo();
m_groupsRootHandle.getDescendant(m_pathToNode).get().setGroup(
m_newGroupBackup.deepCopy());
- groupSelector.revalidateGroups();
}
}
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 e976fd6cd59..baae05a96f7 100644
--- a/src/main/java/org/jabref/gui/importer/actions/AppendDatabaseAction.java
+++ b/src/main/java/org/jabref/gui/importer/actions/AppendDatabaseAction.java
@@ -6,6 +6,7 @@
import java.util.List;
import javax.swing.JOptionPane;
+import javax.swing.undo.CompoundEdit;
import org.jabref.Globals;
import org.jabref.JabRefExecutorService;
@@ -26,12 +27,14 @@
import org.jabref.logic.util.FileExtensions;
import org.jabref.logic.util.UpdateField;
import org.jabref.model.database.BibDatabase;
+import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.database.KeyCollisionException;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.BibtexString;
import org.jabref.model.groups.AllEntriesGroup;
import org.jabref.model.groups.ExplicitGroup;
import org.jabref.model.groups.GroupHierarchyType;
+import org.jabref.model.groups.GroupTreeNode;
import org.jabref.model.metadata.ContentSelector;
import org.jabref.model.metadata.MetaData;
import org.jabref.preferences.JabRefPreferences;
@@ -53,82 +56,29 @@ public AppendDatabaseAction(JabRefFrame frame, BasePanel panel) {
this.panel = panel;
}
- @Override
- public void action() {
-
- filesToOpen.clear();
- final MergeDialog md = new MergeDialog(frame, Localization.lang("Append library"), true);
- md.setLocationRelativeTo(panel);
- md.setVisible(true);
- if (md.isOkPressed()) {
-
- FileDialogConfiguration fileDialogConfiguration = new FileDialogConfiguration.Builder()
- .withDefaultExtension(FileExtensions.BIBTEX_DB)
- .withInitialDirectory(Globals.prefs.get(JabRefPreferences.WORKING_DIRECTORY))
- .build();
- DialogService ds = new FXDialogService();
-
- List chosen = DefaultTaskExecutor
- .runInJavaFXThread(() -> ds.showFileOpenDialogAndGetMultipleFiles(fileDialogConfiguration));
- if (chosen.isEmpty()) {
- return;
- }
- filesToOpen.addAll(chosen);
-
- // Run the actual open in a thread to prevent the program
- // locking until the file is loaded.
- JabRefExecutorService.INSTANCE.execute(
- () -> openIt(md.importEntries(), md.importStrings(), md.importGroups(), md.importSelectorWords()));
-
- }
-
- }
+ private static void mergeFromBibtex(BasePanel panel, ParserResult parserResult, boolean importEntries,
+ boolean importStrings, boolean importGroups, boolean importSelectorWords) throws KeyCollisionException {
- private void openIt(boolean importEntries, boolean importStrings, boolean importGroups,
- boolean importSelectorWords) {
- if (filesToOpen.isEmpty()) {
- return;
- }
- for (Path file : filesToOpen) {
- try {
- Globals.prefs.put(JabRefPreferences.WORKING_DIRECTORY, file.getParent().toString());
- // Should this be done _after_ we know it was successfully opened?
- ParserResult pr = OpenDatabase.loadDatabase(file.toFile(),
- Globals.prefs.getImportFormatPreferences());
- AppendDatabaseAction.mergeFromBibtex(frame, panel, pr, importEntries, importStrings, importGroups,
- importSelectorWords);
- 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.ERROR_MESSAGE);
- }
- }
- }
-
- private static void mergeFromBibtex(JabRefFrame frame, BasePanel panel, ParserResult pr, boolean importEntries,
- boolean importStrings, boolean importGroups, boolean importSelectorWords) throws KeyCollisionException {
-
- BibDatabase fromDatabase = pr.getDatabase();
+ BibDatabase fromDatabase = parserResult.getDatabase();
List appendedEntries = new ArrayList<>();
List originalEntries = new ArrayList<>();
BibDatabase database = panel.getDatabase();
NamedCompound ce = new NamedCompound(Localization.lang("Append library"));
- MetaData meta = pr.getMetaData();
+ MetaData meta = parserResult.getMetaData();
if (importEntries) { // Add entries
boolean overwriteOwner = Globals.prefs.getBoolean(JabRefPreferences.OVERWRITE_OWNER);
boolean overwriteTimeStamp = Globals.prefs.getBoolean(JabRefPreferences.OVERWRITE_TIME_STAMP);
for (BibEntry originalEntry : fromDatabase.getEntries()) {
- BibEntry be = (BibEntry) originalEntry.clone();
- UpdateField.setAutomaticFields(be, overwriteOwner, overwriteTimeStamp,
+ BibEntry entry = (BibEntry) originalEntry.clone();
+ UpdateField.setAutomaticFields(entry, overwriteOwner, overwriteTimeStamp,
Globals.prefs.getUpdateFieldPreferences());
- database.insertEntry(be);
- appendedEntries.add(be);
+ database.insertEntry(entry);
+ appendedEntries.add(entry);
originalEntries.add(originalEntry);
- ce.addEdit(new UndoableInsertEntry(database, be, panel));
+ ce.addEdit(new UndoableInsertEntry(database, entry, panel));
}
}
@@ -156,10 +106,7 @@ private static void mergeFromBibtex(JabRefFrame frame, BasePanel panel, ParserRe
}
}
- // groupsSelector is always created, even when no groups
- // have been defined. therefore, no check for null is
- // required here
- frame.getGroupSelector().addGroups(newGroups, ce);
+ addGroups(newGroups, ce);
});
}
@@ -173,4 +120,77 @@ private static void mergeFromBibtex(JabRefFrame frame, BasePanel panel, ParserRe
panel.getUndoManager().addEdit(ce);
panel.markBaseChanged();
}
+
+ /**
+ * Adds the specified node as a child of the current root. The group contained in newGroups must not be of
+ * type AllEntriesGroup, since every tree has exactly one AllEntriesGroup (its root). The newGroups are
+ * inserted directly, i.e. they are not deepCopy()'d.
+ */
+ private static void addGroups(GroupTreeNode newGroups, CompoundEdit ce) {
+
+ // paranoia: ensure that there are never two instances of AllEntriesGroup
+ if (newGroups.getGroup() instanceof AllEntriesGroup) {
+ return; // this should be impossible anyway
+ }
+
+ Globals.stateManager.getActiveDatabase()
+ .map(BibDatabaseContext::getMetaData)
+ .flatMap(MetaData::getGroups)
+ .ifPresent(newGroups::moveTo);
+
+ //UndoableAddOrRemoveGroup undo = new UndoableAddOrRemoveGroup(groupsRoot,
+ // new GroupTreeNodeViewModel(newGroups), UndoableAddOrRemoveGroup.ADD_NODE);
+ //ce.addEdit(undo);
+ }
+
+ @Override
+ public void action() {
+ filesToOpen.clear();
+ final MergeDialog dialog = new MergeDialog(frame, Localization.lang("Append library"), true);
+ dialog.setLocationRelativeTo(panel);
+ dialog.setVisible(true);
+ if (dialog.isOkPressed()) {
+
+ FileDialogConfiguration fileDialogConfiguration = new FileDialogConfiguration.Builder()
+ .withDefaultExtension(FileExtensions.BIBTEX_DB)
+ .withInitialDirectory(Globals.prefs.get(JabRefPreferences.WORKING_DIRECTORY))
+ .build();
+ DialogService dialogService = new FXDialogService();
+
+ List chosen = DefaultTaskExecutor
+ .runInJavaFXThread(() -> dialogService.showFileOpenDialogAndGetMultipleFiles(fileDialogConfiguration));
+ if (chosen.isEmpty()) {
+ return;
+ }
+ filesToOpen.addAll(chosen);
+
+ // Run the actual open in a thread to prevent the program
+ // locking until the file is loaded.
+ JabRefExecutorService.INSTANCE.execute(
+ () -> openIt(dialog.importEntries(), dialog.importStrings(), dialog.importGroups(), dialog.importSelectorWords()));
+ }
+ }
+
+ private void openIt(boolean importEntries, boolean importStrings, boolean importGroups,
+ boolean importSelectorWords) {
+ if (filesToOpen.isEmpty()) {
+ return;
+ }
+ for (Path file : filesToOpen) {
+ try {
+ Globals.prefs.put(JabRefPreferences.WORKING_DIRECTORY, file.getParent().toString());
+ // Should this be done _after_ we know it was successfully opened?
+ ParserResult parserResult = OpenDatabase.loadDatabase(file.toFile(),
+ Globals.prefs.getImportFormatPreferences());
+ AppendDatabaseAction.mergeFromBibtex(panel, parserResult, importEntries, importStrings, importGroups,
+ importSelectorWords);
+ 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.ERROR_MESSAGE);
+ }
+ }
+ }
+
}
diff --git a/src/main/java/org/jabref/gui/preftabs/GroupsPrefsTab.java b/src/main/java/org/jabref/gui/preftabs/GroupsPrefsTab.java
index 6b6cd35e365..061fe5719ed 100644
--- a/src/main/java/org/jabref/gui/preftabs/GroupsPrefsTab.java
+++ b/src/main/java/org/jabref/gui/preftabs/GroupsPrefsTab.java
@@ -9,6 +9,7 @@
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
+import javax.swing.JRadioButton;
import javax.swing.JTextField;
import org.jabref.logic.l10n.Localization;
@@ -23,6 +24,9 @@ class GroupsPrefsTab extends JPanel implements PrefsTab {
private final JCheckBox grayOut = new JCheckBox(Localization.lang("Gray out non-hits"));
private final JCheckBox autoAssignGroup = new JCheckBox(
Localization.lang("Automatically assign new entry to selected groups"));
+ private final JRadioButton multiSelectionModeIntersection = new JRadioButton(Localization.lang("Intersection"));
+ private final JRadioButton multiSelectionModeUnion = new JRadioButton(Localization.lang("Union"));
+
private final JTextField groupingField = new JTextField(20);
private final JTextField keywordSeparator = new JTextField(2);
@@ -49,8 +53,15 @@ public void focusLost(FocusEvent e) {
hideMode.add(grayOut);
hideMode.add(hideNonHits);
+ ButtonGroup multiSelectionMode = new ButtonGroup();
+ multiSelectionMode.add(multiSelectionModeIntersection);
+ multiSelectionMode.add(multiSelectionModeUnion);
+ multiSelectionModeIntersection.setToolTipText(Localization.lang("Display only entries belonging to all selected groups."));
+ multiSelectionModeUnion.setToolTipText(Localization.lang("Display all entries belonging to one or more of the selected groups."));
+
+
FormLayout layout = new FormLayout("9dlu, pref", //500px",
- "p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, p");
+ "p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, p");
DefaultFormBuilder builder = new DefaultFormBuilder(layout);
builder.appendSeparator(Localization.lang("View"));
builder.nextLine();
@@ -64,6 +75,14 @@ public void focusLost(FocusEvent e) {
builder.nextLine();
builder.nextLine();
builder.nextColumn();
+ builder.append(multiSelectionModeIntersection);
+ builder.nextLine();
+ builder.nextLine();
+ builder.nextColumn();
+ builder.append(multiSelectionModeUnion);
+ builder.nextLine();
+ builder.nextLine();
+ builder.nextColumn();
builder.append(autoAssignGroup);
builder.nextLine();
builder.nextLine();
@@ -95,6 +114,7 @@ public void setValues() {
groupingField.setText(prefs.get(JabRefPreferences.GROUPS_DEFAULT_FIELD));
keywordSeparator.setText(prefs.get(JabRefPreferences.KEYWORD_SEPARATOR));
autoAssignGroup.setSelected(prefs.getBoolean(JabRefPreferences.AUTO_ASSIGN_GROUP));
+ multiSelectionModeIntersection.setSelected(prefs.getBoolean(JabRefPreferences.GROUP_INTERSECT_SELECTIONS));
}
@Override
@@ -103,6 +123,7 @@ public void storeSettings() {
prefs.put(JabRefPreferences.GROUPS_DEFAULT_FIELD, groupingField.getText().trim());
prefs.putBoolean(JabRefPreferences.AUTO_ASSIGN_GROUP, autoAssignGroup.isSelected());
prefs.put(JabRefPreferences.KEYWORD_SEPARATOR, keywordSeparator.getText());
+ prefs.putBoolean(JabRefPreferences.GROUP_INTERSECT_SELECTIONS, multiSelectionModeIntersection.isSelected());
}
@Override
diff --git a/src/main/java/org/jabref/gui/preftabs/PreferencesDialog.java b/src/main/java/org/jabref/gui/preftabs/PreferencesDialog.java
index fa880318a9a..156bbe872b1 100644
--- a/src/main/java/org/jabref/gui/preftabs/PreferencesDialog.java
+++ b/src/main/java/org/jabref/gui/preftabs/PreferencesDialog.java
@@ -256,10 +256,18 @@ private void storeAllSettings() {
MainTable.updateRenderers();
GUIGlobals.updateEntryEditorColors();
frame.setupAllTables();
- frame.getGroupSelector().revalidateGroups(); // icons may have changed
frame.output(Localization.lang("Preferences recorded."));
}
+ public void setValues() {
+ // Update all field values in the tabs:
+ int count = main.getComponentCount();
+ Component[] comps = main.getComponents();
+ for (int i = 0; i < count; i++) {
+ ((PrefsTab) comps[i]).setValues();
+ }
+ }
+
class OkAction extends AbstractAction {
public OkAction() {
@@ -303,15 +311,6 @@ public void actionPerformed(ActionEvent e) {
}
}
- public void setValues() {
- // Update all field values in the tabs:
- int count = main.getComponentCount();
- Component[] comps = main.getComponents();
- for (int i = 0; i < count; i++) {
- ((PrefsTab) comps[i]).setValues();
- }
- }
-
class CancelAction extends AbstractAction {
public CancelAction() {
diff --git a/src/main/java/org/jabref/gui/util/BindingsHelper.java b/src/main/java/org/jabref/gui/util/BindingsHelper.java
index f2158a065f4..88ca45210af 100644
--- a/src/main/java/org/jabref/gui/util/BindingsHelper.java
+++ b/src/main/java/org/jabref/gui/util/BindingsHelper.java
@@ -18,6 +18,9 @@
import javafx.css.PseudoClass;
import javafx.scene.Node;
+import net.corda.client.jfx.utils.MappedList;
+
+
/**
* Helper methods for javafx binding.
* Some methods are taken from https://bugs.openjdk.java.net/browse/JDK-8134679
@@ -56,6 +59,18 @@ public String getName() {
pseudoClassState.bind(condition);
}
+ /**
+ * Creates a new list in which each element is converted using the provided mapping.
+ * All changes to the underlying list are propagated to the converted list.
+ *
+ * In contrast to {@link org.fxmisc.easybind.EasyBind#map(ObservableList, Function)},
+ * the items are converted when the are inserted (and at the initialization) instead of when they are accessed.
+ * Thus the initial CPU overhead and memory consumption is higher but the access to list items is quicker.
+ */
+ public static ObservableList mapBacked(ObservableList source, Function mapper) {
+ return new MappedList<>(source, mapper::apply);
+ }
+
/**
* Binds propertA bidirectional to propertyB using the provided map functions to convert between them.
*/
@@ -86,14 +101,33 @@ public static void bindBidirectional(ObservableValue propertyA, Observ
propertyB.addListener(binding.getChangeListenerB());
}
- public static void bindContentBidirectional(ListProperty listProperty, Property property, Function, B> mapToB, Function> mapToList) {
- final BidirectionalListBinding binding = new BidirectionalListBinding<>(listProperty, property, mapToB, mapToList);
+ public static void bindContentBidirectional(ObservableList propertyA, ListProperty propertyB, Consumer> updateA, Consumer> updateB) {
+ bindContentBidirectional(
+ propertyA,
+ (ObservableValue>) propertyB,
+ updateA,
+ updateB);
+ }
+
+ public static void bindContentBidirectional(ObservableList propertyA, ObservableValue propertyB, Consumer updateA, Consumer> updateB) {
+ final BidirectionalListBinding binding = new BidirectionalListBinding<>(propertyA, propertyB, updateA, updateB);
// use property as initial source
- listProperty.setAll(mapToList.apply(property.getValue()));
+ updateA.accept(propertyB.getValue());
+
+ propertyA.addListener(binding);
+ propertyB.addListener(binding);
+ }
- listProperty.addListener(binding);
- property.addListener(binding);
+ public static void bindContentBidirectional(ListProperty listProperty, Property property, Function, B> mapToB, Function> mapToList) {
+ Consumer updateList = newValueB -> listProperty.setAll(mapToList.apply(newValueB));
+ Consumer> updateB = newValueList -> property.setValue(mapToB.apply(newValueList));
+
+ bindContentBidirectional(
+ listProperty,
+ property,
+ updateList,
+ updateB);
}
private static class BidirectionalBinding {
@@ -139,17 +173,17 @@ private void updateLocked(Consumer update, T oldValue, T newValue) {
private static class BidirectionalListBinding implements ListChangeListener, ChangeListener {
- private final ListProperty listProperty;
- private final Property property;
- private final Function, B> mapToB;
- private final Function> mapToList;
+ private final ObservableList listProperty;
+ private final ObservableValue property;
+ private final Consumer updateA;
+ private final Consumer> updateB;
private boolean updating = false;
- public BidirectionalListBinding(ListProperty listProperty, Property property, Function, B> mapToB, Function> mapToList) {
+ public BidirectionalListBinding(ObservableList listProperty, ObservableValue property, Consumer updateA, Consumer> updateB) {
this.listProperty = listProperty;
this.property = property;
- this.mapToB = mapToB;
- this.mapToList = mapToList;
+ this.updateA = updateA;
+ this.updateB = updateB;
}
@Override
@@ -157,7 +191,7 @@ public void changed(ObservableValue extends B> observable, B oldValue, B newVa
if (!updating) {
try {
updating = true;
- listProperty.setAll(mapToList.apply(newValue));
+ updateA.accept(newValue);
} finally {
updating = false;
}
@@ -169,7 +203,7 @@ public void onChanged(Change extends A> c) {
if (!updating) {
try {
updating = true;
- property.setValue(mapToB.apply(listProperty.getValue()));
+ updateB.accept(listProperty);
} finally {
updating = false;
}
diff --git a/src/main/java/org/jabref/gui/util/RecursiveTreeItem.java b/src/main/java/org/jabref/gui/util/RecursiveTreeItem.java
index e6f15fb2caf..1117f9dad36 100644
--- a/src/main/java/org/jabref/gui/util/RecursiveTreeItem.java
+++ b/src/main/java/org/jabref/gui/util/RecursiveTreeItem.java
@@ -70,28 +70,28 @@ private void addChildrenListener(T value) {
children = new FilteredList<>(childrenFactory.call(value));
children.predicateProperty().bind(Bindings.createObjectBinding(() -> this::showNode, filter));
- children.forEach(this::addAsChild);
+ addAsChildren(children, 0);
children.addListener((ListChangeListener) change -> {
while (change.next()) {
if (change.wasRemoved()) {
change.getRemoved().forEach(t-> {
- final List> itemsToRemove = RecursiveTreeItem.this.getChildren().stream().filter(treeItem -> treeItem.getValue().equals(t)).collect(Collectors.toList());
-
- RecursiveTreeItem.this.getChildren().removeAll(itemsToRemove);
+ final List> itemsToRemove = getChildren().stream().filter(treeItem -> treeItem.getValue().equals(t)).collect(Collectors.toList());
+ getChildren().removeAll(itemsToRemove);
});
}
if (change.wasAdded()) {
- change.getAddedSubList().forEach(this::addAsChild);
+ addAsChildren(change.getAddedSubList(), change.getFrom());
}
}
});
}
- private boolean addAsChild(T child) {
- return RecursiveTreeItem.this.getChildren().add(new RecursiveTreeItem<>(child, getGraphic(), childrenFactory, expandedProperty, filter));
+ private void addAsChildren(List extends T> children, int startIndex) {
+ List> treeItems = children.stream().map(child -> new RecursiveTreeItem<>(child, getGraphic(), childrenFactory, expandedProperty, filter)).collect(Collectors.toList());
+ getChildren().addAll(startIndex, treeItems);
}
private boolean showNode(T t) {
diff --git a/src/main/java/org/jabref/logic/importer/WebFetchers.java b/src/main/java/org/jabref/logic/importer/WebFetchers.java
index a0ca5f0cfd3..628ebb41953 100644
--- a/src/main/java/org/jabref/logic/importer/WebFetchers.java
+++ b/src/main/java/org/jabref/logic/importer/WebFetchers.java
@@ -14,6 +14,7 @@
import org.jabref.logic.importer.fetcher.GoogleScholar;
import org.jabref.logic.importer.fetcher.GvkFetcher;
import org.jabref.logic.importer.fetcher.IsbnFetcher;
+import org.jabref.logic.importer.fetcher.LibraryOfCongress;
import org.jabref.logic.importer.fetcher.MathSciNet;
import org.jabref.logic.importer.fetcher.MedlineFetcher;
import org.jabref.logic.importer.fetcher.TitleFetcher;
@@ -88,6 +89,7 @@ public static List getIdBasedFetchers(ImportFormatPreferences im
list.add(new TitleFetcher(importFormatPreferences));
list.add(new MathSciNet(importFormatPreferences));
list.add(new CrossRef());
+ list.add(new LibraryOfCongress());
list.sort(Comparator.comparing(WebFetcher::getName));
return list;
}
diff --git a/src/main/java/org/jabref/logic/importer/fetcher/AstrophysicsDataSystem.java b/src/main/java/org/jabref/logic/importer/fetcher/AstrophysicsDataSystem.java
index f3ecdc21700..d8a50a9d333 100644
--- a/src/main/java/org/jabref/logic/importer/fetcher/AstrophysicsDataSystem.java
+++ b/src/main/java/org/jabref/logic/importer/fetcher/AstrophysicsDataSystem.java
@@ -10,6 +10,7 @@
import java.util.List;
import java.util.Objects;
+import org.jabref.logic.cleanup.MoveFieldCleanup;
import org.jabref.logic.formatter.bibtexfields.ClearFormatter;
import org.jabref.logic.formatter.bibtexfields.NormalizeNamesFormatter;
import org.jabref.logic.formatter.bibtexfields.RemoveBracesFormatter;
@@ -154,8 +155,9 @@ public void doPostCleanup(BibEntry entry) {
new FieldFormatterCleanup(FieldName.TITLE, new RemoveBracesFormatter()).cleanup(entry);
new FieldFormatterCleanup(FieldName.AUTHOR, new NormalizeNamesFormatter()).cleanup(entry);
- // Remove url to ADS page
+ // Remove ADS note
new FieldFormatterCleanup("adsnote", new ClearFormatter()).cleanup(entry);
- new FieldFormatterCleanup("adsurl", new ClearFormatter()).cleanup(entry);
+ // Move adsurl to url field
+ new MoveFieldCleanup("adsurl", FieldName.URL).cleanup(entry);
}
}
diff --git a/src/main/java/org/jabref/logic/importer/fetcher/LibraryOfCongress.java b/src/main/java/org/jabref/logic/importer/fetcher/LibraryOfCongress.java
new file mode 100644
index 00000000000..60ca3bc13d8
--- /dev/null
+++ b/src/main/java/org/jabref/logic/importer/fetcher/LibraryOfCongress.java
@@ -0,0 +1,34 @@
+package org.jabref.logic.importer.fetcher;
+
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+
+import org.jabref.logic.importer.FetcherException;
+import org.jabref.logic.importer.IdBasedParserFetcher;
+import org.jabref.logic.importer.Parser;
+import org.jabref.logic.importer.fileformat.ModsImporter;
+
+import org.apache.http.client.utils.URIBuilder;
+
+/**
+ * Fetcher for the Library of Congress Control Number (LCCN) using https://lccn.loc.gov/
+ */
+public class LibraryOfCongress implements IdBasedParserFetcher {
+
+ @Override
+ public String getName() {
+ return "Library of Congress";
+ }
+
+ @Override
+ public URL getURLForID(String identifier) throws URISyntaxException, MalformedURLException, FetcherException {
+ URIBuilder uriBuilder = new URIBuilder("https://lccn.loc.gov/" + identifier + "/mods");
+ return uriBuilder.build().toURL();
+ }
+
+ @Override
+ public Parser getParser() {
+ return new ModsImporter();
+ }
+}
diff --git a/src/main/java/org/jabref/logic/importer/fileformat/ModsImporter.java b/src/main/java/org/jabref/logic/importer/fileformat/ModsImporter.java
index 2708b05ae20..325683a2326 100644
--- a/src/main/java/org/jabref/logic/importer/fileformat/ModsImporter.java
+++ b/src/main/java/org/jabref/logic/importer/fileformat/ModsImporter.java
@@ -2,7 +2,11 @@
import java.io.BufferedReader;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -17,6 +21,8 @@
import javax.xml.bind.Unmarshaller;
import org.jabref.logic.importer.Importer;
+import org.jabref.logic.importer.ParseException;
+import org.jabref.logic.importer.Parser;
import org.jabref.logic.importer.ParserResult;
import org.jabref.logic.importer.fileformat.mods.AbstractDefinition;
import org.jabref.logic.importer.fileformat.mods.DateDefinition;
@@ -61,7 +67,7 @@
* More details about the format can be found here http://www.loc.gov/standards/mods/.
* The newest xml schema can also be found here www.loc.gov/standards/mods/mods-schemas.html..
*/
-public class ModsImporter extends Importer {
+public class ModsImporter extends Importer implements Parser {
private static final Log LOGGER = LogFactory.getLog(ModsImporter.class);
private static final String KEYWORD_SEPARATOR = JabRefPreferences.getInstance().getImportFormatPreferences()
@@ -476,4 +482,13 @@ public String getDescription() {
return "Importer for the MODS format";
}
+ @Override
+ public List parseEntries(InputStream inputStream) throws ParseException {
+ try {
+ return importDatabase(new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))).getDatabase().getEntries();
+ } catch (IOException e) {
+ LOGGER.error(e.getLocalizedMessage(), e);
+ }
+ return Collections.emptyList();
+ }
}
diff --git a/src/main/java/org/jabref/logic/msbib/MSBibEntry.java b/src/main/java/org/jabref/logic/msbib/MSBibEntry.java
index 7e1cb3d2758..2155ee5a56f 100644
--- a/src/main/java/org/jabref/logic/msbib/MSBibEntry.java
+++ b/src/main/java/org/jabref/logic/msbib/MSBibEntry.java
@@ -10,6 +10,7 @@
import org.jabref.model.entry.Author;
import org.jabref.model.entry.AuthorList;
+import org.jabref.model.entry.Date;
import org.jabref.model.strings.StringUtil;
import org.w3c.dom.Document;
@@ -26,14 +27,6 @@
*/
class MSBibEntry {
- /**
- * Allows 20.3-2007|||20/3- 2007 etc.
- * (\d{1,2})\s?[.,-/]\s?(\d{1,2})\s?[.,-/]\s?(\d{2,4})
- * 1-2 DIGITS SPACE SEPERATOR SPACE 1-2 DIGITS SPACE SEPERATOR SPACE 2-4 DIGITS
- */
- private static final Pattern DATE_PATTERN = Pattern
- .compile("(\\d{1,2})\\s*[.,-/]\\s*(\\d{1,2})\\s*[.,-/]\\s*(\\d{2,4})");
-
// MSBib fields and values
public Map fields = new HashMap<>();
public List authors;
@@ -165,22 +158,11 @@ private void populateFromXml(Element entry) {
String dayAccessed = getXmlElementTextContent("DayAccessed", entry);
String yearAccessed = getXmlElementTextContent("YearAccessed", entry);
- StringBuilder sbDateAccesed = new StringBuilder();
- if (monthAccessed != null) {
- sbDateAccesed.append(monthAccessed);
- sbDateAccesed.append(' ');
- }
- if (dayAccessed != null) {
- sbDateAccesed.append(dayAccessed);
- sbDateAccesed.append(", ");
- }
- if (yearAccessed != null) {
- sbDateAccesed.append(yearAccessed);
- }
- dateAccessed = sbDateAccesed.toString().trim();
- if (dateAccessed.isEmpty() || ",".equals(dateAccessed)) {
- dateAccessed = null;
- }
+ Optional parsedDateAcessed = Date.parse(Optional.ofNullable(yearAccessed),
+ Optional.ofNullable(monthAccessed),
+ Optional.ofNullable(dayAccessed));
+
+ parsedDateAcessed.map(Date::getNormalized).ifPresent(date -> dateAccessed = date);
NodeList nodeLst = entry.getElementsByTagNameNS("*", "Author");
if (nodeLst.getLength() > 0) {
@@ -262,15 +244,7 @@ public Element getEntryDom(Document document) {
addField(document, rootNode, entry.getKey(), entry.getValue());
}
- // based on bibtex content
- if (dateAccessed != null) {
- Matcher matcher = DATE_PATTERN.matcher(dateAccessed);
- if (matcher.matches() && (matcher.groupCount() >= 3)) {
- addField(document, rootNode, "Month" + "Accessed", matcher.group(1));
- addField(document, rootNode, "Day" + "Accessed", matcher.group(2));
- addField(document, rootNode, "Year" + "Accessed", matcher.group(3));
- }
- }
+ Optional.ofNullable(dateAccessed).ifPresent(field -> addDateAcessedFields(document, rootNode));
Element allAuthors = document.createElementNS(MSBibDatabase.NAMESPACE, MSBibDatabase.PREFIX + "Author");
@@ -361,6 +335,23 @@ private void addAuthor(Document document, Element allAuthors, String entryName,
}
+ private void addDateAcessedFields(Document document, Element rootNode) {
+ Optional parsedDateAcesseField = Date.parse(dateAccessed);
+ parsedDateAcesseField.flatMap(Date::getYear).map(accYear -> accYear.toString()).ifPresent(yearAccessed -> {
+ addField(document, rootNode, "Year" + "Accessed", yearAccessed);
+ });
+
+ parsedDateAcesseField.flatMap(Date::getMonth)
+ .map(accMonth -> accMonth.getTwoDigitNumber()).ifPresent(monthAcessed -> {
+ addField(document, rootNode, "Month" + "Accessed", monthAcessed);
+
+ });
+ parsedDateAcesseField.flatMap(Date::getDay).map(accDay -> accDay.toString()).ifPresent(dayAccessed -> {
+ addField(document, rootNode, "Day" + "Accessed", dayAccessed);
+ });
+
+ }
+
private void addAddress(Document document, Element parent, String addressToSplit) {
if (addressToSplit == null) {
return;
diff --git a/src/main/java/org/jabref/model/entry/Date.java b/src/main/java/org/jabref/model/entry/Date.java
index 5b4db035bfd..08bb3d7f552 100644
--- a/src/main/java/org/jabref/model/entry/Date.java
+++ b/src/main/java/org/jabref/model/entry/Date.java
@@ -31,21 +31,25 @@ public Date(TemporalAccessor date) {
* The code is essentially taken from http://stackoverflow.com/questions/4024544/how-to-parse-dates-in-multiple-formats-using-simpledateformat.
*/
public static Optional parse(String dateString) {
- List formatStrings = Arrays.asList("uuuu-M-d", "uuuu-M", "d-M-uuuu", "M/uu", "M/uuuu", "MMMM d, uuuu", "MMMM, uuuu",
+ Objects.requireNonNull(dateString);
+ List formatStrings = Arrays.asList("uuuu-M-d", "uuuu-M", "d-M-uuuu", "M/uu", "M/uuuu", "MMMM d, uuuu",
+ "MMMM, uuuu",
"d.M.uuuu", "uuuu.M.d", "uuuu");
- for (String formatString : formatStrings) {
- try {
- TemporalAccessor parsedDate = DateTimeFormatter.ofPattern(formatString).parse(dateString);
- return Optional.of(new Date(parsedDate));
- } catch (DateTimeParseException ignored) {
- // Ignored
+
+ for (String formatString : formatStrings) {
+ try {
+ TemporalAccessor parsedDate = DateTimeFormatter.ofPattern(formatString).parse(dateString);
+ return Optional.of(new Date(parsedDate));
+ } catch (DateTimeParseException ignored) {
+ // Ignored
+ }
}
- }
return Optional.empty();
}
- public static Optional parse(Optional yearValue, Optional monthValue, Optional dayValue) {
+ public static Optional parse(Optional yearValue, Optional monthValue,
+ Optional dayValue) {
Optional year = yearValue.flatMap(Date::convertToInt).map(Year::of);
Optional month = monthValue.flatMap(Month::parse);
Optional day = dayValue.flatMap(Date::convertToInt);
@@ -107,8 +111,12 @@ public TemporalAccessor toTemporalAccessor() {
@Override
public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
+ if (this == o) {
+ return true;
+ }
+ if ((o == null) || (getClass() != o.getClass())) {
+ return false;
+ }
Date date1 = (Date) o;
return Objects.equals(getYear(), date1.getYear()) &&
Objects.equals(getMonth(), date1.getMonth()) &&
diff --git a/src/main/java/org/jabref/model/pdf/FileAnnotation.java b/src/main/java/org/jabref/model/pdf/FileAnnotation.java
index 1c09eaaa78e..79e478b946c 100644
--- a/src/main/java/org/jabref/model/pdf/FileAnnotation.java
+++ b/src/main/java/org/jabref/model/pdf/FileAnnotation.java
@@ -12,7 +12,7 @@ public class FileAnnotation {
private final static int ABBREVIATED_ANNOTATION_NAME_LENGTH = 45;
private static final String DATE_TIME_STRING = "^D:\\d{14}$";
- private static final String DATE_TIME_STRING_WITH_TIME_ZONE = "^D:\\d{14}\\+.+";
+ private static final String DATE_TIME_STRING_WITH_TIME_ZONE = "^D:\\d{14}.+";
private static final String ANNOTATION_DATE_FORMAT = "yyyyMMddHHmmss";
private final String author;
diff --git a/src/main/java/org/jabref/model/util/TreeCollector.java b/src/main/java/org/jabref/model/util/TreeCollector.java
index 2955774bc1f..28614f4d448 100644
--- a/src/main/java/org/jabref/model/util/TreeCollector.java
+++ b/src/main/java/org/jabref/model/util/TreeCollector.java
@@ -40,7 +40,7 @@ private TreeCollector(Function> getChildren, BiConsumer addChil
}
public static > TreeCollector mergeIntoTree(BiPredicate equivalence) {
- return new TreeCollector(
+ return new TreeCollector<>(
TreeNode::getChildren,
(parent, child) -> child.moveTo(parent),
equivalence);
diff --git a/src/main/java/org/jabref/preferences/JabRefPreferences.java b/src/main/java/org/jabref/preferences/JabRefPreferences.java
index 946001eef94..4ffcccd55cd 100644
--- a/src/main/java/org/jabref/preferences/JabRefPreferences.java
+++ b/src/main/java/org/jabref/preferences/JabRefPreferences.java
@@ -185,9 +185,7 @@ public class JabRefPreferences implements PreferencesService {
public static final String EDITOR_EMACS_KEYBINDINGS_REBIND_CA = "editorEMACSkeyBindingsRebindCA";
public static final String EDITOR_EMACS_KEYBINDINGS_REBIND_CF = "editorEMACSkeyBindingsRebindCF";
public static final String GROUPS_DEFAULT_FIELD = "groupsDefaultField";
- public static final String GROUP_INVERT_SELECTIONS = "groupInvertSelections";
public static final String GROUP_INTERSECT_SELECTIONS = "groupIntersectSelections";
- public static final String GROUP_FLOAT_SELECTIONS = "groupFloatSelections";
public static final String KEYWORD_SEPARATOR = "groupKeywordSeparator";
public static final String AUTO_ASSIGN_GROUP = "autoAssignGroup";
public static final String LIST_OF_FILE_COLUMNS = "listOfFileColumns";
@@ -568,9 +566,7 @@ private JabRefPreferences() {
defaults.put(EDITOR_EMACS_KEYBINDINGS_REBIND_CF, Boolean.TRUE);
defaults.put(AUTO_COMPLETE, Boolean.FALSE);
AutoCompletePreferences.putDefaults(defaults);
- defaults.put(GROUP_FLOAT_SELECTIONS, Boolean.TRUE);
- defaults.put(GROUP_INTERSECT_SELECTIONS, Boolean.TRUE);
- defaults.put(GROUP_INVERT_SELECTIONS, Boolean.FALSE);
+ defaults.put(GROUP_INTERSECT_SELECTIONS, Boolean.FALSE);
defaults.put(GROUPS_DEFAULT_FIELD, FieldName.KEYWORDS);
defaults.put(AUTO_ASSIGN_GROUP, Boolean.TRUE);
defaults.put(KEYWORD_SEPARATOR, ", ");
diff --git a/src/main/resources/l10n/JabRef_da.properties b/src/main/resources/l10n/JabRef_da.properties
index b2cd3e0416c..395756a5870 100644
--- a/src/main/resources/l10n/JabRef_da.properties
+++ b/src/main/resources/l10n/JabRef_da.properties
@@ -80,8 +80,6 @@ All_entries_of_this_type_will_be_declared_typeless._Continue?=Alle_posterne_af_d
All_fields=Alle_felter
-All_subgroups_(recursively)=Alle_undergrupper_(rekursivt)
-
Always_reformat_BIB_file_on_save_and_export=
A_SAX_exception_occurred_while_parsing_'%0'\:=En_SAXException_forekom_ved_læsning_af_'%0'\:
@@ -352,8 +350,6 @@ Display_help_on_command_line_options=Vis_kommandolinjehjælp
Display_only_entries_belonging_to_all_selected_groups.=Vis_kun_poster_indeholdt_i_alle_valgte_grupper.
Display_version=Vis_versionsnummer
-Displaying_no_groups=Viser_ingen_grupper
-
Do_not_abbreviate_names=Forkort_ikke_navn
Do_not_automatically_set=Sæt_ikke_links_automatisk
@@ -577,8 +573,6 @@ Generated_BibTeX_key_for=Genererede_BibTeX-nøgle_for
Generating_BibTeX_key_for=Genererer_BibTeX-nøgle_for
Get_fulltext=
-Gray_out_entries_not_in_group_selection=Skraver_poster_udenfor_valgte_grupper
-
Gray_out_non-hits=Skraver_ikke-træffere
Groups=Gruppering
@@ -587,8 +581,6 @@ Have_you_chosen_the_correct_package_path?=Har_du_valgt_korrekt_pakke-sti?
Help=Hjælp
-Help_on_groups=Hjælp_om_grupper
-
Help_on_key_patterns=Hjælp_om_nøglegenerering
Help_on_regular_expression_search=Hjælp_om_søgning_med_regulære_udtryk
@@ -612,8 +604,6 @@ Icon=Ikon
Ignore=Ignorer
-Immediate_subgroups=Nærmeste_undergrupper
-
Import=Importer
Import_and_keep_old_entry=Importer_og_behold_den_gamle_post
@@ -671,8 +661,6 @@ Invalid_date_format=Ugyldigt_datoformat
Invalid_URL=Ugyldig_URL
-Inverted=Inverteret
-
Online_help=
JabRef_preferences=JabRef-indstillinger
@@ -760,7 +748,6 @@ modify_group=ændre_gruppe
Move_down=Flyt_ned
-Move_entries_in_group_selection_to_the_top=Flyt_poster_i_valgte_grupper_til_toppen
Move_external_links_to_'file'_field=Flyt_eksterne_links_til_'file'-feltet
move_group=flyt_gruppe
@@ -1117,8 +1104,6 @@ Show_confirmation_dialog_when_deleting_entries=Vis_dialog_for_at_bekræfte_sletn
Show_description=Vis_beskrivelse
-Show_entries_not_in_group_selection=Vis_poster_udenfor_valgte_grupper
-
Show_file_column=Vis_'file'-kolonne
Show_last_names_only=Vis_kun_efternavn
@@ -1140,14 +1125,6 @@ Skipped_-_PDF_does_not_exist=Sprang_over_-_PDF-filen_findes_ikke
Skipped_entry.=Sprang_over_post.
-Sort_alphabetically=Sorter_alfabetisk
-
-sort_subgroups=sorter_undergrupper
-
-Sorted_all_subgroups_recursively.=Sorterede_alle_undergrupper_rekursivt.
-
-Sorted_immediate_subgroups.=Sorterede_nærmeste_undergrupper.
-
source_edit=redigering_af_kilde
Special_name_formatters=Specielle_navneformateringer
diff --git a/src/main/resources/l10n/JabRef_de.properties b/src/main/resources/l10n/JabRef_de.properties
index 9ac956f6419..1067d4340df 100644
--- a/src/main/resources/l10n/JabRef_de.properties
+++ b/src/main/resources/l10n/JabRef_de.properties
@@ -80,8 +80,6 @@ All_entries_of_this_type_will_be_declared_typeless._Continue?=Alle_Einträge_die
All_fields=Alle_Felder
-All_subgroups_(recursively)=Alle_Untergruppen_(rekursiv)
-
Always_reformat_BIB_file_on_save_and_export=Formatiere_BIB_Datei_immer_neu_beim_Exportieren
A_SAX_exception_occurred_while_parsing_'%0'\:=Beim_Parsen_von_'%0'_ist_eine_SAX-Exception_aufgetreten\:
@@ -352,8 +350,6 @@ Display_help_on_command_line_options=Zeige_Kommandozeilenhilfe
Display_only_entries_belonging_to_all_selected_groups.=Nur_Einträge_anzeigen,_die_zu_allen_ausgewählten_Gruppen_gehören.
Display_version=Version_anzeigen
-Displaying_no_groups=Keine_Gruppen_anzeigen
-
Do_not_abbreviate_names=Namen_nicht_abkürzen
Do_not_automatically_set=Nicht_automatisch_zuordnen
@@ -577,8 +573,6 @@ Generated_BibTeX_key_for=BibTeX-Key_erzeugt_für
Generating_BibTeX_key_for=Erzeuge_BibTeX-Key_für
Get_fulltext=Hole_Volltext
-Gray_out_entries_not_in_group_selection=Einträge_ausblenden,_die_nicht_in_der_Gruppenauswahl_sind
-
Gray_out_non-hits=Nicht-Treffer_grau_einfärben
Groups=Gruppen
@@ -587,8 +581,6 @@ Have_you_chosen_the_correct_package_path?=Habe_Sie_den_richtigen_Klassenpfad_gew
Help=Hilfe
-Help_on_groups=Hilfe_zu_Gruppen
-
Help_on_key_patterns=Hilfe_zu_BibTeX-Key-Mustern
Help_on_regular_expression_search=Hilfe_zur_Suche_mit_regulärem_Ausdruck
@@ -612,8 +604,6 @@ Icon=Icon
Ignore=Ignorieren
-Immediate_subgroups=Direkte_Untergruppen
-
Import=Importieren
Import_and_keep_old_entry=Importieren_und_alten_Eintrag_behalten
@@ -671,8 +661,6 @@ Invalid_date_format=Ungültiges_Datumsformat
Invalid_URL=Ungültige_URL
-Inverted=Invertiert
-
Online_help=Online_Hilfe
JabRef_preferences=JabRef_Einstellungen
@@ -760,7 +748,6 @@ modify_group=Gruppe_bearbeiten
Move_down=Nach_unten
-Move_entries_in_group_selection_to_the_top=Sortiere_Einträge_der_Gruppenauswahl_nach_oben
Move_external_links_to_'file'_field=Externe_Links_in_das_Feld_'file'_verschieben
move_group=Gruppe_verschieben
@@ -1117,8 +1104,6 @@ Show_confirmation_dialog_when_deleting_entries=Dialog_zum_Löschen_von_Einträge
Show_description=Beschreibung_anzeigen
-Show_entries_not_in_group_selection=Zeige_Einträge,_die_nicht_in_der_Gruppenauswahl_sind
-
Show_file_column=Datei-Spalte_anzeigen
Show_last_names_only=Zeige_nur_Nachnamen
@@ -1140,14 +1125,6 @@ Skipped_-_PDF_does_not_exist=Übersprungen_-_PDF_exisitert_nicht
Skipped_entry.=Eintrag_übersprungen.
-Sort_alphabetically=Alphabetisch_sortieren
-
-sort_subgroups=Untergruppen_sortieren
-
-Sorted_all_subgroups_recursively.=Alle_Untergruppen_rekursiv_sortiert.
-
-Sorted_immediate_subgroups.=Alle_direkten_Untergruppen_sortiert.
-
source_edit=Quelltextbearbeitung
Special_name_formatters=Spezielle_Namens-Formatierer
diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties
index bb2264f24cd..11385b6ee24 100644
--- a/src/main/resources/l10n/JabRef_en.properties
+++ b/src/main/resources/l10n/JabRef_en.properties
@@ -80,8 +80,6 @@ All_entries_of_this_type_will_be_declared_typeless._Continue?=All_entries_of_thi
All_fields=All_fields
-All_subgroups_(recursively)=All_subgroups_(recursively)
-
Always_reformat_BIB_file_on_save_and_export=Always_reformat_BIB_file_on_save_and_export
A_SAX_exception_occurred_while_parsing_'%0'\:=A_SAX_exception_occurred_while_parsing_'%0'\:
@@ -352,8 +350,6 @@ Display_help_on_command_line_options=Display_help_on_command_line_options
Display_only_entries_belonging_to_all_selected_groups.=Display_only_entries_belonging_to_all_selected_groups.
Display_version=Display_version
-Displaying_no_groups=Displaying_no_groups
-
Do_not_abbreviate_names=Do_not_abbreviate_names
Do_not_automatically_set=Do_not_automatically_set
@@ -577,8 +573,6 @@ Generated_BibTeX_key_for=Generated_BibTeX_key_for
Generating_BibTeX_key_for=Generating_BibTeX_key_for
Get_fulltext=Get_fulltext
-Gray_out_entries_not_in_group_selection=Gray_out_entries_not_in_group_selection
-
Gray_out_non-hits=Gray_out_non-hits
Groups=Groups
@@ -587,8 +581,6 @@ Have_you_chosen_the_correct_package_path?=Have_you_chosen_the_correct_package_pa
Help=Help
-Help_on_groups=Help_on_groups
-
Help_on_key_patterns=Help_on_key_patterns
Help_on_regular_expression_search=Help_on_regular_expression_search
@@ -612,8 +604,6 @@ Icon=Icon
Ignore=Ignore
-Immediate_subgroups=Immediate_subgroups
-
Import=Import
Import_and_keep_old_entry=Import_and_keep_old_entry
@@ -671,8 +661,6 @@ Invalid_date_format=Invalid_date_format
Invalid_URL=Invalid_URL
-Inverted=Inverted
-
Online_help=Online_help
JabRef_preferences=JabRef_preferences
@@ -760,7 +748,6 @@ modify_group=modify_group
Move_down=Move_down
-Move_entries_in_group_selection_to_the_top=Move_entries_in_group_selection_to_the_top
Move_external_links_to_'file'_field=Move_external_links_to_'file'_field
move_group=move_group
@@ -1117,8 +1104,6 @@ Show_confirmation_dialog_when_deleting_entries=Show_confirmation_dialog_when_del
Show_description=Show_description
-Show_entries_not_in_group_selection=Show_entries_not_in_group_selection
-
Show_file_column=Show_file_column
Show_last_names_only=Show_last_names_only
@@ -1140,14 +1125,6 @@ Skipped_-_PDF_does_not_exist=Skipped_-_PDF_does_not_exist
Skipped_entry.=Skipped_entry.
-Sort_alphabetically=Sort_alphabetically
-
-sort_subgroups=sort_subgroups
-
-Sorted_all_subgroups_recursively.=Sorted_all_subgroups_recursively.
-
-Sorted_immediate_subgroups.=Sorted_immediate_subgroups.
-
source_edit=source_edit
Special_name_formatters=Special_name_formatters
diff --git a/src/main/resources/l10n/JabRef_es.properties b/src/main/resources/l10n/JabRef_es.properties
index 8ddc2b2ed6c..45c5bd953ac 100644
--- a/src/main/resources/l10n/JabRef_es.properties
+++ b/src/main/resources/l10n/JabRef_es.properties
@@ -80,8 +80,6 @@ All_entries_of_this_type_will_be_declared_typeless._Continue?=Todas_las_entradas
All_fields=Todos_los_campos
-All_subgroups_(recursively)=Todos_los_subgrupos(Recursivamente)
-
Always_reformat_BIB_file_on_save_and_export=Siempre_reformatear_el_fichero_BIB_al_guardar_y_exportar
A_SAX_exception_occurred_while_parsing_'%0'\:=Ocurrió_una_Excepción_SAX_mientras_se_analizaba_la_sintaxis_de_'%0'\:
@@ -352,8 +350,6 @@ Display_help_on_command_line_options=Mosrar_ayuda_en_las_opciones_de_línea_de_c
Display_only_entries_belonging_to_all_selected_groups.=Mostrar_sólo_entradas_pertenecientes_a_todos_los_grupos_seleccionados.
Display_version=Mostrar_versión
-Displaying_no_groups=No_se_muestran_grupos
-
Do_not_abbreviate_names=No_abreviar_nombres
Do_not_automatically_set=No_establecer_automáticamente
@@ -577,8 +573,6 @@ Generated_BibTeX_key_for=Generar_clabe_BibTeX_para
Generating_BibTeX_key_for=Generarando_clave_BibTeX_para
Get_fulltext=Obtener_texto_completo
-Gray_out_entries_not_in_group_selection=Poner_en_gris_entradas_que_no_estén_en_el_grupo_de_selección
-
Gray_out_non-hits=Poner_en_gris_los_no_encontrados
Groups=Grupos
@@ -587,8 +581,6 @@ Have_you_chosen_the_correct_package_path?=¿Ha_escogido_la_ruta_de_paquetes_corr
Help=Ayuda
-Help_on_groups=Ayuda_sobre_grupos
-
Help_on_key_patterns=Ayuda_sobre_patrones_de_teclas
Help_on_regular_expression_search=Ayuda_sobre_búsqueda_mediante_expresión_regular
@@ -612,8 +604,6 @@ Icon=Icono
Ignore=Ignorar
-Immediate_subgroups=Subgrupos_inmediatos
-
Import=Importar
Import_and_keep_old_entry=Importar_y_conservar_entrada_antigua
@@ -671,8 +661,6 @@ Invalid_date_format=Formato_de_fecha_no_válido
Invalid_URL=URL_no_válida
-Inverted=Invertido
-
Online_help=Ayuda_online
JabRef_preferences=Preferencias_de_JabRef
@@ -760,7 +748,6 @@ modify_group=Modificar_grupo
Move_down=Mover_hacia_abajo
-Move_entries_in_group_selection_to_the_top=Mover_entradas_en_el_grupo_seleccionado_al_inicio
Move_external_links_to_'file'_field=Mover_enlaces_externos_al_campo_'archivo'
move_group=Mover_grupo
@@ -1117,8 +1104,6 @@ Show_confirmation_dialog_when_deleting_entries=Mostra_diálogo_de_confirmación_
Show_description=Mostrar_descripción
-Show_entries_not_in_group_selection=Mostrar_entradas_que_NO_estén_en_la_selección_de_grupo
-
Show_file_column=Mostrar_columna_de_archivo
Show_last_names_only=Mostrar_sólo_apellidos
@@ -1140,14 +1125,6 @@ Skipped_-_PDF_does_not_exist=Omitido_-_No_existe_el_PDF
Skipped_entry.=Entrada_omitida.
-Sort_alphabetically=Ordenar_alfabéticamente
-
-sort_subgroups=ordenar_subgrupos
-
-Sorted_all_subgroups_recursively.=Ordenar_todos_los_subgrupos_recursivamente.
-
-Sorted_immediate_subgroups.=Subgrupos_inmediatos_ordenados.
-
source_edit=editar_fuente
Special_name_formatters=Formateadores_con_nombre_especial
diff --git a/src/main/resources/l10n/JabRef_fa.properties b/src/main/resources/l10n/JabRef_fa.properties
index ddbe5713999..77fef62ff50 100644
--- a/src/main/resources/l10n/JabRef_fa.properties
+++ b/src/main/resources/l10n/JabRef_fa.properties
@@ -80,8 +80,6 @@ All_entries_of_this_type_will_be_declared_typeless._Continue?=
All_fields=
-All_subgroups_(recursively)=
-
Always_reformat_BIB_file_on_save_and_export=
A_SAX_exception_occurred_while_parsing_'%0'\:=
@@ -352,8 +350,6 @@ Display_help_on_command_line_options=
Display_only_entries_belonging_to_all_selected_groups.=
Display_version=
-Displaying_no_groups=
-
Do_not_abbreviate_names=
Do_not_automatically_set=
@@ -577,8 +573,6 @@ Generated_BibTeX_key_for=
Generating_BibTeX_key_for=
Get_fulltext=
-Gray_out_entries_not_in_group_selection=
-
Gray_out_non-hits=
Groups=
@@ -587,8 +581,6 @@ Have_you_chosen_the_correct_package_path?=
Help=
-Help_on_groups=
-
Help_on_key_patterns=
Help_on_regular_expression_search=
@@ -612,8 +604,6 @@ Icon=
Ignore=
-Immediate_subgroups=
-
Import=
Import_and_keep_old_entry=
@@ -671,8 +661,6 @@ Invalid_date_format=
Invalid_URL=
-Inverted=
-
Online_help=
JabRef_preferences=
@@ -760,7 +748,6 @@ modify_group=
Move_down=
-Move_entries_in_group_selection_to_the_top=
Move_external_links_to_'file'_field=
move_group=
@@ -1117,8 +1104,6 @@ Show_confirmation_dialog_when_deleting_entries=
Show_description=
-Show_entries_not_in_group_selection=
-
Show_file_column=
Show_last_names_only=
@@ -1140,14 +1125,6 @@ Skipped_-_PDF_does_not_exist=
Skipped_entry.=
-Sort_alphabetically=
-
-sort_subgroups=
-
-Sorted_all_subgroups_recursively.=
-
-Sorted_immediate_subgroups.=
-
source_edit=
Special_name_formatters=
diff --git a/src/main/resources/l10n/JabRef_fr.properties b/src/main/resources/l10n/JabRef_fr.properties
index 94f0d637875..c9c63d16c23 100644
--- a/src/main/resources/l10n/JabRef_fr.properties
+++ b/src/main/resources/l10n/JabRef_fr.properties
@@ -80,8 +80,6 @@ All_entries_of_this_type_will_be_declared_typeless._Continue?=Toutes_les_entrée
All_fields=Tous_les_champs
-All_subgroups_(recursively)=Tous_les_sous-groupes_(récursivement)
-
Always_reformat_BIB_file_on_save_and_export=Toujours_remettre_en_forme_les_fichiers_BIB_lors_de_l'enregistrement_et_de_l'exportation
A_SAX_exception_occurred_while_parsing_'%0'\:=Une_exception_SAX_est_survenue_pendant_le_traitement_de_'%0'_\:
@@ -352,8 +350,6 @@ Display_help_on_command_line_options=Afficher_l'aide_sur_les_options_de_la_ligne
Display_only_entries_belonging_to_all_selected_groups.=Afficher_uniquement_les_entrées_appartenant_à_tous_les_groupes_sélectionnés.
Display_version=Afficher_la_version
-Displaying_no_groups=Pas_de_groupes_à_afficher
-
Do_not_abbreviate_names=Ne_pas_abréger_les_noms
Do_not_automatically_set=Ne_pas_définir_automatiquement.
@@ -577,8 +573,6 @@ Generated_BibTeX_key_for=Création_terminée_de_la_clef_BibTeX_pour
Generating_BibTeX_key_for=Création_en_cours_d'une_clef_BibTeX_pour
Get_fulltext=Obtenir_le_document
-Gray_out_entries_not_in_group_selection=Griser_les_entrées_hors_de_la_sélection
-
Gray_out_non-hits=Griser_les_entrées_non_correspondantes
Groups=Groupes
@@ -587,8 +581,6 @@ Have_you_chosen_the_correct_package_path?=Avez-vous_choisi_le_bon_chemin_pour_le
Help=Aide
-Help_on_groups=Aide_sur_les_groupes
-
Help_on_key_patterns=Aide_sur_le_paramétrage_des_clefs
Help_on_regular_expression_search=Aide_sur_la_recherche_d'une_expression_régulière
@@ -612,8 +604,6 @@ Icon=Icône
Ignore=Ignorer
-Immediate_subgroups=Uniquement_les_sous-groupes_directs
-
Import=Importer
Import_and_keep_old_entry=Importer_et_conserver_l'ancienne_entrée
@@ -671,8 +661,6 @@ Invalid_date_format=Format_de_date_invalide
Invalid_URL=URL_invalide
-Inverted=Complémentaire
-
Online_help=Aide_en_ligne
JabRef_preferences=Préférences_pour_JabRef
@@ -760,7 +748,6 @@ modify_group=Modifier_le_groupe
Move_down=Déplacer_vers_le_bas
-Move_entries_in_group_selection_to_the_top=Déplacer_les_entrées_sélectionnées_en_haut
Move_external_links_to_'file'_field=Déplacer_les_liens_externes_vers_le_champ_'fichier'
move_group=déplacer_le_groupe
@@ -1117,8 +1104,6 @@ Show_confirmation_dialog_when_deleting_entries=Demander_une_confirmation_lors_de
Show_description=Montrer_la_description
-Show_entries_not_in_group_selection=Montrer_les_entrées_non_sélectionnées
-
Show_file_column=Afficher_la_colonne_Fichier
Show_last_names_only=Afficher_uniquement_les_noms_propres
@@ -1140,14 +1125,6 @@ Skipped_-_PDF_does_not_exist=Omis_-_Le_PDF_n'existe_pas
Skipped_entry.=Entrée_omise
-Sort_alphabetically=Classer_alphabétiquement
-
-sort_subgroups=trier_les_sous-groupes
-
-Sorted_all_subgroups_recursively.=Tous_les_sous-groupes_récursivement_triés.
-
-Sorted_immediate_subgroups.=Sous-groupes_directs_triés.
-
source_edit=édition_du_source
Special_name_formatters=Formateurs_de_nom_spéciaux
diff --git a/src/main/resources/l10n/JabRef_in.properties b/src/main/resources/l10n/JabRef_in.properties
index 63b8a115ce5..5cf62453596 100644
--- a/src/main/resources/l10n/JabRef_in.properties
+++ b/src/main/resources/l10n/JabRef_in.properties
@@ -80,8 +80,6 @@ All_entries_of_this_type_will_be_declared_typeless._Continue?=Semua_entri_tipe_i
All_fields=Semua_bidang
-All_subgroups_(recursively)=Semua_anak_grup_(rekursif)
-
Always_reformat_BIB_file_on_save_and_export=
A_SAX_exception_occurred_while_parsing_'%0'\:=SAXException_terjadi_ketika_mengurai_'%0'\:
@@ -352,8 +350,6 @@ Display_help_on_command_line_options=Tampilkan_bantuan_pada_opsi_perindah_baris
Display_only_entries_belonging_to_all_selected_groups.=Tampilkan_entri_hanya_yang_ada_di_grup_pilihan.
Display_version=Tampilkan_versi
-Displaying_no_groups=Grup_tidak_ditampilkan
-
Do_not_abbreviate_names=Jangan_singkat_nama
Do_not_automatically_set=Jangan_pengaturan_otomatis
@@ -577,8 +573,6 @@ Generated_BibTeX_key_for=Kunci_BibTeX_dibuat_untuk
Generating_BibTeX_key_for=Membuat_kunci_BibTeX_untuk
Get_fulltext=
-Gray_out_entries_not_in_group_selection=Kelabukan_entri_yang_tidak_dalam_pilihan_grup
-
Gray_out_non-hits=Kelabukan_non-hits
Groups=Grup
@@ -587,8 +581,6 @@ Have_you_chosen_the_correct_package_path?=Apakah_anda_sudah_memilih_lokasi_paket
Help=Bantuan
-Help_on_groups=Bantuan_untuk_grup
-
Help_on_key_patterns=Bantuan_untuk_pola_kunci
Help_on_regular_expression_search=Bantuan_untuk_Pencarian_Ekspresi_Reguler
@@ -612,8 +604,6 @@ Icon=Ikon
Ignore=Abaikan
-Immediate_subgroups=sub-grup_seketika
-
Import=Impor
Import_and_keep_old_entry=Impor_dan_pertahankan_entri_lama
@@ -671,8 +661,6 @@ Invalid_date_format=Format_hari_salah
Invalid_URL=URL_salah
-Inverted=Dibalik
-
Online_help=
JabRef_preferences=Preferensi_JabRef
@@ -760,7 +748,6 @@ modify_group=memodifikasi_grup
Move_down=Pindah_kebawah
-Move_entries_in_group_selection_to_the_top=Pindah_entri_dalam_grup_pilihan_ke_atas
Move_external_links_to_'file'_field=Pindah_tautan_eksternal_ke_bidang_'berkas'
move_group=pindah_grup
@@ -1117,8 +1104,6 @@ Show_confirmation_dialog_when_deleting_entries=Tampilkan_dialog_konfirmasi_jika_
Show_description=Tampilkan_deskripsi
-Show_entries_not_in_group_selection=Tampilkan_entri_tidak_dalam_pilihan_grup
-
Show_file_column=Tampilkan_kolom_berkas
Show_last_names_only=Tampil_hanya_nama_belakang
@@ -1140,14 +1125,6 @@ Skipped_-_PDF_does_not_exist=Dilompati_-_PDF_tidak_ada
Skipped_entry.=Entri_dilompati.
-Sort_alphabetically=Urut_alfabet
-
-sort_subgroups=urut_sub-grup
-
-Sorted_all_subgroups_recursively.=Diurutkan_semua_sub-grup_secara_rekursif
-
-Sorted_immediate_subgroups.=Diurutkan_sub-grup_seketika.
-
source_edit=sunting_sumber
Special_name_formatters=Pemformat_Nama_Spesial
diff --git a/src/main/resources/l10n/JabRef_it.properties b/src/main/resources/l10n/JabRef_it.properties
index 8d9727cb899..f7251d8f8a4 100644
--- a/src/main/resources/l10n/JabRef_it.properties
+++ b/src/main/resources/l10n/JabRef_it.properties
@@ -80,8 +80,6 @@ All_entries_of_this_type_will_be_declared_typeless._Continue?=Tutte_le_voci_di_q
All_fields=Tutti_i_campi
-All_subgroups_(recursively)=Tutti_i_sottogruppi_(ricorsivamente)
-
Always_reformat_BIB_file_on_save_and_export=Riformatta_sempre_il_file_BIB_quando_salvi_o_esporti
A_SAX_exception_occurred_while_parsing_'%0'\:=Eccezione_SAX_durante_l'analisi_di_'%0'\:
@@ -352,8 +350,6 @@ Display_help_on_command_line_options=Mostra_l'aiuto_sulle_opzioni_della_riga_di_
Display_only_entries_belonging_to_all_selected_groups.=Mostra_solo_le_voci_appartenenti_a_tutti_i_gruppi_selezionati.
Display_version=Versione
-Displaying_no_groups=Nessun_gruppo_da_visualizzare
-
Do_not_abbreviate_names=Non_abbreviare_i_nomi
Do_not_automatically_set=Non_effettuare_definizioni_automatiche
@@ -577,8 +573,6 @@ Generated_BibTeX_key_for=Generata_la_chiave_BibTeX_per
Generating_BibTeX_key_for=Generazione_in_corso_della_chiave_BibTeX_per
Get_fulltext=Prendi_testo_completo
-Gray_out_entries_not_in_group_selection=Evidenzia_in_grigio_le_voci_fuori_dai_gruppi_selezionati
-
Gray_out_non-hits=Disattiva_le_voci_non_corrispondenti
Groups=Gruppi
@@ -587,8 +581,6 @@ Have_you_chosen_the_correct_package_path?=Il_classpath_è_corretto?
Help=Aiuto
-Help_on_groups=Aiuto_sui_gruppi
-
Help_on_key_patterns=Aiuto_sulla_composizione_delle_chiavi
Help_on_regular_expression_search=Aiuto_sulla_ricerca_di_un'espressione_regolare
@@ -612,8 +604,6 @@ Icon=Icona
Ignore=Ignora
-Immediate_subgroups=Sottogruppi_diretti
-
Import=Importa
Import_and_keep_old_entry=Importa_e_mantieni_le_vecchie_voci
@@ -671,8 +661,6 @@ Invalid_date_format=Formato_data_non_valido
Invalid_URL=URL_non_valido
-Inverted=Complementare
-
Online_help=Help_online
JabRef_preferences=Preferenze_JabRef
@@ -760,7 +748,6 @@ modify_group=modifica_gruppo
Move_down=Sposta_in_giù
-Move_entries_in_group_selection_to_the_top=Sposta_le_voci_selezionate_in_su
Move_external_links_to_'file'_field=Sposta_i_collegamenti_esterni_nel_campo_'file'
move_group=sposta_gruppo
@@ -1117,8 +1104,6 @@ Show_confirmation_dialog_when_deleting_entries=Chiedere_conferma_della_cancellaz
Show_description=Mostra_descrizione
-Show_entries_not_in_group_selection=Mostra_le_voci_non_comprese_nei_gruppi_selezionati
-
Show_file_column=Visualizza_la_colonna_File
Show_last_names_only=Mostra_solo_i_cognomi
@@ -1140,14 +1125,6 @@ Skipped_-_PDF_does_not_exist=Saltato_-_Il_file_PDF_non_esiste
Skipped_entry.=Voce_saltata
-Sort_alphabetically=Ordina_alfabeticamente
-
-sort_subgroups=ordina_i_sottogruppi
-
-Sorted_all_subgroups_recursively.=Ordina_tutti_i_sottogruppi_ricorsivamente.
-
-Sorted_immediate_subgroups.=Ordinati_i_sottogruppi_immediati.
-
source_edit=modifica_sorgente
Special_name_formatters=Formattazioni_speciali_dei_nomi
diff --git a/src/main/resources/l10n/JabRef_ja.properties b/src/main/resources/l10n/JabRef_ja.properties
index 5cf62087ac7..5c9ea80343c 100644
--- a/src/main/resources/l10n/JabRef_ja.properties
+++ b/src/main/resources/l10n/JabRef_ja.properties
@@ -80,8 +80,6 @@ All_entries_of_this_type_will_be_declared_typeless._Continue?=この型の項目
All_fields=全フィールド
-All_subgroups_(recursively)=全下層グループ(再帰的に)
-
Always_reformat_BIB_file_on_save_and_export=保存・書出の際、つねにBIBファイルを再整形する
A_SAX_exception_occurred_while_parsing_'%0'\:=「%0」を解析中にSAX例外エラーが発生しました\:
@@ -352,8 +350,6 @@ Display_help_on_command_line_options=コマンドラインオプションに関
Display_only_entries_belonging_to_all_selected_groups.=選択したグループ全てに属する項目のみ表示する。
Display_version=バージョンを表示
-Displaying_no_groups=グループを表示しない
-
Do_not_abbreviate_names=名前を略さない
Do_not_automatically_set=自動設定しない
@@ -577,8 +573,6 @@ Generated_BibTeX_key_for=以下の項目のBibTeX鍵を生成しました\:
Generating_BibTeX_key_for=以下の項目のBibTeX鍵を生成しています\:
Get_fulltext=フルテキストを得る
-Gray_out_entries_not_in_group_selection=グループ選択にない項目を淡色化する
-
Gray_out_non-hits=合致しないものを淡色化
Groups=グループ
@@ -587,8 +581,6 @@ Have_you_chosen_the_correct_package_path?=正しいパッケージパスを選
Help=ヘルプ
-Help_on_groups=グループに関するヘルプ
-
Help_on_key_patterns=キーパターンに関するヘルプ
Help_on_regular_expression_search=正規表現検索に関するヘルプ
@@ -612,8 +604,6 @@ Icon=アイコン
Ignore=無視
-Immediate_subgroups=直下の下層グループ
-
Import=読み込み
Import_and_keep_old_entry=読み込みを行い、旧項目は維持
@@ -671,8 +661,6 @@ Invalid_date_format=無効な日付書式です
Invalid_URL=無効なURLです
-Inverted=否定
-
Online_help=オンラインヘルプ
JabRef_preferences=JabRefの設定
@@ -760,7 +748,6 @@ modify_group=グループを修正
Move_down=下げる
-Move_entries_in_group_selection_to_the_top=グループ選択中の項目を上に移動
Move_external_links_to_'file'_field=外部リンクを「ファイル」フィールドに移動
move_group=グループを移動
@@ -1117,8 +1104,6 @@ Show_confirmation_dialog_when_deleting_entries=項目を削除する際に確認
Show_description=説明を表示
-Show_entries_not_in_group_selection=グループ選択に「ない」項目を表示する
-
Show_file_column=ファイル列を表示
Show_last_names_only=姓のみを表示する
@@ -1140,14 +1125,6 @@ Skipped_-_PDF_does_not_exist=跳ばしました_-_PDFが存在しません
Skipped_entry.=項目を跳ばしました。
-Sort_alphabetically=アルファベット順に整序
-
-sort_subgroups=下層グループを整序
-
-Sorted_all_subgroups_recursively.=下層グループをすべて再帰的に整序しました。
-
-Sorted_immediate_subgroups.=直下の下層グループを整序しました。
-
source_edit=ソースの編集
Special_name_formatters=名前の整形の定義
diff --git a/src/main/resources/l10n/JabRef_nl.properties b/src/main/resources/l10n/JabRef_nl.properties
index ce725f8b4ea..df337381b16 100644
--- a/src/main/resources/l10n/JabRef_nl.properties
+++ b/src/main/resources/l10n/JabRef_nl.properties
@@ -80,8 +80,6 @@ All_entries_of_this_type_will_be_declared_typeless._Continue?=
All_fields=Alle_velden
-All_subgroups_(recursively)=Alle_subgroepen_(recursief)
-
Always_reformat_BIB_file_on_save_and_export=
A_SAX_exception_occurred_while_parsing_'%0'\:=
@@ -352,8 +350,6 @@ Display_help_on_command_line_options=Toon_help_over_commandline_opties
Display_only_entries_belonging_to_all_selected_groups.=Toon_alleen_entries_die_tot_alle_geselecteerde_groepen_behoren.
Display_version=Display_versie
-Displaying_no_groups=Geen_groepen_tonend
-
Do_not_abbreviate_names=Namen_niet_afkorten
Do_not_automatically_set=Niet_automatisch_instellen
@@ -577,8 +573,6 @@ Generated_BibTeX_key_for=Gegenereerde_BibTeX-sleutel_voor
Generating_BibTeX_key_for=BibTeX-sleutel_aan_het_genereren_voor
Get_fulltext=
-Gray_out_entries_not_in_group_selection=Maak_entries_die_niet_in_de_groep_selectie_zitten_grijs
-
Gray_out_non-hits=Maak_niet_gevonden_items_grijs
Groups=Groepen
@@ -587,8 +581,6 @@ Have_you_chosen_the_correct_package_path?=Heeft_u_het_correcte_pakket_pad_gekoze
Help=Help
-Help_on_groups=Help_over_groepen
-
Help_on_key_patterns=Help_over_sleutelpatronen
Help_on_regular_expression_search=Help_over_Regular_Expression_Zoekopdracht
@@ -612,8 +604,6 @@ Icon=
Ignore=Negeren
-Immediate_subgroups=Directe_subgroepen
-
Import=Importeren
Import_and_keep_old_entry=Importeren_en_oude_entry_behouden
@@ -671,8 +661,6 @@ Invalid_date_format=Ongeldig_datumformaat
Invalid_URL=Ongeldige_URL
-Inverted=Ge\u00efnverteerd
-
Online_help=
JabRef_preferences=JabRef_instellingen
@@ -760,7 +748,6 @@ modify_group=wijzig_groep
Move_down=Verplaats_naar_beneden
-Move_entries_in_group_selection_to_the_top=Verplaats_entries_in_de_groep_selectie_naar_de_top
Move_external_links_to_'file'_field=
move_group=verplaats_groep
@@ -1117,8 +1104,6 @@ Show_confirmation_dialog_when_deleting_entries=Toon_bevestigingsdialoog_bij_verw
Show_description=Toon_beschrijving
-Show_entries_not_in_group_selection=Toon_entries_die_zich_niet_in_de_groep_selectie_bevinden
-
Show_file_column=
Show_last_names_only=Toon_enkel_laatste_namen
@@ -1140,14 +1125,6 @@ Skipped_-_PDF_does_not_exist=Overgeslagen_-_PDF_bestaat_niet
Skipped_entry.=Overgeslagen_entry.
-Sort_alphabetically=Alphabetisch_sorteren
-
-sort_subgroups=subgroepen_sorteren
-
-Sorted_all_subgroups_recursively.=Alle_subgroepen_recursief_gesorteerd.
-
-Sorted_immediate_subgroups.=Onmiddellijke_subgroepen_sorteren.
-
source_edit=broncode_aanpassen
Special_name_formatters=
diff --git a/src/main/resources/l10n/JabRef_no.properties b/src/main/resources/l10n/JabRef_no.properties
index 2e4512a0b40..98619ebcb9b 100644
--- a/src/main/resources/l10n/JabRef_no.properties
+++ b/src/main/resources/l10n/JabRef_no.properties
@@ -80,8 +80,6 @@ All_entries_of_this_type_will_be_declared_typeless._Continue?=Alle_enhetene_av_d
All_fields=Alle_felter
-All_subgroups_(recursively)=Alle_undergrupper_(rekursivt)
-
Always_reformat_BIB_file_on_save_and_export=
A_SAX_exception_occurred_while_parsing_'%0'\:=En_SAXException_forekom_ved_lesing_av_'%0'\:
@@ -352,8 +350,6 @@ Display_help_on_command_line_options=Vis_kommandolinjehjelp
Display_only_entries_belonging_to_all_selected_groups.=Vis_kun_enheter_inneholdt_i_alle_valgte_grupper.
Display_version=Vis_versjonsnummer
-Displaying_no_groups=Viser_ingen_grupper
-
Do_not_abbreviate_names=Ikke_forkort_navn
Do_not_automatically_set=Ikke_sett_linker_automatisk
@@ -577,8 +573,6 @@ Generated_BibTeX_key_for=Genererte_BibTeX-n\u00f8kkel_for
Generating_BibTeX_key_for=Genererer_BibTeX-n\u00f8kkel_for
Get_fulltext=
-Gray_out_entries_not_in_group_selection=Skraver_enheter_utenfor_valgte_grupper
-
Gray_out_non-hits=Vis_ikke-treff_i-gr\u00e5tt
Groups=Gruppering
@@ -587,8 +581,6 @@ Have_you_chosen_the_correct_package_path?=Har_du_valgt_riktig_pakkenavn?
Help=Hjelp
-Help_on_groups=Hjelp_om_grupper
-
Help_on_key_patterns=Hjelp_om_n\u00f8kkelgenerering
Help_on_regular_expression_search=Hjelp_for_s\u00f8k_med_regul\u00e6ruttrykk
@@ -612,8 +604,6 @@ Icon=Ikon
Ignore=Ignorer
-Immediate_subgroups=N\u00e6rmeste_undergrupper
-
Import=Importer
Import_and_keep_old_entry=Importer_og_behold_den_gamle_enheten
@@ -671,8 +661,6 @@ Invalid_date_format=Ugyldig_datoformat
Invalid_URL=Ugyldig_URL
-Inverted=Invertert
-
Online_help=
JabRef_preferences=JabRef-oppsett
@@ -760,7 +748,6 @@ modify_group=endre_gruppe
Move_down=Flytt_ned
-Move_entries_in_group_selection_to_the_top=Flytt_enheter_i_valgte_grupper_\u00f8verst
Move_external_links_to_'file'_field=Flytt_eksterne_linker_til_'file'-feltet
move_group=flytt_gruppe
@@ -1117,8 +1104,6 @@ Show_confirmation_dialog_when_deleting_entries=Vis_dialog_for_\u00e5_bekrefte_sl
Show_description=Vis_beskrivelse
-Show_entries_not_in_group_selection=Vis_enheter_utenfor_valgte_grupper
-
Show_file_column=Vis_'file'-kolonne
Show_last_names_only=Vis_bare_etternavn
@@ -1140,14 +1125,6 @@ Skipped_-_PDF_does_not_exist=Hoppet_over_-_PDF-filen_finnes_ikke
Skipped_entry.=Hoppet_over_enhet.
-Sort_alphabetically=Sorter_alfabetisk
-
-sort_subgroups=sorter_undergrupper
-
-Sorted_all_subgroups_recursively.=Sorterte_alle_undergrupper_rekursivt.
-
-Sorted_immediate_subgroups.=Sorterte_n\u00e6rmeste_undergrupper.
-
source_edit=redigering_av_kilde
Special_name_formatters=Spesielle_navneformaterere
diff --git a/src/main/resources/l10n/JabRef_pt_BR.properties b/src/main/resources/l10n/JabRef_pt_BR.properties
index 9a1a4f4be10..1c324798b14 100644
--- a/src/main/resources/l10n/JabRef_pt_BR.properties
+++ b/src/main/resources/l10n/JabRef_pt_BR.properties
@@ -80,8 +80,6 @@ All_entries_of_this_type_will_be_declared_typeless._Continue?=Todas_as_referênc
All_fields=Todos_os_campos
-All_subgroups_(recursively)=Todos_os_subgrupos_(recursivamente)
-
Always_reformat_BIB_file_on_save_and_export=
A_SAX_exception_occurred_while_parsing_'%0'\:=Uma_exceção_ocorreu_durante_a_análise_de_'%0'
@@ -352,8 +350,6 @@ Display_help_on_command_line_options=Exibir_ajuda_para_opções_de_linha_de_coma
Display_only_entries_belonging_to_all_selected_groups.=Exibir_apenas_referências_pertencentes_aos_grupos_selecionados.
Display_version=Exibir_versão
-Displaying_no_groups=Nenhum_grupo_sendo_exibido
-
Do_not_abbreviate_names=Não_abreviar_nomes
Do_not_automatically_set=Não_definir_automaticamente
@@ -577,8 +573,6 @@ Generated_BibTeX_key_for=Chave_BibTeX_gerada_para
Generating_BibTeX_key_for=Gerando_chave_BibTeX_para
Get_fulltext=
-Gray_out_entries_not_in_group_selection=Esmaecer_referências_fora_da_seleção_do_grupo
-
Gray_out_non-hits=Esmaecer_referências_não_encontradas
Groups=Grupos
@@ -587,8 +581,6 @@ Have_you_chosen_the_correct_package_path?=Você_escolheu_o_caminho_de_pacote_cor
Help=Ajuda
-Help_on_groups=Ajuda_sobre_grupos
-
Help_on_key_patterns=Ajuda_sobre_modelos_de_chave
Help_on_regular_expression_search=Ajuda_sobre_busca_por_expressão_regular
@@ -612,8 +604,6 @@ Icon=Ícone
Ignore=Ignorar
-Immediate_subgroups=Subgrupos_imediatos
-
Import=Importar
Import_and_keep_old_entry=Importar_e_manter_referências_antigas
@@ -671,8 +661,6 @@ Invalid_date_format=Formato_de_data_inválido
Invalid_URL=URL_inválida
-Inverted=invertido
-
Online_help=
JabRef_preferences=Preferências_do_JabRef
@@ -760,7 +748,6 @@ modify_group=Modificar_grupo
Move_down=Mover_para_baixo
-Move_entries_in_group_selection_to_the_top=Mover_referências_nos_grupos_selecionados_para_o_topo
Move_external_links_to_'file'_field=Mover_links_externos_para_o_campo_'arquivo'
move_group=mover_grupo
@@ -1117,8 +1104,6 @@ Show_confirmation_dialog_when_deleting_entries=Exibir_diálogo_de_confirmação_
Show_description=Exibir_descrição
-Show_entries_not_in_group_selection=Exibir_referências_que_não_estão_no_grupo_selecionado
-
Show_file_column=Exibir_coluna_de_arquivo
Show_last_names_only=Exibir_apenas_últimos_nomes
@@ -1140,14 +1125,6 @@ Skipped_-_PDF_does_not_exist=Omitido_-_O_PDF_não_existe
Skipped_entry.=Referência_omitida.
-Sort_alphabetically=Ordenar_alfabeticamente
-
-sort_subgroups=ordenar_subgrupos
-
-Sorted_all_subgroups_recursively.=Todos_os_grupos_foram_recursivamente_ordenados.
-
-Sorted_immediate_subgroups.=Grupos_imediatos_ordenados.
-
source_edit=edição_de_fonte
Special_name_formatters=Formatadores_de_nome_espepciais
diff --git a/src/main/resources/l10n/JabRef_ru.properties b/src/main/resources/l10n/JabRef_ru.properties
index 7d1ca0bcb38..289c44321d5 100644
--- a/src/main/resources/l10n/JabRef_ru.properties
+++ b/src/main/resources/l10n/JabRef_ru.properties
@@ -80,8 +80,6 @@ All_entries_of_this_type_will_be_declared_typeless._Continue?=Все_запис
All_fields=Все_поля
-All_subgroups_(recursively)=Все_подгруппы_(рекурсивно)
-
Always_reformat_BIB_file_on_save_and_export=Всегда_преобразовывать_формат_файла_BIB_при_сохранении_и_экспорте
A_SAX_exception_occurred_while_parsing_'%0'\:=Исключение_SAX_при_анализе_'%0'\:
@@ -352,8 +350,6 @@ Display_help_on_command_line_options=Отображать_справку_по_п
Display_only_entries_belonging_to_all_selected_groups.=Отображать_только_записи,_принадлежащие_всем_выбранным_группам.
Display_version=Отобразить_сведения_о_версии
-Displaying_no_groups=Без_отображения_групп
-
Do_not_abbreviate_names=Не_сокращать_названия
Do_not_automatically_set=Без_автоопределения
@@ -577,8 +573,6 @@ Generated_BibTeX_key_for=Создать_ключ_BibTeX_для
Generating_BibTeX_key_for=Создание_ключа_BibTeX_для
Get_fulltext=Получить_весь_текст
-Gray_out_entries_not_in_group_selection=Деактивировать_записи,_не_выделенные_в_группу
-
Gray_out_non-hits=Деактивировать_неподходящие
Groups=Группы
@@ -587,8 +581,6 @@ Have_you_chosen_the_correct_package_path?=Проверьте_правильно
Help=Справка
-Help_on_groups=Справка_по_группам
-
Help_on_key_patterns=Справка_по_шаблонам_ключей
Help_on_regular_expression_search=Справка_по_поиску_с_помощью_регулярных_выражений
@@ -612,8 +604,6 @@ Icon=Значок
Ignore=Пропуск
-Immediate_subgroups=Непосредственные_подгруппы
-
Import=Импорт
Import_and_keep_old_entry=Импорт_с_сохранением_старой_записи
@@ -671,8 +661,6 @@ Invalid_date_format=Недопустимый_формат_даты
Invalid_URL=Недопустимый_URL-адрес
-Inverted=Обратный
-
Online_help=Онлайн-справка
JabRef_preferences=Пользовательские_настройки_JabRef
@@ -760,7 +748,6 @@ modify_group=модифицировать_группу
Move_down=Переместить_вниз
-Move_entries_in_group_selection_to_the_top=Переместить_выделенные_записи_вверх
Move_external_links_to_'file'_field=Переместить_внешние_ссылки_в_поле_'файл'
move_group=переместить_группу
@@ -1117,8 +1104,6 @@ Show_confirmation_dialog_when_deleting_entries=Запрос_подтвержде
Show_description=Показать_описание
-Show_entries_not_in_group_selection=Показать_записи_не_выбранные_в_группе
-
Show_file_column=Показать_столбец_Файл
Show_last_names_only=Показать_только_фамилии
@@ -1140,14 +1125,6 @@ Skipped_-_PDF_does_not_exist=Пропущено_-_PDF_не_существует
Skipped_entry.=Запись_пропущена.
-Sort_alphabetically=Сортировка_в_алфавитном_порядке
-
-sort_subgroups=сортировка_подгрупп
-
-Sorted_all_subgroups_recursively.=Все_подгруппы_с_рекурсивной_сортировкой.
-
-Sorted_immediate_subgroups.=Непосредственные_подгруппы_с_сортировкой.
-
source_edit=изменение_источника
Special_name_formatters=Особые_программы_форматирования_имени
diff --git a/src/main/resources/l10n/JabRef_sv.properties b/src/main/resources/l10n/JabRef_sv.properties
index ed60d53fdab..83bd5391554 100644
--- a/src/main/resources/l10n/JabRef_sv.properties
+++ b/src/main/resources/l10n/JabRef_sv.properties
@@ -80,8 +80,6 @@ All_entries_of_this_type_will_be_declared_typeless._Continue?=Alla_poster_av_den
All_fields=Alla_fält
-All_subgroups_(recursively)=Alla_undergrupper_(rekursivt)
-
Always_reformat_BIB_file_on_save_and_export=Formattera_alltid_om_BIB-filen_vid_när_den_sparas_eller_exporteras
A_SAX_exception_occurred_while_parsing_'%0'\:=Ett_SAX-undantag_inträffade_när_'%0'_tolkades\:
@@ -352,8 +350,6 @@ Display_help_on_command_line_options=Visa_hjälp_för_kommandoradsalternativ
Display_only_entries_belonging_to_all_selected_groups.=Visa_bara_poster_som_ingår_i_alla_valda_grupper.
Display_version=Visa_version
-Displaying_no_groups=Visar_inga_grupper
-
Do_not_abbreviate_names=Förkorta_ej_namn
Do_not_automatically_set=Sätt_ej_automatiskt
@@ -577,8 +573,6 @@ Generated_BibTeX_key_for=Genererade_BibTeX-nycklar_för
Generating_BibTeX_key_for=Genererar_BibTeX-nycklar_för
Get_fulltext=Hämta_dokument
-Gray_out_entries_not_in_group_selection=Skugga_poster_som_inte_är_med_i_en_grupp
-
Gray_out_non-hits=Skugga_icke-träffar
Groups=Grupper
@@ -587,8 +581,6 @@ Have_you_chosen_the_correct_package_path?=Har_du_valt_rätt_sökväg_till_pakete
Help=Hjälp
-Help_on_groups=Hjälp_för_grupper
-
Help_on_key_patterns=Hjälp_för_nyckelmönster
Help_on_regular_expression_search=Hjälp_för_sökning_med_reguljära_uttryck
@@ -612,8 +604,6 @@ Icon=Ikon
Ignore=Ignorera
-Immediate_subgroups=
-
Import=Importera
Import_and_keep_old_entry=Importera_och_behåll_gammal_post
@@ -671,8 +661,6 @@ Invalid_date_format=Ogiltigt_datumformat
Invalid_URL=Ogiltig_URL
-Inverted=Omvänd
-
Online_help=Onlinehjälp
JabRef_preferences=Inställningar_för_JabRef
@@ -760,7 +748,6 @@ modify_group=ändra_grupp
Move_down=Flytta_nedåt
-Move_entries_in_group_selection_to_the_top=
Move_external_links_to_'file'_field=Flytta_externa_länkar_till_'file'-fältet
move_group=flytta_grupp
@@ -1117,8 +1104,6 @@ Show_confirmation_dialog_when_deleting_entries=Visa_bekräftelseruta_när_poster
Show_description=Visa_beskrivning
-Show_entries_not_in_group_selection=Visa_poster_som_inte_är_i_vald_grupp
-
Show_file_column=Visa_filkolumn
Show_last_names_only=Visa_bara_efternamn
@@ -1140,14 +1125,6 @@ Skipped_-_PDF_does_not_exist=Hoppade_över_-_PDF_fanns_ej
Skipped_entry.=Hoppade_över_post.
-Sort_alphabetically=Sortera_i_bokstavsordning
-
-sort_subgroups=sortera_undergrupper
-
-Sorted_all_subgroups_recursively.=Sorterade_alla_undergrupper_rekursivt.
-
-Sorted_immediate_subgroups.=
-
source_edit=ändring_av_källkod
Special_name_formatters=Speciella_format_för_namn
diff --git a/src/main/resources/l10n/JabRef_tr.properties b/src/main/resources/l10n/JabRef_tr.properties
index 703f9fc0e2b..877afdaed70 100644
--- a/src/main/resources/l10n/JabRef_tr.properties
+++ b/src/main/resources/l10n/JabRef_tr.properties
@@ -80,8 +80,6 @@ All_entries_of_this_type_will_be_declared_typeless._Continue?=Bu_türeden_tüm_g
All_fields=Tüm_alanlar
-All_subgroups_(recursively)=Tüm_alt-gruplar_(özyinelemeli)
-
Always_reformat_BIB_file_on_save_and_export=Kaydetme_ve_dışa_aktarmada_BIB_dosyasını_her_zaman_yeniden_biçemle
A_SAX_exception_occurred_while_parsing_'%0'\:='%0'_ayrıştırılırken_bir_SAXİstisnası_oluştu\:
@@ -352,8 +350,6 @@ Display_help_on_command_line_options=Komut_satırı_seçenekleri_hakkındaki_yar
Display_only_entries_belonging_to_all_selected_groups.=Yalnızca_seçili_tüm_gruplara_ait_girdileri_göster.
Display_version=Sürümü_göster
-Displaying_no_groups=Gruplar_gösterilmiyor
-
Do_not_abbreviate_names=İsimleri_kısaltma
Do_not_automatically_set=Otomatik_kurma
@@ -577,8 +573,6 @@ Generated_BibTeX_key_for=Şunun_için_BibTeX_anahtarı_oluşturuldu
Generating_BibTeX_key_for=Şunun_için_BibTeX_anahtarı_oluşturuluyor
Get_fulltext=Tammetni_getir
-Gray_out_entries_not_in_group_selection=Grup_seçiminde_olmayan_girdileri_grileştir
-
Gray_out_non-hits=İsabet_almayanları_grileştir
Groups=Gruplar
@@ -587,8 +581,6 @@ Have_you_chosen_the_correct_package_path?=Doğru_paket_yolunu_seçtiniz_mi?
Help=Yardım
-Help_on_groups=Gruplar_hakkında_yardım
-
Help_on_key_patterns=Tuş_desenleri_hakkında_yardım
Help_on_regular_expression_search=Düzenli_İfade_Arama_hakkında_yardım
@@ -612,8 +604,6 @@ Icon=Simge
Ignore=Yoksay
-Immediate_subgroups=Bir_sonraki_altgruplar
-
Import=İçe_aktar
Import_and_keep_old_entry=İçe_aktar_ve_eski_girdiyi_koru
@@ -671,8 +661,6 @@ Invalid_date_format=Geçersiz_tarih_biçemi
Invalid_URL=Geçersiz_URL
-Inverted=Ters_çevrilmiş
-
Online_help=Çevrimiçi_yardım
JabRef_preferences=JabRef_tercihler
@@ -760,7 +748,6 @@ modify_group=grubu_değiştir
Move_down=Aşağı_taşı
-Move_entries_in_group_selection_to_the_top=Grup_seçimindeki_girdileri_en_üste_taşı
Move_external_links_to_'file'_field=Harici_linkleri_'dosya'_alanına_taşı
move_group=grubu_taşı
@@ -1117,8 +1104,6 @@ Show_confirmation_dialog_when_deleting_entries=Girdileri_silerken_onaylama_ileti
Show_description=Açıklamayı_göster
-Show_entries_not_in_group_selection=Girdileri_grup_seçiminde_gösterme
-
Show_file_column=Dosya_sütununu_göster
Show_last_names_only=Yalnızca_soyadları_göster
@@ -1140,14 +1125,6 @@ Skipped_-_PDF_does_not_exist=Atlandı_-_PDF_mevcut_değil
Skipped_entry.=Girdi_atlandı.
-Sort_alphabetically=Alfabetik_sırala
-
-sort_subgroups=altgrupları_sırala
-
-Sorted_all_subgroups_recursively.=Tüm_altgruplar_özyineli_sıralandı.
-
-Sorted_immediate_subgroups.=En_yakın_altgruplar_sıralandı.
-
source_edit=kaynak_düzenle
Special_name_formatters=Özel_Ad_Biçemleyicileri
diff --git a/src/main/resources/l10n/JabRef_vi.properties b/src/main/resources/l10n/JabRef_vi.properties
index 365cc9fa218..d54a9d3d6eb 100644
--- a/src/main/resources/l10n/JabRef_vi.properties
+++ b/src/main/resources/l10n/JabRef_vi.properties
@@ -80,8 +80,6 @@ All_entries_of_this_type_will_be_declared_typeless._Continue?=Tất_cả_các_m
All_fields=Tất_cả_các_dữ_liệu
-All_subgroups_(recursively)=Tất_cả_các_nhóm_con_(đệ_quy)
-
Always_reformat_BIB_file_on_save_and_export=
A_SAX_exception_occurred_while_parsing_'%0'\:=Một_lỗi_SAXException_xảy_ra_khi_đang_phân_tách_'%0'\:
@@ -352,8 +350,6 @@ Display_help_on_command_line_options=Trình_bày_trợ_giúp_ở_các_tùy_chọ
Display_only_entries_belonging_to_all_selected_groups.=Chỉ_trình_bày_các_mục_thuộc_về_tất_cả_các_nhóm_được_chọn.
Display_version=Trình_bày_phiên_bản
-Displaying_no_groups=Không_trình_bày_các_nhóm
-
Do_not_abbreviate_names=Không_viết_tắt_tên
Do_not_automatically_set=Không_thiết_lập_tự_động
@@ -577,8 +573,6 @@ Generated_BibTeX_key_for=Khóa_BibTeX_được_tạo_ra_cho
Generating_BibTeX_key_for=Đang_tạo_khóa_BibTeX_cho
Get_fulltext=Nhập_toàn_văn_bản
-Gray_out_entries_not_in_group_selection=Tô_xám_các_mục_không_thuộc_phép_chọn_nhóm
-
Gray_out_non-hits=Tô_xám_các_mục_không_gặp
Groups=Các_nhóm
@@ -587,8 +581,6 @@ Have_you_chosen_the_correct_package_path?=Bạn_đã_chọn_đường_dẫn_gói
Help=Trợ_giúp
-Help_on_groups=Trợ_giúp_về_nhóm
-
Help_on_key_patterns=Trợ_giúp_về_các_kiểu_khóa
Help_on_regular_expression_search=Trợ_giúp_về_tìm_kiếm_bằng_biểu_thức_chính_tắc
@@ -612,8 +604,6 @@ Icon=Biểu_tượng
Ignore=Bỏ_qua
-Immediate_subgroups=Các_nhóm_con_sát_nhau
-
Import=Nhập
Import_and_keep_old_entry=Nhập_và_giữ_mục_cũ
@@ -671,8 +661,6 @@ Invalid_date_format=Định_dạng_ngày_không_hợp_lệ
Invalid_URL=URL_không_hợp_lệ
-Inverted=Đảo_ngược
-
Online_help=Trợ_giúp_trực_tuyến
JabRef_preferences=Các_tùy_thích_JabRef
@@ -760,7 +748,6 @@ modify_group=điều_chỉnh_nhóm
Move_down=Chuyển_xuống
-Move_entries_in_group_selection_to_the_top=Chuyển_các_mục_trong_nhóm_được_chọn_lên_trên_cùng
Move_external_links_to_'file'_field=Chuyển_các_liên_kết_ngoài_vào_dữ_liệu_'file'
move_group=chuyển_nhóm
@@ -1117,8 +1104,6 @@ Show_confirmation_dialog_when_deleting_entries=Hiển_thị_hộp_thoại_xác_n
Show_description=Hiển_thị_mô_tả
-Show_entries_not_in_group_selection=Hiển_thị_các_mục_không_ở_trong_phép_chọn_nhóm
-
Show_file_column=Hiển_thị_cột_tập_tin
Show_last_names_only=Chỉ_hiển_thị_Họ
@@ -1140,14 +1125,6 @@ Skipped_-_PDF_does_not_exist=Bỏ_qua_-_tập_tin_PDF_không_tồn_tại
Skipped_entry.=Mục_bị_bỏ_qua.
-Sort_alphabetically=Xếp_theo_thứ_tự_ABC
-
-sort_subgroups=Xếp_thứ_tự_các_nhóm_con
-
-Sorted_all_subgroups_recursively.=Xếp_thứ_tự_tất_cả_các_nhóm_con_theo_cách_đệ_quy.
-
-Sorted_immediate_subgroups.=Các_nhóm_con_cạnh_nhau_được_xếp_thứ_tự.
-
source_edit=chỉnh_sửa_nguồn
Special_name_formatters=Các_trình_định_dạng_tên_đặc_biệt
diff --git a/src/main/resources/l10n/JabRef_zh.properties b/src/main/resources/l10n/JabRef_zh.properties
index f176aebf8db..da9d7a22384 100644
--- a/src/main/resources/l10n/JabRef_zh.properties
+++ b/src/main/resources/l10n/JabRef_zh.properties
@@ -80,8 +80,6 @@ All_entries_of_this_type_will_be_declared_typeless._Continue?=所有此类型记
All_fields=所有域
-All_subgroups_(recursively)=所有子分组(递归地)
-
Always_reformat_BIB_file_on_save_and_export=当保存和导出时重新格式化_BIB_文件
A_SAX_exception_occurred_while_parsing_'%0'\:=当解析'%0'时发生了一个_SAXException\:
@@ -352,8 +350,6 @@ Display_help_on_command_line_options=用命令行选项显示帮助
Display_only_entries_belonging_to_all_selected_groups.=只显示属于所有选中分组的记录,即显示选中分组的交集。
Display_version=显示版本
-Displaying_no_groups=非分组视图
-
Do_not_abbreviate_names=不要缩写姓名
Do_not_automatically_set=不要自动设置
@@ -577,8 +573,6 @@ Generated_BibTeX_key_for=已生成_BibTeX_键——为
Generating_BibTeX_key_for=正在生成_BibTeX_键——为
Get_fulltext=获取全文
-Gray_out_entries_not_in_group_selection=灰色显示未选中记录
-
Gray_out_non-hits=置灰未选中
Groups=分组
@@ -587,8 +581,6 @@ Have_you_chosen_the_correct_package_path?=您选择了正确的包路径吗?
Help=帮助
-Help_on_groups=分组帮助
-
Help_on_key_patterns=键表达式帮助
Help_on_regular_expression_search=正则表达式搜索帮助
@@ -612,8 +604,6 @@ Icon=图标
Ignore=忽略
-Immediate_subgroups=直接子分组
-
Import=导入
Import_and_keep_old_entry=导入且保存旧记录
@@ -671,8 +661,6 @@ Invalid_date_format=非法的日期格式
Invalid_URL=非法的_URL
-Inverted=补集
-
Online_help=在线帮助
JabRef_preferences=JabRef_首选项
@@ -760,7 +748,6 @@ modify_group=修改分组
Move_down=下移
-Move_entries_in_group_selection_to_the_top=移动选中分组的记录到顶部
Move_external_links_to_'file'_field=移动外部链接到_'file'_域
move_group=移动分组
@@ -1117,8 +1104,6 @@ Show_confirmation_dialog_when_deleting_entries=删除多条记录时发出警告
Show_description=显示描述
-Show_entries_not_in_group_selection=显示那些不在选中分组中的记录
-
Show_file_column=显示“文件”列
Show_last_names_only=只显示“姓_(Lastname)”
@@ -1140,14 +1125,6 @@ Skipped_-_PDF_does_not_exist=跳过-PDF_不存在
Skipped_entry.=已跳过记录
-Sort_alphabetically=按字母表排序
-
-sort_subgroups=排序子分组
-
-Sorted_all_subgroups_recursively.=递归排序所有子分组。
-
-Sorted_immediate_subgroups.=完成排序直接子分组。
-
source_edit=源代码编辑
Special_name_formatters=特殊的姓名格式化器
diff --git a/src/main/resources/l10n/Menu_el.properties b/src/main/resources/l10n/Menu_el.properties
new file mode 100644
index 00000000000..65889232211
--- /dev/null
+++ b/src/main/resources/l10n/Menu_el.properties
@@ -0,0 +1,125 @@
+Abbreviate_journal_names_(ISO)=Συντομογραφίες_ονομάτων_περιοδικών_(ISO)
+Abbreviate_journal_names_(MEDLINE)=Συντομογραφίες_ονομάτων_περιοδικών_(MEDLINE)
+About_JabRef=&Σχετικά_με_το_JabRef
+Append_database=&Σύναψη_βάση_δεδομένων
+Autogenerate_BibTeX_keys=&Autogenerate_BibTeX_keys
+Close_database=&Κλείσιμο_βάσης_δεδομένων
+Copy=Αντιγραφή
+Copy_\\cite{BibTeX_key}=Αντιγραφή_\\c&ite{BibTeX_key}
+Copy_BibTeX_key=Αντιγραφή&BibTeX_key
+Customize_entry_types=&Προσαρμογή_τύπου_καταχώρησης
+Cut=&Αποκοπή
+Database_properties=Ιδιότητες_βασης_δεδομένων
+Edit=&Επεξεργασία
+# Bibtex
+Edit_entry=&Επεξεργασία_καταχώρησης
+Edit_preamble=Επεξεργασία_&preamble
+Edit_strings=Επεξεργασία_&strings
+Export=&Εξαγωγή
+Export_selected_entries_to_clipboard=&Εξαγωγή_επιλεγμένων_καταχωρήσεων_στο_clipboard
+
+# Menu names
+File=&Φάκελος
+Find_duplicates=&Εύρεση_διπλότυπων
+Help=&Βοήθεια
+Highlight_groups_matching_all_selected_entries=Υπογράμμιση_ομάδων_που_ταιριάζουν_ολές_τις_επιλεγμένες_καταχωρήσεις
+Highlight_groups_matching_any_selected_entry=Υπογράμμιση_ομάδων_που_ταιριάζουν_οποιαδήποτε_επιλεγμένη_καταχωρήση
+Disable_highlight_groups_matching_entries=Απενεργοποίηση_υπογράμμισης_ομάδων_αντιστοιχούμενων_καταχωρήσεων
+
+# Help
+Online_help=Online_βοήθεια
+Donate_to_JabRef=Δωρεά_στο_JabRef
+Manage_content_selectors=Διαχείριση&Επιλογείς_Περιεχομένου
+Manage_custom_exports=&Διαχείριση_Εξαγωγής_Προτιμήσεων
+Manage_custom_imports=Διαχείριση_Προτιμήσεων_&Εισαγωγών
+Manage_journal_abbreviations=Διαχείριση_&συντομογραφιών_περιοδικών
+Mark_entries=&Επισύμανση_καταχωρήσεων
+# File menu
+New_%0_database=&Νέα_%0_βάση_δεδομένων
+# Menu BibTeX (BibTeX)
+New_entry=&Νέα_καταχώρηση
+New_entry_by_type...=&Νέα_καταχώρηση_ανα_τύπο...
+New_entry_from_plain_text=&Νέα_καταχώρηση_από_plain_κείμενο
+New_subdatabase_based_on_AUX_file=Nέα_subdatabase_βασισμένη_σε_αρχείο_AU&X
+# View
+Next_tab=&Επόμενη_καρτέλα
+Open_database=&Άνοιγμα_βάσης_δεδομένων
+Open_URL_or_DOI=Άνοιγμα_&URL_ή_DOI
+Open_terminal_here=Open_terminal_here
+Options=&Επιλογές
+Paste=&Επικόλληση
+# Options
+Preferences=&Προτιμήσεις
+Previous_tab=&Προηγούμενη_καρτέλα
+Quit=&Έξοδος
+Recent_files=&Πρόσφατα_αρχεία
+Redo=&Επαναφορά
+Replace_string=&Αντικατάσταση_string
+Save_database=&Αποθήκευση_database
+Save_database_as...=Αποθήκευση_βάσης_δεδομένων_ως...
+Save_selected_as...=Αποθήκεση_επιλεγμένου_ως...
+# Tools
+Search=&Αναζήτηση
+Select_all=Επιλογή_&όλων
+Set_up_general_fields=Ρύθμιση&γενικών_πεδίων
+Show_error_console=Προβολή_κονσόλας_λαθών
+Sort_tabs=&Σύντομες_καρτέλες
+Switch_preview_layout=&Αλλαγή_προεπισκόπησης_layout
+# Export menu
+Toggle_entry_preview=&Toggle_entry_preview
+Toggle_groups_interface=Toggle_&groups_interface
+Tools=&Εργαλεία
+Unabbreviate_journal_names=Ονόματα_περιοδικών_χωρίς_συντομογραφία
+# Edit
+Undo=&Αναίρεση
+Mark_specific_color=Επισύμανση_συγκεκριμένου_χρώματος
+Unmark_all=Απεπιλογή_όλων
+Unmark_entries=Απεπιλογή_καταχωρήσεων
+View=&Προβολή
+Import_into_new_database=Εισαγωγή_σε_νέα_βάση_δεδομένων
+Import_into_current_database=Εισαγωγή_σε_υπάρχουσα_βάση_δεδομένων
+
+Switch_to_%0_mode=Αλλαγή_%0_κατάστασης
+Push_entries_to_external_application_(%0)=Push_entries_to_external_application_(%0)
+Write_XMP-metadata_to_PDFs=Εγγραφή_XMP-μεταδεδομένων_σε_PDF
+
+Export_selected_entries=Εξαγωγή_επιλεγμένων_καταχωρήσεων
+
+Save_all=Αποθήκευση_όλων
+
+Manage_external_file_types=Διαχείριση_εξωτερικού_τυπου_αρχείων
+
+Open_file=Άνοιγμα_αρχείου
+
+Connect_to_external_SQL_database=Σύνδεση_σε_εξωτερική_βάση_SQL
+Export_to_external_SQL_database=Εξαγωγή_σε_εξωτερική_βάση_SQL
+Import_from_external_SQL_database=Εισαγωγή_σε_εξωτερική_βάση_SQL
+Focus_entry_table=Επικεντρωμένη_εισαγωγή_πίνακα
+
+Increase_table_font_size=&Μεγένθυση_γραμματοσειράς_πίνακα
+Decrease_table_font_size=&Σμίκρυνση_γραμματοσειράς_πίνακα
+Forward=Επόμενο
+Back=Πίσω
+
+Look_up_full_text_document=Εύρεση_πλήρες_κειμένο_εγγράφου
+Set/clear/rename_fields=Ρύθμιση/καθαρισμός/μετονομασία_πεδίων
+
+Resolve_duplicate_BibTeX_keys=Resolve_διπλότυπων_BibTeX_keys
+Copy_BibTeX_key_and_title=Αντιγραφή_BibTeX_και_τίτλου
+
+Cleanup_entries=Καθαρισμός_καταχωρήσεων
+Manage_keywords=Διαχείριση_λέξεων_κλειδιών
+Merge_entries=Συγχώνευση_καταχωρήσεων
+Open_folder=Άνοιγμα_φακέλου
+Find_unlinked_files...=Εύρεση_αποσυνδεμένων_αρχείων...
+Hide/show_toolbar=Απόκρυψη/προβολή_εργαλειοθήκης
+
+Fork_me_on_GitHub=Fork_me_on_GitHub
+Save_selected_as_plain_BibTeX...=Αποθήκευση_επιλεγμένου_ως_plain_BibTeX...
+
+Groups=Ομάδες
+Delete_entry=Διαγραφή_καταχώρησης
+Check_integrity=Έλεγχος_συνοχής
+
+Quality=Ποιότητα
+Online_help_forum=Online_forum_βοήθειας
diff --git a/src/test/java/org/jabref/gui/groups/GroupNodeViewModelTest.java b/src/test/java/org/jabref/gui/groups/GroupNodeViewModelTest.java
index cb8801ed880..c1956a7e5e7 100644
--- a/src/test/java/org/jabref/gui/groups/GroupNodeViewModelTest.java
+++ b/src/test/java/org/jabref/gui/groups/GroupNodeViewModelTest.java
@@ -1,5 +1,7 @@
package org.jabref.gui.groups;
+import java.util.Arrays;
+
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
@@ -87,7 +89,71 @@ public void treeOfAutomaticKeywordGroupIsCombined() throws Exception {
assertEquals(expected, groupViewModel.getChildren());
}
+ @Test
+ public void draggedOnTopOfGroupAddsBeforeIt() throws Exception {
+ GroupNodeViewModel rootViewModel = getViewModelForGroup(new WordKeywordGroup("root", GroupHierarchyType.INCLUDING, "keywords", "A", true, ',', true));
+ WordKeywordGroup groupA = new WordKeywordGroup("A", GroupHierarchyType.INCLUDING, "keywords", "A", true, ',', true);
+ WordKeywordGroup groupB = new WordKeywordGroup("B", GroupHierarchyType.INCLUDING, "keywords", "A > B", true, ',', true);
+ WordKeywordGroup groupC = new WordKeywordGroup("C", GroupHierarchyType.INCLUDING, "keywords", "A > B > B1", true, ',', true);
+ GroupNodeViewModel groupAViewModel = getViewModelForGroup(rootViewModel.addSubgroup(groupA));
+ GroupNodeViewModel groupBViewModel = getViewModelForGroup(rootViewModel.addSubgroup(groupB));
+ GroupNodeViewModel groupCViewModel = getViewModelForGroup(rootViewModel.addSubgroup(groupC));
+
+ groupCViewModel.draggedOn(groupBViewModel, DroppingMouseLocation.TOP);
+
+ assertEquals(Arrays.asList(groupAViewModel, groupCViewModel, groupBViewModel), rootViewModel.getChildren());
+ }
+
+ @Test
+ public void draggedOnBottomOfGroupAddsAfterIt() throws Exception {
+ GroupNodeViewModel rootViewModel = getViewModelForGroup(new WordKeywordGroup("root", GroupHierarchyType.INCLUDING, "keywords", "A", true, ',', true));
+ WordKeywordGroup groupA = new WordKeywordGroup("A", GroupHierarchyType.INCLUDING, "keywords", "A", true, ',', true);
+ WordKeywordGroup groupB = new WordKeywordGroup("B", GroupHierarchyType.INCLUDING, "keywords", "A > B", true, ',', true);
+ WordKeywordGroup groupC = new WordKeywordGroup("C", GroupHierarchyType.INCLUDING, "keywords", "A > B > B1", true, ',', true);
+ GroupNodeViewModel groupAViewModel = getViewModelForGroup(rootViewModel.addSubgroup(groupA));
+ GroupNodeViewModel groupBViewModel = getViewModelForGroup(rootViewModel.addSubgroup(groupB));
+ GroupNodeViewModel groupCViewModel = getViewModelForGroup(rootViewModel.addSubgroup(groupC));
+
+ groupCViewModel.draggedOn(groupAViewModel, DroppingMouseLocation.BOTTOM);
+
+ assertEquals(Arrays.asList(groupAViewModel, groupCViewModel, groupBViewModel), rootViewModel.getChildren());
+ }
+
+ @Test
+ public void draggedOnBottomOfGroupAddsAfterItWhenSourceGroupWasBefore() throws Exception {
+ GroupNodeViewModel rootViewModel = getViewModelForGroup(new WordKeywordGroup("root", GroupHierarchyType.INCLUDING, "keywords", "A", true, ',', true));
+ WordKeywordGroup groupA = new WordKeywordGroup("A", GroupHierarchyType.INCLUDING, "keywords", "A", true, ',', true);
+ WordKeywordGroup groupB = new WordKeywordGroup("B", GroupHierarchyType.INCLUDING, "keywords", "A > B", true, ',', true);
+ WordKeywordGroup groupC = new WordKeywordGroup("C", GroupHierarchyType.INCLUDING, "keywords", "A > B > B1", true, ',', true);
+ GroupNodeViewModel groupAViewModel = getViewModelForGroup(rootViewModel.addSubgroup(groupA));
+ GroupNodeViewModel groupBViewModel = getViewModelForGroup(rootViewModel.addSubgroup(groupB));
+ GroupNodeViewModel groupCViewModel = getViewModelForGroup(rootViewModel.addSubgroup(groupC));
+
+ groupAViewModel.draggedOn(groupBViewModel, DroppingMouseLocation.BOTTOM);
+
+ assertEquals(Arrays.asList(groupBViewModel, groupAViewModel, groupCViewModel), rootViewModel.getChildren());
+ }
+
+ @Test
+ public void draggedOnTopOfGroupAddsBeforeItWhenSourceGroupWasBefore() throws Exception {
+ GroupNodeViewModel rootViewModel = getViewModelForGroup(new WordKeywordGroup("root", GroupHierarchyType.INCLUDING, "keywords", "A", true, ',', true));
+ WordKeywordGroup groupA = new WordKeywordGroup("A", GroupHierarchyType.INCLUDING, "keywords", "A", true, ',', true);
+ WordKeywordGroup groupB = new WordKeywordGroup("B", GroupHierarchyType.INCLUDING, "keywords", "A > B", true, ',', true);
+ WordKeywordGroup groupC = new WordKeywordGroup("C", GroupHierarchyType.INCLUDING, "keywords", "A > B > B1", true, ',', true);
+ GroupNodeViewModel groupAViewModel = getViewModelForGroup(rootViewModel.addSubgroup(groupA));
+ GroupNodeViewModel groupBViewModel = getViewModelForGroup(rootViewModel.addSubgroup(groupB));
+ GroupNodeViewModel groupCViewModel = getViewModelForGroup(rootViewModel.addSubgroup(groupC));
+
+ groupAViewModel.draggedOn(groupCViewModel, DroppingMouseLocation.TOP);
+
+ assertEquals(Arrays.asList(groupBViewModel, groupAViewModel, groupCViewModel), rootViewModel.getChildren());
+ }
+
private GroupNodeViewModel getViewModelForGroup(AbstractGroup group) {
return new GroupNodeViewModel(databaseContext, stateManager, taskExecutor, group);
}
+
+ private GroupNodeViewModel getViewModelForGroup(GroupTreeNode group) {
+ return new GroupNodeViewModel(databaseContext, stateManager, taskExecutor, group);
+ }
}
diff --git a/src/test/java/org/jabref/logic/importer/fetcher/LibraryOfCongressTest.java b/src/test/java/org/jabref/logic/importer/fetcher/LibraryOfCongressTest.java
new file mode 100644
index 00000000000..4ee2dca2d8c
--- /dev/null
+++ b/src/test/java/org/jabref/logic/importer/fetcher/LibraryOfCongressTest.java
@@ -0,0 +1,34 @@
+package org.jabref.logic.importer.fetcher;
+
+import java.util.Optional;
+
+import org.jabref.model.entry.BibEntry;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class LibraryOfCongressTest {
+
+ private LibraryOfCongress fetcher = new LibraryOfCongress();
+
+ @Test
+ public void performSearchById() throws Exception {
+ BibEntry expected = new BibEntry();
+ expected.setField("address", "Burlington, MA");
+ expected.setField("author", "West, Matthew");
+ expected.setField("isbn", "0123751063 (pbk.)");
+ expected.setField("issuance", "monographic");
+ expected.setField("keywords", "Database design, Data structures (Computer science)");
+ expected.setField("language", "eng");
+ expected.setField("lccn", "2010045158");
+ expected.setField("note", "Matthew West., Includes index.");
+ expected.setField("oclc", "ocn665135773");
+ expected.setField("publisher", "Morgan Kaufmann");
+ expected.setField("source", "DLC");
+ expected.setField("title", "Developing high quality data models");
+ expected.setField("year", "2011");
+
+ assertEquals(Optional.of(expected), fetcher.performSearchById("2010045158"));
+ }
+}
diff --git a/src/test/java/org/jabref/model/TreeNodeTest.java b/src/test/java/org/jabref/model/TreeNodeTest.java
index 841dfaeab29..cff784ef02b 100644
--- a/src/test/java/org/jabref/model/TreeNodeTest.java
+++ b/src/test/java/org/jabref/model/TreeNodeTest.java
@@ -172,6 +172,36 @@ public void moveToInSameLevelAddsAtEnd() {
assertEquals(Arrays.asList(child2, child1), root.getChildren());
}
+ @Test
+ public void moveToInSameLevelWhenNodeWasBeforeTargetIndex() {
+ TreeNodeTestData.TreeNodeMock root = new TreeNodeTestData.TreeNodeMock();
+ TreeNodeTestData.TreeNodeMock child1 = new TreeNodeTestData.TreeNodeMock();
+ TreeNodeTestData.TreeNodeMock child2 = new TreeNodeTestData.TreeNodeMock();
+ TreeNodeTestData.TreeNodeMock child3 = new TreeNodeTestData.TreeNodeMock();
+ root.addChild(child1);
+ root.addChild(child2);
+ root.addChild(child3);
+
+ child1.moveTo(root, 1);
+
+ assertEquals(Arrays.asList(child2, child1, child3), root.getChildren());
+ }
+
+ @Test
+ public void moveToInSameLevelWhenNodeWasAfterTargetIndex() {
+ TreeNodeTestData.TreeNodeMock root = new TreeNodeTestData.TreeNodeMock();
+ TreeNodeTestData.TreeNodeMock child1 = new TreeNodeTestData.TreeNodeMock();
+ TreeNodeTestData.TreeNodeMock child2 = new TreeNodeTestData.TreeNodeMock();
+ TreeNodeTestData.TreeNodeMock child3 = new TreeNodeTestData.TreeNodeMock();
+ root.addChild(child1);
+ root.addChild(child2);
+ root.addChild(child3);
+
+ child3.moveTo(root, 1);
+
+ assertEquals(Arrays.asList(child1, child3, child2), root.getChildren());
+ }
+
@Test
public void getPathFromRootInSimpleTree() {
TreeNodeTestData.TreeNodeMock root = new TreeNodeTestData.TreeNodeMock();
diff --git a/src/test/java/org/jabref/model/entry/DateTest.java b/src/test/java/org/jabref/model/entry/DateTest.java
index 5c55cc92179..3192ef78554 100644
--- a/src/test/java/org/jabref/model/entry/DateTest.java
+++ b/src/test/java/org/jabref/model/entry/DateTest.java
@@ -14,4 +14,9 @@ public void parseCorrectlyDayMonthYearDate() throws Exception {
Date expected = new Date(LocalDate.of(2014, 6, 19));
assertEquals(Optional.of(expected), Date.parse("19-06-2014"));
}
+
+ @Test(expected = NullPointerException.class)
+ public void parseDateNull() {
+ assertEquals(Optional.empty(), Date.parse(null));
+ }
}
diff --git a/src/test/java/org/jabref/model/pdf/FileAnnotationTest.java b/src/test/java/org/jabref/model/pdf/FileAnnotationTest.java
new file mode 100644
index 00000000000..054f3d99d95
--- /dev/null
+++ b/src/test/java/org/jabref/model/pdf/FileAnnotationTest.java
@@ -0,0 +1,32 @@
+package org.jabref.model.pdf;
+
+import java.time.LocalDateTime;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+
+public class FileAnnotationTest {
+
+ @Test
+ public void testParseDateMinusBeforeTimezone() {
+ String dateString = "D:20170512224019-03'00'";
+ LocalDateTime date = FileAnnotation.extractModifiedTime(dateString);
+ assertEquals(LocalDateTime.of(2017, 05, 12, 22, 40, 19), date);
+ }
+
+ @Test
+ public void testParseDatePlusBeforeTimezone() {
+ String dateString = "D:20170512224019+03'00'";
+ LocalDateTime date = FileAnnotation.extractModifiedTime(dateString);
+ assertEquals(LocalDateTime.of(2017, 05, 12, 22, 40, 19), date);
+ }
+
+ @Test
+ public void testParseDateNoTimezone() {
+ String dateString = "D:20170512224019";
+ LocalDateTime date = FileAnnotation.extractModifiedTime(dateString);
+ assertEquals(LocalDateTime.of(2017, 05, 12, 22, 40, 19), date);
+ }
+}
diff --git a/src/test/resources/org/jabref/logic/exporter/MsBibExportFormatTest1.xml b/src/test/resources/org/jabref/logic/exporter/MsBibExportFormatTest1.xml
index 960fd22d6b3..d92aaaa3a05 100644
--- a/src/test/resources/org/jabref/logic/exporter/MsBibExportFormatTest1.xml
+++ b/src/test/resources/org/jabref/logic/exporter/MsBibExportFormatTest1.xml
@@ -24,8 +24,8 @@
10
abb
1000
-12
-10
+10
+12
2015
5
diff --git a/src/test/resources/org/jabref/logic/exporter/MsBibExportFormatTestDateAcessed.bib b/src/test/resources/org/jabref/logic/exporter/MsBibExportFormatTestDateAcessed.bib
new file mode 100644
index 00000000000..bc4edda355f
--- /dev/null
+++ b/src/test/resources/org/jabref/logic/exporter/MsBibExportFormatTestDateAcessed.bib
@@ -0,0 +1,12 @@
+% Encoding: UTF-8
+
+@Article{Testa,
+ author = {Sam and jason},
+ title = {Test},
+ journaltitle = {Test},
+ year = {2012},
+ date = {2016},
+ msbib-accessed = {2015-12-12},
+}
+
+@Comment{jabref-meta: databaseType:biblatex;}
diff --git a/src/test/resources/org/jabref/logic/exporter/MsBibExportFormatTestDateAcessed.xml b/src/test/resources/org/jabref/logic/exporter/MsBibExportFormatTestDateAcessed.xml
new file mode 100644
index 00000000000..03524e8a072
--- /dev/null
+++ b/src/test/resources/org/jabref/logic/exporter/MsBibExportFormatTestDateAcessed.xml
@@ -0,0 +1,27 @@
+
+
+
+2012
+article
+JournalArticle
+2015-12-12
+Test
+Testa
+2015
+12
+12
+
+
+
+
+Sam
+
+
+jason
+
+
+
+
+Test
+
+