diff --git a/src/main/java/org/jabref/gui/JabRefFrame.java b/src/main/java/org/jabref/gui/JabRefFrame.java index 6361fd9d76e..6a5638649e7 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -565,7 +565,7 @@ public void showLibraryTab(LibraryTab libraryTab) { } public void init() { - sidePaneManager = new SidePaneManager(prefs, this, dialogService, stateManager); + sidePaneManager = new SidePaneManager(prefs, this, taskExecutor, dialogService, stateManager); sidePane = sidePaneManager.getPane(); tabbedPane = new TabPane(); diff --git a/src/main/java/org/jabref/gui/SidePaneManager.java b/src/main/java/org/jabref/gui/SidePaneManager.java index f87c948b57c..58ffa349624 100644 --- a/src/main/java/org/jabref/gui/SidePaneManager.java +++ b/src/main/java/org/jabref/gui/SidePaneManager.java @@ -10,6 +10,7 @@ import org.jabref.gui.groups.GroupSidePane; import org.jabref.gui.importer.fetcher.WebSearchPane; import org.jabref.gui.openoffice.OpenOfficeSidePanel; +import org.jabref.gui.util.TaskExecutor; import org.jabref.logic.openoffice.OpenOfficePreferences; import org.jabref.preferences.PreferencesService; @@ -23,13 +24,13 @@ public class SidePaneManager { private final List visibleComponents = new LinkedList<>(); private final PreferencesService preferencesService; - public SidePaneManager(PreferencesService preferencesService, JabRefFrame frame, DialogService dialogService, StateManager stateManager) { + public SidePaneManager(PreferencesService preferencesService, JabRefFrame frame, TaskExecutor taskExecutor, DialogService dialogService, StateManager stateManager) { this.preferencesService = preferencesService; this.sidePane = new SidePane(); OpenOfficePreferences openOfficePreferences = preferencesService.getOpenOfficePreferences(); Stream.of( - new GroupSidePane(this, preferencesService, dialogService), + new GroupSidePane(this, taskExecutor, stateManager, preferencesService, dialogService), new WebSearchPane(this, preferencesService, dialogService, stateManager), new OpenOfficeSidePanel(this, preferencesService, frame)) .forEach(pane -> components.put(pane.getType(), pane)); diff --git a/src/main/java/org/jabref/gui/groups/GroupSidePane.java b/src/main/java/org/jabref/gui/groups/GroupSidePane.java index 8c2e1598742..4484bee6700 100644 --- a/src/main/java/org/jabref/gui/groups/GroupSidePane.java +++ b/src/main/java/org/jabref/gui/groups/GroupSidePane.java @@ -11,14 +11,14 @@ import org.jabref.gui.SidePaneComponent; import org.jabref.gui.SidePaneManager; import org.jabref.gui.SidePaneType; +import org.jabref.gui.StateManager; import org.jabref.gui.actions.Action; import org.jabref.gui.actions.StandardActions; import org.jabref.gui.icon.IconTheme; +import org.jabref.gui.util.TaskExecutor; import org.jabref.logic.l10n.Localization; import org.jabref.preferences.PreferencesService; -import com.airhacks.afterburner.views.ViewLoader; - /** * The groups side pane. */ @@ -26,11 +26,15 @@ public class GroupSidePane extends SidePaneComponent { private final PreferencesService preferences; private final DialogService dialogService; + private final TaskExecutor taskExecutor; + private final StateManager stateManager; private final Button intersectionUnionToggle = IconTheme.JabRefIcons.GROUP_INTERSECTION.asButton(); - public GroupSidePane(SidePaneManager manager, PreferencesService preferences, DialogService dialogService) { + public GroupSidePane(SidePaneManager manager, TaskExecutor taskExecutor, StateManager stateManager, PreferencesService preferences, DialogService dialogService) { super(manager, IconTheme.JabRefIcons.TOGGLE_GROUPS, Localization.lang("Groups")); this.preferences = preferences; + this.taskExecutor = taskExecutor; + this.stateManager = stateManager; this.dialogService = dialogService; } @@ -83,9 +87,7 @@ private void setGraphicsAndTooltipForButton(GroupViewMode mode) { @Override protected Node createContentPane() { - return ViewLoader.view(GroupTreeView.class) - .load() - .getView(); + return new GroupTreeView(taskExecutor, stateManager, preferences, dialogService); } @Override diff --git a/src/main/java/org/jabref/gui/groups/GroupTree.fxml b/src/main/java/org/jabref/gui/groups/GroupTree.fxml deleted file mode 100644 index 93e858dba01..00000000000 --- a/src/main/java/org/jabref/gui/groups/GroupTree.fxml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - - - -
- - - - - - - - - - -
- - - - - - -
diff --git a/src/main/java/org/jabref/gui/groups/GroupTreeView.java b/src/main/java/org/jabref/gui/groups/GroupTreeView.java index efffd504d78..b99df83eb98 100644 --- a/src/main/java/org/jabref/gui/groups/GroupTreeView.java +++ b/src/main/java/org/jabref/gui/groups/GroupTreeView.java @@ -6,15 +6,13 @@ import java.util.ArrayList; import java.util.LinkedList; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; -import javax.inject.Inject; - import javafx.application.Platform; import javafx.beans.property.ObjectProperty; import javafx.css.PseudoClass; -import javafx.fxml.FXML; import javafx.scene.control.Button; import javafx.scene.control.ContextMenu; import javafx.scene.control.Control; @@ -23,6 +21,7 @@ import javafx.scene.control.SelectionMode; import javafx.scene.control.SeparatorMenuItem; import javafx.scene.control.TextField; +import javafx.scene.control.Tooltip; import javafx.scene.control.TreeItem; import javafx.scene.control.TreeTableColumn; import javafx.scene.control.TreeTableRow; @@ -32,6 +31,9 @@ import javafx.scene.input.MouseButton; import javafx.scene.input.MouseEvent; import javafx.scene.input.TransferMode; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; import javafx.scene.layout.StackPane; import javafx.scene.text.Text; @@ -57,29 +59,85 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class GroupTreeView { +public class GroupTreeView extends BorderPane { private static final Logger LOGGER = LoggerFactory.getLogger(GroupTreeView.class); - @FXML private TreeTableView groupTree; - @FXML private TreeTableColumn mainColumn; - @FXML private TreeTableColumn numberColumn; - @FXML private TreeTableColumn expansionNodeColumn; - @FXML private CustomTextField searchField; - @FXML private Button addNewGroup; + private TreeTableView groupTree; + private TreeTableColumn mainColumn; + private TreeTableColumn numberColumn; + private TreeTableColumn expansionNodeColumn; + private CustomTextField searchField; + private Button addNewGroup; - @Inject private StateManager stateManager; - @Inject private DialogService dialogService; - @Inject private TaskExecutor taskExecutor; - @Inject private PreferencesService preferencesService; + private final StateManager stateManager; + private final DialogService dialogService; + private final TaskExecutor taskExecutor; + private final PreferencesService preferencesService; private GroupTreeViewModel viewModel; private CustomLocalDragboard localDragboard; private DragExpansionHandler dragExpansionHandler; - @FXML - public void initialize() { + /** + * The groups panel + * + * Note: This panel is deliberately not created in FXML, since parsing of this took about 500 msecs. In an attempt + * to speed up the startup time of JabRef, this has been rewritten to plain java. + */ + public GroupTreeView(TaskExecutor taskExecutor, StateManager stateManager, PreferencesService preferencesService, DialogService dialogService) { + this.taskExecutor = taskExecutor; + this.stateManager = stateManager; + this.preferencesService = preferencesService; + this.dialogService = dialogService; + + createNodes(); + this.getStylesheets().add(Objects.requireNonNull(GroupTreeView.class.getResource("GroupTree.css")).toExternalForm()); + initialize(); + } + + private void createNodes() { + searchField = new CustomTextField(); + + searchField.setPromptText(Localization.lang("Filter groups")); + searchField.setId("searchField"); + HBox.setHgrow(searchField, Priority.ALWAYS); + HBox groupFilterBar = new HBox(searchField); + groupFilterBar.setId("groupFilterBar"); + this.setTop(groupFilterBar); + + mainColumn = new TreeTableColumn<>(); + mainColumn.setId("mainColumn"); + numberColumn = new TreeTableColumn<>(); + numberColumn.getStyleClass().add("numberColumn"); + numberColumn.setMinWidth(50d); + numberColumn.setMaxWidth(70d); + numberColumn.setPrefWidth(60d); + expansionNodeColumn = new TreeTableColumn<>(); + expansionNodeColumn.getStyleClass().add("expansionNodeColumn"); + expansionNodeColumn.setMaxWidth(25d); + expansionNodeColumn.setMinWidth(25d); + + groupTree = new TreeTableView<>(); + groupTree.setId("groupTree"); + groupTree.setColumnResizePolicy(TreeTableView.CONSTRAINED_RESIZE_POLICY); + groupTree.getColumns().addAll(List.of(mainColumn, numberColumn, expansionNodeColumn)); + this.setCenter(groupTree); + + addNewGroup = new Button(Localization.lang("Add group")); + addNewGroup.setId("addNewGroup"); + addNewGroup.setMaxWidth(Double.MAX_VALUE); + HBox.setHgrow(addNewGroup, Priority.ALWAYS); + addNewGroup.setTooltip(new Tooltip(Localization.lang("New group"))); + addNewGroup.setOnAction(event -> addNewGroup()); + + HBox groupBar = new HBox(addNewGroup); + groupBar.setId("groupBar"); + this.setBottom(groupBar); + } + + private void initialize() { this.localDragboard = stateManager.getLocalDragboard(); viewModel = new GroupTreeViewModel(stateManager, dialogService, preferencesService, taskExecutor, localDragboard); @@ -396,13 +454,12 @@ private ContextMenu createContextMenuForGroup(GroupNodeViewModel group) { return menu; } - @FXML private void addNewGroup() { viewModel.addNewGroupToRoot(); } /** - * Workaround taken from https://bitbucket.org/controlsfx/controlsfx/issues/330/making-textfieldssetupclearbuttonfield + * Workaround taken from https://github.com/controlsfx/controlsfx/issues/330 */ private void setupClearButtonField(CustomTextField customTextField) { try {