Reordered the disposal of the old resources, because of errors
[Mograsim.git] / plugins / net.mograsim.plugin.core / src / net / mograsim / plugin / editors / SimulationViewEditor.java
1 package net.mograsim.plugin.editors;
2
3 import java.io.ByteArrayInputStream;
4 import java.util.Optional;
5
6 import org.eclipse.core.resources.IFile;
7 import org.eclipse.core.runtime.CoreException;
8 import org.eclipse.core.runtime.IProgressMonitor;
9 import org.eclipse.jface.util.SafeRunnable;
10 import org.eclipse.swt.SWT;
11 import org.eclipse.swt.events.MouseEvent;
12 import org.eclipse.swt.events.MouseTrackListener;
13 import org.eclipse.swt.layout.FillLayout;
14 import org.eclipse.swt.layout.GridData;
15 import org.eclipse.swt.layout.GridLayout;
16 import org.eclipse.swt.widgets.Button;
17 import org.eclipse.swt.widgets.Composite;
18 import org.eclipse.swt.widgets.Display;
19 import org.eclipse.swt.widgets.Label;
20 import org.eclipse.swt.widgets.Slider;
21 import org.eclipse.ui.IEditorInput;
22 import org.eclipse.ui.IEditorSite;
23 import org.eclipse.ui.IFileEditorInput;
24 import org.eclipse.ui.PartInitException;
25 import org.eclipse.ui.part.EditorPart;
26
27 import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasUserInput;
28 import net.mograsim.logic.core.LogicObserver;
29 import net.mograsim.logic.core.components.CoreClock;
30 import net.mograsim.logic.model.LogicExecuter;
31 import net.mograsim.logic.model.LogicUICanvas;
32 import net.mograsim.machine.Machine;
33 import net.mograsim.machine.Memory.MemoryCellModifiedListener;
34 import net.mograsim.machine.mi.AssignableMicroInstructionMemory;
35 import net.mograsim.plugin.nature.MachineContext;
36 import net.mograsim.plugin.nature.ProjectMachineContext;
37 import net.mograsim.plugin.tables.DisplaySettings;
38 import net.mograsim.plugin.tables.mi.ActiveInstructionPreviewContentProvider;
39 import net.mograsim.plugin.tables.mi.InstructionTable;
40
41 //TODO what if we open multiple editors?
42 //TODO actually save / load register and latch states
43 public class SimulationViewEditor extends EditorPart
44 {
45         private MachineContext context;
46
47         private LogicExecuter exec;
48         private Machine machine;
49
50         private Composite parent;
51         private Button sbseButton;
52         private Button pauseButton;
53         private Slider simSpeedSlider;
54         private Composite canvasParent;
55         private LogicUICanvas canvas;
56         private InstructionTable instPreview;
57         private Label noMachineLabel;
58
59         private MemoryCellModifiedListener currentRegisteredCellListener;
60         private LogicObserver currentClockObserver;
61
62         @Override
63         public void createPartControl(Composite parent)
64         {
65                 this.parent = parent;
66                 // initialize UI
67                 parent.setLayout(new GridLayout());
68
69                 noMachineLabel = new Label(parent, SWT.NONE);
70                 noMachineLabel.setText("No machine present...");// TODO internationalize?
71                 addSimulationControlWidgets(parent);
72                 canvasParent = new Composite(parent, SWT.NONE);
73                 canvasParent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
74                 canvasParent.setLayout(new FillLayout());
75                 addInstructionPreviewControlWidgets(parent);
76                 recreateContextDependentControls();
77         }
78
79         private void recreateContextDependentControls()
80         {
81                 if (parent == null)
82                         // createPartControls has not been called yet
83                         return;
84
85                 double offX;
86                 double offY;
87                 double zoom;
88                 if (exec != null)
89                         exec.stopLiveExecution();
90                 if (machine != null)
91                 {
92                         machine.getMicroInstructionMemory().deregisterCellModifiedListener(currentRegisteredCellListener);
93                         machine.getClock().deregisterObserver(currentClockObserver);
94                 }
95                 if (canvas != null)
96                 {
97                         offX = canvas.getOffX();
98                         offY = canvas.getOffY();
99                         zoom = canvas.getZoom();
100                         canvas.dispose();
101                 } else
102                 {
103                         offX = 0;
104                         offY = 0;
105                         zoom = -1;
106                 }
107
108                 Optional<Machine> machineOptional;
109                 if (context != null && (machineOptional = context.getActiveMachine()).isPresent())
110                 {
111                         noMachineLabel.setVisible(false);
112                         sbseButton.setEnabled(true);
113                         pauseButton.setEnabled(true);
114                         simSpeedSlider.setEnabled(true);
115
116                         machine = machineOptional.get();
117                         canvas = new LogicUICanvas(canvasParent, SWT.NONE, machine.getModel());
118                         ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(canvas);
119                         userInput.buttonDrag = 3;
120                         userInput.buttonZoom = 2;
121                         userInput.enableUserInput();
122                         if (zoom > 0)
123                         {
124                                 canvas.moveTo(offX, offY, zoom);
125                                 canvas.commitTransform();
126                         }
127
128                         AssignableMicroInstructionMemory mIMemory = machine.getMicroInstructionMemory();
129                         instPreview.bindMicroInstructionMemory(mIMemory);
130                         currentRegisteredCellListener = a -> instPreview.refresh();
131                         mIMemory.registerCellModifiedListener(currentRegisteredCellListener);
132
133                         canvasParent.layout();
134
135                         // initialize executer
136                         exec = new LogicExecuter(machine.getTimeline());
137                         exec.startLiveExecution();
138                 } else
139                 {
140                         noMachineLabel.setVisible(true);
141                         sbseButton.setEnabled(false);
142                         pauseButton.setEnabled(false);
143                         simSpeedSlider.setEnabled(false);
144                 }
145         }
146
147         private void addSimulationControlWidgets(Composite parent)
148         {
149                 Composite c = new Composite(parent, SWT.NONE);
150                 c.setLayout(new GridLayout(7, false));
151
152                 sbseButton = new Button(c, SWT.CHECK);
153                 pauseButton = new Button(c, SWT.TOGGLE);
154                 currentClockObserver = o ->
155                 {
156                         if (((CoreClock) o).isOn())
157                         {
158                                 exec.pauseLiveExecution();
159                                 if (!pauseButton.isDisposed())
160                                         Display.getDefault().asyncExec(() ->
161                                         {
162                                                 if (!pauseButton.isDisposed())
163                                                         pauseButton.setSelection(false);
164                                                 setPauseText(pauseButton, false);
165                                         });
166                         }
167                 };
168
169                 sbseButton.setText("Step by step execution");
170                 sbseButton.addListener(SWT.Selection, e ->
171                 {
172                         CoreClock cl = machine.getClock();
173                         if (sbseButton.getSelection())
174                                 cl.registerObserver(currentClockObserver);
175                         else
176                                 cl.deregisterObserver(currentClockObserver);
177                 });
178                 sbseButton.setSelection(false);
179
180                 pauseButton.setSelection(true);
181                 setPauseText(pauseButton, false);
182
183                 pauseButton.addListener(SWT.Selection, e ->
184                 {
185                         setPauseText(pauseButton, false);
186                         if (pauseButton.getSelection())
187                         {
188                                 exec.unpauseLiveExecution();
189                         } else
190                         {
191                                 exec.pauseLiveExecution();
192                         }
193                 });
194                 pauseButton.addMouseTrackListener(new MouseTrackListener()
195                 {
196                         @Override
197                         public void mouseHover(MouseEvent e)
198                         {
199                                 // nothing
200                         }
201
202                         @Override
203                         public void mouseExit(MouseEvent e)
204                         {
205                                 setPauseText(pauseButton, false);
206                         }
207
208                         @Override
209                         public void mouseEnter(MouseEvent e)
210                         {
211                                 setPauseText(pauseButton, true);
212                         }
213                 });
214
215                 Label speedLabel = new Label(c, SWT.NONE);
216                 speedLabel.setText("Simulation Speed: ");
217
218                 simSpeedSlider = new Slider(c, SWT.NONE);
219                 simSpeedSlider.setMinimum(1);
220                 simSpeedSlider.setMaximum(100 + simSpeedSlider.getThumb());
221                 simSpeedSlider.setIncrement(1);
222
223                 Label speedPercentageLabel = new Label(c, SWT.NONE);
224                 speedPercentageLabel.setText("100%");
225
226                 simSpeedSlider.addListener(SWT.Selection, e ->
227                 {
228                         int selection = simSpeedSlider.getSelection();
229                         speedPercentageLabel.setText(selection + "%");
230
231                         exec.setSpeedPercentage(simSpeedSlider.getSelection());
232                 });
233                 simSpeedSlider.setSelection(100);
234
235                 c.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.FILL_HORIZONTAL));
236                 c.pack();
237         }
238
239         private void addInstructionPreviewControlWidgets(Composite parent)
240         {
241                 instPreview = new InstructionTable(parent, new DisplaySettings());
242                 instPreview.getTableViewer().getTable().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
243                 instPreview.setContentProvider(new ActiveInstructionPreviewContentProvider(instPreview.getTableViewer()));
244         }
245
246         private static void setPauseText(Button pauseButton, boolean hovered)
247         {
248                 if (hovered)
249                         if (pauseButton.getSelection())
250                                 pauseButton.setText("Pause?");
251                         else
252                                 pauseButton.setText("Resume?");
253                 else if (pauseButton.getSelection())
254                         pauseButton.setText("Running");
255                 else
256                         pauseButton.setText("Paused");
257         }
258
259         @Override
260         public void init(IEditorSite site, IEditorInput input) throws PartInitException
261         {
262                 if (input instanceof IFileEditorInput)
263                 {
264                         IFileEditorInput fileInput = (IFileEditorInput) input;
265                         context = ProjectMachineContext.getMachineContextOf(fileInput.getFile().getProject());
266                         context.registerObserver(m -> recreateContextDependentControls());
267                         recreateContextDependentControls();
268
269                         setPartName(fileInput.getName());
270                         open(fileInput.getFile());
271                 } else
272                         throw new IllegalArgumentException("SimulationViewEditor can only be used with Files");
273
274                 setSite(site);
275                 setInput(input);
276         }
277
278         @Override
279         public void doSave(IProgressMonitor monitor)
280         {
281                 IEditorInput input = getEditorInput();
282                 if (input instanceof IFileEditorInput)
283                         SafeRunnable.getRunner().run(() -> save(((IFileEditorInput) input).getFile(), monitor));
284                 else
285                         throw new IllegalArgumentException("SimulationViewEditor can only be used with Files");
286         }
287
288         private void save(IFile file, IProgressMonitor monitor) throws CoreException
289         {
290                 file.setContents(new ByteArrayInputStream("actual contents will go here".getBytes()), 0, monitor);
291         }
292
293         private void open(IFile file)
294         {
295                 // do nothing yet
296         }
297
298         @Override
299         public void doSaveAs()
300         {
301                 throw new UnsupportedOperationException();
302         }
303
304         @Override
305         public boolean isDirty()
306         {
307                 return false;
308         }
309
310         @Override
311         public boolean isSaveAsAllowed()
312         {
313                 return false;
314         }
315
316         @Override
317         public void setFocus()
318         {
319                 canvas.setFocus();
320         }
321
322         @Override
323         public void dispose()
324         {
325                 exec.stopLiveExecution();
326                 super.dispose();
327         }
328 }