package org.jabref.gui.collab;

import javax.swing.JComponent;
import javax.swing.JLabel;

import org.jabref.gui.BasePanel;
import org.jabref.gui.groups.GroupTreeNodeViewModel;
import org.jabref.gui.groups.UndoableModifySubtree;
import org.jabref.gui.undo.NamedCompound;
import org.jabref.logic.bibtex.comparator.GroupDiff;
import org.jabref.logic.groups.DefaultGroupsFactory;
import org.jabref.logic.l10n.Localization;
import org.jabref.model.database.BibDatabase;
import org.jabref.model.groups.GroupTreeNode;

class GroupChangeViewModel extends ChangeViewModel {

    private final GroupTreeNode changedGroups;
    private final GroupTreeNode tmpGroupRoot;


    public GroupChangeViewModel(GroupDiff diff) {
        super(diff.getOriginalGroupRoot() == null ? Localization.lang("Removed all groups") : Localization
                .lang("Modified groups tree"));
        this.changedGroups = diff.getOriginalGroupRoot();
        this.tmpGroupRoot = diff.getNewGroupRoot();
    }

    @Override
    public boolean makeChange(BasePanel panel, BibDatabase secondary, NamedCompound undoEdit) {
        final GroupTreeNode root = panel.getBibDatabaseContext().getMetaData().getGroups().orElse(null);
        final UndoableModifySubtree undo = new UndoableModifySubtree(
                new GroupTreeNodeViewModel(panel.getBibDatabaseContext().getMetaData().getGroups().orElse(null)),
                new GroupTreeNodeViewModel(root), Localization.lang("Modified groups"));
        root.removeAllChildren();
        if (changedGroups == null) {
            // I think setting root to null is not possible
            root.setGroup(DefaultGroupsFactory.getAllEntriesGroup());
        } else {
            // change root group, even though it'll be AllEntries anyway
            root.setGroup(changedGroups.getGroup());
            for (GroupTreeNode child : changedGroups.getChildren()) {
                child.copySubtree().moveTo(root);
            }
        }

        undoEdit.addEdit(undo);

        // Update tmp database:
        tmpGroupRoot.removeAllChildren();
        if (changedGroups != null) {
            GroupTreeNode copied = changedGroups.copySubtree();
            tmpGroupRoot.setGroup(copied.getGroup());
            for (GroupTreeNode child : copied.getChildren()) {
                child.copySubtree().moveTo(tmpGroupRoot);
            }
        }
        return true;
    }

    @Override
    public JComponent description() {
        return new JLabel("<html>" + toString() + '.'
                + (changedGroups == null ? "" : ' ' + Localization
                        .lang("Accepting the change replaces the complete groups tree with the externally modified groups tree."))
                + "</html>");

    }
}

@@ -1095,22 +1095,16 @@
         
-final 
 GroupTre
@@ -1186,16 +1186,208 @@
 (null);%0A
+        if (root == null) %7B%0A            root = new GroupTreeNode(DefaultGroupsFactory.getAllEntriesGroup());%0A            panel.getBibDatabaseContext().getMetaData().setGroups(root);%0A        %7D%0A
         
@@ -2205,16 +2205,56 @@
 tabase:%0A
+        if (tmpGroupRoot != null) %7B%0A    
         
@@ -2279,32 +2279,36 @@
 eAllChildren();%0A
+    
         if (chan
@@ -2332,32 +2332,36 @@
 ) %7B%0A            
+    
 GroupTreeNode co
@@ -2400,32 +2400,36 @@
 ();%0A            
+ 
+   
 tmpGroupRoot.set
@@ -2446,32 +2446,36 @@
 ed.getGroup());%0A
+    
             for 
@@ -2529,32 +2529,36 @@
                 
+   
+ 
 child.copySubtre
@@ -2579,24 +2579,42 @@
 GroupRoot);%0A
+                %7D%0A
             
@@ -2607,32 +2607,32 @@
 %7D%0A            %7D%0A
-
         %7D%0A      
@@ -2617,32 +2617,33 @@
     %7D%0A        %7D%0A
+%0A
         return t

Add null checks in GroupChangeViewModel (#3529)