initial commit

This commit is contained in:
MrLetsplay 2023-11-26 19:38:46 +01:00
commit f92f15dbd2
Signed by: mr
SSH Key Fingerprint: SHA256:92jBH80vpXyaZHjaIl47pjRq+Yt7XGTArqQg1V7hSqg
13 changed files with 681 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
.settings/
bin/
.classpath

28
.project Normal file
View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>ShareClient</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

16
META-INF/MANIFEST.MF Normal file
View File

@ -0,0 +1,16 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: ShareClient
Bundle-SymbolicName: ShareClient;singleton:=true
Bundle-Version: 1.0.0
Import-Package: javax.inject;version="[1.0.0,2.0.0)"
Bundle-Activator: me.mrletsplay.shareclient.Activator
Require-Bundle: org.eclipse.ui,
org.eclipse.core.runtime,
org.eclipse.ui.editors;bundle-version="3.17.0",
org.eclipse.text,
Java-WebSocket;bundle-version="1.5.4",
wrapped.me.mrletsplay.ShareClient-Core;bundle-version="1.0.0"
Bundle-RequiredExecutionEnvironment: JavaSE-17
Automatic-Module-Name: ShareClient
Bundle-ActivationPolicy: lazy

6
build.properties Normal file
View File

@ -0,0 +1,6 @@
source.. = src/main/java/
output.. = bin/
bin.includes = plugin.xml,\
META-INF/,\
.,\
icons/

13
contexts.xml Normal file
View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<contexts>
<context id="viewer" title="Sample View">
<description>This is the context help for the sample view with a table viewer. It was generated by a PDE template.</description>
<topic href="/PLUGINS_ROOT/org.eclipse.platform.doc.isv/guide/ua_help_context.htm" label="Context-sensitive help">
<enablement>
<with variable="platform">
<test property="org.eclipse.core.runtime.isBundleInstalled" args="org.eclipse.platform.doc.isv"/>
</with>
</enablement>
</topic>
</context>
</contexts>

BIN
icons/sample.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 B

BIN
icons/sample@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 526 B

95
plugin.xml Normal file
View File

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
<extension
point="org.eclipse.ui.commands">
<category
id="ShareClient.commands.category"
name="Sample Category">
</category>
<command
categoryId="ShareClient.commands.category"
name="Sample Command"
id="ShareClient.commands.sampleCommand">
</command>
</extension>
<extension
point="org.eclipse.ui.handlers">
<handler
class="me.mrletsplay.shareclient.handlers.SampleHandler"
commandId="ShareClient.commands.sampleCommand">
</handler>
</extension>
<extension
point="org.eclipse.ui.bindings">
<key
commandId="ShareClient.commands.sampleCommand"
schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"
contextId="org.eclipse.ui.contexts.window"
sequence="M1+6">
</key>
</extension>
<extension
point="org.eclipse.ui.menus">
<menuContribution
locationURI="menu:org.eclipse.ui.main.menu?after=additions">
<menu
id="ShareClient.menus.sampleMenu"
label="Sample Menu"
mnemonic="M">
<command
commandId="ShareClient.commands.sampleCommand"
id="ShareClient.menus.sampleCommand"
mnemonic="S">
</command>
</menu>
</menuContribution>
<menuContribution
locationURI="toolbar:org.eclipse.ui.main.toolbar?after=additions">
<toolbar
id="ShareClient.toolbars.sampleToolbar">
<command
id="ShareClient.toolbars.sampleCommand"
commandId="ShareClient.commands.sampleCommand"
icon="icons/sample.png"
tooltip="Say hello world">
</command>
</toolbar>
</menuContribution>
</extension>
<extension
point="org.eclipse.ui.views">
<category
id="me.mrletsplay.shareclient"
name="ShareClient">
</category>
<view
category="me.mrletsplay.shareclient"
class="me.mrletsplay.shareclient.views.ShareView"
icon="icons/sample.png"
id="shareclient.views.SampleView"
inject="true"
name="Share Client">
</view>
</extension>
<extension
point="org.eclipse.ui.perspectiveExtensions">
<perspectiveExtension
targetID="org.eclipse.jdt.ui.JavaPerspective">
<view
id="me.mrletsplay.shareclient.views.ShareView"
ratio="0.5"
relationship="right"
relative="org.eclipse.ui.views.ProblemView">
</view>
</perspectiveExtension>
</extension>
<extension
point="org.eclipse.help.contexts">
<contexts
file="contexts.xml">
</contexts>
</extension>
</plugin>

