]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/modelBrowser/handlers/StandardCopyHandler.java
Removed trailing newline from clipboard text
[simantics/platform.git] / bundles / org.simantics.modeling.ui / src / org / simantics / modeling / ui / modelBrowser / handlers / StandardCopyHandler.java
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
7  *
8  * Contributors:
9  *     VTT Technical Research Centre of Finland - initial API and implementation
10  *******************************************************************************/
11 package org.simantics.modeling.ui.modelBrowser.handlers;
12
13 import gnu.trove.set.hash.THashSet;
14
15 import java.util.Collections;
16 import java.util.List;
17 import java.util.Set;
18
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.jface.action.IStatusLineManager;
23 import org.eclipse.jface.viewers.ISelection;
24 import org.eclipse.jface.viewers.StructuredSelection;
25 import org.eclipse.swt.dnd.Clipboard;
26 import org.eclipse.swt.dnd.TextTransfer;
27 import org.eclipse.swt.dnd.Transfer;
28 import org.eclipse.swt.widgets.Control;
29 import org.eclipse.swt.widgets.Display;
30 import org.eclipse.swt.widgets.Shell;
31 import org.eclipse.swt.widgets.Tree;
32 import org.eclipse.swt.widgets.TreeItem;
33 import org.eclipse.ui.PlatformUI;
34 import org.eclipse.ui.handlers.HandlerUtil;
35 import org.simantics.Simantics;
36 import org.simantics.browsing.ui.BuiltinKeys;
37 import org.simantics.browsing.ui.GraphExplorer;
38 import org.simantics.browsing.ui.NodeContext;
39 import org.simantics.db.ReadGraph;
40 import org.simantics.db.Resource;
41 import org.simantics.db.common.request.ReadRequest;
42 import org.simantics.db.common.utils.Logger;
43 import org.simantics.db.exception.DatabaseException;
44 import org.simantics.db.layer0.SelectionHints;
45 import org.simantics.db.layer0.adapter.CopyHandler;
46 import org.simantics.db.layer0.util.ClipboardUtils;
47 import org.simantics.db.layer0.util.SimanticsClipboardImpl;
48 import org.simantics.db.layer0.variable.Variable;
49 import org.simantics.ui.utils.ResourceAdaptionUtils;
50 import org.simantics.utils.datastructures.hints.IHintContext;
51 import org.simantics.utils.ui.ISelectionUtils;
52 import org.simantics.utils.ui.SWTUtils;
53 import org.simantics.utils.ui.SWTUtils.ControlFilter;
54 import org.simantics.utils.ui.workbench.WorkbenchUtils;
55
56 public class StandardCopyHandler extends AbstractHandler {
57
58     private static IStatusLineManager status;
59
60     private static List<Variable> getVariables(ISelection selection) {
61         NodeContext context = ISelectionUtils.getSinglePossibleKey(selection, SelectionHints.KEY_MAIN, NodeContext.class);
62         if(context == null) return Collections.emptyList();
63         Object input = context.getConstant(BuiltinKeys.INPUT);
64         IHintContext hints = input instanceof IHintContext ? (IHintContext) input : null;
65         if(hints == null) return Collections.emptyList();
66         Variable var = hints.getHint(SelectionHints.KEY_SELECTION_PROPERTY);
67         if(var == null) return Collections.emptyList();
68         else return Collections.singletonList(var);
69     }
70
71     private boolean copyText(ISelection selection) {
72         if(selection instanceof StructuredSelection) {
73                 StructuredSelection sel = (StructuredSelection)selection;
74                 if(sel.size() == 1) {
75                         Object element = sel.getFirstElement();
76                         if(element instanceof String) {
77                                 setSystemClipboardText((String) element);
78                         }
79                 }
80         }
81         return false;
82     }
83     
84     @Override
85     public Object execute(ExecutionEvent event) throws ExecutionException {
86         
87         status = WorkbenchUtils.getStatusLine( HandlerUtil.getActiveSite(event) );
88         ISelection selection = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService().getSelection();
89         
90         // If the selection is plain text copy it into system clipboard and be happy
91         if(copyText(selection)) return null;
92
93         formatSelectionToClipboardText(event);
94
95         final Resource[] rs = ResourceAdaptionUtils.toResources(selection);
96         copyResourcesToClipboard(rs, selection);
97         return null;
98     }
99     
100     public static String copyResourcesToClipboard(final Resource[] rs, ISelection selection) {
101         
102         if(rs == null || rs.length == 0) {
103             // This support was added for copying of properties (variables)
104             final List<Variable> variables = getVariables(selection);
105             if(!variables.isEmpty()) {
106                 final SimanticsClipboardImpl builder = new SimanticsClipboardImpl();
107                 for(Variable var : variables) {
108                     builder.addContent(Collections.singleton(ClipboardUtils.createVariable(Simantics.getSession(), var)));
109                 }
110                 Simantics.setClipboard(builder);
111                 setCopyMessage(builder.getContents().size(), "variable");
112                 return null;
113             }
114             setCopyMessage(0, "");
115             return null;
116         }
117
118         try {
119             final SimanticsClipboardImpl builder = new SimanticsClipboardImpl();
120             Simantics.getSession().syncRequest(new ReadRequest() {
121                 @Override
122                 public void run(ReadGraph graph) throws DatabaseException {
123                     for (Resource r : rs) {
124                         CopyHandler handler = graph.adapt(r, CopyHandler.class);
125                         handler.copyToClipboard(graph, builder);
126                     }
127                 }
128             });
129             Simantics.setClipboard(builder);
130             setCopyMessage(builder.getContents().size(), "resource");
131         } catch (DatabaseException e) {
132             Logger.defaultLogError(e);
133         }
134
135         return null;
136     }
137
138     private static void setCopyMessage(int count, String elementName) {
139         if (count > 1)
140             setStatus("Copied " + count + " " + elementName + "s to clipboard");
141         else if (count == 1)
142             setStatus("Copied " + elementName + " to clipboard");
143         else
144             setStatus("Nothing to copy.");
145     }
146
147     private static void setStatus(String message) {
148         if (status != null)
149             status.setMessage(message);
150     }
151
152     private boolean formatSelectionToClipboardText(ExecutionEvent event) {
153         Shell shell = HandlerUtil.getActiveShell(event);
154         Tree tree = shell == null ? null : tryGetExplorer(shell.getDisplay().getFocusControl());
155         if (tree == null)
156             return false;
157
158         TreeItem[] selection = tree.getSelection();
159         if (selection.length == 0)
160             return false;
161
162         StringBuilder sb = format(selection, new StringBuilder());
163         if (sb.length() > 0) {
164             setSystemClipboardText(sb.toString());
165             return true;
166         }
167         return false;
168     }
169
170     private static StringBuilder format(TreeItem[] selection, StringBuilder sb) {
171         Set<TreeItem> items = new THashSet<TreeItem>(selection.length);
172         for (TreeItem item : selection)
173             items.add(item);
174         boolean firstRow = true;
175         for (TreeItem item : selection) {
176             if (!firstRow)
177                 sb.append('\n');
178             firstRow = false;
179             int cc = item.getParent().getColumnCount();
180             int indent = indentLevel(item, items);
181             for (int i = 0; i < indent; ++i)
182                 sb.append('\t');
183             boolean firstColumn = true;
184             for (int c = 0; c < cc; ++c) {
185                 String ct = item.getText(c);
186                 if (!firstColumn)
187                     sb.append('\t');
188                 firstColumn = false;
189                 sb.append(ct);
190             }
191         }
192         return sb;
193     }
194
195     private static int indentLevel(TreeItem item, Set<TreeItem> items) {
196         TreeItem p = item.getParentItem();
197         for (int i = 1; ; p = p.getParentItem()) {
198             if (p == null)
199                 return 0;
200             if (items.contains(p))
201                 return i;
202         }
203     }
204
205     private static Tree tryGetExplorer(Control control) {
206         return SWTUtils.tryGetObject(control, new ControlFilter<Tree>() {
207             @Override
208             public Tree accept(Control control) {
209                 if (!control.isDisposed()
210                         && control instanceof Tree
211                         && control.getData(GraphExplorer.KEY_GRAPH_EXPLORER) != null)
212                     return (Tree) control;
213                 return null;
214             }
215         });
216     }
217
218     private static void setSystemClipboardText(String text) {
219         Clipboard clipboard = new Clipboard(Display.getCurrent());
220         clipboard.setContents(new Object[]{ text }, new Transfer[] { TextTransfer.getInstance() });
221         clipboard.dispose();
222     }
223
224 }