diff --git a/jabgui/src/main/java/org/jabref/gui/collab/groupchange/GroupChange.java b/jabgui/src/main/java/org/jabref/gui/collab/groupchange/GroupChange.java index 29457b24d7a..addc86a9ecc 100644 --- a/jabgui/src/main/java/org/jabref/gui/collab/groupchange/GroupChange.java +++ b/jabgui/src/main/java/org/jabref/gui/collab/groupchange/GroupChange.java @@ -6,7 +6,7 @@ import org.jabref.gui.groups.UndoableModifySubtree; import org.jabref.gui.undo.NamedCompoundEdit; import org.jabref.logic.bibtex.comparator.GroupDiff; -import org.jabref.logic.groups.DefaultGroupsFactory; +import org.jabref.logic.groups.GroupsFactory; import org.jabref.logic.l10n.Localization; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.groups.GroupTreeNode; @@ -27,7 +27,7 @@ public void applyChange(NamedCompoundEdit undoEdit) { GroupTreeNode newRoot = groupDiff.getNewGroupRoot(); GroupTreeNode root = databaseContext.getMetaData().getGroups().orElseGet(() -> { - GroupTreeNode groupTreeNode = new GroupTreeNode(DefaultGroupsFactory.getAllEntriesGroup()); + GroupTreeNode groupTreeNode = new GroupTreeNode(GroupsFactory.createAllEntriesGroup()); databaseContext.getMetaData().setGroups(groupTreeNode); return groupTreeNode; }); @@ -38,7 +38,7 @@ public void applyChange(NamedCompoundEdit undoEdit) { root.removeAllChildren(); if (newRoot == null) { // I think setting root to null is not possible - root.setGroup(DefaultGroupsFactory.getAllEntriesGroup(), false, false, null); + root.setGroup(GroupsFactory.createAllEntriesGroup(), false, false, null); } else { // change root group, even though it'll be AllEntries anyway root.setGroup(newRoot.getGroup(), false, false, null); diff --git a/jabgui/src/main/java/org/jabref/gui/externalfiles/ImportHandler.java b/jabgui/src/main/java/org/jabref/gui/externalfiles/ImportHandler.java index 780d047a5cb..eff6b7bb250 100644 --- a/jabgui/src/main/java/org/jabref/gui/externalfiles/ImportHandler.java +++ b/jabgui/src/main/java/org/jabref/gui/externalfiles/ImportHandler.java @@ -56,9 +56,9 @@ import org.jabref.model.entry.BibtexString; import org.jabref.model.entry.LinkedFile; import org.jabref.model.entry.field.StandardField; +import org.jabref.model.groups.ExplicitGroup; import org.jabref.model.groups.GroupEntryChanger; import org.jabref.model.groups.GroupTreeNode; -import org.jabref.model.groups.SmartGroup; import org.jabref.model.util.FileUpdateMonitor; import org.jabref.model.util.OptionalUtil; @@ -533,14 +533,17 @@ private List handlePdfUrl(String pdfUrl) throws IOException { private void addToImportEntriesGroup(List entriesToInsert) { if (preferences.getLibraryPreferences().isAddImportedEntriesEnabled()) { - // Only one SmartGroup + String groupName = preferences.getLibraryPreferences().getAddImportedEntriesGroupName(); + // We cannot add the new group here directly because we don't have access to the group node viewmoel stuff here + // We would need to add the groups to the metadata first which is a bit more complicated, thus we decided against it atm this.targetBibDatabaseContext.getMetaData() .getGroups() .flatMap(grp -> grp.getChildren() .stream() - .filter(node -> node.getGroup() instanceof SmartGroup) + .filter(node -> node.getGroup() instanceof ExplicitGroup + && node.getGroup().getName().equals(groupName)) .findFirst()) - .ifPresent(smtGrp -> smtGrp.addEntriesToGroup(entriesToInsert)); + .ifPresent(importGroup -> importGroup.addEntriesToGroup(entriesToInsert)); } } } diff --git a/jabgui/src/main/java/org/jabref/gui/groups/GroupDescriptions.java b/jabgui/src/main/java/org/jabref/gui/groups/GroupDescriptions.java index 38499ea5ddc..2c90a222e0f 100644 --- a/jabgui/src/main/java/org/jabref/gui/groups/GroupDescriptions.java +++ b/jabgui/src/main/java/org/jabref/gui/groups/GroupDescriptions.java @@ -5,7 +5,6 @@ import org.jabref.model.groups.ExplicitGroup; import org.jabref.model.groups.KeywordGroup; import org.jabref.model.groups.SearchGroup; -import org.jabref.model.groups.SmartGroup; public class GroupDescriptions { @@ -62,10 +61,6 @@ public static String getShortDescriptionAllEntriesGroup() { return Localization.lang("All Entries (this group cannot be edited or removed)"); } - public static String getShortDescriptionSmartGroup(SmartGroup smartGroup) { - return Localization.lang("Smart Group (Import Entries)"); - } - public static String getShortDescription(SearchGroup searchGroup, boolean showDynamic) { StringBuilder sb = new StringBuilder(); sb.append(""); diff --git a/jabgui/src/main/java/org/jabref/gui/groups/GroupDialogViewModel.java b/jabgui/src/main/java/org/jabref/gui/groups/GroupDialogViewModel.java index 30eb4c07b39..a16362bf811 100644 --- a/jabgui/src/main/java/org/jabref/gui/groups/GroupDialogViewModel.java +++ b/jabgui/src/main/java/org/jabref/gui/groups/GroupDialogViewModel.java @@ -30,7 +30,7 @@ import org.jabref.gui.preferences.GuiPreferences; import org.jabref.gui.util.FileDialogConfiguration; import org.jabref.logic.auxparser.DefaultAuxParser; -import org.jabref.logic.groups.DefaultGroupsFactory; +import org.jabref.logic.groups.GroupsFactory; import org.jabref.logic.l10n.Localization; import org.jabref.logic.search.IndexManager; import org.jabref.logic.util.StandardFileType; @@ -416,14 +416,14 @@ public void setValues() { if (editedGroup == null) { // creating new group -> defaults! - // TODO: Create default group (via org.jabref.logic.groups.DefaultGroupsFactory) and use values + // TODO: Create default group (via org.jabref.logic.groups.GroupsFactory) and use values colorUseProperty.setValue(false); colorProperty.setValue(determineColor()); if (parentNode != null) { parentNode.getGroup() .getIconName() - .filter(iconName -> !DefaultGroupsFactory.ALL_ENTRIES_GROUP_DEFAULT_ICON.equals(iconName)) + .filter(iconName -> !GroupsFactory.ALL_ENTRIES_GROUP_DEFAULT_ICON.equals(iconName)) .ifPresent(iconProperty::setValue); parentNode.getGroup().getColor().ifPresent(color -> colorUseProperty.setValue(true)); } diff --git a/jabgui/src/main/java/org/jabref/gui/groups/GroupNodeViewModel.java b/jabgui/src/main/java/org/jabref/gui/groups/GroupNodeViewModel.java index 97eecde244e..ed9052ddd60 100644 --- a/jabgui/src/main/java/org/jabref/gui/groups/GroupNodeViewModel.java +++ b/jabgui/src/main/java/org/jabref/gui/groups/GroupNodeViewModel.java @@ -26,7 +26,7 @@ import org.jabref.gui.util.CustomLocalDragboard; import org.jabref.gui.util.DroppingMouseLocation; import org.jabref.gui.util.UiTaskExecutor; -import org.jabref.logic.groups.DefaultGroupsFactory; +import org.jabref.logic.groups.GroupsFactory; import org.jabref.logic.layout.format.LatexToUnicodeFormatter; import org.jabref.logic.util.BackgroundTask; import org.jabref.logic.util.TaskExecutor; @@ -48,7 +48,6 @@ import org.jabref.model.groups.LastNameGroup; import org.jabref.model.groups.RegexKeywordGroup; import org.jabref.model.groups.SearchGroup; -import org.jabref.model.groups.SmartGroup; import org.jabref.model.groups.TexGroup; import org.jabref.model.search.event.IndexAddedOrUpdatedEvent; import org.jabref.model.search.event.IndexClosedEvent; @@ -141,7 +140,7 @@ public GroupNodeViewModel(BibDatabaseContext databaseContext, StateManager state } static GroupNodeViewModel getAllEntriesGroup(BibDatabaseContext newDatabase, StateManager stateManager, TaskExecutor taskExecutor, CustomLocalDragboard localDragBoard, GuiPreferences preferences) { - return new GroupNodeViewModel(newDatabase, stateManager, taskExecutor, DefaultGroupsFactory.getAllEntriesGroup(), localDragBoard, preferences); + return new GroupNodeViewModel(newDatabase, stateManager, taskExecutor, GroupsFactory.createAllEntriesGroup(), localDragBoard, preferences); } private GroupNodeViewModel toViewModel(GroupTreeNode child) { @@ -437,16 +436,14 @@ public boolean hasSimilarSearchGroup(SearchGroup searchGroup) { } public boolean hasAllSuggestedGroups() { - return hasSimilarSearchGroup(JabRefSuggestedGroups.createWithoutFilesGroup()) - && hasSimilarSearchGroup(JabRefSuggestedGroups.createWithoutGroupsGroup()); + return hasSimilarSearchGroup(GroupsFactory.createWithoutFilesGroup()) + && hasSimilarSearchGroup(GroupsFactory.createWithoutGroupsGroup()); } public boolean canAddEntriesIn() { AbstractGroup group = groupNode.getGroup(); if (group instanceof AllEntriesGroup) { return false; - } else if (group instanceof SmartGroup) { - return false; } else if (group instanceof ExplicitGroup) { return true; } else if (group instanceof LastNameGroup || group instanceof RegexKeywordGroup) { @@ -477,8 +474,7 @@ public boolean canAddEntriesIn() { public boolean canBeDragged() { AbstractGroup group = groupNode.getGroup(); return switch (group) { - case AllEntriesGroup _, - SmartGroup _ -> + case AllEntriesGroup _ -> false; case ExplicitGroup _, SearchGroup _, @@ -513,8 +509,7 @@ public boolean canAddGroupsIn() { case AutomaticKeywordGroup _, AutomaticPersonsGroup _, AutomaticDateGroup _, - DateGroup _, - SmartGroup _ -> + DateGroup _ -> false; case KeywordGroup _ -> // KeywordGroup is parent of LastNameGroup, RegexKeywordGroup and WordKeywordGroup @@ -532,8 +527,7 @@ public boolean canAddGroupsIn() { public boolean canRemove() { AbstractGroup group = groupNode.getGroup(); return switch (group) { - case AllEntriesGroup _, - SmartGroup _ -> + case AllEntriesGroup _ -> false; case ExplicitGroup _, SearchGroup _, @@ -560,8 +554,7 @@ public boolean isEditable() { AbstractGroup group = groupNode.getGroup(); return switch (group) { case AllEntriesGroup _, - DateGroup _, - SmartGroup _ -> + DateGroup _ -> false; case ExplicitGroup _, SearchGroup _, diff --git a/jabgui/src/main/java/org/jabref/gui/groups/GroupTreeNodeViewModel.java b/jabgui/src/main/java/org/jabref/gui/groups/GroupTreeNodeViewModel.java index d8f454931da..38f9c532988 100644 --- a/jabgui/src/main/java/org/jabref/gui/groups/GroupTreeNodeViewModel.java +++ b/jabgui/src/main/java/org/jabref/gui/groups/GroupTreeNodeViewModel.java @@ -17,7 +17,6 @@ import org.jabref.model.groups.GroupTreeNode; import org.jabref.model.groups.KeywordGroup; import org.jabref.model.groups.SearchGroup; -import org.jabref.model.groups.SmartGroup; public class GroupTreeNodeViewModel { private final GroupTreeNode node; @@ -52,8 +51,6 @@ public String getDescription() { String shortDescription = ""; boolean showDynamic = true; shortDescription = switch (group) { - case SmartGroup smartGroup -> - GroupDescriptions.getShortDescriptionSmartGroup(smartGroup); case ExplicitGroup explicitGroup -> GroupDescriptions.getShortDescriptionExplicitGroup(explicitGroup); case KeywordGroup keywordGroup -> diff --git a/jabgui/src/main/java/org/jabref/gui/groups/GroupTreeViewModel.java b/jabgui/src/main/java/org/jabref/gui/groups/GroupTreeViewModel.java index 3048874495e..2aaf3ac3977 100644 --- a/jabgui/src/main/java/org/jabref/gui/groups/GroupTreeViewModel.java +++ b/jabgui/src/main/java/org/jabref/gui/groups/GroupTreeViewModel.java @@ -28,6 +28,7 @@ import org.jabref.gui.preferences.GuiPreferences; import org.jabref.gui.util.CustomLocalDragboard; import org.jabref.logic.ai.AiService; +import org.jabref.logic.groups.GroupsFactory; import org.jabref.logic.l10n.Localization; import org.jabref.logic.util.TaskExecutor; import org.jabref.model.database.BibDatabaseContext; @@ -41,7 +42,6 @@ import org.jabref.model.groups.GroupTreeNode; import org.jabref.model.groups.RegexKeywordGroup; import org.jabref.model.groups.SearchGroup; -import org.jabref.model.groups.SmartGroup; import org.jabref.model.groups.TexGroup; import org.jabref.model.groups.WordKeywordGroup; import org.jabref.model.metadata.MetaData; @@ -179,7 +179,7 @@ private void onActiveDatabaseChanged(Optional newDatabase) { rootGroup.setValue(null); } currentDatabase = newDatabase; - newDatabase.ifPresent(db -> addGroupImportEntries(rootGroup.get())); + newDatabase.ifPresent(_ -> addGroupImportEntries(rootGroup.get())); } private void addGroupImportEntries(GroupNodeViewModel parent) { @@ -187,15 +187,16 @@ private void addGroupImportEntries(GroupNodeViewModel parent) { return; } - String grpName = preferences.getLibraryPreferences().getAddImportedEntriesGroupName(); - AbstractGroup importEntriesGroup = new SmartGroup(grpName, GroupHierarchyType.INDEPENDENT, ','); - boolean isGrpExist = parent.getGroupNode() - .getChildren() - .stream() - .map(GroupTreeNode::getGroup) - .anyMatch(grp -> grp instanceof SmartGroup); - if (!isGrpExist) { + String groupName = preferences.getLibraryPreferences().getAddImportedEntriesGroupName(); + boolean groupExists = parent.getGroupNode() + .getChildren() + .stream() + .map(GroupTreeNode::getGroup) + .anyMatch(grp -> grp instanceof ExplicitGroup && grp.getName().equals(groupName)); + if (!groupExists) { currentDatabase.ifPresent(db -> { + char keywordSeparator = preferences.getBibEntryPreferences().getKeywordSeparator(); + AbstractGroup importEntriesGroup = new ExplicitGroup(groupName, GroupHierarchyType.INDEPENDENT, keywordSeparator); GroupTreeNode newSubgroup = parent.addSubgroup(importEntriesGroup); newSubgroup.moveTo(parent.getGroupNode(), 0); selectedGroups.setAll(new GroupNodeViewModel(db, stateManager, taskExecutor, newSubgroup, localDragboard, preferences)); @@ -251,14 +252,14 @@ public void addSuggestedGroups(GroupNodeViewModel parent) { List newSuggestedSubgroups = new ArrayList<>(); // 1. Create "Entries without linked files" group if it doesn't exist - SearchGroup withoutFilesGroup = JabRefSuggestedGroups.createWithoutFilesGroup(); + SearchGroup withoutFilesGroup = GroupsFactory.createWithoutFilesGroup(); if (!parent.hasSimilarSearchGroup(withoutFilesGroup)) { GroupTreeNode subGroup = rootNode.addSubgroup(withoutFilesGroup); newSuggestedSubgroups.add(subGroup); } // 2. Create "Entries without groups" group if it doesn't exist - SearchGroup withoutGroupsGroup = JabRefSuggestedGroups.createWithoutGroupsGroup(); + SearchGroup withoutGroupsGroup = GroupsFactory.createWithoutGroupsGroup(); if (!parent.hasSimilarSearchGroup(withoutGroupsGroup)) { GroupTreeNode subGroup = rootNode.addSubgroup(withoutGroupsGroup); newSuggestedSubgroups.add(subGroup); diff --git a/jabgui/src/main/java/org/jabref/migrations/ConvertMarkingToGroups.java b/jabgui/src/main/java/org/jabref/migrations/ConvertMarkingToGroups.java index 4eb7c5611ae..03c68e924f3 100644 --- a/jabgui/src/main/java/org/jabref/migrations/ConvertMarkingToGroups.java +++ b/jabgui/src/main/java/org/jabref/migrations/ConvertMarkingToGroups.java @@ -9,7 +9,7 @@ import javafx.collections.ObservableList; -import org.jabref.logic.groups.DefaultGroupsFactory; +import org.jabref.logic.groups.GroupsFactory; import org.jabref.logic.importer.ParserResult; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; @@ -48,7 +48,7 @@ public void performMigration(@NonNull ParserResult parserResult) { } if (parserResult.getMetaData().getGroups().isEmpty()) { - parserResult.getMetaData().setGroups(GroupTreeNode.fromGroup(DefaultGroupsFactory.getAllEntriesGroup())); + parserResult.getMetaData().setGroups(GroupTreeNode.fromGroup(GroupsFactory.createAllEntriesGroup())); } GroupTreeNode root = parserResult.getMetaData().getGroups().get(); root.addChild(markingRoot, 0); diff --git a/jabgui/src/test/java/org/jabref/gui/groups/GroupTreeViewModelTest.java b/jabgui/src/test/java/org/jabref/gui/groups/GroupTreeViewModelTest.java index 685cb646cca..5c05e061835 100644 --- a/jabgui/src/test/java/org/jabref/gui/groups/GroupTreeViewModelTest.java +++ b/jabgui/src/test/java/org/jabref/gui/groups/GroupTreeViewModelTest.java @@ -12,10 +12,12 @@ import org.jabref.gui.util.CustomLocalDragboard; import org.jabref.logic.LibraryPreferences; import org.jabref.logic.ai.AiService; +import org.jabref.logic.groups.GroupsFactory; import org.jabref.logic.util.CurrentThreadTaskExecutor; import org.jabref.logic.util.TaskExecutor; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.BibEntryPreferences; import org.jabref.model.entry.field.StandardField; import org.jabref.model.groups.AbstractGroup; import org.jabref.model.groups.AllEntriesGroup; @@ -63,6 +65,9 @@ void setUp() { true, true, GroupHierarchyType.INDEPENDENT)); + BibEntryPreferences bibEntryPreferences = mock(BibEntryPreferences.class); + when(bibEntryPreferences.getKeywordSeparator()).thenReturn(','); + when(preferences.getBibEntryPreferences()).thenReturn(bibEntryPreferences); groupTree = new GroupTreeViewModel(stateManager, mock(DialogService.class), mock(AiService.class), preferences, mock(AdaptVisibleTabs.class), taskExecutor, new CustomLocalDragboard()); } @@ -173,7 +178,7 @@ void shouldAddsAllSuggestedGroupsWhenNoneExist() { void shouldAddOnlyMissingGroup() { GroupTreeViewModel model = new GroupTreeViewModel(stateManager, dialogService, mock(AiService.class), preferences, mock(AdaptVisibleTabs.class), taskExecutor, new CustomLocalDragboard()); GroupNodeViewModel rootGroup = model.rootGroupProperty().getValue(); - rootGroup.getGroupNode().addSubgroup(JabRefSuggestedGroups.createWithoutFilesGroup()); + rootGroup.getGroupNode().addSubgroup(GroupsFactory.createWithoutFilesGroup()); assertEquals(1, rootGroup.getChildren().size()); model.addSuggestedGroups(rootGroup); @@ -186,8 +191,8 @@ void shouldAddOnlyMissingGroup() { void shouldNotAddSuggestedGroupsWhenAllExist() { GroupTreeViewModel model = new GroupTreeViewModel(stateManager, dialogService, mock(AiService.class), preferences, mock(AdaptVisibleTabs.class), taskExecutor, new CustomLocalDragboard()); GroupNodeViewModel rootGroup = model.rootGroupProperty().getValue(); - rootGroup.getGroupNode().addSubgroup(JabRefSuggestedGroups.createWithoutFilesGroup()); - rootGroup.getGroupNode().addSubgroup(JabRefSuggestedGroups.createWithoutGroupsGroup()); + rootGroup.getGroupNode().addSubgroup(GroupsFactory.createWithoutFilesGroup()); + rootGroup.getGroupNode().addSubgroup(GroupsFactory.createWithoutGroupsGroup()); assertEquals(2, rootGroup.getChildren().size()); model.addSuggestedGroups(rootGroup); diff --git a/jabgui/src/test/java/org/jabref/migrations/ConvertMarkingToGroupsTest.java b/jabgui/src/test/java/org/jabref/migrations/ConvertMarkingToGroupsTest.java index 2ea2f07a225..e64ccdfec73 100644 --- a/jabgui/src/test/java/org/jabref/migrations/ConvertMarkingToGroupsTest.java +++ b/jabgui/src/test/java/org/jabref/migrations/ConvertMarkingToGroupsTest.java @@ -3,7 +3,7 @@ import java.util.Optional; import java.util.Set; -import org.jabref.logic.groups.DefaultGroupsFactory; +import org.jabref.logic.groups.GroupsFactory; import org.jabref.logic.importer.ParserResult; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.InternalField; @@ -24,7 +24,7 @@ void performMigrationForSingleEntry() { new ConvertMarkingToGroups().performMigration(parserResult); - GroupTreeNode rootExpected = GroupTreeNode.fromGroup(DefaultGroupsFactory.getAllEntriesGroup()); + GroupTreeNode rootExpected = GroupTreeNode.fromGroup(GroupsFactory.createAllEntriesGroup()); GroupTreeNode markings = rootExpected.addSubgroup(new ExplicitGroup("Markings", GroupHierarchyType.INCLUDING, ',')); markings.addSubgroup(new ExplicitGroup("Nicolas:6", GroupHierarchyType.INCLUDING, ',')); diff --git a/jablib/src/main/java/org/jabref/logic/bibtex/comparator/MetaDataDiff.java b/jablib/src/main/java/org/jabref/logic/bibtex/comparator/MetaDataDiff.java index af1e27b9736..20f0b66770a 100644 --- a/jablib/src/main/java/org/jabref/logic/bibtex/comparator/MetaDataDiff.java +++ b/jablib/src/main/java/org/jabref/logic/bibtex/comparator/MetaDataDiff.java @@ -8,7 +8,7 @@ import org.jabref.logic.citationkeypattern.CitationKeyPattern; import org.jabref.logic.citationkeypattern.GlobalCitationKeyPatterns; -import org.jabref.logic.groups.DefaultGroupsFactory; +import org.jabref.logic.groups.GroupsFactory; import org.jabref.model.entry.field.Field; import org.jabref.model.groups.GroupTreeNode; import org.jabref.model.metadata.ContentSelectors; @@ -94,7 +94,7 @@ private boolean isDefaultGroup(Optional groups) { if (!groupRoot.getChildren().isEmpty()) { return false; } - return groupRoot.getGroup().equals(DefaultGroupsFactory.getAllEntriesGroup()); + return groupRoot.getGroup().equals(GroupsFactory.createAllEntriesGroup()); } /** diff --git a/jablib/src/main/java/org/jabref/logic/exporter/GroupSerializer.java b/jablib/src/main/java/org/jabref/logic/exporter/GroupSerializer.java index 0d49bb5bfa8..272d5e20257 100644 --- a/jablib/src/main/java/org/jabref/logic/exporter/GroupSerializer.java +++ b/jablib/src/main/java/org/jabref/logic/exporter/GroupSerializer.java @@ -17,7 +17,6 @@ import org.jabref.model.groups.KeywordGroup; import org.jabref.model.groups.RegexKeywordGroup; import org.jabref.model.groups.SearchGroup; -import org.jabref.model.groups.SmartGroup; import org.jabref.model.groups.TexGroup; import org.jabref.model.search.SearchFlags; @@ -26,19 +25,6 @@ private static String serializeAllEntriesGroup() { return MetadataSerializationConfiguration.ALL_ENTRIES_GROUP_ID; } - private String serializeSmartGroup(SmartGroup group) { - StringBuilder sb = new StringBuilder(); - sb.append(MetadataSerializationConfiguration.SMART_GROUP_ID); - sb.append(StringUtil.quote(group.getName(), MetadataSerializationConfiguration.GROUP_UNIT_SEPARATOR, MetadataSerializationConfiguration.GROUP_QUOTE_CHAR)); - sb.append(MetadataSerializationConfiguration.GROUP_UNIT_SEPARATOR); - sb.append(group.getHierarchicalContext().ordinal()); - sb.append(MetadataSerializationConfiguration.GROUP_UNIT_SEPARATOR); - - appendGroupDetails(sb, group); - - return sb.toString(); - } - private String serializeExplicitGroup(ExplicitGroup group) { StringBuilder sb = new StringBuilder(); sb.append(MetadataSerializationConfiguration.EXPLICIT_GROUP_ID); @@ -130,8 +116,6 @@ private String serializeGroup(AbstractGroup group) { return switch (group) { case AllEntriesGroup _ -> serializeAllEntriesGroup(); - case SmartGroup smartGroup -> - serializeSmartGroup(smartGroup); case ExplicitGroup explicitGroup -> serializeExplicitGroup(explicitGroup); case KeywordGroup keywordGroup -> diff --git a/jablib/src/main/java/org/jabref/logic/groups/DefaultGroupsFactory.java b/jablib/src/main/java/org/jabref/logic/groups/DefaultGroupsFactory.java deleted file mode 100644 index d59599165cc..00000000000 --- a/jablib/src/main/java/org/jabref/logic/groups/DefaultGroupsFactory.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.jabref.logic.groups; - -import org.jabref.logic.l10n.Localization; -import org.jabref.model.groups.AllEntriesGroup; - -/** - * This factory creates default groups. Currently only the allEntriesGroup is supported. - */ -public class DefaultGroupsFactory { - - public static final String ALL_ENTRIES_GROUP_DEFAULT_ICON = "ALL_ENTRIES_GROUP_ICON"; - - private DefaultGroupsFactory() { - } - - public static AllEntriesGroup getAllEntriesGroup() { - AllEntriesGroup group = new AllEntriesGroup(Localization.lang("All entries")); - group.setIconName(ALL_ENTRIES_GROUP_DEFAULT_ICON); - return group; - } -} diff --git a/jabgui/src/main/java/org/jabref/gui/groups/JabRefSuggestedGroups.java b/jablib/src/main/java/org/jabref/logic/groups/GroupsFactory.java similarity index 62% rename from jabgui/src/main/java/org/jabref/gui/groups/JabRefSuggestedGroups.java rename to jablib/src/main/java/org/jabref/logic/groups/GroupsFactory.java index 644452de5db..09fa3f3d98e 100644 --- a/jabgui/src/main/java/org/jabref/gui/groups/JabRefSuggestedGroups.java +++ b/jablib/src/main/java/org/jabref/logic/groups/GroupsFactory.java @@ -1,13 +1,25 @@ -package org.jabref.gui.groups; +package org.jabref.logic.groups; import java.util.EnumSet; import org.jabref.logic.l10n.Localization; +import org.jabref.model.groups.AllEntriesGroup; import org.jabref.model.groups.GroupHierarchyType; import org.jabref.model.groups.SearchGroup; import org.jabref.model.search.SearchFlags; -public class JabRefSuggestedGroups { +public class GroupsFactory { + + public static final String ALL_ENTRIES_GROUP_DEFAULT_ICON = "ALL_ENTRIES_GROUP_ICON"; + + private GroupsFactory() { + } + + public static AllEntriesGroup createAllEntriesGroup() { + AllEntriesGroup group = new AllEntriesGroup(Localization.lang("All entries")); + group.setIconName(ALL_ENTRIES_GROUP_DEFAULT_ICON); + return group; + } public static SearchGroup createWithoutFilesGroup() { return new SearchGroup( diff --git a/jablib/src/main/java/org/jabref/logic/importer/fileformat/BibtexParser.java b/jablib/src/main/java/org/jabref/logic/importer/fileformat/BibtexParser.java index 5dee7354cac..ee1c4441506 100644 --- a/jablib/src/main/java/org/jabref/logic/importer/fileformat/BibtexParser.java +++ b/jablib/src/main/java/org/jabref/logic/importer/fileformat/BibtexParser.java @@ -28,7 +28,7 @@ import org.jabref.logic.bibtex.FieldWriter; import org.jabref.logic.exporter.BibDatabaseWriter; import org.jabref.logic.exporter.SaveConfiguration; -import org.jabref.logic.groups.DefaultGroupsFactory; +import org.jabref.logic.groups.GroupsFactory; import org.jabref.logic.importer.ImportFormatPreferences; import org.jabref.logic.importer.Importer; import org.jabref.logic.importer.ParseException; @@ -290,7 +290,7 @@ private ParserResult parseFileContent() throws IOException { }, // metadata does not contain any groups, so we need to create an AllEntriesGroup and add the other groups as children () -> { - GroupTreeNode rootNode = new GroupTreeNode(DefaultGroupsFactory.getAllEntriesGroup()); + GroupTreeNode rootNode = new GroupTreeNode(GroupsFactory.createAllEntriesGroup()); bibDeskGroupTreeNode.moveTo(rootNode); metaData.setGroups(rootNode); } diff --git a/jablib/src/main/java/org/jabref/logic/importer/util/GroupsParser.java b/jablib/src/main/java/org/jabref/logic/importer/util/GroupsParser.java index b85c391d455..8ce056292c0 100644 --- a/jablib/src/main/java/org/jabref/logic/importer/util/GroupsParser.java +++ b/jablib/src/main/java/org/jabref/logic/importer/util/GroupsParser.java @@ -7,7 +7,7 @@ import java.util.List; import org.jabref.logic.auxparser.DefaultAuxParser; -import org.jabref.logic.groups.DefaultGroupsFactory; +import org.jabref.logic.groups.GroupsFactory; import org.jabref.logic.importer.ParseException; import org.jabref.logic.l10n.Localization; import org.jabref.logic.util.MetadataSerializationConfiguration; @@ -27,7 +27,6 @@ import org.jabref.model.groups.KeywordGroup; import org.jabref.model.groups.RegexKeywordGroup; import org.jabref.model.groups.SearchGroup; -import org.jabref.model.groups.SmartGroup; import org.jabref.model.groups.TexGroup; import org.jabref.model.groups.WordKeywordGroup; import org.jabref.model.metadata.MetaData; @@ -42,12 +41,24 @@ */ public class GroupsParser { + /** + * Identifier for SmartGroup (deprecated, replaced by {@link ExplicitGroup}). + * + * @deprecated Kept for backward compatibility during migration. + */ + @Deprecated + private static final String SMART_GROUP_ID_FOR_MIGRATION = "SmartGroup:"; + private static final Logger LOGGER = LoggerFactory.getLogger(GroupsParser.class); private GroupsParser() { } - public static GroupTreeNode importGroups(List orderedData, Character keywordSeparator, FileUpdateMonitor fileMonitor, MetaData metaData, String userAndHost) + public static GroupTreeNode importGroups(List orderedData, + Character keywordSeparator, + FileUpdateMonitor fileMonitor, + MetaData metaData, + String userAndHost) throws ParseException { try { GroupTreeNode cursor = null; @@ -90,64 +101,67 @@ public static GroupTreeNode importGroups(List orderedData, Character key /** * Re-create a group instance from a textual representation. * - * @param s The result from the group's toString() method. + * @param input The result from the group's toString() method. * @return New instance of the encoded group. * @throws ParseException If an error occurred and a group could not be created, e.g. due to a malformed regular expression. */ - public static AbstractGroup fromString(String s, Character keywordSeparator, FileUpdateMonitor fileMonitor, MetaData metaData, String userAndHost) + public static AbstractGroup fromString(String input, Character keywordSeparator, FileUpdateMonitor fileMonitor, MetaData metaData, String userAndHost) throws ParseException { - if (s.startsWith(MetadataSerializationConfiguration.KEYWORD_GROUP_ID)) { - return keywordGroupFromString(s, keywordSeparator); + if (input.startsWith(MetadataSerializationConfiguration.KEYWORD_GROUP_ID)) { + return keywordGroupFromString(input, keywordSeparator); } - if (s.startsWith(MetadataSerializationConfiguration.ALL_ENTRIES_GROUP_ID)) { - return allEntriesGroupFromString(s); + if (input.startsWith(MetadataSerializationConfiguration.ALL_ENTRIES_GROUP_ID)) { + return allEntriesGroupFromString(input); } - if (s.startsWith(MetadataSerializationConfiguration.SMART_GROUP_ID)) { - return smartGroupFromString(s, keywordSeparator); + if (input.startsWith(SMART_GROUP_ID_FOR_MIGRATION)) { + // Migration: SmartGroup is replaced by ExplicitGroup + return smartGroupFromString(input, keywordSeparator); } - if (s.startsWith(MetadataSerializationConfiguration.SEARCH_GROUP_ID)) { - return searchGroupFromString(s); + if (input.startsWith(MetadataSerializationConfiguration.SEARCH_GROUP_ID)) { + return searchGroupFromString(input); } - if (s.startsWith(MetadataSerializationConfiguration.EXPLICIT_GROUP_ID)) { - return explicitGroupFromString(s, keywordSeparator); + if (input.startsWith(MetadataSerializationConfiguration.EXPLICIT_GROUP_ID)) { + return explicitGroupFromString(input, keywordSeparator); } - if (s.startsWith(MetadataSerializationConfiguration.LEGACY_EXPLICIT_GROUP_ID)) { - return legacyExplicitGroupFromString(s, keywordSeparator); + if (input.startsWith(MetadataSerializationConfiguration.LEGACY_EXPLICIT_GROUP_ID)) { + return legacyExplicitGroupFromString(input, keywordSeparator); } - if (s.startsWith(MetadataSerializationConfiguration.AUTOMATIC_PERSONS_GROUP_ID)) { - return automaticPersonsGroupFromString(s); + if (input.startsWith(MetadataSerializationConfiguration.AUTOMATIC_PERSONS_GROUP_ID)) { + return automaticPersonsGroupFromString(input); } - if (s.startsWith(MetadataSerializationConfiguration.AUTOMATIC_KEYWORD_GROUP_ID)) { - return automaticKeywordGroupFromString(s); + if (input.startsWith(MetadataSerializationConfiguration.AUTOMATIC_KEYWORD_GROUP_ID)) { + return automaticKeywordGroupFromString(input); } - if (s.startsWith(MetadataSerializationConfiguration.AUTOMATIC_DATE_GROUP_ID)) { - return automaticDateGroupFromString(s); + if (input.startsWith(MetadataSerializationConfiguration.AUTOMATIC_DATE_GROUP_ID)) { + return automaticDateGroupFromString(input); } - if (s.startsWith(MetadataSerializationConfiguration.TEX_GROUP_ID)) { - return texGroupFromString(s, fileMonitor, metaData, userAndHost); + if (input.startsWith(MetadataSerializationConfiguration.TEX_GROUP_ID)) { + return texGroupFromString(input, fileMonitor, metaData, userAndHost); } - throw new ParseException("Unknown group: " + s); + throw new ParseException("Unknown group: " + input); } - private static AbstractGroup texGroupFromString(String string, FileUpdateMonitor fileMonitor, MetaData metaData, String userAndHost) throws ParseException { - QuotedStringTokenizer tok = new QuotedStringTokenizer(string.substring(MetadataSerializationConfiguration.TEX_GROUP_ID + private static AbstractGroup texGroupFromString(String input, FileUpdateMonitor fileMonitor, MetaData metaData, String userAndHost) throws ParseException { + assert input.startsWith(MetadataSerializationConfiguration.TEX_GROUP_ID); + + QuotedStringTokenizer token = new QuotedStringTokenizer(input.substring(MetadataSerializationConfiguration.TEX_GROUP_ID .length()), MetadataSerializationConfiguration.GROUP_UNIT_SEPARATOR, MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); - String name = StringUtil.unquote(tok.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); - GroupHierarchyType context = GroupHierarchyType.getByNumberOrDefault(Integer.parseInt(tok.nextToken())); + String name = StringUtil.unquote(token.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); + GroupHierarchyType context = GroupHierarchyType.getByNumberOrDefault(Integer.parseInt(token.nextToken())); try { - Path path = Path.of(tok.nextToken()); + Path path = Path.of(token.nextToken()); try { TexGroup newGroup = TexGroup.create(name, context, path, new DefaultAuxParser(new BibDatabase()), fileMonitor, metaData, userAndHost); - addGroupDetails(tok, newGroup); + addGroupDetails(token, newGroup); return newGroup; } catch (IOException ex) { // Problem accessing file -> create without file monitoring LOGGER.warn("Could not access file {}. The group {} will not reflect changes to the aux file.", path, name, ex); TexGroup newGroup = TexGroup.create(name, context, path, new DefaultAuxParser(new BibDatabase()), metaData, userAndHost); - addGroupDetails(tok, newGroup); + addGroupDetails(token, newGroup); return newGroup; } } catch (InvalidPathException | IOException ex) { @@ -155,113 +169,101 @@ private static AbstractGroup texGroupFromString(String string, FileUpdateMonitor } } - private static AbstractGroup automaticPersonsGroupFromString(String string) { - if (!string.startsWith(MetadataSerializationConfiguration.AUTOMATIC_PERSONS_GROUP_ID)) { - throw new IllegalArgumentException("KeywordGroup cannot be created from \"" + string + "\"."); - } - QuotedStringTokenizer tok = new QuotedStringTokenizer(string.substring(MetadataSerializationConfiguration.AUTOMATIC_PERSONS_GROUP_ID + private static AbstractGroup automaticPersonsGroupFromString(String input) { + assert input.startsWith(MetadataSerializationConfiguration.AUTOMATIC_PERSONS_GROUP_ID); + + QuotedStringTokenizer token = new QuotedStringTokenizer(input.substring(MetadataSerializationConfiguration.AUTOMATIC_PERSONS_GROUP_ID .length()), MetadataSerializationConfiguration.GROUP_UNIT_SEPARATOR, MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); - String name = StringUtil.unquote(tok.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); - GroupHierarchyType context = GroupHierarchyType.getByNumberOrDefault(Integer.parseInt(tok.nextToken())); - Field field = FieldFactory.parseField(StringUtil.unquote(tok.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR)); + String name = StringUtil.unquote(token.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); + GroupHierarchyType context = GroupHierarchyType.getByNumberOrDefault(Integer.parseInt(token.nextToken())); + Field field = FieldFactory.parseField(StringUtil.unquote(token.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR)); AutomaticPersonsGroup newGroup = new AutomaticPersonsGroup(name, context, field); - addGroupDetails(tok, newGroup); + addGroupDetails(token, newGroup); return newGroup; } - private static AbstractGroup automaticDateGroupFromString(String string) { - if (!string.startsWith(MetadataSerializationConfiguration.AUTOMATIC_DATE_GROUP_ID)) { - throw new IllegalArgumentException("AutomaticDateGroup cannot be created from \"" + string + "\"."); - } - QuotedStringTokenizer tok = new QuotedStringTokenizer(string.substring(MetadataSerializationConfiguration.AUTOMATIC_DATE_GROUP_ID + private static AbstractGroup automaticDateGroupFromString(String input) { + assert input.startsWith(MetadataSerializationConfiguration.AUTOMATIC_DATE_GROUP_ID); + + QuotedStringTokenizer token = new QuotedStringTokenizer(input.substring(MetadataSerializationConfiguration.AUTOMATIC_DATE_GROUP_ID .length()), MetadataSerializationConfiguration.GROUP_UNIT_SEPARATOR, MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); - String name = StringUtil.unquote(tok.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); - GroupHierarchyType context = GroupHierarchyType.getByNumberOrDefault(Integer.parseInt(tok.nextToken())); - Field field = FieldFactory.parseField(StringUtil.unquote(tok.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR)); - String granularityString = StringUtil.unquote(tok.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); + String name = StringUtil.unquote(token.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); + GroupHierarchyType context = GroupHierarchyType.getByNumberOrDefault(Integer.parseInt(token.nextToken())); + Field field = FieldFactory.parseField(StringUtil.unquote(token.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR)); + String granularityString = StringUtil.unquote(token.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); DateGranularity granularity = DateGranularity.valueOf(granularityString); AutomaticDateGroup newGroup = new AutomaticDateGroup(name, context, field, granularity); - addGroupDetails(tok, newGroup); + addGroupDetails(token, newGroup); return newGroup; } - private static AbstractGroup automaticKeywordGroupFromString(String string) { - if (!string.startsWith(MetadataSerializationConfiguration.AUTOMATIC_KEYWORD_GROUP_ID)) { - throw new IllegalArgumentException("KeywordGroup cannot be created from \"" + string + "\"."); - } - QuotedStringTokenizer tok = new QuotedStringTokenizer(string.substring(MetadataSerializationConfiguration.AUTOMATIC_KEYWORD_GROUP_ID + private static AbstractGroup automaticKeywordGroupFromString(String input) { + assert input.startsWith(MetadataSerializationConfiguration.AUTOMATIC_KEYWORD_GROUP_ID); + + QuotedStringTokenizer token = new QuotedStringTokenizer(input.substring(MetadataSerializationConfiguration.AUTOMATIC_KEYWORD_GROUP_ID .length()), MetadataSerializationConfiguration.GROUP_UNIT_SEPARATOR, MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); - String name = StringUtil.unquote(tok.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); - GroupHierarchyType context = GroupHierarchyType.getByNumberOrDefault(Integer.parseInt(tok.nextToken())); - Field field = FieldFactory.parseField(StringUtil.unquote(tok.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR)); - Character delimiter = StringUtil.unquote(tok.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR).charAt(0); - Character hierarchicalDelimiter = StringUtil.unquote(tok.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR).charAt(0); + String name = StringUtil.unquote(token.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); + GroupHierarchyType context = GroupHierarchyType.getByNumberOrDefault(Integer.parseInt(token.nextToken())); + Field field = FieldFactory.parseField(StringUtil.unquote(token.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR)); + Character delimiter = StringUtil.unquote(token.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR).charAt(0); + Character hierarchicalDelimiter = StringUtil.unquote(token.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR).charAt(0); AutomaticKeywordGroup newGroup = new AutomaticKeywordGroup(name, context, field, delimiter, hierarchicalDelimiter); - addGroupDetails(tok, newGroup); + addGroupDetails(token, newGroup); return newGroup; } /** * Parses s and recreates the KeywordGroup from it. * - * @param s The String representation obtained from KeywordGroup.toString() + * @param input The String representation obtained from KeywordGroup.toString() */ - private static KeywordGroup keywordGroupFromString(String s, Character keywordSeparator) { - if (!s.startsWith(MetadataSerializationConfiguration.KEYWORD_GROUP_ID)) { - throw new IllegalArgumentException("KeywordGroup cannot be created from \"" + s + "\"."); - } - QuotedStringTokenizer tok = new QuotedStringTokenizer(s.substring(MetadataSerializationConfiguration.KEYWORD_GROUP_ID + private static KeywordGroup keywordGroupFromString(String input, Character keywordSeparator) { + assert input.startsWith(MetadataSerializationConfiguration.KEYWORD_GROUP_ID); + + QuotedStringTokenizer token = new QuotedStringTokenizer(input.substring(MetadataSerializationConfiguration.KEYWORD_GROUP_ID .length()), MetadataSerializationConfiguration.GROUP_UNIT_SEPARATOR, MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); - String name = StringUtil.unquote(tok.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); - GroupHierarchyType context = GroupHierarchyType.getByNumberOrDefault(Integer.parseInt(tok.nextToken())); - Field field = FieldFactory.parseField(StringUtil.unquote(tok.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR)); - String expression = StringUtil.unquote(tok.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); - boolean caseSensitive = Integer.parseInt(tok.nextToken()) == 1; - boolean regExp = Integer.parseInt(tok.nextToken()) == 1; + String name = StringUtil.unquote(token.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); + GroupHierarchyType context = GroupHierarchyType.getByNumberOrDefault(Integer.parseInt(token.nextToken())); + Field field = FieldFactory.parseField(StringUtil.unquote(token.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR)); + String expression = StringUtil.unquote(token.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); + boolean caseSensitive = Integer.parseInt(token.nextToken()) == 1; + boolean regExp = Integer.parseInt(token.nextToken()) == 1; KeywordGroup newGroup; if (regExp) { newGroup = new RegexKeywordGroup(name, context, field, expression, caseSensitive); } else { newGroup = new WordKeywordGroup(name, context, field, expression, caseSensitive, keywordSeparator, false); } - addGroupDetails(tok, newGroup); + addGroupDetails(token, newGroup); return newGroup; } - private static SmartGroup smartGroupFromString(String input, Character keywordSeparator) throws ParseException { - if (!input.startsWith(MetadataSerializationConfiguration.SMART_GROUP_ID)) { - throw new IllegalArgumentException("SmartGroup cannot be created from \"" + input + "\"."); - } - QuotedStringTokenizer tok = new QuotedStringTokenizer(input.substring(MetadataSerializationConfiguration.SMART_GROUP_ID.length()), - MetadataSerializationConfiguration.GROUP_UNIT_SEPARATOR, MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); + /** + * Migration method: Converts old SmartGroup serializations to ExplicitGroup. + * SmartGroup has been replaced by ExplicitGroup for the "Imported Entries" group Issue 14143. + */ + private static ExplicitGroup smartGroupFromString(String input, Character keywordSeparator) throws ParseException { + assert input.startsWith(SMART_GROUP_ID_FOR_MIGRATION); - String name = StringUtil.unquote(tok.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); - try { - int context = Integer.parseInt(tok.nextToken()); - SmartGroup newGroup = new SmartGroup(name, GroupHierarchyType.getByNumberOrDefault(context), keywordSeparator); - addGroupDetails(tok, newGroup); - return newGroup; - } catch (NumberFormatException exception) { - throw new ParseException("Could not parse context in " + input); - } + input = input.replace(SMART_GROUP_ID_FOR_MIGRATION, MetadataSerializationConfiguration.EXPLICIT_GROUP_ID); + return explicitGroupFromString(input, keywordSeparator); } private static ExplicitGroup explicitGroupFromString(String input, Character keywordSeparator) throws ParseException { - if (!input.startsWith(MetadataSerializationConfiguration.EXPLICIT_GROUP_ID)) { - throw new IllegalArgumentException("ExplicitGroup cannot be created from \"" + input + "\"."); - } - QuotedStringTokenizer tok = new QuotedStringTokenizer(input.substring(MetadataSerializationConfiguration.EXPLICIT_GROUP_ID.length()), + assert input.startsWith(MetadataSerializationConfiguration.EXPLICIT_GROUP_ID); + + QuotedStringTokenizer token = new QuotedStringTokenizer(input.substring(MetadataSerializationConfiguration.EXPLICIT_GROUP_ID.length()), MetadataSerializationConfiguration.GROUP_UNIT_SEPARATOR, MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); - String name = StringUtil.unquote(tok.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); + String name = StringUtil.unquote(token.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); try { - int context = Integer.parseInt(tok.nextToken()); + int context = Integer.parseInt(token.nextToken()); ExplicitGroup newGroup = new ExplicitGroup(name, GroupHierarchyType.getByNumberOrDefault(context), keywordSeparator); - addGroupDetails(tok, newGroup); + addGroupDetails(token, newGroup); return newGroup; } catch (NumberFormatException exception) { throw new ParseException("Could not parse context in " + input); @@ -269,17 +271,16 @@ private static ExplicitGroup explicitGroupFromString(String input, Character key } private static ExplicitGroup legacyExplicitGroupFromString(String input, Character keywordSeparator) throws ParseException { - if (!input.startsWith(MetadataSerializationConfiguration.LEGACY_EXPLICIT_GROUP_ID)) { - throw new IllegalArgumentException("ExplicitGroup cannot be created from \"" + input + "\"."); - } - QuotedStringTokenizer tok = new QuotedStringTokenizer(input.substring(MetadataSerializationConfiguration.LEGACY_EXPLICIT_GROUP_ID.length()), + assert input.startsWith(MetadataSerializationConfiguration.LEGACY_EXPLICIT_GROUP_ID); + + QuotedStringTokenizer token = new QuotedStringTokenizer(input.substring(MetadataSerializationConfiguration.LEGACY_EXPLICIT_GROUP_ID.length()), MetadataSerializationConfiguration.GROUP_UNIT_SEPARATOR, MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); - String name = StringUtil.unquote(tok.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); + String name = StringUtil.unquote(token.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); try { - int context = Integer.parseInt(tok.nextToken()); + int context = Integer.parseInt(token.nextToken()); ExplicitGroup newGroup = new ExplicitGroup(name, GroupHierarchyType.getByNumberOrDefault(context), keywordSeparator); - GroupsParser.addLegacyEntryKeys(tok, newGroup); + GroupsParser.addLegacyEntryKeys(token, newGroup); return newGroup; } catch (NumberFormatException exception) { throw new ParseException("Could not parse context in " + input); @@ -299,33 +300,30 @@ private static void addLegacyEntryKeys(QuotedStringTokenizer tok, ExplicitGroup } } - private static AbstractGroup allEntriesGroupFromString(String s) { - if (!s.startsWith(MetadataSerializationConfiguration.ALL_ENTRIES_GROUP_ID)) { - throw new IllegalArgumentException("AllEntriesGroup cannot be created from \"" + s + "\"."); - } - return DefaultGroupsFactory.getAllEntriesGroup(); + private static AbstractGroup allEntriesGroupFromString(String input) { + assert input.startsWith(MetadataSerializationConfiguration.ALL_ENTRIES_GROUP_ID); + + return GroupsFactory.createAllEntriesGroup(); } /** * Parses s and recreates the SearchGroup from it. * - * @param s The String representation obtained from SearchGroup.toString(), or null if incompatible + * @param input The String representation obtained from SearchGroup.toString(), or null if incompatible */ - private static AbstractGroup searchGroupFromString(String s) { - if (!s.startsWith(MetadataSerializationConfiguration.SEARCH_GROUP_ID)) { - throw new IllegalArgumentException("SearchGroup cannot be created from \"" + s + "\"."); - } - QuotedStringTokenizer tok = new QuotedStringTokenizer(s.substring(MetadataSerializationConfiguration.SEARCH_GROUP_ID.length()), + private static AbstractGroup searchGroupFromString(String input) { + assert input.startsWith(MetadataSerializationConfiguration.SEARCH_GROUP_ID); + QuotedStringTokenizer token = new QuotedStringTokenizer(input.substring(MetadataSerializationConfiguration.SEARCH_GROUP_ID.length()), MetadataSerializationConfiguration.GROUP_UNIT_SEPARATOR, MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); - String name = StringUtil.unquote(tok.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); - int context = Integer.parseInt(tok.nextToken()); - String expression = StringUtil.unquote(tok.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); + String name = StringUtil.unquote(token.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); + int context = Integer.parseInt(token.nextToken()); + String expression = StringUtil.unquote(token.nextToken(), MetadataSerializationConfiguration.GROUP_QUOTE_CHAR); EnumSet searchFlags = EnumSet.noneOf(SearchFlags.class); - if (Integer.parseInt(tok.nextToken()) == 1) { + if (Integer.parseInt(token.nextToken()) == 1) { searchFlags.add(SearchFlags.CASE_SENSITIVE); } - if (Integer.parseInt(tok.nextToken()) == 1) { + if (Integer.parseInt(token.nextToken()) == 1) { searchFlags.add(SearchFlags.REGULAR_EXPRESSION); } // version 0 contained 4 additional booleans to specify search @@ -333,7 +331,7 @@ private static AbstractGroup searchGroupFromString(String s) { SearchGroup searchGroup = new SearchGroup(name, GroupHierarchyType.getByNumberOrDefault(context), expression, searchFlags ); - addGroupDetails(tok, searchGroup); + addGroupDetails(token, searchGroup); return searchGroup; } diff --git a/jablib/src/main/java/org/jabref/logic/util/MetadataSerializationConfiguration.java b/jablib/src/main/java/org/jabref/logic/util/MetadataSerializationConfiguration.java index 887a6428d7f..a475a70b80a 100644 --- a/jablib/src/main/java/org/jabref/logic/util/MetadataSerializationConfiguration.java +++ b/jablib/src/main/java/org/jabref/logic/util/MetadataSerializationConfiguration.java @@ -6,7 +6,6 @@ import org.jabref.model.groups.ExplicitGroup; import org.jabref.model.groups.RegexKeywordGroup; import org.jabref.model.groups.SearchGroup; -import org.jabref.model.groups.SmartGroup; import org.jabref.model.groups.TexGroup; import org.jabref.model.groups.WordKeywordGroup; @@ -49,11 +48,6 @@ public class MetadataSerializationConfiguration { */ public static final String EXPLICIT_GROUP_ID = "StaticGroup:"; - /** - * Identifier for {@link SmartGroup}. - */ - public static final String SMART_GROUP_ID = "SmartGroup:"; - /** * Identifier for {@link SearchGroup}. */ diff --git a/jablib/src/main/java/org/jabref/model/groups/SmartGroup.java b/jablib/src/main/java/org/jabref/model/groups/SmartGroup.java deleted file mode 100644 index e42a830f6c6..00000000000 --- a/jablib/src/main/java/org/jabref/model/groups/SmartGroup.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.jabref.model.groups; - -import java.util.Objects; - -import org.jabref.model.entry.field.StandardField; - -/** - * This group contains entries, which were automatically assigned to it. - * Assignments are stored in the {@link StandardField#GROUPS} field. - */ -public class SmartGroup extends WordKeywordGroup { - - public SmartGroup(String name, GroupHierarchyType context, Character keywordSeparator) { - super(name, context, StandardField.GROUPS, name, true, keywordSeparator, true); - } - - @Override - public AbstractGroup deepCopy() { - return new SmartGroup(getName(), getHierarchicalContext(), keywordSeparator); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if ((o == null) || (getClass() != o.getClass())) { - return false; - } - // no instanceof check as we don't want to go up the hierarchy - if (!super.equals(o)) { - return false; - } - SmartGroup other = (SmartGroup) o; - return Objects.equals(getName(), other.getName()) - && Objects.equals(getHierarchicalContext(), other.getHierarchicalContext()) - && Objects.equals(getIconName(), other.getIconName()) - && Objects.equals(getDescription(), other.getDescription()) - && Objects.equals(getColor(), other.getColor()) - && Objects.equals(isExpanded(), other.isExpanded()); - } - - @Override - public boolean isDynamic() { - return false; - } - - @Override - public int hashCode() { - return Objects.hash(name.getValue(), context, iconName, color, description, isExpanded); - } -} diff --git a/jablib/src/main/resources/l10n/JabRef_en.properties b/jablib/src/main/resources/l10n/JabRef_en.properties index 064e16b9b96..4cf1c70b1ed 100644 --- a/jablib/src/main/resources/l10n/JabRef_en.properties +++ b/jablib/src/main/resources/l10n/JabRef_en.properties @@ -2530,7 +2530,6 @@ Unprotect\ terms=Unprotect terms Generate\ a\ new\ key\ for\ imported\ entries\ (overwriting\ their\ default)=Generate a new key for imported entries (overwriting their default) Warn\ about\ duplicates\ on\ import=Warn about duplicates on import Add\ imported\ entries\ to\ group=Add imported entries to group -Smart\ Group\ (Import\ Entries)=Smart Group (Import Entries) Imported\ entries=Imported entries Custom\ DOI\ URI=Custom DOI URI diff --git a/jablib/src/test/java/org/jabref/logic/bibtex/comparator/MetaDataDiffTest.java b/jablib/src/test/java/org/jabref/logic/bibtex/comparator/MetaDataDiffTest.java index 447c227f705..cf74944b46a 100644 --- a/jablib/src/test/java/org/jabref/logic/bibtex/comparator/MetaDataDiffTest.java +++ b/jablib/src/test/java/org/jabref/logic/bibtex/comparator/MetaDataDiffTest.java @@ -3,7 +3,7 @@ import java.util.List; import java.util.Optional; -import org.jabref.logic.groups.DefaultGroupsFactory; +import org.jabref.logic.groups.GroupsFactory; import org.jabref.model.entry.field.StandardField; import org.jabref.model.groups.ExplicitGroup; import org.jabref.model.groups.GroupHierarchyType; @@ -43,7 +43,7 @@ void defaultSettingEqualsEmptySetting() { @Test void allEntriesGroupIgnored() { MetaData one = new MetaData(); - one.setGroups(GroupTreeNode.fromGroup(DefaultGroupsFactory.getAllEntriesGroup())); + one.setGroups(GroupTreeNode.fromGroup(GroupsFactory.createAllEntriesGroup())); MetaData two = new MetaData(); assertEquals(Optional.empty(), MetaDataDiff.compare(one, two)); @@ -52,7 +52,7 @@ void allEntriesGroupIgnored() { @Test void allEntriesGroupContainingGroupNotIgnored() { MetaData one = new MetaData(); - GroupTreeNode root = GroupTreeNode.fromGroup(DefaultGroupsFactory.getAllEntriesGroup()); + GroupTreeNode root = GroupTreeNode.fromGroup(GroupsFactory.createAllEntriesGroup()); root.addSubgroup(new ExplicitGroup("ExplicitA", GroupHierarchyType.INCLUDING, ',')); one.setGroups(root); diff --git a/jablib/src/test/java/org/jabref/logic/exporter/GroupSerializerTest.java b/jablib/src/test/java/org/jabref/logic/exporter/GroupSerializerTest.java index e32f587e60f..24b10a0e563 100644 --- a/jablib/src/test/java/org/jabref/logic/exporter/GroupSerializerTest.java +++ b/jablib/src/test/java/org/jabref/logic/exporter/GroupSerializerTest.java @@ -24,7 +24,6 @@ import org.jabref.model.groups.KeywordGroup; import org.jabref.model.groups.RegexKeywordGroup; import org.jabref.model.groups.SearchGroup; -import org.jabref.model.groups.SmartGroup; import org.jabref.model.groups.TexGroup; import org.jabref.model.groups.WordKeywordGroup; import org.jabref.model.metadata.MetaData; @@ -54,13 +53,6 @@ void serializeSingleAllEntriesGroup() { assertEquals(List.of("0 AllEntriesGroup:"), serialization); } - @Test - void serializeSmartGroup() { - SmartGroup group = new SmartGroup("mySmartGroup", GroupHierarchyType.INDEPENDENT, ','); - List serialization = groupSerializer.serializeTree(GroupTreeNode.fromGroup(group)); - assertEquals(List.of("0 SmartGroup:mySmartGroup;0;1;;;;"), serialization); - } - @Test void serializeSingleExplicitGroup() { ExplicitGroup group = new ExplicitGroup("myExplicitGroup", GroupHierarchyType.INDEPENDENT, ','); diff --git a/jablib/src/test/java/org/jabref/logic/importer/util/GroupsParserTest.java b/jablib/src/test/java/org/jabref/logic/importer/util/GroupsParserTest.java index 76572f39cdc..3d6a87097f2 100644 --- a/jablib/src/test/java/org/jabref/logic/importer/util/GroupsParserTest.java +++ b/jablib/src/test/java/org/jabref/logic/importer/util/GroupsParserTest.java @@ -9,6 +9,7 @@ import javafx.scene.paint.Color; import org.jabref.logic.auxparser.DefaultAuxParser; +import org.jabref.logic.exporter.GroupSerializer; import org.jabref.logic.importer.ParseException; import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.field.StandardField; @@ -33,6 +34,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; class GroupsParserTest { private FileUpdateMonitor fileMonitor; @@ -174,4 +176,36 @@ void fromStringParsesAutomaticDateGroupWithColorAndIcon() throws ParseException AbstractGroup parsed = GroupsParser.fromString("AutomaticDateGroup:Publications;0;year;YEAR;1;0x0000ffff;calendar;Group by publication year;", ',', fileMonitor, metaData, "userAndHost"); assertEquals(expected, parsed); } + + @Test + void fromStringParsesSmartGroupAndMigratesToExplicitGroup() throws ParseException { + ExplicitGroup expected = new ExplicitGroup("MySmartGroup", GroupHierarchyType.INDEPENDENT, ','); + AbstractGroup parsed = GroupsParser.fromString("SmartGroup:MySmartGroup;0;", ',', fileMonitor, metaData, "userAndHost"); + + assertEquals(ExplicitGroup.class, parsed.getClass()); + assertEquals(expected, parsed); + } + + @Test + void roundtripSmartGroupToExplicitGroup() throws ParseException { + // Read old SmartGroup format + String smartGroupString = "SmartGroup:MyGroup;0;1;0xf0f8ffff;icon-name;Group description;"; + AbstractGroup parsed = GroupsParser.fromString(smartGroupString, ',', fileMonitor, metaData, "userAndHost"); + assertEquals(ExplicitGroup.class, parsed.getClass()); + + // Store in new format (serialize) + GroupSerializer serializer = new GroupSerializer(); + List serialized = serializer.serializeTree(GroupTreeNode.fromGroup(parsed)); + String serializedString = serialized.getFirst().substring(2); // Remove level prefix "0 " + + // Verify it's stored as StaticGroup (ExplicitGroup format), not SmartGroup + assertTrue(serializedString.startsWith("StaticGroup:")); + + // Read the new format + AbstractGroup roundtripParsed = GroupsParser.fromString(serializedString, ',', fileMonitor, metaData, "userAndHost"); + + // Verify it's still ExplicitGroup and properties are preserved + assertEquals(ExplicitGroup.class, roundtripParsed.getClass()); + assertEquals(parsed, roundtripParsed); + } }