View File

@ -0,0 +1,47 @@
package me.mrletsplay.shareclient;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
/**
* The activator class controls the plug-in life cycle
*/
public class Activator extends AbstractUIPlugin {
// The plug-in ID
public static final String PLUGIN_ID = "ShareClient"; //$NON-NLS-1$
// The shared instance
private static Activator plugin;
/**
* The constructor
*/
public Activator() {
}
@Override
public void start(BundleContext context) throws Exception {
super.start(context);
plugin = this;
System.out.println("STARTING");
// new ShareWSClient(URI.create("ws://localhost:5473")).connect();
}
@Override
public void stop(BundleContext context) throws Exception {
plugin = null;
super.stop(context);
}
/**
* Returns the shared instance
*
* @return the shared instance
*/
public static Activator getDefault() {
return plugin;
}
}

View File

@ -0,0 +1,105 @@
package me.mrletsplay.shareclient.handlers;
import java.io.IOException;
import java.net.URI;
import java.util.concurrent.atomic.AtomicBoolean;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentListener;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.ui.texteditor.ITextEditor;
import me.mrletsplay.shareclientcore.connection.RemoteConnection;
import me.mrletsplay.shareclientcore.connection.WebSocketConnection;
import me.mrletsplay.shareclientcore.document.DocumentListener;
import me.mrletsplay.shareclientcore.document.SharedDocument;
public class SampleHandler extends AbstractHandler {
@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindowChecked(event);
MessageDialog.openInformation(
window.getShell(),
"ShareClient",
"Hello, Eclipse world");
IEditorPart editor = window.getActivePage().getActiveEditor();
if(!(editor instanceof ITextEditor)) return null;
ITextEditor textEditor = (ITextEditor) editor;
IDocument eclipseDocument = textEditor.getDocumentProvider().getDocument(textEditor.getEditorInput());
RemoteConnection con = new WebSocketConnection(URI.create("ws://localhost:5473"));
try {
con.connect();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
AtomicBoolean ignoreChanges = new AtomicBoolean(false);
SharedDocument doc = new SharedDocument(con);
doc.localInsert(0, eclipseDocument.get());
doc.addListener(new DocumentListener() {
@Override
public void onInsert(int index, char character) {
Display.getDefault().asyncExec(() -> {
try {
ignoreChanges.set(true);
eclipseDocument.replace(index, 0, String.valueOf(character));
ignoreChanges.set(false);
} catch (BadLocationException e) {
e.printStackTrace();
}
});
}
@Override
public void onDelete(int index) {
Display.getDefault().asyncExec(() -> {
try {
ignoreChanges.set(true);
eclipseDocument.replace(index, 1, "");
ignoreChanges.set(false);
} catch (BadLocationException e) {
e.printStackTrace();
}
});
}
});
eclipseDocument.addDocumentListener(new IDocumentListener() {
@Override
public void documentChanged(DocumentEvent event) {
if(ignoreChanges.get()) return; // TODO: not very ideal
if(event.getLength() > 0) {
doc.localDelete(event.getOffset(), event.getLength());
}
doc.localInsert(event.getOffset(), event.getText());
}
@Override
public void documentAboutToBeChanged(DocumentEvent event) {
}
});
return null;
}
}

View File

