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.IAction;
14 import org.eclipse.jface.action.IMenuCreator;
15 import org.eclipse.jface.action.IToolBarManager;
16 import org.eclipse.jface.dialogs.Dialog;
17 import org.eclipse.jface.preference.IPersistentPreferenceStore;
18 import org.eclipse.swt.SWT;
19 import org.eclipse.swt.dnd.DND;
20 import org.eclipse.swt.dnd.DropTarget;
21 import org.eclipse.swt.dnd.DropTargetAdapter;
22 import org.eclipse.swt.dnd.DropTargetEvent;
23 import org.eclipse.swt.dnd.FileTransfer;
24 import org.eclipse.swt.dnd.Transfer;
25 import org.eclipse.swt.events.SelectionAdapter;
26 import org.eclipse.swt.events.SelectionEvent;
27 import org.eclipse.swt.widgets.Composite;
28 import org.eclipse.swt.widgets.Control;
29 import org.eclipse.swt.widgets.Menu;
30 import org.eclipse.swt.widgets.MenuItem;
31 import org.eclipse.ui.part.ViewPart;
32 import org.eclipse.ui.preferences.ScopedPreferenceStore;
33 import org.simantics.scl.compiler.commands.CommandSessionImportEntry;
34 import org.simantics.scl.compiler.commands.SCLConsoleListener;
35 import org.simantics.scl.compiler.module.repository.UpdateListener;
36 import org.simantics.scl.compiler.testing.TestRunnable;
37 import org.simantics.scl.osgi.internal.TestUtils;
38 import org.simantics.scl.ui.Activator;
39 import org.simantics.scl.ui.imports.internal.ManageImportsDialog;
40 import org.simantics.scl.ui.tests.SCLTestsDialog;
42 public class SCLConsoleView extends ViewPart {
44 public static final String PLUGIN_ID = "org.simantics.scl.ui";
45 public static final String IMPORTS = "imports";
46 public static final String REFRESH_AUTOMATICALLY = "refresh-automatically";
47 public static final String SEPARATOR = ";";
48 public static final String DISABLED_TAG = "[DISABLED]";
50 IPersistentPreferenceStore store;
52 boolean refreshAutomatically = false;
53 MenuItem refreshAutomaticallyItem;
55 private ArrayList<CommandSessionImportEntry> readImportPreferences() {
56 String importsString = store.getString(IMPORTS);
58 String[] splitted = importsString.split(SEPARATOR);
59 ArrayList<CommandSessionImportEntry> result = new ArrayList<CommandSessionImportEntry>(splitted.length);
60 for(String entryString : splitted) {
61 if(entryString.isEmpty())
63 boolean disabled = false;
64 if(entryString.startsWith(DISABLED_TAG)) {
66 entryString = entryString.substring(DISABLED_TAG.length());
68 String[] parts = entryString.split("=");
69 CommandSessionImportEntry entry;
71 entry = new CommandSessionImportEntry(parts[0], "", true);
73 entry = new CommandSessionImportEntry(parts[1], parts[0], true);
74 entry.disabled = disabled;
80 private void writeImportPreferences(ArrayList<CommandSessionImportEntry> entries) {
81 StringBuilder b = new StringBuilder();
84 for(CommandSessionImportEntry entry : entries)
85 if(entry.persistent) {
91 b.append(DISABLED_TAG);
92 if(!entry.localName.isEmpty()) {
93 b.append(entry.localName);
96 b.append(entry.moduleName);
99 IPersistentPreferenceStore store = new ScopedPreferenceStore(InstanceScope.INSTANCE, PLUGIN_ID);
100 store.setValue(IMPORTS, b.toString());
103 private ArrayList<CommandSessionImportEntry> getCurrentImports() {
104 return console.getSession().getImportEntries();
107 private void setCurrentImports(ArrayList<CommandSessionImportEntry> entries) {
108 console.getSession().setImportEntries(entries);
111 private void manageImports() {
112 ManageImportsDialog dialog = new ManageImportsDialog(
113 getSite().getShell(),
114 getCurrentImports());
115 if(dialog.open() == Dialog.OK) {
116 writeImportPreferences(dialog.getImports());
117 setCurrentImports(dialog.getImports());
121 private void sclTestDialog() {
122 List<TestRunnable> tests = TestUtils.getTests();
123 SCLTestsDialog dialog = new SCLTestsDialog(
124 getSite().getShell(),
126 if(dialog.open() == Dialog.OK) {
127 for(Object result : dialog.getResult()) {
128 TestRunnable test = (TestRunnable) result;
130 // Bit of a haxx solution to get around a deadlock caused by simply
131 // running the test with test.run()
132 console.execute("import \"Commands/Tests\"");
133 console.execute("runByName \"" + test.getName() + "\"");
135 } catch (Exception e) {
142 private UpdateListener dependencyListener = new UpdateListener() {
144 public void notifyAboutUpdate() {
145 if(refreshAutomatically)
146 console.getSession().updateRuntimeEnvironment(true);
150 private void setRefreshAutomatically(boolean refreshAutomatically, boolean refreshAlso) {
151 this.refreshAutomatically = refreshAutomatically;
152 if(refreshAutomaticallyItem != null)
153 refreshAutomaticallyItem.setSelection(refreshAutomatically);
155 store.setValue(REFRESH_AUTOMATICALLY, refreshAutomatically);
157 if(refreshAutomatically) {
158 console.getSession().setDependenciesListener(dependencyListener);
160 console.getSession().updateRuntimeEnvironment(true);
163 console.getSession().setDependenciesListener(null);
164 dependencyListener.stopListening();
169 public void createPartControl(Composite parent) {
170 store = new ScopedPreferenceStore(InstanceScope.INSTANCE, PLUGIN_ID);
171 this.console = new SCLConsole(parent, SWT.NONE);
173 setRefreshAutomatically(store.getBoolean(REFRESH_AUTOMATICALLY), false);
174 setCurrentImports(readImportPreferences());
176 addScriptDropSupport(console);
178 IToolBarManager toolBarManager = getViewSite().getActionBars().getToolBarManager();
181 final Action interruptAction = new Action("Interrupt current command",
182 Activator.imageDescriptorFromPlugin("org.simantics.scl.ui", "icons/stop.png")) {
185 console.interruptCurrentCommands();
188 interruptAction.setDisabledImageDescriptor(
189 Activator.imageDescriptorFromPlugin("org.simantics.scl.ui", "icons/stop_disabled.png"));
190 interruptAction.setEnabled(false);
191 toolBarManager.add(interruptAction);
193 // Clear console action
194 final Action clearAction = new Action("Clear console",
195 Activator.imageDescriptorFromPlugin("org.simantics.scl.ui", "icons/clear_console.png")) {
202 clearAction.setDisabledImageDescriptor(
203 Activator.imageDescriptorFromPlugin("org.simantics.scl.ui", "icons/clear_console_disabled.png"));
204 clearAction.setEnabled(false);
205 toolBarManager.add(clearAction);
206 console.addListener(new SCLConsoleListener() {
208 public void startedExecution() {
209 interruptAction.setEnabled(true);
212 public void finishedExecution() {
213 interruptAction.setEnabled(false);
216 public void consoleIsNotEmptyAnymore() {
217 clearAction.setEnabled(true);
222 toolBarManager.add(new Action("Refresh modules", IAction.AS_DROP_DOWN_MENU) {
224 setImageDescriptor(Activator.imageDescriptorFromPlugin("org.simantics.scl.ui", "icons/arrow_refresh.png"));
225 setMenuCreator(new IMenuCreator() {
228 public Menu getMenu(Menu parent) {
229 throw new UnsupportedOperationException();
233 public Menu getMenu(Control parent) {
235 menu = new Menu(parent);
236 refreshAutomaticallyItem = new MenuItem(menu, SWT.CHECK);
237 refreshAutomaticallyItem.setText("Refresh automatically");
238 refreshAutomaticallyItem.setSelection(refreshAutomatically);
239 refreshAutomaticallyItem.addSelectionListener(new SelectionAdapter() {
241 public void widgetSelected(SelectionEvent e) {
242 setRefreshAutomatically(!refreshAutomatically, true);
250 public void dispose() {
258 console.getSession().getModuleRepository().getSourceRepository().checkUpdates();
259 console.getSession().updateRuntimeEnvironment(true);
260 console.appendOutput("refresh completed\n", console.greenColor, null);
263 toolBarManager.add(new Action("Manage imports",
264 Activator.imageDescriptorFromPlugin("org.simantics.scl.ui", "icons/configure_imports.png")) {
271 // Show action for running SCL tests if in development mode
272 if (Platform.inDevelopmentMode()) {
273 toolBarManager.add(new Action("Run tests",
274 Activator.imageDescriptorFromPlugin("org.simantics.scl.ui", "icons/run_tests.png")) {
282 toolBarManager.update(true);
285 private class ScriptRunningDropTarget extends DropTargetAdapter {
287 public void dragEnter(DropTargetEvent event) {
288 if (event.detail == DND.DROP_DEFAULT) {
289 event.detail = DND.DROP_LINK;
294 public void dragOperationChanged(DropTargetEvent event) {
295 if (event.detail == DND.DROP_DEFAULT) {
296 event.detail = DND.DROP_LINK;
300 public void drop(DropTargetEvent event) {
301 if (FileTransfer.getInstance().isSupportedType(event.currentDataType)) {
302 String[] files = ((String[]) event.data).clone();
303 // Sort files by name to allow deterministic multi-file drop
305 for (String file : files) {
306 Path p = Paths.get(file).toAbsolutePath();
307 if (isScriptFile(p)) {
308 console.execute("runFromFile \"" + p.toString().replace('\\', '/') + "\"");
314 private boolean isScriptFile(Path p) {
315 return Files.isRegularFile(p)
316 //&& p.toString().toLowerCase().endsWith(".scl")
321 private void addScriptDropSupport(SCLConsole console) {
322 DropTarget target = new DropTarget(console.getOutputWidget(), DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK | DND.DROP_DEFAULT);
323 target.setTransfer(new Transfer[] { FileTransfer.getInstance() });
324 target.addDropListener(new ScriptRunningDropTarget());
328 public void setFocus() {
333 public void dispose() {