Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve drag and drop #5306

Merged
merged 3 commits into from
Sep 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .idea/runConfigurations/JabRef_Main.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 16 additions & 3 deletions src/main/java/org/jabref/gui/Base.css
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
/* Highlights */
-jr-blue: #0abde3;
-jr-light-blue: #48dbfb;
-jr-purple: #f368e0;
-jr-purple: #7559C2;
-jr-light-purple: #ff9ff3;
-jr-green: #10ac84;
-jr-light-green: #1dd1a1;
Expand All @@ -53,8 +53,6 @@
-jr-menu-item-foreground: -fx-dark-text-color;
-jr-menu-forground-active: -fx-dark-text-color;

-jr-drag-target: -jr-accent;

-jr-head-fg: -fx-text-inner-color;

/* All icons/text on toolbars */
Expand Down Expand Up @@ -96,6 +94,10 @@

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

/* For drag and drop actions */
-jr-drag-target: -jr-purple;
-jr-drag-target-hover: derive(-jr-purple, 80%);

/*
Here are redefinitions of the default properties of modena. They should in principle all be derived from the
above colors. Goal should be to make as few as possible direct color-changes to elements and only do this for
Expand Down Expand Up @@ -491,6 +493,17 @@
-fx-border-radius: 0;
}

.tab-pane > .tab-header-area > .headers-region > .tab.drop {
-fx-border-color: -jr-drag-target;
-fx-background-color: -jr-drag-target-hover;
-fx-border-width: 3 1 1 1;
}

.tab-pane > .tab-header-area > .headers-region > .tab.drop .tab-label {
-fx-fill: -jr-drag-target;
-fx-text-fill: -jr-drag-target;
}

.tab-pane > .tab-header-area > .tab-header-background {
-fx-background-color: -jr-background-alt;
}
Expand Down
2 changes: 0 additions & 2 deletions src/main/java/org/jabref/gui/DragAndDropDataFormats.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import javafx.scene.input.DataFormat;

import org.jabref.logic.citationstyle.PreviewLayout;
import org.jabref.model.entry.BibEntry;

/**
* Contains all the different {@link DataFormat}s that may occur in JabRef.
Expand All @@ -15,7 +14,6 @@ public class DragAndDropDataFormats {
public static final DataFormat GROUP = new DataFormat("dnd/org.jabref.model.groups.GroupTreeNode");
public static final DataFormat LINKED_FILE = new DataFormat("dnd/org.jabref.model.entry.LinkedFile");
public static final DataFormat ENTRIES = new DataFormat("dnd/org.jabref.model.entry.BibEntries");
@SuppressWarnings("unchecked") public static final Class<List<BibEntry>> BIBENTRY_LIST_CLASS = (Class<List<BibEntry>>) (Class<?>) List.class;
public static final DataFormat PREVIEWLAYOUTS = new DataFormat("dnd/org.jabref.logic.citationstyle.PreviewLayouts");
@SuppressWarnings("unchecked") public static final Class<List<PreviewLayout>> PREVIEWLAYOUT_LIST_CLASS = (Class<List<PreviewLayout>>) (Class<?>) List.class;
}
26 changes: 26 additions & 0 deletions src/main/java/org/jabref/gui/DragAndDropHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.jabref.gui;

import java.io.File;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

import javafx.scene.input.Dragboard;

import org.jabref.logic.util.io.FileUtil;

public class DragAndDropHelper {

public static boolean hasBibFiles(Dragboard dragboard) {
return !getBibFiles(dragboard).isEmpty();
}

public static List<Path> getBibFiles(Dragboard dragboard) {
if (!dragboard.hasFiles()) {
return Collections.emptyList();
} else {
return dragboard.getFiles().stream().map(File::toPath).filter(FileUtil::isBibFile).collect(Collectors.toList());
}
}
}
77 changes: 53 additions & 24 deletions src/main/java/org/jabref/gui/JabRefFrame.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import java.util.Objects;
import java.util.Optional;
import java.util.TimerTask;
import java.util.stream.Collectors;

import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
Expand All @@ -35,7 +34,7 @@
import javafx.scene.control.TextInputControl;
import javafx.scene.control.ToolBar;
import javafx.scene.control.Tooltip;
import javafx.scene.input.DataFormat;
import javafx.scene.control.skin.TabPaneSkin;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.BorderPane;
Expand Down Expand Up @@ -175,28 +174,7 @@ public void init() {

initKeyBindings();

tabbedPane.setOnDragOver(event -> {
if (event.getDragboard().hasFiles()) {
event.acceptTransferModes(TransferMode.COPY, TransferMode.MOVE, TransferMode.LINK);
}
});

tabbedPane.setOnDragDropped(event -> {
boolean success = false;

if (event.getDragboard().hasContent(DataFormat.FILES)) {
List<Path> files = event.getDragboard().getFiles().stream().map(File::toPath).filter(FileUtil::isBibFile).collect(Collectors.toList());
success = true;

for (Path file : files) {
ParserResult pr = OpenDatabase.loadDatabase(file.toString(), Globals.prefs.getImportFormatPreferences(), Globals.getFileUpdateMonitor());
addParserResult(pr, true);
}
}

event.setDropCompleted(success);
event.consume();
});
initDragAndDrop();

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

public void initDragAndDrop() {
Tab dndIndicator = new Tab(Localization.lang("Open files..."), null);
tobiasdiez marked this conversation as resolved.
Show resolved Hide resolved
dndIndicator.getStyleClass().add("drop");

EasyBind.subscribe(tabbedPane.skinProperty(), skin -> {
if (!(skin instanceof TabPaneSkin)) {
return;
}

// We need to get the tab header, the following is a ugly workaround
Node tabHeaderArea = ((TabPaneSkin) this.tabbedPane.getSkin())
.getChildren()
.stream()
.filter(node -> node.getStyleClass().contains("tab-header-area"))
.findFirst()
.orElseThrow();

tabHeaderArea.setOnDragOver(event -> {
if (DragAndDropHelper.hasBibFiles(event.getDragboard())) {
event.acceptTransferModes(TransferMode.ANY);
if (!tabbedPane.getTabs().contains(dndIndicator)) {
tabbedPane.getTabs().add(dndIndicator);
}
event.consume();
} else {
tabbedPane.getTabs().remove(dndIndicator);
}
});

tabHeaderArea.setOnDragExited(event -> tabbedPane.getTabs().remove(dndIndicator));

tabHeaderArea.setOnDragDropped(event -> {
tabbedPane.getTabs().remove(dndIndicator);

boolean success = false;

List<Path> bibFiles = DragAndDropHelper.getBibFiles(event.getDragboard());
if (!bibFiles.isEmpty()) {
for (Path file : bibFiles) {
ParserResult pr = OpenDatabase.loadDatabase(file.toString(), Globals.prefs.getImportFormatPreferences(), Globals.getFileUpdateMonitor());
addParserResult(pr, true);
}
success = true;
}

event.setDropCompleted(success);
event.consume();
});
});
}

private void initKeyBindings() {
addEventFilter(KeyEvent.KEY_PRESSED, event -> {
Optional<KeyBinding> keyBinding = Globals.getKeyPrefs().mapToKeyBinding(event);
Expand Down
7 changes: 2 additions & 5 deletions src/main/java/org/jabref/gui/externalfiles/ImportHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ public void importAsNewEntries(List<Path> files) {
entriesToAdd = Collections.singletonList(createEmptyEntryWithLink(file));
}
}
} else if (FileUtil.isBibFile(file)) {
entriesToAdd = contentImporter.importFromBibFile(file, fileUpdateMonitor);
} else {
entriesToAdd = Collections.singletonList(createEmptyEntryWithLink(file));
}
Expand All @@ -105,11 +107,6 @@ private BibEntry createEmptyEntryWithLink(Path file) {
return entry;
}

public void importEntriesFromBibFiles(Path bibFile) {
List<BibEntry> entriesToImport = contentImporter.importFromBibFile(bibFile, fileUpdateMonitor);
importEntries(entriesToImport);
}

public void importEntries(List<BibEntry> entries) {
//TODO: Add undo/redo
//ce.addEdit(new UndoableInsertEntry(panel.getDatabase(), entry));
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/org/jabref/gui/groups/GroupNodeViewModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.jabref.gui.util.BackgroundTask;
import org.jabref.gui.util.BindingsHelper;
import org.jabref.gui.util.CustomLocalDragboard;
import org.jabref.gui.util.DroppingMouseLocation;
import org.jabref.gui.util.TaskExecutor;
import org.jabref.logic.groups.DefaultGroupsFactory;
import org.jabref.logic.layout.format.LatexToUnicodeFormatter;
Expand Down Expand Up @@ -262,8 +263,7 @@ public Optional<GroupNodeViewModel> getChildByPath(String pathToSource) {
public boolean acceptableDrop(Dragboard dragboard) {
// TODO: we should also check isNodeDescendant
boolean canDropOtherGroup = dragboard.hasContent(DragAndDropDataFormats.GROUP);
boolean canDropEntries = localDragBoard.hasType(DragAndDropDataFormats.BIBENTRY_LIST_CLASS)
&& (groupNode.getGroup() instanceof GroupEntryChanger);
boolean canDropEntries = localDragBoard.hasBibEntries() && (groupNode.getGroup() instanceof GroupEntryChanger);
return canDropOtherGroup || canDropEntries;
}

Expand Down
5 changes: 3 additions & 2 deletions src/main/java/org/jabref/gui/groups/GroupTree.css
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,9 @@

.tree-table-row-cell:dragOver-center {
-fx-border-color: -jr-drag-target;
-fx-border-width: 2 2 2 2;
-fx-padding: -2 -2 -2 -2;
-fx-border-width: 1 1 1 1;
-fx-padding: -1 -1 -1 -1;
-fx-background-color: -jr-drag-target-hover;
}

.tree-table-row-cell:dragOver-top {
Expand Down
48 changes: 9 additions & 39 deletions src/main/java/org/jabref/gui/groups/GroupTreeView.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import javafx.scene.control.TreeTableRow;
import javafx.scene.control.TreeTableView;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
Expand All @@ -40,6 +39,7 @@
import org.jabref.gui.GUIGlobals;
import org.jabref.gui.StateManager;
import org.jabref.gui.util.BindingsHelper;
import org.jabref.gui.util.ControlHelper;
import org.jabref.gui.util.CustomLocalDragboard;
import org.jabref.gui.util.RecursiveTreeItem;
import org.jabref.gui.util.TaskExecutor;
Expand Down Expand Up @@ -74,12 +74,6 @@ public class GroupTreeView {

private DragExpansionHandler dragExpansionHandler;

private static void removePseudoClasses(TreeTableRow<GroupNodeViewModel> row, PseudoClass... pseudoClasses) {
for (PseudoClass pseudoClass : pseudoClasses) {
row.pseudoClassStateChanged(pseudoClass, false);
}
}

@FXML
public void initialize() {
this.localDragboard = GUIGlobals.localDragboard;
Expand Down Expand Up @@ -169,10 +163,6 @@ public void initialize() {
PseudoClass rootPseudoClass = PseudoClass.getPseudoClass("root");
PseudoClass subElementPseudoClass = PseudoClass.getPseudoClass("sub");

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

removePseudoClasses(row, dragOverBottom, dragOverCenter, dragOverTop);
switch (getDroppingMouseLocation(row, event)) {
case BOTTOM:
row.pseudoClassStateChanged(dragOverBottom, true);
break;
case CENTER:
row.pseudoClassStateChanged(dragOverCenter, true);
break;
case TOP:
row.pseudoClassStateChanged(dragOverTop, true);
break;
if (localDragboard.hasBibEntries()) {
ControlHelper.setDroppingPseudoClasses(row);
} else {
ControlHelper.setDroppingPseudoClasses(row, event);
}
}
event.consume();
});
row.setOnDragExited(event -> {
removePseudoClasses(row, dragOverBottom, dragOverCenter, dragOverTop);
ControlHelper.removeDroppingPseudoClasses(row);
});

row.setOnDragDropped(event -> {
Expand All @@ -255,13 +238,13 @@ public void initialize() {
Optional<GroupNodeViewModel> source = viewModel.rootGroupProperty().get()
.getChildByPath(pathToSource);
if (source.isPresent()) {
source.get().draggedOn(row.getItem(), getDroppingMouseLocation(row, event));
source.get().draggedOn(row.getItem(), ControlHelper.getDroppingMouseLocation(row, event));
success = true;
}
}
}

if (localDragboard.hasType(DragAndDropDataFormats.BIBENTRY_LIST_CLASS)) {
if (localDragboard.hasBibEntries()) {
List<BibEntry> entries = localDragboard.getBibEntries();
row.getItem().addEntriesToGroup(entries);
success = true;
Expand All @@ -281,7 +264,7 @@ private void updateSelection(List<TreeItem<GroupNodeViewModel>> newSelectedGroup
if ((newSelectedGroups == null) || newSelectedGroups.isEmpty()) {
viewModel.selectedGroupsProperty().clear();
} else {
List<GroupNodeViewModel> list = newSelectedGroups.stream().filter(model -> model != null && !(model.getValue().getGroupNode().getGroup() instanceof AllEntriesGroup)).map(TreeItem<GroupNodeViewModel>::getValue).collect(Collectors.toList());
List<GroupNodeViewModel> list = newSelectedGroups.stream().filter(model -> model != null && !(model.getValue().getGroupNode().getGroup() instanceof AllEntriesGroup)).map(TreeItem::getValue).collect(Collectors.toList());
viewModel.selectedGroupsProperty().setAll(list);
}
}
Expand Down Expand Up @@ -378,19 +361,6 @@ private void setupClearButtonField(CustomTextField customTextField) {
}
}

/**
* Determines where the mouse is in the given row.
*/
private DroppingMouseLocation getDroppingMouseLocation(TreeTableRow<GroupNodeViewModel> row, DragEvent event) {
if ((row.getHeight() * 0.25) > event.getY()) {
return DroppingMouseLocation.TOP;
} else if ((row.getHeight() * 0.75) < event.getY()) {
return DroppingMouseLocation.BOTTOM;
} else {
return DroppingMouseLocation.CENTER;
}
}

private class DragExpansionHandler {
private static final long DRAG_TIME_BEFORE_EXPANDING_MS = 1000;
private TreeItem<GroupNodeViewModel> draggedItem;
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/org/jabref/gui/maintable/MainTable.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,25 @@
-fx-fill: -jr-gray-2;
}

.table-row-cell:dragOver-bottom {
-fx-border-color: -jr-drag-target;
-fx-border-width: 0 0 2 0;
-fx-padding: 0 0 -2 0;
}

.table-row-cell:dragOver-center {
-fx-border-color: -jr-drag-target;
-fx-border-width: 1 1 1 1;
-fx-padding: -1 -1 -1 -1;
-fx-background-color: -jr-drag-target-hover;
}

.table-row-cell:dragOver-top {
-fx-border-color: -jr-drag-target;
-fx-border-width: 2 0 0 0;
-fx-padding: -2 0 0 0;
}

.rating > .container {
-fx-spacing: 2;
}
Expand Down
Loading