@ -0,0 +1,186 @@
package me.mrletsplay.shareclient.views;
import javax.inject.Inject;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;
/**
* This sample class demonstrates how to plug-in a new
* workbench view. The view shows data obtained from the
* model. The sample creates a dummy model on the fly,
* but a real implementation would connect to the model
* available either in this or another plug-in (e.g. the workspace).
* The view is connected to the model using a content provider.
* <p>
* The view uses a label provider to define how model
* objects should be presented in the view. Each
* view can present the same model objects using
* different labels and icons, if needed. Alternatively,
* a single label provider can be shared between views
* in order to ensure that objects of the same type are
* presented in the same way everywhere.
* <p>
*/
public class ShareView extends ViewPart {
/**
* The ID of the view as specified by the extension.
*/
public static final String ID = "me.mrletsplay.shareclient.views.ShareView";
@Inject IWorkbench workbench;
private TableViewer viewer;
private Action action1;
private Action action2;
private Action doubleClickAction;
class ViewLabelProvider extends LabelProvider implements ITableLabelProvider {
@Override
public String getColumnText(Object obj, int index) {
return getText(obj);
}
@Override
public Image getColumnImage(Object obj, int index) {
return getImage(obj);
}
@Override
public Image getImage(Object obj) {
return workbench.getSharedImages().getImage(ISharedImages.IMG_OBJ_ELEMENT);
}
}
@Override
public void createPartControl(Composite parent) {
viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
viewer.setContentProvider(ArrayContentProvider.getInstance());
viewer.setInput(new String[] { "One", "Two", "Three" });
viewer.setLabelProvider(new ViewLabelProvider());
// Create the help context id for the viewer's control
workbench.getHelpSystem().setHelp(viewer.getControl(), "ShareClient.viewer");
getSite().setSelectionProvider(viewer);
makeActions();
hookContextMenu();
hookDoubleClickAction();
contributeToActionBars();
}
private void hookContextMenu() {
MenuManager menuMgr = new MenuManager("#PopupMenu");
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(new IMenuListener() {
@Override
public void menuAboutToShow(IMenuManager manager) {
ShareView.this.fillContextMenu(manager);
}
});
Menu menu = menuMgr.createContextMenu(viewer.getControl());
viewer.getControl().setMenu(menu);
getSite().registerContextMenu(menuMgr, viewer);
}
private void contributeToActionBars() {
IActionBars bars = getViewSite().getActionBars();
fillLocalPullDown(bars.getMenuManager());
fillLocalToolBar(bars.getToolBarManager());
}
private void fillLocalPullDown(IMenuManager manager) {
manager.add(action1);
manager.add(new Separator());
manager.add(action2);
}
private void fillContextMenu(IMenuManager manager) {
manager.add(action1);
manager.add(action2);
// Other plug-ins can contribute there actions here
manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
}
private void fillLocalToolBar(IToolBarManager manager) {
manager.add(action1);
manager.add(action2);
}
private void makeActions() {
action1 = new Action() {
@Override
public void run() {
showMessage("Action 1 executed");
}
};
action1.setText("Action 1");
action1.setToolTipText("Action 1 tooltip");
action1.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().
getImageDescriptor(ISharedImages.IMG_OBJS_INFO_TSK));
action2 = new Action() {
@Override
public void run() {
showMessage("Action 2 executed");
}
};
action2.setText("Action 2");
action2.setToolTipText("Action 2 tooltip");
action2.setImageDescriptor(workbench.getSharedImages().
getImageDescriptor(ISharedImages.IMG_OBJS_INFO_TSK));
doubleClickAction = new Action() {
@Override
public void run() {
IStructuredSelection selection = viewer.getStructuredSelection();
Object obj = selection.getFirstElement();
showMessage("Double-click detected on "+obj.toString());
}
};
}
private void hookDoubleClickAction() {
viewer.addDoubleClickListener(new IDoubleClickListener() {
@Override
public void doubleClick(DoubleClickEvent event) {
doubleClickAction.run();
}
});
}
private void showMessage(String message) {
MessageDialog.openInformation(
viewer.getControl().getShell(),
"Sample View",
message);
}
@Override
public void setFocus() {
viewer.getControl().setFocus();
}
}

