Add editor listeners
This commit is contained in:
parent
050b09d1aa
commit
9812d9bd2f
@ -97,5 +97,11 @@
|
|||||||
name="Share Client">
|
name="Share Client">
|
||||||
</page>
|
</page>
|
||||||
</extension>
|
</extension>
|
||||||
|
<extension
|
||||||
|
point="org.eclipse.ui.startup">
|
||||||
|
<startup
|
||||||
|
class="me.mrletsplay.shareclient.ShareClient">
|
||||||
|
</startup>
|
||||||
|
</extension>
|
||||||
|
|
||||||
</plugin>
|
</plugin>
|
||||||
|
@ -4,6 +4,7 @@ import java.io.IOException;
|
|||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
@ -20,26 +21,38 @@ import org.eclipse.core.resources.ResourcesPlugin;
|
|||||||
import org.eclipse.core.runtime.CoreException;
|
import org.eclipse.core.runtime.CoreException;
|
||||||
import org.eclipse.jface.dialogs.MessageDialog;
|
import org.eclipse.jface.dialogs.MessageDialog;
|
||||||
import org.eclipse.swt.widgets.Display;
|
import org.eclipse.swt.widgets.Display;
|
||||||
|
import org.eclipse.ui.IStartup;
|
||||||
|
import org.eclipse.ui.PlatformUI;
|
||||||
import org.eclipse.ui.plugin.AbstractUIPlugin;
|
import org.eclipse.ui.plugin.AbstractUIPlugin;
|
||||||
import org.osgi.framework.BundleContext;
|
import org.osgi.framework.BundleContext;
|
||||||
|
|
||||||
|
import me.mrletsplay.shareclient.util.ChecksumUtil;
|
||||||
import me.mrletsplay.shareclient.util.Peer;
|
import me.mrletsplay.shareclient.util.Peer;
|
||||||
import me.mrletsplay.shareclient.util.ProjectRelativePath;
|
import me.mrletsplay.shareclient.util.ProjectRelativePath;
|
||||||
import me.mrletsplay.shareclient.util.ShareSession;
|
import me.mrletsplay.shareclient.util.ShareSession;
|
||||||
|
import me.mrletsplay.shareclient.util.listeners.ShareClientPageListener;
|
||||||
|
import me.mrletsplay.shareclient.util.listeners.ShareClientPartListener;
|
||||||
|
import me.mrletsplay.shareclient.util.listeners.ShareClientWindowListener;
|
||||||
import me.mrletsplay.shareclient.views.ShareView;
|
import me.mrletsplay.shareclient.views.ShareView;
|
||||||
|
import me.mrletsplay.shareclientcore.connection.Change;
|
||||||
import me.mrletsplay.shareclientcore.connection.ConnectionException;
|
import me.mrletsplay.shareclientcore.connection.ConnectionException;
|
||||||
import me.mrletsplay.shareclientcore.connection.MessageListener;
|
import me.mrletsplay.shareclientcore.connection.MessageListener;
|
||||||
import me.mrletsplay.shareclientcore.connection.RemoteConnection;
|
import me.mrletsplay.shareclientcore.connection.RemoteConnection;
|
||||||
import me.mrletsplay.shareclientcore.connection.WebSocketConnection;
|
import me.mrletsplay.shareclientcore.connection.WebSocketConnection;
|
||||||
|
import me.mrletsplay.shareclientcore.connection.message.AddressableMessage;
|
||||||
|
import me.mrletsplay.shareclientcore.connection.message.ChangeMessage;
|
||||||
|
import me.mrletsplay.shareclientcore.connection.message.ChecksumMessage;
|
||||||
import me.mrletsplay.shareclientcore.connection.message.FullSyncMessage;
|
import me.mrletsplay.shareclientcore.connection.message.FullSyncMessage;
|
||||||
import me.mrletsplay.shareclientcore.connection.message.Message;
|
import me.mrletsplay.shareclientcore.connection.message.Message;
|
||||||
import me.mrletsplay.shareclientcore.connection.message.PeerJoinMessage;
|
import me.mrletsplay.shareclientcore.connection.message.PeerJoinMessage;
|
||||||
|
import me.mrletsplay.shareclientcore.connection.message.PeerLeaveMessage;
|
||||||
import me.mrletsplay.shareclientcore.connection.message.RequestFullSyncMessage;
|
import me.mrletsplay.shareclientcore.connection.message.RequestFullSyncMessage;
|
||||||
|
import me.mrletsplay.shareclientcore.document.SharedDocument;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The activator class controls the plug-in life cycle
|
* The activator class controls the plug-in life cycle
|
||||||
*/
|
*/
|
||||||
public class ShareClient extends AbstractUIPlugin implements MessageListener {
|
public class ShareClient extends AbstractUIPlugin implements MessageListener, IStartup {
|
||||||
|
|
||||||
// The plug-in ID
|
// The plug-in ID
|
||||||
public static final String PLUGIN_ID = "ShareClient"; //$NON-NLS-1$
|
public static final String PLUGIN_ID = "ShareClient"; //$NON-NLS-1$
|
||||||
@ -47,11 +60,15 @@ public class ShareClient extends AbstractUIPlugin implements MessageListener {
|
|||||||
// The shared instance
|
// The shared instance
|
||||||
private static ShareClient plugin;
|
private static ShareClient plugin;
|
||||||
|
|
||||||
|
private ShareClientPartListener partListener = new ShareClientPartListener();
|
||||||
|
|
||||||
private ShareView view;
|
private ShareView view;
|
||||||
private ShareSession activeSession;
|
private ShareSession activeSession;
|
||||||
|
|
||||||
public ShareClient() {
|
private Map<ProjectRelativePath, SharedDocument> sharedDocuments;
|
||||||
|
|
||||||
|
public ShareClient() {
|
||||||
|
this.sharedDocuments = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -147,6 +164,11 @@ public class ShareClient extends AbstractUIPlugin implements MessageListener {
|
|||||||
updateView();
|
updateView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(message instanceof PeerLeaveMessage leave) {
|
||||||
|
activeSession.getPeers().removeIf(p -> p.siteID() == leave.peerSiteID());
|
||||||
|
updateView();
|
||||||
|
}
|
||||||
|
|
||||||
if (message instanceof FullSyncMessage sync) {
|
if (message instanceof FullSyncMessage sync) {
|
||||||
// TODO: handle FULL_SYNC
|
// TODO: handle FULL_SYNC
|
||||||
ProjectRelativePath path;
|
ProjectRelativePath path;
|
||||||
@ -182,6 +204,8 @@ public class ShareClient extends AbstractUIPlugin implements MessageListener {
|
|||||||
Files.createFile(filePath);
|
Files.createFile(filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: update sharedDocuments
|
||||||
|
|
||||||
Files.write(filePath, sync.content());
|
Files.write(filePath, sync.content());
|
||||||
project.refreshLocal(IResource.DEPTH_INFINITE, null);
|
project.refreshLocal(IResource.DEPTH_INFINITE, null);
|
||||||
} catch (IOException | CoreException e) {
|
} catch (IOException | CoreException e) {
|
||||||
@ -227,18 +251,50 @@ public class ShareClient extends AbstractUIPlugin implements MessageListener {
|
|||||||
|
|
||||||
RemoteConnection connection = activeSession.getConnection();
|
RemoteConnection connection = activeSession.getConnection();
|
||||||
for (var en : paths.entrySet()) {
|
for (var en : paths.entrySet()) {
|
||||||
if (!Files.isRegularFile(en.getValue()))
|
if(!sendFullSyncOrChecksum(connection, req.siteID(), en.getKey(), en.getValue(), false)) return;
|
||||||
continue;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(message instanceof ChangeMessage change) {
|
||||||
|
Change c = change.change();
|
||||||
try {
|
try {
|
||||||
byte[] bytes = Files.readAllBytes(en.getValue());
|
ProjectRelativePath path = ProjectRelativePath.of(c.documentPath());
|
||||||
connection.send(new FullSyncMessage(req.siteID(), en.getKey().toString(), bytes));
|
}catch(IllegalArgumentException e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: insert change into document in sharedDocuments
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSharedProject(IProject project) {
|
||||||
|
activeSession.getSharedProjects().add(project);
|
||||||
|
|
||||||
|
RemoteConnection connection = activeSession.getConnection();
|
||||||
|
for(Map.Entry<ProjectRelativePath, Path> en : getProjectFiles(project).entrySet()) {
|
||||||
|
// TODO: add new document to sharedDocuments
|
||||||
|
if(!sendFullSyncOrChecksum(connection, AddressableMessage.BROADCAST_SITE_ID, en.getKey(), en.getValue(), false)) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean sendFullSyncOrChecksum(RemoteConnection connection, int siteID, ProjectRelativePath relativePath, Path filePath, boolean checksum) {
|
||||||
|
if (!Files.isRegularFile(filePath)) return false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
byte[] bytes = Files.readAllBytes(filePath);
|
||||||
|
|
||||||
|
if(!checksum) {
|
||||||
|
connection.send(new FullSyncMessage(siteID, relativePath.toString(), bytes));
|
||||||
|
}else {
|
||||||
|
connection.send(new ChecksumMessage(siteID, relativePath.toString(), ChecksumUtil.generateSHA256(bytes)));
|
||||||
|
}
|
||||||
} catch (IOException | ConnectionException e) {
|
} catch (IOException | ConnectionException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
MessageDialog.openError(null, "Share Client", "Failed to send file contents: " + e.toString());
|
MessageDialog.openError(null, "Share Client", "Failed to send file contents: " + e.toString());
|
||||||
return;
|
return false;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<ProjectRelativePath, Path> getProjectFiles(IProject project) {
|
private Map<ProjectRelativePath, Path> getProjectFiles(IProject project) {
|
||||||
@ -255,4 +311,20 @@ public class ShareClient extends AbstractUIPlugin implements MessageListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ShareClientPartListener getPartListener() {
|
||||||
|
return partListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void earlyStartup() {
|
||||||
|
PlatformUI.getWorkbench().addWindowListener(ShareClientWindowListener.INSTANCE);
|
||||||
|
Arrays.stream(PlatformUI.getWorkbench().getWorkbenchWindows()).forEach(w -> {
|
||||||
|
w.addPageListener(ShareClientPageListener.INSTANCE);
|
||||||
|
Arrays.stream(w.getPages()).forEach(p -> {
|
||||||
|
p.addPartListener(partListener);
|
||||||
|
Arrays.stream(p.getEditorReferences()).forEach(e -> partListener.addDocumentListener(e));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -35,9 +35,7 @@ public class ShareProjectHandler extends AbstractHandler {
|
|||||||
ShareSession session = ShareClient.getDefault().getOrStartSession();
|
ShareSession session = ShareClient.getDefault().getOrStartSession();
|
||||||
if(session == null) return null;
|
if(session == null) return null;
|
||||||
|
|
||||||
session.getSharedProjects().add(project);
|
ShareClient.getDefault().addSharedProject(project);
|
||||||
|
|
||||||
// TODO: broadcast FULL_SYNC for newly added project
|
|
||||||
|
|
||||||
// IEditorPart editor = window.getActivePage().getActiveEditor();
|
// IEditorPart editor = window.getActivePage().getActiveEditor();
|
||||||
// if(!(editor instanceof ITextEditor)) return null;
|
// if(!(editor instanceof ITextEditor)) return null;
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
package me.mrletsplay.shareclient.util;
|
||||||
|
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
|
public class ChecksumUtil {
|
||||||
|
|
||||||
|
private static final MessageDigest SHA_256;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
SHA_256 = MessageDigest.getInstance("SHA-256");
|
||||||
|
}catch(NoSuchAlgorithmException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] generateSHA256(byte[] bytes) {
|
||||||
|
return SHA_256.digest(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package me.mrletsplay.shareclient.util.listeners;
|
||||||
|
|
||||||
|
import org.eclipse.ui.IPageListener;
|
||||||
|
import org.eclipse.ui.IWorkbenchPage;
|
||||||
|
|
||||||
|
import me.mrletsplay.shareclient.ShareClient;
|
||||||
|
|
||||||
|
public class ShareClientPageListener implements IPageListener {
|
||||||
|
|
||||||
|
public static final ShareClientPageListener INSTANCE = new ShareClientPageListener();
|
||||||
|
|
||||||
|
private ShareClientPageListener() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void pageOpened(IWorkbenchPage page) {
|
||||||
|
page.addPartListener(ShareClient.getDefault().getPartListener());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void pageClosed(IWorkbenchPage page) {
|
||||||
|
page.removePartListener(ShareClient.getDefault().getPartListener());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void pageActivated(IWorkbenchPage page) {}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,77 @@
|
|||||||
|
package me.mrletsplay.shareclient.util.listeners;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.core.resources.IFile;
|
||||||
|
import org.eclipse.core.resources.IProject;
|
||||||
|
import org.eclipse.jface.text.DocumentEvent;
|
||||||
|
import org.eclipse.jface.text.IDocument;
|
||||||
|
import org.eclipse.jface.text.IDocumentListener;
|
||||||
|
import org.eclipse.ui.IEditorInput;
|
||||||
|
import org.eclipse.ui.IEditorPart;
|
||||||
|
import org.eclipse.ui.IPartListener2;
|
||||||
|
import org.eclipse.ui.IWorkbenchPart;
|
||||||
|
import org.eclipse.ui.IWorkbenchPartReference;
|
||||||
|
import org.eclipse.ui.part.FileEditorInput;
|
||||||
|
import org.eclipse.ui.texteditor.ITextEditor;
|
||||||
|
|
||||||
|
import me.mrletsplay.shareclient.util.ProjectRelativePath;
|
||||||
|
|
||||||
|
public class ShareClientPartListener implements IPartListener2 {
|
||||||
|
|
||||||
|
private Map<ProjectRelativePath, IDocumentListener> listeners = new HashMap<>();
|
||||||
|
|
||||||
|
private IDocumentListener createListener(ProjectRelativePath path) {
|
||||||
|
if(listeners.containsKey(path)) return listeners.get(path);
|
||||||
|
|
||||||
|
IDocumentListener listener = new IDocumentListener() {
|
||||||
|
|
||||||
|
private boolean ignoreChanges = false;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void documentChanged(DocumentEvent event) {
|
||||||
|
System.out.println("Change in document at " + path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void documentAboutToBeChanged(DocumentEvent event) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
listeners.put(path, listener);
|
||||||
|
return listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addDocumentListener(IWorkbenchPartReference partRef) {
|
||||||
|
IWorkbenchPart part = partRef.getPart(false);
|
||||||
|
if(!(part instanceof IEditorPart)) return;
|
||||||
|
IEditorPart editor = (IEditorPart) part;
|
||||||
|
if(!(editor instanceof ITextEditor)) return;
|
||||||
|
ITextEditor textEditor = (ITextEditor) editor;
|
||||||
|
IEditorInput editorInput = editor.getEditorInput();
|
||||||
|
if(!(editorInput instanceof FileEditorInput)) return;
|
||||||
|
FileEditorInput fileEditorInput = (FileEditorInput) editorInput;
|
||||||
|
IDocument document = textEditor.getDocumentProvider().getDocument(editorInput);
|
||||||
|
|
||||||
|
IFile file = fileEditorInput.getFile();
|
||||||
|
IProject project = file.getProject();
|
||||||
|
|
||||||
|
Path filePath = project.getLocation().toPath().relativize(file.getLocation().toPath());
|
||||||
|
ProjectRelativePath relPath = new ProjectRelativePath(project.getName(), filePath.toString());
|
||||||
|
System.out.println(relPath);
|
||||||
|
document.addDocumentListener(createListener(relPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void partOpened(IWorkbenchPartReference partRef) {
|
||||||
|
addDocumentListener(partRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void partInputChanged(IWorkbenchPartReference partRef) {
|
||||||
|
addDocumentListener(partRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package me.mrletsplay.shareclient.util.listeners;
|
||||||
|
|
||||||
|
import org.eclipse.ui.IWindowListener;
|
||||||
|
import org.eclipse.ui.IWorkbenchWindow;
|
||||||
|
|
||||||
|
public class ShareClientWindowListener implements IWindowListener {
|
||||||
|
|
||||||
|
public static final ShareClientWindowListener INSTANCE = new ShareClientWindowListener();
|
||||||
|
|
||||||
|
private ShareClientWindowListener() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void windowOpened(IWorkbenchWindow window) {
|
||||||
|
window.addPageListener(ShareClientPageListener.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void windowClosed(IWorkbenchWindow window) {
|
||||||
|
window.removePageListener(ShareClientPageListener.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void windowActivated(IWorkbenchWindow window) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void windowDeactivated(IWorkbenchWindow window) {}
|
||||||
|
|
||||||
|
}
|
@ -5,7 +5,6 @@ import java.util.Arrays;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import org.eclipse.core.resources.ResourcesPlugin;
|
|
||||||
import org.eclipse.jface.action.Action;
|
import org.eclipse.jface.action.Action;
|
||||||
import org.eclipse.jface.action.IToolBarManager;
|
import org.eclipse.jface.action.IToolBarManager;
|
||||||
import org.eclipse.jface.dialogs.InputDialog;
|
import org.eclipse.jface.dialogs.InputDialog;
|
||||||
@ -105,8 +104,6 @@ public class ShareView extends ViewPart {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
showMessage(Arrays.stream(ResourcesPlugin.getWorkspace().getRoot().getProjects()).map(p -> p.getName() + ": " + p.getLocation().toString()).toList().toString());
|
|
||||||
|
|
||||||
InputDialog input = new InputDialog(viewer.getControl().getShell(), "Join session", "Enter session id", "EEE", null);
|
InputDialog input = new InputDialog(viewer.getControl().getShell(), "Join session", "Enter session id", "EEE", null);
|
||||||
input.setBlockOnOpen(true);
|
input.setBlockOnOpen(true);
|
||||||
if(input.open() != InputDialog.OK) return;
|
if(input.open() != InputDialog.OK) return;
|
||||||
|
Loading…
Reference in New Issue
Block a user