Skip to content

Commit

Permalink
Implemente drag and drop reordering in General files list
Browse files Browse the repository at this point in the history
Add drag and drop related methods to ViewModelFactory
Make LInkedFile serializeable
  • Loading branch information
Siedlerchr committed Sep 3, 2017
1 parent c619721 commit 1f1dca7
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 12 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `#
- Added 'Filter All' and 'Filter None' buttons with corresponding functionality to Quality Check tool.
- We increased the size of the keywords and file text areas in the entry editor
- When the entry that is currently shown in the entry editor is deleted externally, the editor is now closed automatically [#2946](https://github.com/JabRef/jabref/issues/2946)
- We added reordering of file and link entries in the `General`-Tab [3165, comment](https://github.com/JabRef/jabref/issues/3165#issuecomment-326269715)

### Fixed

Expand Down
1 change: 1 addition & 0 deletions src/main/java/org/jabref/gui/DragAndDropDataFormats.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,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("application/x-java-jvm-local-objectref");
}
82 changes: 72 additions & 10 deletions src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditor.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.Optional;

import javafx.beans.binding.Bindings;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Node;
Expand All @@ -14,14 +15,19 @@
import javafx.scene.control.ProgressBar;
import javafx.scene.control.SeparatorMenuItem;
import javafx.scene.control.Tooltip;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.HBox;
import javafx.scene.text.Text;

import org.jabref.Globals;
import org.jabref.gui.DialogService;
import org.jabref.gui.DragAndDropDataFormats;
import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider;
import org.jabref.gui.keyboard.KeyBinding;
import org.jabref.gui.util.ControlHelper;
Expand All @@ -31,6 +37,7 @@
import org.jabref.logic.l10n.Localization;
import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.LinkedFile;

import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon;
import de.jensd.fx.glyphs.materialdesignicons.utils.MaterialDesignIconFactory;
Expand All @@ -49,12 +56,66 @@ public LinkedFilesEditor(String fieldName, DialogService dialogService, BibDatab
.withTooltip(LinkedFileViewModel::getDescription)
.withGraphic(LinkedFilesEditor::createFileDisplay)
.withContextMenu(this::createContextMenuForFile)
.withOnMouseClickedEvent(this::handleItemMouseClick);
.withOnMouseClickedEvent(this::handleItemMouseClick)
.setOnDragDetected(this::handleOnDragDetected)
.setOnDragDropped(this::handleOnDragDropped)
.setOnDragOver(this::handleOnDragOver);

listView.setCellFactory(cellFactory);

Bindings.bindContent(listView.itemsProperty().get(), viewModel.filesProperty());
setUpKeyBindings();
}

private void handleOnDragOver(LinkedFileViewModel originalItem, DragEvent event) {
if ((event.getGestureSource() != originalItem) && event.getDragboard().hasContent(DragAndDropDataFormats.LINKED_FILE)) {
event.acceptTransferModes(TransferMode.MOVE);
}
}

private void handleOnDragDetected(LinkedFileViewModel linkedFile, MouseEvent event) {
LinkedFile selectedItem = listView.getSelectionModel().getSelectedItem().getFile();
if (selectedItem != null) {
ClipboardContent content = new ClipboardContent();
Dragboard dragboard = listView.startDragAndDrop(TransferMode.MOVE);
//We have to use the model class here, as the content of the dragboard must be serializable
content.put(DragAndDropDataFormats.LINKED_FILE, selectedItem);
dragboard.setContent(content);
}
event.consume();
}

private void handleOnDragDropped(LinkedFileViewModel originalItem, DragEvent event) {
Dragboard dragboard = event.getDragboard();
boolean success = false;

ObservableList<LinkedFileViewModel> items = listView.getItems();

if (dragboard.hasContent(DragAndDropDataFormats.LINKED_FILE)) {

LinkedFile linkedFile = (LinkedFile) dragboard.getContent(DragAndDropDataFormats.LINKED_FILE);
LinkedFileViewModel transferedItem = null;
int draggedIdx = 0;
for (int i = 0; i < items.size(); i++) {
if (items.get(i).getFile().equals(linkedFile)) {
draggedIdx = i;
transferedItem = items.get(i);
break;
}
}

int thisIdx = items.indexOf(originalItem);
items.set(draggedIdx, originalItem);
items.set(thisIdx, transferedItem);

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

private static Node createFileDisplay(LinkedFileViewModel linkedFile) {
Text icon = MaterialDesignIconFactory.get().createIcon(linkedFile.getTypeIcon());
Text text = new Text(linkedFile.getLink());
Expand All @@ -79,15 +140,15 @@ private void setUpKeyBindings() {
Optional<KeyBinding> keyBinding = Globals.getKeyPrefs().mapToKeyBinding(event);
if (keyBinding.isPresent()) {
switch (keyBinding.get()) {
case DELETE_ENTRY:
LinkedFileViewModel selectedItem = listView.getSelectionModel().getSelectedItem();
if (selectedItem != null) {
viewModel.deleteFile(selectedItem);
}
event.consume();
break;
default:
// Pass other keys to children
case DELETE_ENTRY:
LinkedFileViewModel selectedItem = listView.getSelectionModel().getSelectedItem();
if (selectedItem != null) {
viewModel.deleteFile(selectedItem);
}
event.consume();
break;
default:
// Pass other keys to children
}
}
});
Expand Down Expand Up @@ -160,6 +221,7 @@ private ContextMenu createContextMenuForFile(LinkedFileViewModel linkedFile) {
}

private void handleItemMouseClick(LinkedFileViewModel linkedFile, MouseEvent event) {

if (event.getButton().equals(MouseButton.PRIMARY) && (event.getClickCount() == 2)) {
// Double click -> edit
linkedFile.edit();
Expand Down
48 changes: 47 additions & 1 deletion src/main/java/org/jabref/gui/util/ViewModelListCellFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.Tooltip;
import javafx.scene.input.DragEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Paint;
import javafx.scene.text.Text;
Expand All @@ -30,6 +31,11 @@ public class ViewModelListCellFactory<T> implements Callback<ListView<T>, ListCe
private BiConsumer<T, ? super MouseEvent> toOnMouseClickedEvent;
private Callback<T, String> toStyleClass;
private Callback<T, ContextMenu> toContextMenu;
private BiConsumer<T, ? super MouseEvent> toOnDragDetected;
private BiConsumer<T, ? super DragEvent> toOnDragDropped;
private BiConsumer<T, ? super DragEvent> toOnDragEntered;
private BiConsumer<T, ? super DragEvent> toOnDragExited;
private BiConsumer<T, ? super DragEvent> toOnDragOver;

public ViewModelListCellFactory<T> withText(Callback<T, String> toText) {
this.toText = toText;
Expand Down Expand Up @@ -76,6 +82,31 @@ public ViewModelListCellFactory<T> withOnMouseClickedEvent(
return this;
}

public ViewModelListCellFactory<T> setOnDragDetected(BiConsumer<T, ? super MouseEvent> toOnDragDetected) {
this.toOnDragDetected = toOnDragDetected;
return this;
}

public ViewModelListCellFactory<T> setOnDragDropped(BiConsumer<T, ? super DragEvent> toOnDragDropped) {
this.toOnDragDropped = toOnDragDropped;
return this;
}

public ViewModelListCellFactory<T> setOnDragEntered(BiConsumer<T, ? super DragEvent> toOnDragEntered) {
this.toOnDragEntered = toOnDragEntered;
return this;
}

public ViewModelListCellFactory<T> setOnDragExited(BiConsumer<T, ? super DragEvent> toOnDragExited) {
this.toOnDragExited = toOnDragExited;
return this;
}

public ViewModelListCellFactory<T> setOnDragOver(BiConsumer<T, ? super DragEvent> toOnDragOver) {
this.toOnDragOver = toOnDragOver;
return this;
}

@Override
public ListCell<T> call(ListView<T> param) {

Expand All @@ -86,7 +117,7 @@ protected void updateItem(T item, boolean empty) {
super.updateItem(item, empty);

T viewModel = getItem();
if (empty || viewModel == null) {
if (empty || (viewModel == null)) {
setText(null);
setGraphic(null);
setOnMouseClicked(null);
Expand All @@ -113,6 +144,21 @@ protected void updateItem(T item, boolean empty) {
if (toContextMenu != null) {
setContextMenu(toContextMenu.call(viewModel));
}
if (toOnDragDetected != null) {
setOnDragDetected(event -> toOnDragDetected.accept(viewModel, event));
}
if (toOnDragDropped != null) {
setOnDragDropped(event -> toOnDragDropped.accept(viewModel, event));
}
if (toOnDragEntered != null) {
setOnDragEntered(event -> toOnDragEntered.accept(viewModel, event));
}
if (toOnDragExited != null) {
setOnDragExited(event -> toOnDragExited.accept(viewModel, event));
}
if (toOnDragOver != null) {
setOnDragOver(event -> toOnDragOver.accept(viewModel, event));
}
}
getListView().refresh();
}
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/org/jabref/model/entry/LinkedFile.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.jabref.model.entry;

import java.io.Serializable;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
Expand All @@ -14,7 +15,8 @@
/**
* Represents the link to an external file (e.g. associated PDF file).
*/
public class LinkedFile {
//Serialiable is required for drag and drop
public class LinkedFile implements Serializable {

private static final LinkedFile NULL_OBJECT = new LinkedFile("", "", "");
private String description;
Expand Down

0 comments on commit 1f1dca7

Please sign in to comment.