View File

@ -0,0 +1,133 @@
package me.mrletsplay.shareclientcore;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;
import me.mrletsplay.shareclientcore.document.Identifier;
import me.mrletsplay.shareclientcore.document.Util;
public class DecimalTest {
@Test
public void testSimpleSubtraction() {
Identifier[] a = { new Identifier(1, 0), new Identifier(2, 0), new Identifier(3, 0) };
Identifier[] b = { new Identifier(1, 0), new Identifier(1, 0), new Identifier(3, 0) };
assertArrayEquals(new int[] { 0, 1, 0 }, Util.subtract(a, b, 0));
}
@Test
public void testCarrySubtraction() {
Identifier[] a = { new Identifier(2, 0), new Identifier(0, 0), new Identifier(4, 0) };
Identifier[] b = { new Identifier(1, 0), new Identifier(0, 0), new Identifier(5, 0) };
assertArrayEquals(new int[] { 0, Util.BASE - 1, Util.BASE - 1 }, Util.subtract(a, b, 0));
}
@Test
public void testOffsetSubtraction() {
Identifier[] a = { new Identifier(1, 0), new Identifier(0, 0), new Identifier(5, 0) };
Identifier[] b = { new Identifier(1, 0), new Identifier(0, 0), new Identifier(4, 0) };
assertArrayEquals(new int[] { 0, 1 }, Util.subtract(a, b, 1));
}
@Test
public void testReversedInputFails() {
Identifier[] a = { new Identifier(1, 0), new Identifier(1, 0), new Identifier(3, 0) };
Identifier[] b = { new Identifier(1, 0), new Identifier(2, 0), new Identifier(3, 0) };
assertThrows(RuntimeException.class, () -> Util.subtract(a, b, 0));
}
@Test
public void testSimpleAdd1() {
int[] a = { 0, 0 };
Util.add1AtIndex(a, 1);
assertArrayEquals(new int[] { 0, 1 }, a);
}
@Test
public void testCarryAdd1() {
int[] a = { 0, Util.BASE - 1 };
Util.add1AtIndex(a, 1);
assertArrayEquals(new int[] { 1, 0 }, a);
}
@Test
public void testCarryAdd1_2() {
int[] a = { 0, Util.BASE - 1, Util.BASE - 1 };
Util.add1AtIndex(a, 2);
assertArrayEquals(new int[] { 1, 0, 0 }, a);
}
@Test
public void testCarryAdd1_3() {
int[] a = { 0, Util.BASE - 1, Util.BASE - 1 };
Util.add1AtIndex(a, 1);
assertArrayEquals(new int[] { 1, 0, Util.BASE - 1 }, a);
}
@Test
public void testIncrement_1() {
Identifier[] a = { new Identifier(1, 0), new Identifier(2, 0) };
Identifier[] b = { new Identifier(1, 0), new Identifier(3, 0) };
assertArrayEquals(new int[] { 1, 2, 1 }, Util.getIncremented(a, b, 1));
}
@Test
public void testIncrement_2() {
Identifier[] a = { new Identifier(1, 0), new Identifier(2, 0) };
Identifier[] b = { new Identifier(1, 0), new Identifier(2, 0), new Identifier(Util.BASE - 1, 0) };
assertArrayEquals(new int[] { 1, 2, 0, 1 }, Util.getIncremented(a, b, 1));
}
@Test
public void testCarryIncrement() {
Identifier[] a = { new Identifier(1, 0), new Identifier(2, 0), new Identifier(Util.BASE - 1, 0) };
Identifier[] b = { new Identifier(1, 0), new Identifier(4, 0) };
assertArrayEquals(new int[] { 1, 3, 1 }, Util.getIncremented(a, b, 1));
}
@Test
public void testConstructPosition_1() {
Identifier[] a = { new Identifier(1, 0), new Identifier(2, 0), new Identifier(Util.BASE - 1, 0) };
Identifier[] b = { new Identifier(1, 0), new Identifier(4, 0) };
int[] newIdent = Util.getIncremented(a, b, 1);
Identifier[] expected = { new Identifier(1, 0), new Identifier(3, 1), new Identifier(1, 1) };
assertArrayEquals(expected, Util.constructPosition(newIdent, a, b, 1));
}
@Test
public void testConstructPosition_2() {
Identifier[] a = { new Identifier(1, 0), new Identifier(2, 2), new Identifier(2, 2) };
Identifier[] b = { new Identifier(1, 0), new Identifier(4, 1), new Identifier(3, 1) };
int[] newIdent = Util.getIncremented(a, b, 1);
Identifier[] expected = { new Identifier(1, 0), new Identifier(2, 2), new Identifier(3, 3) };
assertArrayEquals(expected, Util.constructPosition(newIdent, a, b, 3));
}
@Test
public void testGeneratePosition_1() {
Identifier[] a = { new Identifier(1, 0), new Identifier(2, 1) };
Identifier[] b = { new Identifier(1, 0), new Identifier(3, 2) };
Identifier[] newIdent = Util.generatePositionBetween(a, b, 3);
Identifier[] expected = { new Identifier(1, 0), new Identifier(2, 1), new Identifier(1, 3) };
assertArrayEquals(expected, newIdent);
}
@Test
public void testGeneratePosition_2() {
Identifier[] a = { new Identifier(1, 0), new Identifier(2, 1) };
Identifier[] b = { new Identifier(1, 0), new Identifier(2, 2) };
Identifier[] newIdent = Util.generatePositionBetween(a, b, 3);
Identifier[] expected = { new Identifier(1, 0), new Identifier(2, 1), new Identifier(1, 3) };
assertArrayEquals(expected, newIdent);
}
@Test
public void testGeneratePositionInvalidInputFails() {
Identifier[] a = { new Identifier(1, 0), new Identifier(2, 2) };
Identifier[] b = { new Identifier(1, 0), new Identifier(2, 1) };
assertThrows(IllegalArgumentException.class, () -> Util.generatePositionBetween(a, b, 3));
}
}

