Skip to content

Commit

Permalink
Rework external changes dialog in JavaFX (#4693)
Browse files Browse the repository at this point in the history
* Rework external changes dialog in JavaFX

* fix exception by running in FX thread

* Fix appearance

* Improve display
  • Loading branch information
tobiasdiez authored Mar 12, 2019
1 parent 74de6b8 commit 930fa4e
Show file tree
Hide file tree
Showing 24 changed files with 431 additions and 895 deletions.
26 changes: 7 additions & 19 deletions src/main/java/org/jabref/gui/BasePanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
import org.jabref.gui.autocompleter.PersonNameSuggestionProvider;
import org.jabref.gui.autocompleter.SuggestionProviders;
import org.jabref.gui.collab.DatabaseChangeMonitor;
import org.jabref.gui.collab.FileUpdatePanel;
import org.jabref.gui.collab.DatabaseChangePane;
import org.jabref.gui.desktop.JabRefDesktop;
import org.jabref.gui.edit.ReplaceStringAction;
import org.jabref.gui.entryeditor.EntryEditor;
Expand Down Expand Up @@ -116,6 +116,7 @@ public class BasePanel extends StackPane {

private final BibDatabaseContext bibDatabaseContext;
private final MainTableDataModel tableModel;
private final DatabaseChangePane changePane;

private final CitationStyleCache citationStyleCache;
private final FileAnnotationCache annotationCache;
Expand Down Expand Up @@ -189,14 +190,17 @@ public BasePanel(JabRefFrame frame, BasePanelPreferences preferences, BibDatabas
Optional<File> file = bibDatabaseContext.getDatabaseFile();
if (file.isPresent()) {
// Register so we get notifications about outside changes to the file.
changeMonitor = Optional.of(new DatabaseChangeMonitor(bibDatabaseContext, Globals.getFileUpdateMonitor(), this));
changeMonitor = Optional.of(new DatabaseChangeMonitor(bibDatabaseContext, Globals.getFileUpdateMonitor(), Globals.TASK_EXECUTOR));
changePane = new DatabaseChangePane(mainTable.getPane(), bibDatabaseContext, changeMonitor.get());
getChildren().add(changePane);
} else {
if (bibDatabaseContext.getDatabase().hasEntries()) {
// if the database is not empty and no file is assigned,
// the database came from an import and has to be treated somehow
// -> mark as changed
this.baseChanged = true;
}
changePane = null;
}

this.getDatabase().registerListener(new UpdateTimestampListener(Globals.prefs));
Expand Down Expand Up @@ -1098,14 +1102,6 @@ private void saveDividerLocation(Number position) {
*/
public void cleanUp() {
changeMonitor.ifPresent(DatabaseChangeMonitor::unregister);

// Check if there is a FileUpdatePanel for this BasePanel being shown. If so remove it:
if (sidePaneManager.isComponentVisible(SidePaneType.FILE_UPDATE_NOTIFICATION)) {
FileUpdatePanel fup = (FileUpdatePanel) sidePaneManager.getComponent(SidePaneType.FILE_UPDATE_NOTIFICATION);
if (fup.getPanel() == this) {
sidePaneManager.hide(SidePaneType.FILE_UPDATE_NOTIFICATION);
}
}
}

/**
Expand All @@ -1122,10 +1118,6 @@ public BibDatabaseContext getBibDatabaseContext() {
return this.bibDatabaseContext;
}

public boolean isUpdatedExternally() {
return changeMonitor.map(DatabaseChangeMonitor::hasBeenModifiedExternally).orElse(false);
}

public void markExternalChangesAsResolved() {
changeMonitor.ifPresent(DatabaseChangeMonitor::markExternalChangesAsResolved);
}
Expand Down Expand Up @@ -1210,17 +1202,13 @@ public FileAnnotationCache getAnnotationCache() {

public void resetChangeMonitor() {
changeMonitor.ifPresent(DatabaseChangeMonitor::unregister);
changeMonitor = Optional.of(new DatabaseChangeMonitor(bibDatabaseContext, Globals.getFileUpdateMonitor(), this));
changeMonitor = Optional.of(new DatabaseChangeMonitor(bibDatabaseContext, Globals.getFileUpdateMonitor(), Globals.TASK_EXECUTOR));
}

public void updateTimeStamp() {
changeMonitor.ifPresent(DatabaseChangeMonitor::markAsSaved);
}

public Path getTempFile() {
return changeMonitor.map(DatabaseChangeMonitor::getTempFile).orElse(null);
}

public void copy() {
mainTable.copy();
}
Expand Down
2 changes: 0 additions & 2 deletions src/main/java/org/jabref/gui/SidePaneManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import java.util.stream.Stream;

import org.jabref.Globals;
import org.jabref.gui.collab.FileUpdatePanel;
import org.jabref.gui.groups.GroupSidePane;
import org.jabref.gui.importer.fetcher.WebSearchPane;
import org.jabref.gui.openoffice.OpenOfficeSidePanel;
Expand All @@ -31,7 +30,6 @@ public SidePaneManager(JabRefPreferences preferences, JabRefFrame frame) {

OpenOfficePreferences openOfficePreferences = preferences.getOpenOfficePreferences();
Stream.of(
new FileUpdatePanel(this),
new GroupSidePane(this, preferences, frame.getDialogService()),
new WebSearchPane(this, preferences, frame),
new OpenOfficeSidePanel(this, preferences, frame))
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/org/jabref/gui/SidePaneType.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@
* Definition of all possible components in the side pane.
*/
public enum SidePaneType {
OPEN_OFFICE, WEB_SEARCH, FILE_UPDATE_NOTIFICATION, GROUPS
OPEN_OFFICE,
WEB_SEARCH,
GROUPS
}
194 changes: 65 additions & 129 deletions src/main/java/org/jabref/gui/collab/ChangeDisplayDialog.java
Original file line number Diff line number Diff line change
@@ -1,145 +1,81 @@
package org.jabref.gui.collab;

import java.awt.BorderLayout;
import java.awt.Insets;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;

import javafx.collections.FXCollections;
import javafx.scene.control.ButtonBar;
import javafx.scene.control.ButtonType;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.SplitPane;
import javafx.scene.layout.BorderPane;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;

import org.jabref.gui.BasePanel;
import org.jabref.gui.JabRefDialog;
import org.jabref.gui.undo.NamedCompound;
import org.jabref.gui.util.BaseDialog;
import org.jabref.logic.l10n.Localization;
import org.jabref.model.database.BibDatabase;

class ChangeDisplayDialog extends JabRefDialog implements TreeSelectionListener {

private final JTree tree;
private final JPanel infoPanel = new JPanel();
private final JCheckBox cb = new JCheckBox(Localization.lang("Accept change"));
private final JLabel rootInfo = new JLabel(Localization.lang("Select the tree nodes to view and accept or reject changes") + '.');
private ChangeViewModel selected;
private JComponent infoShown;
private boolean okPressed;

public ChangeDisplayDialog(final BasePanel panel,
BibDatabase secondary, final DefaultMutableTreeNode root) {
super(Localization.lang("External changes"), true, ChangeDisplayDialog.class);
BibDatabase localSecondary;

// Just to be sure, put in an empty secondary base if none is given:
if (secondary == null) {
localSecondary = new BibDatabase();
} else {
localSecondary = secondary;
}
tree = new JTree(root);
tree.addTreeSelectionListener(this);

JSplitPane pane = new JSplitPane();
pane.setLeftComponent(new JScrollPane(tree));
JPanel infoBorder = new JPanel();
pane.setRightComponent(infoBorder);

cb.setMargin(new Insets(2, 2, 2, 2));
cb.setEnabled(false);
infoPanel.setLayout(new BorderLayout());
infoBorder.setLayout(new BorderLayout());
infoBorder.setBorder(BorderFactory.createEtchedBorder());
infoBorder.add(infoPanel, BorderLayout.CENTER);
setInfo(rootInfo);
infoPanel.add(cb, BorderLayout.SOUTH);

JButton ok = new JButton(Localization.lang("OK"));
JPanel buttonPanel = new JPanel();
buttonPanel.add(ok);
JButton cancel = new JButton(Localization.lang("Cancel"));
buttonPanel.add(cancel);

getContentPane().add(pane, BorderLayout.CENTER);
getContentPane().add(buttonPanel, BorderLayout.SOUTH);
import org.jabref.model.database.BibDatabaseContext;

import org.fxmisc.easybind.EasyBind;

class ChangeDisplayDialog extends BaseDialog<Boolean> {

private final ListView<DatabaseChangeViewModel> tree;
private final BorderPane infoPanel = new BorderPane();
private final CheckBox cb = new CheckBox(Localization.lang("Accept change"));

public ChangeDisplayDialog(BibDatabaseContext database, List<DatabaseChangeViewModel> changes) {
this.setTitle(Localization.lang("External changes"));
this.getDialogPane().setPrefSize(800, 600);

tree = new ListView<>(FXCollections.observableArrayList(changes));
tree.setPrefWidth(190);
EasyBind.subscribe(tree.getSelectionModel().selectedItemProperty(), this::selectedChangeChanged);

SplitPane pane = new SplitPane();
pane.setDividerPositions(0.25);
pane.getItems().addAll(new ScrollPane(tree), infoPanel);
getDialogPane().setContent(pane);

infoPanel.setBottom(cb);
Label rootInfo = new Label(Localization.lang("Select the tree nodes to view and accept or reject changes") + '.');
infoPanel.setCenter(rootInfo);

getDialogPane().getButtonTypes().setAll(
new ButtonType(Localization.lang("Accept changes"), ButtonBar.ButtonData.APPLY),
ButtonType.CANCEL
);

setResultConverter(button -> {
if (button == ButtonType.CANCEL) {
return false;
} else {
// Perform all accepted changes
NamedCompound ce = new NamedCompound(Localization.lang("Merged external changes"));
for (DatabaseChangeViewModel change : changes) {
if (change.isAccepted()) {
change.makeChange(database, ce);
}
}
ce.end();
//TODO: panel.getUndoManager().addEdit(ce);

cb.addChangeListener(e -> {
if (selected != null) {
selected.setAccepted(cb.isSelected());
return true;
}
});

cancel.addActionListener(e -> dispose());

ok.addActionListener(e -> {

// Perform all accepted changes:
// Store all edits in an Undoable object:
NamedCompound ce = new NamedCompound(Localization.lang("Merged external changes"));
Enumeration<ChangeViewModel> enumer = root.children();
boolean anyDisabled = false;
for (ChangeViewModel c : Collections.list(enumer)) {
boolean allAccepted = false;
if (c.isAcceptable() && c.isAccepted()) {
allAccepted = c.makeChange(panel, localSecondary, ce);
}

if (!allAccepted) {
anyDisabled = true;
}
}
ce.end();
panel.getUndoManager().addEdit(ce);
if (anyDisabled) {
panel.markBaseChanged();
EasyBind.subscribe(cb.selectedProperty(), selected -> {
if (selected != null && tree.getSelectionModel().getSelectedItem() != null) {
tree.getSelectionModel().getSelectedItem().setAccepted(selected);
}
panel.markExternalChangesAsResolved();
dispose();
okPressed = true;
});

pack();
}

public boolean isOkPressed() {
return okPressed;
}

private void setInfo(JComponent comp) {
if (infoShown != null) {
infoPanel.remove(infoShown);
}
infoShown = comp;
infoPanel.add(infoShown, BorderLayout.CENTER);
infoPanel.revalidate();
infoPanel.repaint();
}

/**
* valueChanged
*
* @param e TreeSelectionEvent
*/
@Override
public void valueChanged(TreeSelectionEvent e) {
Object o = tree.getLastSelectedPathComponent();
if (o instanceof ChangeViewModel) {
selected = (ChangeViewModel) o;
setInfo(selected.description());
cb.setSelected(selected.isAccepted());
cb.setEnabled(selected.isAcceptable());
} else {
setInfo(rootInfo);
selected = null;
cb.setEnabled(false);
private void selectedChangeChanged(DatabaseChangeViewModel currentChange) {
if (currentChange != null) {
infoPanel.setCenter(currentChange.description());
cb.setSelected(currentChange.isAccepted());
}
}
}
Loading

0 comments on commit 930fa4e

Please sign in to comment.