1 /*******************************************************************************
2 * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
9 * VTT Technical Research Centre of Finland - initial API and implementation
10 *******************************************************************************/
11 package org.simantics.modeling.ui.modelBrowser.handlers;
13 import gnu.trove.set.hash.THashSet;
15 import java.util.Collections;
16 import java.util.List;
19 import org.eclipse.core.commands.AbstractHandler;
20 import org.eclipse.core.commands.ExecutionEvent;
21 import org.eclipse.core.commands.ExecutionException;
22 import org.eclipse.core.runtime.IProgressMonitor;
23 import org.eclipse.core.runtime.IStatus;
24 import org.eclipse.core.runtime.Status;
25 import org.eclipse.core.runtime.SubMonitor;
26 import org.eclipse.core.runtime.jobs.Job;
27 import org.eclipse.jface.action.IStatusLineManager;
28 import org.eclipse.jface.viewers.ISelection;
29 import org.eclipse.jface.viewers.StructuredSelection;
30 import org.eclipse.swt.dnd.Clipboard;
31 import org.eclipse.swt.dnd.TextTransfer;
32 import org.eclipse.swt.dnd.Transfer;
33 import org.eclipse.swt.widgets.Control;
34 import org.eclipse.swt.widgets.Display;
35 import org.eclipse.swt.widgets.Shell;
36 import org.eclipse.swt.widgets.Tree;
37 import org.eclipse.swt.widgets.TreeItem;
38 import org.eclipse.ui.PlatformUI;
39 import org.eclipse.ui.handlers.HandlerUtil;
40 import org.simantics.Simantics;
41 import org.simantics.browsing.ui.BuiltinKeys;
42 import org.simantics.browsing.ui.GraphExplorer;
43 import org.simantics.browsing.ui.NodeContext;
44 import org.simantics.db.ReadGraph;
45 import org.simantics.db.Resource;
46 import org.simantics.db.common.request.ReadRequest;
47 import org.simantics.db.common.utils.Logger;
48 import org.simantics.db.exception.DatabaseException;
49 import org.simantics.db.layer0.SelectionHints;
50 import org.simantics.db.layer0.adapter.CopyHandler;
51 import org.simantics.db.layer0.util.ClipboardUtils;
52 import org.simantics.db.layer0.util.SimanticsClipboardImpl;
53 import org.simantics.db.layer0.variable.Variable;
54 import org.simantics.ui.utils.ResourceAdaptionUtils;
55 import org.simantics.utils.datastructures.hints.IHintContext;
56 import org.simantics.utils.ui.ISelectionUtils;
57 import org.simantics.utils.ui.SWTUtils;
58 import org.simantics.utils.ui.SWTUtils.ControlFilter;
59 import org.simantics.utils.ui.workbench.WorkbenchUtils;
61 public class StandardCopyHandler extends AbstractHandler {
63 private static IStatusLineManager status;
65 private static List<Variable> getVariables(ISelection selection) {
66 NodeContext context = ISelectionUtils.getSinglePossibleKey(selection, SelectionHints.KEY_MAIN, NodeContext.class);
67 if(context == null) return Collections.emptyList();
68 Object input = context.getConstant(BuiltinKeys.INPUT);
69 IHintContext hints = input instanceof IHintContext ? (IHintContext) input : null;
70 if(hints == null) return Collections.emptyList();
71 Variable var = hints.getHint(SelectionHints.KEY_SELECTION_PROPERTY);
72 if(var == null) return Collections.emptyList();
73 else return Collections.singletonList(var);
76 private boolean copyText(ISelection selection) {
77 if(selection instanceof StructuredSelection) {
78 StructuredSelection sel = (StructuredSelection)selection;
80 Object element = sel.getFirstElement();
81 if(element instanceof String) {
82 setSystemClipboardText((String) element);
90 public Object execute(ExecutionEvent event) throws ExecutionException {
92 status = WorkbenchUtils.getStatusLine( HandlerUtil.getActiveSite(event) );
93 ISelection selection = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService().getSelection();
95 // If the selection is plain text copy it into system clipboard and be happy
96 if(copyText(selection)) return null;
98 formatSelectionToClipboardText(event);
99 final Resource[] rs = ResourceAdaptionUtils.toResources(selection);
100 Job job = new Job("Copy resources") {
102 protected IStatus run(IProgressMonitor monitor) {
103 monitor.beginTask("Copy resources to clipboard", 1);
104 copyResourcesToClipboard(rs, selection, SubMonitor.convert(monitor, 1));
105 return Status.OK_STATUS;
114 public static String copyResourcesToClipboard(final Resource[] rs, ISelection selection, IProgressMonitor monitor) {
116 if(rs == null || rs.length == 0) {
117 // This support was added for copying of properties (variables)
118 final List<Variable> variables = getVariables(selection);
119 if(!variables.isEmpty()) {
120 final SimanticsClipboardImpl builder = new SimanticsClipboardImpl();
121 for(Variable var : variables) {
122 builder.addContent(Collections.singleton(ClipboardUtils.createVariable(Simantics.getSession(), var)), monitor);
124 Simantics.setClipboard(builder);
125 setCopyMessage(builder.getContents().size(), "variable");
128 setCopyMessage(0, "");
133 final SimanticsClipboardImpl builder = new SimanticsClipboardImpl();
134 Simantics.getSession().syncRequest(new ReadRequest() {
136 public void run(ReadGraph graph) throws DatabaseException {
137 for (Resource r : rs) {
138 CopyHandler handler = graph.adapt(r, CopyHandler.class);
139 handler.copyToClipboard(graph, builder, monitor);
143 Simantics.setClipboard(builder);
144 setCopyMessage(builder.getContents().size(), "resource");
145 } catch (DatabaseException e) {
146 Logger.defaultLogError(e);
152 private static void setCopyMessage(int count, String elementName) {
154 setStatus("Copied " + count + " " + elementName + "s to clipboard");
156 setStatus("Copied " + elementName + " to clipboard");
158 setStatus("Nothing to copy.");
161 private static void setStatus(String message) {
162 if (status != null) {
164 PlatformUI.getWorkbench().getDisplay(),
165 () -> status.setMessage(message));
169 private boolean formatSelectionToClipboardText(ExecutionEvent event) {
170 Shell shell = HandlerUtil.getActiveShell(event);
171 Tree tree = shell == null ? null : tryGetExplorer(shell.getDisplay().getFocusControl());
175 TreeItem[] selection = tree.getSelection();
176 if (selection.length == 0)
179 StringBuilder sb = format(selection, new StringBuilder());
180 if (sb.length() > 0) {
181 setSystemClipboardText(sb.toString());
187 private static StringBuilder format(TreeItem[] selection, StringBuilder sb) {
188 Set<TreeItem> items = new THashSet<TreeItem>(selection.length);
189 for (TreeItem item : selection)
191 for (TreeItem item : selection) {
192 int cc = item.getParent().getColumnCount();
193 int indent = indentLevel(item, items);
194 for (int i = 0; i < indent; ++i)
196 boolean first = true;
197 for (int c = 0; c < cc; ++c) {
198 String ct = item.getText(c);
210 private static int indentLevel(TreeItem item, Set<TreeItem> items) {
211 TreeItem p = item.getParentItem();
212 for (int i = 1; ; p = p.getParentItem()) {
215 if (items.contains(p))
220 private static Tree tryGetExplorer(Control control) {
221 return SWTUtils.tryGetObject(control, new ControlFilter<Tree>() {
223 public Tree accept(Control control) {
224 if (!control.isDisposed()
225 && control instanceof Tree
226 && control.getData(GraphExplorer.KEY_GRAPH_EXPLORER) != null)
227 return (Tree) control;
233 private static void setSystemClipboardText(String text) {
234 Clipboard clipboard = new Clipboard(Display.getCurrent());
235 clipboard.setContents(new Object[]{ text }, new Transfer[] { TextTransfer.getInstance() });