1 package org.simantics.scl.ui.console;
3 import java.nio.file.Files;
4 import java.nio.file.Path;
5 import java.nio.file.Paths;
6 import java.util.ArrayList;
7 import java.util.Arrays;
10 import org.eclipse.core.runtime.Platform;
11 import org.eclipse.core.runtime.preferences.InstanceScope;
12 import org.eclipse.jface.action.Action;
13 import org.eclipse.jface.action.IToolBarManager;
14 import org.eclipse.jface.dialogs.Dialog;
15 import org.eclipse.jface.preference.IPersistentPreferenceStore;
16 import org.eclipse.swt.SWT;
17 import org.eclipse.swt.dnd.DND;
18 import org.eclipse.swt.dnd.DropTarget;
19 import org.eclipse.swt.dnd.DropTargetAdapter;
20 import org.eclipse.swt.dnd.DropTargetEvent;
21 import org.eclipse.swt.dnd.FileTransfer;
22 import org.eclipse.swt.dnd.Transfer;
23 import org.eclipse.swt.widgets.Composite;
24 import org.eclipse.ui.part.ViewPart;
25 import org.eclipse.ui.preferences.ScopedPreferenceStore;
26 import org.simantics.scl.compiler.commands.CommandSessionImportEntry;
27 import org.simantics.scl.compiler.commands.SCLConsoleListener;
28 import org.simantics.scl.compiler.testing.TestRunnable;
29 import org.simantics.scl.osgi.internal.TestUtils;
30 import org.simantics.scl.ui.Activator;
31 import org.simantics.scl.ui.imports.internal.ManageImportsDialog;
32 import org.simantics.scl.ui.tests.SCLTestsDialog;
34 public class SCLConsoleView extends ViewPart {
36 public static final String PLUGIN_ID = "org.simantics.scl.ui";
37 public static final String IMPORTS = "imports";
38 public static final String SEPARATOR = ";";
39 public static final String DISABLED_TAG = "[DISABLED]";
43 private ArrayList<CommandSessionImportEntry> readImportPreferences() {
44 IPersistentPreferenceStore store = new ScopedPreferenceStore(InstanceScope.INSTANCE, PLUGIN_ID);
45 String importsString = store.getString(IMPORTS);
47 String[] splitted = importsString.split(SEPARATOR);
48 ArrayList<CommandSessionImportEntry> result = new ArrayList<CommandSessionImportEntry>(splitted.length);
49 for(String entryString : splitted) {
50 if(entryString.isEmpty())
52 boolean disabled = false;
53 if(entryString.startsWith(DISABLED_TAG)) {
55 entryString = entryString.substring(DISABLED_TAG.length());
57 String[] parts = entryString.split("=");
58 CommandSessionImportEntry entry;
60 entry = new CommandSessionImportEntry(parts[0], "", true);
62 entry = new CommandSessionImportEntry(parts[1], parts[0], true);
63 entry.disabled = disabled;
69 private void writeImportPreferences(ArrayList<CommandSessionImportEntry> entries) {
70 StringBuilder b = new StringBuilder();
73 for(CommandSessionImportEntry entry : entries)
74 if(entry.persistent) {
80 b.append(DISABLED_TAG);
81 if(!entry.localName.isEmpty()) {
82 b.append(entry.localName);
85 b.append(entry.moduleName);
88 IPersistentPreferenceStore store = new ScopedPreferenceStore(InstanceScope.INSTANCE, PLUGIN_ID);
89 store.putValue(IMPORTS, b.toString());
92 private ArrayList<CommandSessionImportEntry> getCurrentImports() {
93 return console.getSession().getImportEntries();
96 private void setCurrentImports(ArrayList<CommandSessionImportEntry> entries) {
97 console.getSession().setImportEntries(entries);
100 private void manageImports() {
101 ManageImportsDialog dialog = new ManageImportsDialog(
102 getSite().getShell(),
103 getCurrentImports());
104 if(dialog.open() == Dialog.OK) {
105 writeImportPreferences(dialog.getImports());
106 setCurrentImports(dialog.getImports());
110 private void sclTestDialog() {
111 List<TestRunnable> tests = TestUtils.getTests();
112 SCLTestsDialog dialog = new SCLTestsDialog(
113 getSite().getShell(),
115 if(dialog.open() == Dialog.OK) {
116 for(Object result : dialog.getResult()) {
117 TestRunnable test = (TestRunnable) result;
119 // Bit of a haxx solution to get around a deadlock caused by simply
120 // running the test with test.run()
121 console.execute("import \"Commands/Tests\"");
122 console.execute("runByName \"" + test.getName() + "\"");
124 } catch (Exception e) {
132 public void createPartControl(Composite parent) {
133 this.console = new SCLConsole(parent, SWT.NONE);
134 setCurrentImports(readImportPreferences());
136 addScriptDropSupport(console);
138 IToolBarManager toolBarManager = getViewSite().getActionBars().getToolBarManager();
141 final Action interruptAction = new Action("Interrupt current command",
142 Activator.imageDescriptorFromPlugin("org.simantics.scl.ui", "icons/stop.png")) {
145 console.interruptCurrentCommands();
148 interruptAction.setDisabledImageDescriptor(
149 Activator.imageDescriptorFromPlugin("org.simantics.scl.ui", "icons/stop_disabled.png"));
150 interruptAction.setEnabled(false);
151 toolBarManager.add(interruptAction);
153 // Clear console action
154 final Action clearAction = new Action("Clear console",
155 Activator.imageDescriptorFromPlugin("org.simantics.scl.ui", "icons/clear_console.png")) {
162 clearAction.setDisabledImageDescriptor(
163 Activator.imageDescriptorFromPlugin("org.simantics.scl.ui", "icons/clear_console_disabled.png"));
164 clearAction.setEnabled(false);
165 toolBarManager.add(clearAction);
166 console.addListener(new SCLConsoleListener() {
168 public void startedExecution() {
169 interruptAction.setEnabled(true);
172 public void finishedExecution() {
173 interruptAction.setEnabled(false);
176 public void consoleIsNotEmptyAnymore() {
177 clearAction.setEnabled(true);
182 toolBarManager.add(new Action("Refresh modules",
183 Activator.imageDescriptorFromPlugin("org.simantics.scl.ui", "icons/arrow_refresh.png")) {
186 console.getSession().getModuleRepository().getSourceRepository().checkUpdates();
187 console.getSession().updateRuntimeEnvironment(true);
188 console.appendOutput("refresh completed\n", console.greenColor, null);
191 toolBarManager.add(new Action("Manage imports",
192 Activator.imageDescriptorFromPlugin("org.simantics.scl.ui", "icons/configure_imports.png")) {
199 // Show action for running SCL tests if in development mode
200 if (Platform.inDevelopmentMode()) {
201 toolBarManager.add(new Action("Run tests",
202 Activator.imageDescriptorFromPlugin("org.simantics.scl.ui", "icons/run_tests.png")) {
210 toolBarManager.update(true);
213 private class ScriptRunningDropTarget extends DropTargetAdapter {
215 public void dragEnter(DropTargetEvent event) {
216 if (event.detail == DND.DROP_DEFAULT) {
217 event.detail = DND.DROP_LINK;
222 public void dragOperationChanged(DropTargetEvent event) {
223 if (event.detail == DND.DROP_DEFAULT) {
224 event.detail = DND.DROP_LINK;
228 public void drop(DropTargetEvent event) {
229 if (FileTransfer.getInstance().isSupportedType(event.currentDataType)) {
230 String[] files = ((String[]) event.data).clone();
231 // Sort files by name to allow deterministic multi-file drop
233 for (String file : files) {
234 Path p = Paths.get(file).toAbsolutePath();
235 if (isScriptFile(p)) {
236 console.execute("runFromFile \"" + p.toString().replace('\\', '/') + "\"");
242 private boolean isScriptFile(Path p) {
243 return Files.isRegularFile(p)
244 //&& p.toString().toLowerCase().endsWith(".scl")
249 private void addScriptDropSupport(SCLConsole console) {
250 DropTarget target = new DropTarget(console.getOutputWidget(), DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK | DND.DROP_DEFAULT);
251 target.setTransfer(new Transfer[] { FileTransfer.getInstance() });
252 target.addDropListener(new ScriptRunningDropTarget());
256 public void setFocus() {
261 public void dispose() {