Skip to content

Commit d931d4e

Browse files
committed
Merge remote-tracking branch 'upstream/master' into fixOpenOffice
* upstream/master: Improve drag and drop (#5306)
2 parents 9e9a94c + 381f0f3 commit d931d4e

File tree

17 files changed

+262
-138
lines changed

17 files changed

+262
-138
lines changed

.idea/runConfigurations/JabRef_Main.xml

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/main/java/org/jabref/gui/Base.css

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
/* Highlights */
2727
-jr-blue: #0abde3;
2828
-jr-light-blue: #48dbfb;
29-
-jr-purple: #f368e0;
29+
-jr-purple: #7559C2;
3030
-jr-light-purple: #ff9ff3;
3131
-jr-green: #10ac84;
3232
-jr-light-green: #1dd1a1;
@@ -53,8 +53,6 @@
5353
-jr-menu-item-foreground: -fx-dark-text-color;
5454
-jr-menu-forground-active: -fx-dark-text-color;
5555

56-
-jr-drag-target: -jr-accent;
57-
5856
-jr-head-fg: -fx-text-inner-color;
5957

6058
/* All icons/text on toolbars */
@@ -96,6 +94,10 @@
9694

9795
-jr-search-text: -fx-text-base-color;
9896

97+
/* For drag and drop actions */
98+
-jr-drag-target: -jr-purple;
99+
-jr-drag-target-hover: derive(-jr-purple, 80%);
100+
99101
/*
100102
Here are redefinitions of the default properties of modena. They should in principle all be derived from the
101103
above colors. Goal should be to make as few as possible direct color-changes to elements and only do this for
@@ -491,6 +493,17 @@
491493
-fx-border-radius: 0;
492494
}
493495

496+
.tab-pane > .tab-header-area > .headers-region > .tab.drop {
497+
-fx-border-color: -jr-drag-target;
498+
-fx-background-color: -jr-drag-target-hover;
499+
-fx-border-width: 3 1 1 1;
500+
}
501+
502+
.tab-pane > .tab-header-area > .headers-region > .tab.drop .tab-label {
503+
-fx-fill: -jr-drag-target;
504+
-fx-text-fill: -jr-drag-target;
505+
}
506+
494507
.tab-pane > .tab-header-area > .tab-header-background {
495508
-fx-background-color: -jr-background-alt;
496509
}

src/main/java/org/jabref/gui/DragAndDropDataFormats.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import javafx.scene.input.DataFormat;
66

77
import org.jabref.logic.citationstyle.PreviewLayout;
8-
import org.jabref.model.entry.BibEntry;
98

109
/**
1110
* Contains all the different {@link DataFormat}s that may occur in JabRef.
@@ -15,7 +14,6 @@ public class DragAndDropDataFormats {
1514
public static final DataFormat GROUP = new DataFormat("dnd/org.jabref.model.groups.GroupTreeNode");
1615
public static final DataFormat LINKED_FILE = new DataFormat("dnd/org.jabref.model.entry.LinkedFile");
1716
public static final DataFormat ENTRIES = new DataFormat("dnd/org.jabref.model.entry.BibEntries");
18-
@SuppressWarnings("unchecked") public static final Class<List<BibEntry>> BIBENTRY_LIST_CLASS = (Class<List<BibEntry>>) (Class<?>) List.class;
1917
public static final DataFormat PREVIEWLAYOUTS = new DataFormat("dnd/org.jabref.logic.citationstyle.PreviewLayouts");
2018
@SuppressWarnings("unchecked") public static final Class<List<PreviewLayout>> PREVIEWLAYOUT_LIST_CLASS = (Class<List<PreviewLayout>>) (Class<?>) List.class;
2119
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package org.jabref.gui;
2+
3+
import java.io.File;
4+
import java.nio.file.Path;
5+
import java.util.Collections;
6+
import java.util.List;
7+
import java.util.stream.Collectors;
8+
9+
import javafx.scene.input.Dragboard;
10+
11+
import org.jabref.logic.util.io.FileUtil;
12+
13+
public class DragAndDropHelper {
14+
15+
public static boolean hasBibFiles(Dragboard dragboard) {
16+
return !getBibFiles(dragboard).isEmpty();
17+
}
18+
19+
public static List<Path> getBibFiles(Dragboard dragboard) {
20+
if (!dragboard.hasFiles()) {
21+
return Collections.emptyList();
22+
} else {
23+
return dragboard.getFiles().stream().map(File::toPath).filter(FileUtil::isBibFile).collect(Collectors.toList());
24+
}
25+
}
26+
}

src/main/java/org/jabref/gui/JabRefFrame.java

Lines changed: 53 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import java.util.Objects;
1313
import java.util.Optional;
1414
import java.util.TimerTask;
15-
import java.util.stream.Collectors;
1615

1716
import javafx.application.Platform;
1817
import javafx.beans.value.ChangeListener;
@@ -35,7 +34,7 @@
3534
import javafx.scene.control.TextInputControl;
3635
import javafx.scene.control.ToolBar;
3736
import javafx.scene.control.Tooltip;
38-
import javafx.scene.input.DataFormat;
37+
import javafx.scene.control.skin.TabPaneSkin;
3938
import javafx.scene.input.KeyEvent;
4039
import javafx.scene.input.TransferMode;
4140
import javafx.scene.layout.BorderPane;
@@ -175,28 +174,7 @@ public void init() {
175174

176175
initKeyBindings();
177176

178-
tabbedPane.setOnDragOver(event -> {
179-
if (event.getDragboard().hasFiles()) {
180-
event.acceptTransferModes(TransferMode.COPY, TransferMode.MOVE, TransferMode.LINK);
181-
}
182-
});
183-
184-
tabbedPane.setOnDragDropped(event -> {
185-
boolean success = false;
186-
187-
if (event.getDragboard().hasContent(DataFormat.FILES)) {
188-
List<Path> files = event.getDragboard().getFiles().stream().map(File::toPath).filter(FileUtil::isBibFile).collect(Collectors.toList());
189-
success = true;
190-
191-
for (Path file : files) {
192-
ParserResult pr = OpenDatabase.loadDatabase(file.toString(), Globals.prefs.getImportFormatPreferences(), Globals.getFileUpdateMonitor());
193-
addParserResult(pr, true);
194-
}
195-
}
196-
197-
event.setDropCompleted(success);
198-
event.consume();
199-
});
177+
initDragAndDrop();
200178

201179
//setBounds(GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds());
202180
//WindowLocation pw = new WindowLocation(this, JabRefPreferences.POS_X, JabRefPreferences.POS_Y, JabRefPreferences.SIZE_X,
@@ -246,6 +224,57 @@ public void init() {
246224
initShowTrackingNotification();
247225
}
248226

227+
public void initDragAndDrop() {
228+
Tab dndIndicator = new Tab(Localization.lang("Open files..."), null);
229+
dndIndicator.getStyleClass().add("drop");
230+
231+
EasyBind.subscribe(tabbedPane.skinProperty(), skin -> {
232+
if (!(skin instanceof TabPaneSkin)) {
233+
return;
234+
}
235+
236+
// We need to get the tab header, the following is a ugly workaround
237+
Node tabHeaderArea = ((TabPaneSkin) this.tabbedPane.getSkin())
238+
.getChildren()
239+
.stream()
240+
.filter(node -> node.getStyleClass().contains("tab-header-area"))
241+
.findFirst()
242+
.orElseThrow();
243+
244+
tabHeaderArea.setOnDragOver(event -> {
245+
if (DragAndDropHelper.hasBibFiles(event.getDragboard())) {
246+
event.acceptTransferModes(TransferMode.ANY);
247+
if (!tabbedPane.getTabs().contains(dndIndicator)) {
248+
tabbedPane.getTabs().add(dndIndicator);
249+
}
250+
event.consume();
251+
} else {
252+
tabbedPane.getTabs().remove(dndIndicator);
253+
}
254+
});
255+
256+
tabHeaderArea.setOnDragExited(event -> tabbedPane.getTabs().remove(dndIndicator));
257+
258+
tabHeaderArea.setOnDragDropped(event -> {
259+
tabbedPane.getTabs().remove(dndIndicator);
260+
261+
boolean success = false;
262+
263+
List<Path> bibFiles = DragAndDropHelper.getBibFiles(event.getDragboard());
264+
if (!bibFiles.isEmpty()) {
265+
for (Path file : bibFiles) {
266+
ParserResult pr = OpenDatabase.loadDatabase(file.toString(), Globals.prefs.getImportFormatPreferences(), Globals.getFileUpdateMonitor());
267+
addParserResult(pr, true);
268+
}
269+
success = true;
270+
}
271+
272+
event.setDropCompleted(success);
273+
event.consume();
274+
});
275+
});
276+
}
277+
249278
private void initKeyBindings() {
250279
addEventFilter(KeyEvent.KEY_PRESSED, event -> {
251280
Optional<KeyBinding> keyBinding = Globals.getKeyPrefs().mapToKeyBinding(event);

src/main/java/org/jabref/gui/externalfiles/ImportHandler.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ public void importAsNewEntries(List<Path> files) {
8787
entriesToAdd = Collections.singletonList(createEmptyEntryWithLink(file));
8888
}
8989
}
90+
} else if (FileUtil.isBibFile(file)) {
91+
entriesToAdd = contentImporter.importFromBibFile(file, fileUpdateMonitor);
9092
} else {
9193
entriesToAdd = Collections.singletonList(createEmptyEntryWithLink(file));
9294
}
@@ -105,11 +107,6 @@ private BibEntry createEmptyEntryWithLink(Path file) {
105107
return entry;
106108
}
107109

108-
public void importEntriesFromBibFiles(Path bibFile) {
109-
List<BibEntry> entriesToImport = contentImporter.importFromBibFile(bibFile, fileUpdateMonitor);
110-
importEntries(entriesToImport);
111-
}
112-
113110
public void importEntries(List<BibEntry> entries) {
114111
//TODO: Add undo/redo
115112
//ce.addEdit(new UndoableInsertEntry(panel.getDatabase(), entry));

src/main/java/org/jabref/gui/groups/GroupNodeViewModel.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.jabref.gui.util.BackgroundTask;
2525
import org.jabref.gui.util.BindingsHelper;
2626
import org.jabref.gui.util.CustomLocalDragboard;
27+
import org.jabref.gui.util.DroppingMouseLocation;
2728
import org.jabref.gui.util.TaskExecutor;
2829
import org.jabref.logic.groups.DefaultGroupsFactory;
2930
import org.jabref.logic.layout.format.LatexToUnicodeFormatter;
@@ -262,8 +263,7 @@ public Optional<GroupNodeViewModel> getChildByPath(String pathToSource) {
262263
public boolean acceptableDrop(Dragboard dragboard) {
263264
// TODO: we should also check isNodeDescendant
264265
boolean canDropOtherGroup = dragboard.hasContent(DragAndDropDataFormats.GROUP);
265-
boolean canDropEntries = localDragBoard.hasType(DragAndDropDataFormats.BIBENTRY_LIST_CLASS)
266-
&& (groupNode.getGroup() instanceof GroupEntryChanger);
266+
boolean canDropEntries = localDragBoard.hasBibEntries() && (groupNode.getGroup() instanceof GroupEntryChanger);
267267
return canDropOtherGroup || canDropEntries;
268268
}
269269

src/main/java/org/jabref/gui/groups/GroupTree.css

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,9 @@
4949

5050
.tree-table-row-cell:dragOver-center {
5151
-fx-border-color: -jr-drag-target;
52-
-fx-border-width: 2 2 2 2;
53-
-fx-padding: -2 -2 -2 -2;
52+
-fx-border-width: 1 1 1 1;
53+
-fx-padding: -1 -1 -1 -1;
54+
-fx-background-color: -jr-drag-target-hover;
5455
}
5556

5657
.tree-table-row-cell:dragOver-top {

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

Lines changed: 9 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import javafx.scene.control.TreeTableRow;
2828
import javafx.scene.control.TreeTableView;
2929
import javafx.scene.input.ClipboardContent;
30-
import javafx.scene.input.DragEvent;
3130
import javafx.scene.input.Dragboard;
3231
import javafx.scene.input.MouseButton;
3332
import javafx.scene.input.MouseEvent;
@@ -40,6 +39,7 @@
4039
import org.jabref.gui.GUIGlobals;
4140
import org.jabref.gui.StateManager;
4241
import org.jabref.gui.util.BindingsHelper;
42+
import org.jabref.gui.util.ControlHelper;
4343
import org.jabref.gui.util.CustomLocalDragboard;
4444
import org.jabref.gui.util.RecursiveTreeItem;
4545
import org.jabref.gui.util.TaskExecutor;
@@ -74,12 +74,6 @@ public class GroupTreeView {
7474

7575
private DragExpansionHandler dragExpansionHandler;
7676

77-
private static void removePseudoClasses(TreeTableRow<GroupNodeViewModel> row, PseudoClass... pseudoClasses) {
78-
for (PseudoClass pseudoClass : pseudoClasses) {
79-
row.pseudoClassStateChanged(pseudoClass, false);
80-
}
81-
}
82-
8377
@FXML
8478
public void initialize() {
8579
this.localDragboard = GUIGlobals.localDragboard;
@@ -169,10 +163,6 @@ public void initialize() {
169163
PseudoClass rootPseudoClass = PseudoClass.getPseudoClass("root");
170164
PseudoClass subElementPseudoClass = PseudoClass.getPseudoClass("sub");
171165

172-
// Pseudo-classes for drag and drop
173-
PseudoClass dragOverBottom = PseudoClass.getPseudoClass("dragOver-bottom");
174-
PseudoClass dragOverCenter = PseudoClass.getPseudoClass("dragOver-center");
175-
PseudoClass dragOverTop = PseudoClass.getPseudoClass("dragOver-top");
176166
groupTree.setRowFactory(treeTable -> {
177167
TreeTableRow<GroupNodeViewModel> row = new TreeTableRow<>();
178168
row.treeItemProperty().addListener((ov, oldTreeItem, newTreeItem) -> {
@@ -226,23 +216,16 @@ public void initialize() {
226216
//expand node and all children on drag over
227217
dragExpansionHandler.expandGroup(row.getTreeItem());
228218

229-
removePseudoClasses(row, dragOverBottom, dragOverCenter, dragOverTop);
230-
switch (getDroppingMouseLocation(row, event)) {
231-
case BOTTOM:
232-
row.pseudoClassStateChanged(dragOverBottom, true);
233-
break;
234-
case CENTER:
235-
row.pseudoClassStateChanged(dragOverCenter, true);
236-
break;
237-
case TOP:
238-
row.pseudoClassStateChanged(dragOverTop, true);
239-
break;
219+
if (localDragboard.hasBibEntries()) {
220+
ControlHelper.setDroppingPseudoClasses(row);
221+
} else {
222+
ControlHelper.setDroppingPseudoClasses(row, event);
240223
}
241224
}
242225
event.consume();
243226
});
244227
row.setOnDragExited(event -> {
245-
removePseudoClasses(row, dragOverBottom, dragOverCenter, dragOverTop);
228+
ControlHelper.removeDroppingPseudoClasses(row);
246229
});
247230

248231
row.setOnDragDropped(event -> {
@@ -255,13 +238,13 @@ public void initialize() {
255238
Optional<GroupNodeViewModel> source = viewModel.rootGroupProperty().get()
256239
.getChildByPath(pathToSource);
257240
if (source.isPresent()) {
258-
source.get().draggedOn(row.getItem(), getDroppingMouseLocation(row, event));
241+
source.get().draggedOn(row.getItem(), ControlHelper.getDroppingMouseLocation(row, event));
259242
success = true;
260243
}
261244
}
262245
}
263246

264-
if (localDragboard.hasType(DragAndDropDataFormats.BIBENTRY_LIST_CLASS)) {
247+
if (localDragboard.hasBibEntries()) {
265248
List<BibEntry> entries = localDragboard.getBibEntries();
266249
row.getItem().addEntriesToGroup(entries);
267250
success = true;
@@ -281,7 +264,7 @@ private void updateSelection(List<TreeItem<GroupNodeViewModel>> newSelectedGroup
281264
if ((newSelectedGroups == null) || newSelectedGroups.isEmpty()) {
282265
viewModel.selectedGroupsProperty().clear();
283266
} else {
284-
List<GroupNodeViewModel> list = newSelectedGroups.stream().filter(model -> model != null && !(model.getValue().getGroupNode().getGroup() instanceof AllEntriesGroup)).map(TreeItem<GroupNodeViewModel>::getValue).collect(Collectors.toList());
267+
List<GroupNodeViewModel> list = newSelectedGroups.stream().filter(model -> model != null && !(model.getValue().getGroupNode().getGroup() instanceof AllEntriesGroup)).map(TreeItem::getValue).collect(Collectors.toList());
285268
viewModel.selectedGroupsProperty().setAll(list);
286269
}
287270
}
@@ -378,19 +361,6 @@ private void setupClearButtonField(CustomTextField customTextField) {
378361
}
379362
}
380363

381-
/**
382-
* Determines where the mouse is in the given row.
383-
*/
384-
private DroppingMouseLocation getDroppingMouseLocation(TreeTableRow<GroupNodeViewModel> row, DragEvent event) {
385-
if ((row.getHeight() * 0.25) > event.getY()) {
386-
return DroppingMouseLocation.TOP;
387-
} else if ((row.getHeight() * 0.75) < event.getY()) {
388-
return DroppingMouseLocation.BOTTOM;
389-
} else {
390-
return DroppingMouseLocation.CENTER;
391-
}
392-
}
393-
394364
private class DragExpansionHandler {
395365
private static final long DRAG_TIME_BEFORE_EXPANDING_MS = 1000;
396366
private TreeItem<GroupNodeViewModel> draggedItem;

src/main/java/org/jabref/gui/maintable/MainTable.css

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,25 @@
1717
-fx-fill: -jr-gray-2;
1818
}
1919

20+
.table-row-cell:dragOver-bottom {
21+
-fx-border-color: -jr-drag-target;
22+
-fx-border-width: 0 0 2 0;
23+
-fx-padding: 0 0 -2 0;
24+
}
25+
26+
.table-row-cell:dragOver-center {
27+
-fx-border-color: -jr-drag-target;
28+
-fx-border-width: 1 1 1 1;
29+
-fx-padding: -1 -1 -1 -1;
30+
-fx-background-color: -jr-drag-target-hover;
31+
}
32+
33+
.table-row-cell:dragOver-top {
34+
-fx-border-color: -jr-drag-target;
35+
-fx-border-width: 2 0 0 0;
36+
-fx-padding: -2 0 0 0;
37+
}
38+
2039
.rating > .container {
2140
-fx-spacing: 2;
2241
}

0 commit comments

Comments
 (0)