Skip to content

Commit

Permalink
Merge pull request #428 from axonivy/fix-eclipse-copy-paste
Browse files Browse the repository at this point in the history
XIVY-12896 Fix eclipse copy/paste, delete handlers
  • Loading branch information
ivy-lli committed Nov 27, 2023
2 parents ad03a0d + 35c52f2 commit f35ce0f
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 3 deletions.
86 changes: 86 additions & 0 deletions integration/eclipse/src/copy-paste/copy-paste.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/********************************************************************************
* Copyright (c) 2020-2023 EclipseSource and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/
import {
Action,
CutOperation,
EditorContextService,
IActionDispatcher,
IActionHandler,
IAsyncClipboardService,
PasteOperation,
RequestClipboardDataAction,
TYPES,
ViewerOptions
} from '@eclipse-glsp/client';
import { inject, injectable } from 'inversify';

// Eclipse-specific integration: in Eclipse, we trigger the Copy/Paste actions from
// the IDE Keybindings. We don't use the browser events. This is fine, because we
// don't need browser clipboard support (We use the Eclipse System Clipboard); so
// we don't need special permission from the Browser.

@injectable()
export class IvyEclipseCopyPasteActionHandler implements IActionHandler {
@inject(TYPES.IActionDispatcher) protected actionDispatcher: IActionDispatcher;
@inject(TYPES.ViewerOptions) protected viewerOptions: ViewerOptions;
@inject(TYPES.IAsyncClipboardService) protected clipboardService: IAsyncClipboardService;
@inject(EditorContextService) protected editorContext: EditorContextService;

handle(action: Action): void {
switch (action.kind) {
case 'invoke-copy':
this.handleCopy();
break;
case 'invoke-paste':
this.handlePaste();
break;
case 'invoke-cut':
this.handleCut();
break;
}
}

handleCopy() {
if (this.shouldCopy()) {
this.actionDispatcher.request(RequestClipboardDataAction.create(this.editorContext.get()));
} else {
this.clipboardService.clear();
}
}

handleCut() {
if (this.shouldCopy()) {
this.handleCopy();
this.actionDispatcher.dispatch(CutOperation.create(this.editorContext.get()));
}
}

handlePaste() {
if (this.isDiagramActive()) {
// In the Eclipse Integration case, the server manages its own clipboard.
// Just pass an empty clipboard data to remain compliant with the API.
const clipboardData = {};
this.actionDispatcher.dispatch(PasteOperation.create({ clipboardData: clipboardData, editorContext: this.editorContext.get() }));
}
}

protected shouldCopy(): boolean {
return this.editorContext.get().selectedElementIds.length > 0 && this.isDiagramActive();
}
protected isDiagramActive(): boolean {
return document.activeElement?.parentElement?.id === this.viewerOptions.baseDiv;
}
}
12 changes: 12 additions & 0 deletions integration/eclipse/src/copy-paste/di.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { configureActionHandler } from '@eclipse-glsp/client';
import { ContainerModule } from 'inversify';

import { IvyEclipseCopyPasteActionHandler } from './copy-paste';

const ivyEclipseCopyPasteModule = new ContainerModule((bind, _unbind, isBound) => {
configureActionHandler({ bind, isBound }, 'invoke-copy', IvyEclipseCopyPasteActionHandler);
configureActionHandler({ bind, isBound }, 'invoke-cut', IvyEclipseCopyPasteActionHandler);
configureActionHandler({ bind, isBound }, 'invoke-paste', IvyEclipseCopyPasteActionHandler);
});

export default ivyEclipseCopyPasteModule;
57 changes: 57 additions & 0 deletions integration/eclipse/src/delete/delete.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/********************************************************************************
* Copyright (c) 2020-2021 EclipseSource and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/
import {
Action,
DeleteElementOperation,
EditorContextService,
IActionDispatcher,
IActionHandler,
TYPES,
ViewerOptions
} from '@eclipse-glsp/client';
import { inject, injectable } from 'inversify';

export class InvokeDeleteAction implements Action {
static KIND = 'invoke-delete';
readonly kind = InvokeDeleteAction.KIND;
}

export function isInvokeDeleteAction(action: Action): action is InvokeDeleteAction {
return action.kind === InvokeDeleteAction.KIND;
}

@injectable()
export class IvyInvokeDeleteActionHandler implements IActionHandler {
@inject(TYPES.IActionDispatcher) protected actionDispatcher: IActionDispatcher;
@inject(EditorContextService) protected editorContext: EditorContextService;
@inject(TYPES.ViewerOptions) protected viewerOptions: ViewerOptions;

handle(action: Action): void {
if (isInvokeDeleteAction(action)) {
this.handleDelete();
}
}

handleDelete(): void {
if (this.isDiagramActive()) {
this.actionDispatcher.dispatch(DeleteElementOperation.create(this.editorContext.get().selectedElementIds));
}
}

protected isDiagramActive(): boolean {
return document.activeElement?.parentElement?.id === this.viewerOptions.baseDiv;
}
}
25 changes: 25 additions & 0 deletions integration/eclipse/src/delete/di.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/********************************************************************************
* Copyright (c) 2020 EclipseSource and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/
import { configureActionHandler } from '@eclipse-glsp/client';
import { ContainerModule } from 'inversify';

import { IvyInvokeDeleteActionHandler } from './delete';

const ivyEclipseDeleteModule = new ContainerModule((bind, _unbind, isBound) => {
configureActionHandler({ bind, isBound }, 'invoke-delete', IvyInvokeDeleteActionHandler);
});

export default ivyEclipseDeleteModule;
7 changes: 4 additions & 3 deletions integration/eclipse/src/di.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,18 @@ import { ConsoleLogger, LogLevel, TYPES } from '@eclipse-glsp/client';
import ivyOpenQuickOutlineModule from './open-quick-outline/di.config';
import ivyToolBarModule from './tool-bar/di.config';
import { IvyEclipseGLSPDiagramServer } from './ivy-eclipse-glsp-diagram-server';
import { eclipseCopyPasteModule, eclipseDeleteModule } from '@eclipse-glsp/ide';
import { ivyInscriptionModule } from '@axonivy/process-editor-inscription';
import ivyEclipseCopyPasteModule from './copy-paste/di.config';
import ivyEclipseDeleteModule from './delete/di.config';

export default function createContainer(widgetId: string): Container {
const container = createIvyDiagramContainer(widgetId);
container.bind(TYPES.ModelSource).to(IvyEclipseGLSPDiagramServer).inSingletonScope();
container.rebind(TYPES.ILogger).to(ConsoleLogger).inSingletonScope();
container.rebind(TYPES.LogLevel).toConstantValue(LogLevel.warn);

container.load(eclipseCopyPasteModule);
container.load(eclipseDeleteModule);
container.load(ivyEclipseCopyPasteModule);
container.load(ivyEclipseDeleteModule);
container.load(ivyOpenInscriptionModule);
container.load(ivyOpenDecoratorBrowserModule);
container.load(ivyOpenQuickOutlineModule);
Expand Down

0 comments on commit f35ce0f

Please sign in to comment.