Skip to content
Snippets Groups Projects
Commit 6ee2cd97 authored by Tobias Ask's avatar Tobias Ask
Browse files

Synchronize external changes

Add a resource change listener that tracks changes made to the editor's document from outside of Eclipse itself, so that the editor is in sync with the underlying file at all times. Note that this works best when the "Refresh using native hooks or pulling" option is enabled; otherwise, a refresh of the workspace is required to detect the changes.
parent 93b336b9
No related branches found
No related tags found
No related merge requests found
Pipeline #45771 failed
......@@ -34,6 +34,10 @@ public class JavaProjectGlossary extends Glossary implements IElementChangedList
this.fxmlLocation = fxmlLocation;
}
public void setFxmlLocation(URL fxmlLocation) {
this.fxmlLocation = fxmlLocation;
}
@Override
public List<String> queryControllerClasses(URL fxmlLocation) {
if (candidateControllers == null) {
......
package no.tobask.sb4e.editors;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
public class EditorInputWatcher implements IResourceChangeListener {
private IFile input;
private IInputChangeListener listener;
public EditorInputWatcher(IFile input, IInputChangeListener listener) {
this.input = input;
this.listener = listener;
}
public void setInput(IFile input) {
this.input = input;
}
@Override
public void resourceChanged(IResourceChangeEvent event) {
IResourceDelta delta = event.getDelta();
if (delta == null) {
return;
}
delta = delta.findMember(input.getFullPath());
if (delta != null) {
int flags = delta.getFlags();
switch (delta.getKind()) {
case IResourceDelta.CHANGED:
if ((IResourceDelta.CONTENT & flags) != 0) {
listener.inputContentChanged();
}
break;
case IResourceDelta.REMOVED:
if ((IResourceDelta.MOVED_TO & flags) != 0) {
listener.inputMoved(delta.getMovedToPath());
} else {
listener.inputRemoved();
}
break;
default:
break;
}
}
}
}
......@@ -5,7 +5,6 @@ import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import org.eclipse.core.commands.operations.IOperationHistory;
import org.eclipse.core.commands.operations.IUndoContext;
import org.eclipse.core.commands.operations.ObjectUndoContext;
......@@ -13,18 +12,24 @@ import org.eclipse.core.commands.operations.OperationHistoryFactory;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.ElementChangedEvent;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorReference;
......@@ -35,7 +40,6 @@ import org.eclipse.ui.operations.RedoActionHandler;
import org.eclipse.ui.operations.UndoActionHandler;
import org.eclipse.ui.part.EditorPart;
import org.eclipse.ui.part.FileEditorInput;
import com.oracle.javafx.scenebuilder.kit.editor.EditorController;
import com.oracle.javafx.scenebuilder.kit.editor.JobManager;
import com.oracle.javafx.scenebuilder.kit.editor.EditorController.ControlAction;
......@@ -44,6 +48,7 @@ import com.oracle.javafx.scenebuilder.kit.editor.job.Job;
import com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument;
import com.oracle.javafx.scenebuilder.kit.fxom.FXOMObject;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.embed.swt.FXCanvas;
import no.tobask.sb4e.CustomClassLoaderLibrary;
......@@ -54,7 +59,7 @@ import no.tobask.sb4e.handlers.SceneBuilderControlActionHandler;
import no.tobask.sb4e.handlers.SceneBuilderEditActionHandler;
import no.tobask.sb4e.handlers.SceneBuilderOperation;
public class FXMLEditor extends EditorPart {
public class FXMLEditor extends EditorPart implements IInputChangeListener {
private EditorController editorController;
private FXCanvas canvas;
......@@ -71,6 +76,8 @@ public class FXMLEditor extends EditorPart {
private IAction deleteHandler;
private UndoActionHandler undoActionHandler;
private RedoActionHandler redoActionHandler;
private String fxmlText = null;
private EditorInputWatcher inputWatcher;
private ChangeListener<Number> editorSelectionListener = (oV, oldNum, newNum) -> {
FXOMObject fxomRoot = editorController.getFxomDocument().getFxomRoot();
......@@ -96,8 +103,7 @@ public class FXMLEditor extends EditorPart {
if (fxId != null) {
int[] location = getLocation(fxId, controllerClass);
if (location != null) {
IFile file = ((FileEditorInput) editor.getEditorInput())
.getFile();
IFile file = ((FileEditorInput) editor.getEditorInput()).getFile();
IDE.gotoMarker(editor, createMarker(file, location));
}
}
......@@ -127,6 +133,8 @@ public class FXMLEditor extends EditorPart {
undoContext = new ObjectUndoContext(this);
undoActionHandler = new UndoActionHandler(site, undoContext);
redoActionHandler = new RedoActionHandler(site, undoContext);
inputWatcher = new EditorInputWatcher(((FileEditorInput) input).getFile(), this);
ResourcesPlugin.getWorkspace().addResourceChangeListener(inputWatcher);
}
@Override
......@@ -136,12 +144,13 @@ public class FXMLEditor extends EditorPart {
canvas = new FXCanvas(parent, SWT.None);
editorController = new EditorController();
EditorWindowController editorWindowController = new EditorWindowController(editorController);
// make sure the other controllers have their references set before setting the input file
// make sure the other controllers have their references set before setting the
// input file
// for the editor controller so they can react to the update
try {
editorController.setLibrary(new CustomClassLoaderLibrary(new EclipseProjectsClassLoader()));
editorController.setFxmlTextAndLocation(FXOMDocument
.readContentFromURL(fxmlUrl), fxmlUrl);
fxmlText = FXOMDocument.readContentFromURL(fxmlUrl);
editorController.setFxmlTextAndLocation(fxmlText, fxmlUrl);
FXOMObject root = editorController.getFxomDocument().getFxomRoot();
String controllerName = null;
......@@ -179,19 +188,16 @@ public class FXMLEditor extends EditorPart {
@Override
public void doSave(IProgressMonitor monitor) {
IFile file = ((FileEditorInput) getEditorInput()).getFile();
byte[] fxmlBytes = null;
try {
fxmlBytes = editorController.getFxmlText().getBytes("UTF-8");
} catch (UnsupportedEncodingException e2) {
e2.printStackTrace();
}
try {
String newFxmlText = editorController.getFxmlText();
byte[] fxmlBytes = newFxmlText.getBytes("UTF-8");
updateDirtyStatus(false);
file.setContents(new ByteArrayInputStream(fxmlBytes), IResource.FORCE, monitor);
} catch (CoreException e1) {
e1.printStackTrace();
this.fxmlText = newFxmlText;
} catch (UnsupportedEncodingException | CoreException e) {
e.printStackTrace();
updateDirtyStatus(true);
}
dirty = false;
firePropertyChange(PROP_DIRTY);
}
@Override
......@@ -215,6 +221,9 @@ public class FXMLEditor extends EditorPart {
if (glossary != null) {
JavaCore.removeElementChangedListener(glossary);
}
if (inputWatcher != null) {
ResourcesPlugin.getWorkspace().removeResourceChangeListener(inputWatcher);
}
}
public IAction getUndoActionHandler() {
......@@ -248,8 +257,9 @@ public class FXMLEditor extends EditorPart {
private void setupUndoRedo() {
JobManager jobManager = editorController.getJobManager();
jobManager.revisionProperty().addListener((observable, oldValue, newValue) -> {
dirty = jobManager.canUndo();
firePropertyChange(PROP_DIRTY);
String newFxmlText = editorController.getFxmlText();
updateDirtyStatus(!newFxmlText.equals(this.fxmlText));
if (!jobManager.canRedo()) {
// only add unique, previously unseen jobs to the operation history
Job currentJob = jobManager.getCurrentJob();
......@@ -273,8 +283,8 @@ public class FXMLEditor extends EditorPart {
IEditorPart editor = editorRef.getEditor(true);
if (editor != null && editor.getEditorInput() instanceof FileEditorInput) {
IFile file = ((FileEditorInput) editor.getEditorInput()).getFile();
if (file.getName().equals(controllerClass.getElementName()) &&
getSite().getPage().isPartVisible(editor)) {
if (file.getName().equals(controllerClass.getElementName())
&& getSite().getPage().isPartVisible(editor)) {
return editor;
}
}
......@@ -299,9 +309,70 @@ public class FXMLEditor extends EditorPart {
}
private boolean isFreshJob(Job job) {
SceneBuilderOperation topOperation = (SceneBuilderOperation) operationHistory
.getRedoOperation(undoContext);
SceneBuilderOperation topOperation = (SceneBuilderOperation) operationHistory.getRedoOperation(undoContext);
return topOperation == null || topOperation.getJob() != job;
}
private void loadFxml(URL location) {
Platform.runLater(() -> {
try {
fxmlText = FXOMDocument.readContentFromURL(location);
editorController.setFxmlTextAndLocation(fxmlText, fxmlUrl);
glossary.setFxmlLocation(fxmlUrl);
updateDirtyStatus(false);
} catch (IOException e) {
e.printStackTrace();
}
});
}
private void updateDirtyStatus(boolean dirty) {
boolean previousStatus = this.dirty;
this.dirty = dirty;
if (previousStatus != dirty) {
firePropertyChange(PROP_DIRTY);
}
}
@Override
public void inputRemoved() {
Display display = getSite().getShell().getDisplay();
display.asyncExec(() -> getSite().getPage().closeEditor(FXMLEditor.this, false));
}
@Override
public void inputContentChanged() {
if (dirty) {
Display display = getSite().getShell().getDisplay();
display.asyncExec(() -> {
boolean reload = (Dialog.OK != MessageDialog.open(MessageDialog.WARNING, getSite().getShell(),
"Reload data?",
getEditorInput().getName() + " has changed outside editor, would you like to reload it?",
SWT.SHEET, "Keep editing", "Reload data"));
if (reload) {
loadFxml(fxmlUrl);
}
});
} else {
loadFxml(fxmlUrl);
}
}
@Override
public void inputMoved(IPath newLocation) {
IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(newLocation);
FileEditorInput newInput = new FileEditorInput(file);
try {
loadFxml(file.getLocationURI().toURL());
Display display = getSite().getShell().getDisplay();
display.asyncExec(() -> {
setInputWithNotify(newInput);
setPartName(newInput.getName());
});
inputWatcher.setInput(file);
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
package no.tobask.sb4e.editors;
import org.eclipse.core.runtime.IPath;
public interface IInputChangeListener {
public void inputRemoved();
public void inputContentChanged();
public void inputMoved(IPath newLocation);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment