Skip to content

Commit b2bc718

Browse files
authored
Add hover button to group rows for adding groups (#15502)
* Add hover button to group rows for adding groups * Changelog entry * Change addNewGroup method visibility to private * Address qodo feedback * Replace numbers with constants and change button position * fixed vertical centering of group names when hovering on subgroups
1 parent 4d519d4 commit b2bc718

File tree

3 files changed

+85
-8
lines changed

3 files changed

+85
-8
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
1111

1212
### Added
1313

14+
- We added a hover button on group rows to quickly add a new group or subgroup. [#12289](https://github.com/JabRef/jabref/issues/12289)
1415
- We added a shorthand for protecting terms in the fields: user can now select a text and type a opening curling brace to quickly wrap the selection in braces. [#15442](https://github.com/JabRef/jabref/pull/15442)
1516
- We added fallback search for `[DATE]` patterns in the file finder, so that if an exact date match is not found, progressively less specific dates (year-month, then year) are tried. [#8152](https://github.com/JabRef/jabref/issues/8152)
1617
- We added support for downloading full-text PDFs from Wiley journals via the Wiley TDM API. [#13404](https://github.com/JabRef/jabref/issues/13404)

jabgui/src/main/java/org/jabref/gui/groups/GroupTreeView.java

Lines changed: 71 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import javafx.scene.control.TextField;
3333
import javafx.scene.control.Tooltip;
3434
import javafx.scene.control.TreeItem;
35+
import javafx.scene.control.TreeTableCell;
3536
import javafx.scene.control.TreeTableColumn;
3637
import javafx.scene.control.TreeTableRow;
3738
import javafx.scene.control.TreeTableView;
@@ -90,6 +91,11 @@ public class GroupTreeView extends BorderPane {
9091
private static final PseudoClass PSEUDOCLASS_ROOTELEMENT = PseudoClass.getPseudoClass("root");
9192
private static final PseudoClass PSEUDOCLASS_SUBELEMENT = PseudoClass.getPseudoClass("sub"); // > 1 deep
9293

94+
private static final double NUMBER_COL_WIDTH = 60d;
95+
private static final double EXPANSION_COL_WIDTH = 20d;
96+
private static final double ADD_SUBGROUP_COL_WIDTH = 28d;
97+
private static final double SCROLLBAR_WIDTH = 15d;
98+
9399
private final StateManager stateManager;
94100
private final DialogService dialogService;
95101
private final AiService aiService;
@@ -105,6 +111,7 @@ public class GroupTreeView extends BorderPane {
105111
private TreeTableColumn<GroupNodeViewModel, GroupNodeViewModel> mainColumn;
106112
private TreeTableColumn<GroupNodeViewModel, GroupNodeViewModel> numberColumn;
107113
private TreeTableColumn<GroupNodeViewModel, GroupNodeViewModel> expansionNodeColumn;
114+
private TreeTableColumn<GroupNodeViewModel, GroupNodeViewModel> addSubgroupColumn;
108115
private CustomTextField searchField;
109116
private GroupTreeViewModel viewModel;
110117
private CustomLocalDragboard localDragboard;
@@ -154,21 +161,28 @@ private void createNodes() {
154161
mainColumn.setResizable(true);
155162
numberColumn = new TreeTableColumn<>();
156163
numberColumn.getStyleClass().add("numberColumn");
157-
numberColumn.setMinWidth(60d);
158-
numberColumn.setMaxWidth(60d);
159-
numberColumn.setPrefWidth(60d);
164+
numberColumn.setMinWidth(NUMBER_COL_WIDTH);
165+
numberColumn.setMaxWidth(NUMBER_COL_WIDTH);
166+
numberColumn.setPrefWidth(NUMBER_COL_WIDTH);
160167
numberColumn.setResizable(false);
161168
expansionNodeColumn = new TreeTableColumn<>();
162169
expansionNodeColumn.getStyleClass().add("expansionNodeColumn");
163-
expansionNodeColumn.setMaxWidth(20d);
164-
expansionNodeColumn.setMinWidth(20d);
165-
expansionNodeColumn.setPrefWidth(20d);
170+
expansionNodeColumn.setMaxWidth(EXPANSION_COL_WIDTH);
171+
expansionNodeColumn.setMinWidth(EXPANSION_COL_WIDTH);
172+
expansionNodeColumn.setPrefWidth(EXPANSION_COL_WIDTH);
166173
expansionNodeColumn.setResizable(false);
167174

175+
addSubgroupColumn = new TreeTableColumn<>();
176+
addSubgroupColumn.getStyleClass().add("addSubgroupColumn");
177+
addSubgroupColumn.setMinWidth(ADD_SUBGROUP_COL_WIDTH);
178+
addSubgroupColumn.setMaxWidth(ADD_SUBGROUP_COL_WIDTH);
179+
addSubgroupColumn.setPrefWidth(ADD_SUBGROUP_COL_WIDTH);
180+
addSubgroupColumn.setResizable(false);
181+
168182
groupTree = new TreeTableView<>();
169183
groupTree.setId("groupTree");
170184
groupTree.setColumnResizePolicy(TreeTableView.CONSTRAINED_RESIZE_POLICY_FLEX_LAST_COLUMN);
171-
groupTree.getColumns().addAll(List.of(mainColumn, numberColumn, expansionNodeColumn));
185+
groupTree.getColumns().addAll(List.of(mainColumn, numberColumn, addSubgroupColumn, expansionNodeColumn));
172186
groupTree.setOnKeyPressed(event -> {
173187
if (event.getCode().toString().equals(KeyBinding.GROUP_RENAME.getDefaultKeyBinding())) {
174188
TreeItem<GroupNodeViewModel> selectedItem = groupTree.getSelectionModel().getSelectedItem();
@@ -179,7 +193,11 @@ private void createNodes() {
179193
});
180194
this.setCenter(groupTree);
181195

182-
mainColumn.prefWidthProperty().bind(groupTree.widthProperty().subtract(80d).subtract(15d));
196+
mainColumn.prefWidthProperty().bind(groupTree.widthProperty()
197+
.subtract(NUMBER_COL_WIDTH)
198+
.subtract(EXPANSION_COL_WIDTH)
199+
.subtract(ADD_SUBGROUP_COL_WIDTH)
200+
.subtract(SCROLLBAR_WIDTH));
183201

184202
Button addNewGroup = new Button(Localization.lang("Add group"));
185203
addNewGroup.setMaxWidth(Double.MAX_VALUE);
@@ -258,6 +276,51 @@ private void initialize() {
258276
})
259277
.install(expansionNodeColumn);
260278

279+
// "Add subgroup" button shown on row hover
280+
addSubgroupColumn.setCellValueFactory(cellData -> cellData.getValue().valueProperty());
281+
addSubgroupColumn.setCellFactory(col -> {
282+
Button button = IconTheme.JabRefIcons.ADD.asButton();
283+
button.setVisible(false);
284+
button.managedProperty().bind(button.visibleProperty());
285+
StackPane pane = new StackPane(button);
286+
pane.setMinHeight(0);
287+
pane.setPrefHeight(0);
288+
pane.setMaxHeight(0);
289+
290+
TreeTableCell<GroupNodeViewModel, GroupNodeViewModel> cell = new TreeTableCell<>() {
291+
@Override
292+
protected void updateItem(GroupNodeViewModel group, boolean empty) {
293+
super.updateItem(group, empty);
294+
if (empty || group == null) {
295+
setGraphic(null);
296+
} else if (group.isRoot() || group.isEditable() && group.canAddGroupsIn()) {
297+
if (group.isRoot()) {
298+
button.setTooltip(new Tooltip(Localization.lang("New group")));
299+
} else {
300+
button.setTooltip(new Tooltip(Localization.lang("Add subgroup")));
301+
}
302+
setGraphic(pane);
303+
button.setOnAction(event -> viewModel.addNewSubgroup(
304+
group,
305+
group.isRoot() ? GroupDialogHeader.GROUP : GroupDialogHeader.SUBGROUP));
306+
} else {
307+
setGraphic(null);
308+
}
309+
}
310+
};
311+
312+
cell.tableRowProperty().addListener((obs, oldRow, newRow) -> {
313+
button.visibleProperty().unbind();
314+
if (newRow != null) {
315+
button.visibleProperty().bind(newRow.hoverProperty());
316+
} else {
317+
button.setVisible(false);
318+
}
319+
});
320+
321+
return cell;
322+
});
323+
261324
new ViewModelTreeTableRowFactory<GroupNodeViewModel>()
262325
.withContextMenu(this::createContextMenuForGroup)
263326
.withEventFilter(MouseEvent.MOUSE_PRESSED, (row, event) -> {

jabgui/src/main/resources/org/jabref/gui/Base.css

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2284,6 +2284,11 @@ We want to have a look that matches our icons in the tool-bar */
22842284
-fx-alignment: top-right;
22852285
}
22862286

2287+
#groupTree .addSubgroupColumn {
2288+
-fx-padding: 0;
2289+
-fx-alignment: center;
2290+
}
2291+
22872292
#groupTree .tree-table-row-cell:dragOver-bottom {
22882293
-fx-border-color: -jr-drag-target;
22892294
-fx-border-width: 0 0 2 0;
@@ -2311,6 +2316,10 @@ We want to have a look that matches our icons in the tool-bar */
23112316
-fx-padding: 0.20em 0.2em 0.20em 0em;
23122317
}
23132318

2319+
#groupTree .tree-table-row-cell:sub > .addSubgroupColumn {
2320+
-fx-padding: 0;
2321+
}
2322+
23142323
#groupTree .tree-table-row-cell:root {
23152324
-fx-border-width: 0 0 1 0;
23162325
-fx-border-color: -jr-separator;
@@ -2328,6 +2337,10 @@ We want to have a look that matches our icons in the tool-bar */
23282337
-fx-padding: 0.45em 0.2em 0.45em 0.2em;
23292338
}
23302339

2340+
#groupTree .tree-table-row-cell:root > .addSubgroupColumn {
2341+
-fx-padding: 0;
2342+
}
2343+
23312344
#groupTree .tree-table-row-cell:empty {
23322345
-fx-background-color: transparent; /* hide cells which are not bound to a group */
23332346
}

0 commit comments

Comments
 (0)