View File

@ -0,0 +1,49 @@
package me.mrletsplay.shareclientcore;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;
import me.mrletsplay.shareclientcore.connection.DummyConnection;
import me.mrletsplay.shareclientcore.document.SharedDocument;
public class DocumentTest {
@Test
public void testLocalInsert() {
SharedDocument doc = new SharedDocument(new DummyConnection());
doc.localInsert(0, "Hello");
assertEquals("Hello", doc.getContents());
doc.localInsert(5, " World");
assertEquals("Hello World", doc.getContents());
doc.localInsert(5, " Test");
assertEquals("Hello Test World", doc.getContents());
}
@Test
public void testLocalInsertInvalidIndexFails() {
SharedDocument doc = new SharedDocument(new DummyConnection());
doc.localInsert(0, "Hello");
assertThrows(IllegalArgumentException.class, () -> doc.localInsert(-1, "Test"));
assertThrows(IllegalArgumentException.class, () -> doc.localInsert(6, "Test"));
}
@Test
public void testLocalDelete() {
SharedDocument doc = new SharedDocument(new DummyConnection());
doc.localInsert(0, "Hello World!");
doc.localDelete(5, 6);
assertEquals("Hello!", doc.getContents());
}
@Test
public void testLocalDeleteInvalidIndexFails() {
SharedDocument doc = new SharedDocument(new DummyConnection());
doc.localInsert(0, "Hello World!");
assertThrows(IllegalArgumentException.class, () -> doc.localDelete(-1, 10));
assertThrows(IllegalArgumentException.class, () -> doc.localDelete(12, 1));
assertThrows(IllegalArgumentException.class, () -> doc.localDelete(0, 13));
}
}