Non-default values are now highlighted in the InstructionTable
[Mograsim.git] / plugins / net.mograsim.plugin.core / src / net / mograsim / plugin / tables / mi / InstructionView.java
1 package net.mograsim.plugin.tables.mi;
2
3 import java.io.IOException;
4 import java.io.InputStream;
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.swt.SWT;
10 import org.eclipse.swt.layout.GridData;
11 import org.eclipse.swt.layout.GridLayout;
12 import org.eclipse.swt.widgets.Button;
13 import org.eclipse.swt.widgets.Composite;
14 import org.eclipse.swt.widgets.Display;
15 import org.eclipse.ui.IEditorInput;
16 import org.eclipse.ui.IEditorSite;
17 import org.eclipse.ui.IFileEditorInput;
18 import org.eclipse.ui.PartInitException;
19 import org.eclipse.ui.part.EditorPart;
20
21 import net.mograsim.machine.Memory.MemoryCellModifiedListener;
22 import net.mograsim.machine.mi.AssignableMicroInstructionMemory.MIMemoryReassignedListener;
23 import net.mograsim.machine.mi.MicroInstructionMemory;
24 import net.mograsim.machine.mi.MicroInstructionMemory.ActiveMicroInstructionChangedListener;
25 import net.mograsim.machine.mi.MicroInstructionMemoryParseException;
26 import net.mograsim.machine.mi.MicroInstructionMemoryParser;
27 import net.mograsim.plugin.nature.MachineContext;
28 import net.mograsim.plugin.nature.ProjectMachineContext;
29 import net.mograsim.plugin.tables.DisplaySettings;
30 import net.mograsim.plugin.tables.LazyTableViewer;
31 import net.mograsim.plugin.tables.RadixSelector;
32
33 public class InstructionView extends EditorPart implements MemoryCellModifiedListener, ActiveMicroInstructionChangedListener
34 {
35         private InstructionTableContentProvider provider;
36         private int highlighted = 0;
37         private boolean dirty = false;
38         private MicroInstructionMemory memory;
39         private InstructionTable table;
40         private MachineContext context;
41
42         @SuppressWarnings("unused")
43         @Override
44         public void createPartControl(Composite parent)
45         {
46                 provider = new InstructionTableLazyContentProvider();
47                 GridLayout layout = new GridLayout(3, false);
48                 parent.setLayout(layout);
49
50                 DisplaySettings displaySettings = new DisplaySettings();
51                 new RadixSelector(parent, displaySettings);
52
53                 addActivationButton(parent);
54                 table = new InstructionTable(parent, displaySettings, getSite().getWorkbenchWindow().getWorkbench().getThemeManager());
55                 table.setContentProvider(provider);
56                 table.bindMicroInstructionMemory(memory);
57
58                 GridData viewerData = new GridData(GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL | GridData.FILL_BOTH);
59                 viewerData.horizontalSpan = 3;
60                 table.getTableViewer().getTable().setLayoutData(viewerData);
61         }
62
63         public void highlight(int index)
64         {
65                 Display.getDefault().asyncExec(() ->
66                 {
67                         LazyTableViewer viewer = table.getTableViewer();
68                         viewer.highlightRow(highlighted, false);
69                         highlighted = index;
70                         if (index != -1)
71                         {
72                                 viewer.highlightRow(index, true);
73                                 viewer.getTable()
74                                                 .showItem(viewer.getTable().getItem(Math.min((int) memory.getDefinition().getMaximalAddress(), index + 2)));
75                                 viewer.getTable().showItem(viewer.getTable().getItem(index));
76                         }
77                 });
78         }
79
80         private void addActivationButton(Composite parent)
81         {
82                 Button activationButton = new Button(parent, SWT.PUSH);
83                 activationButton.setText("Set Active");
84                 activationButton.addListener(SWT.Selection, e -> context.getActiveMachine().ifPresent(m ->
85                 {
86                         // clear highlighting if the memory is reassigned
87                         MIMemoryReassignedListener memReassignedListener = n ->
88                         {
89                                 if (n != memory)
90                                         highlight(-1);
91                         };
92                         m.getMicroInstructionMemory().registerMemoryReassignedListener(memReassignedListener);
93                         // clear highlighting if the active machine changes
94                         context.addActiveMachineListener(n ->
95                         {
96                                 if (n.isEmpty() || n.get() != m)
97                                 {
98                                         highlight(-1);
99                                         m.getMicroInstructionMemory().deregisterMemoryReassignedListener(memReassignedListener);
100                                 }
101                         });
102                         m.getMicroInstructionMemory().bind(memory);
103                 }));
104         }
105
106         public void bindMicroInstructionMemory(MicroInstructionMemory memory)
107         {
108                 if (this.memory != null)
109                 {
110                         this.memory.deregisterCellModifiedListener(this);
111                         this.memory.deregisterActiveMicroInstructionChangedListener(this);
112                 }
113                 this.memory = memory;
114                 if (memory != null)
115                 {
116                         this.memory.registerCellModifiedListener(this);
117                         this.memory.registerActiveMicroInstructionChangedListener(this);
118                 }
119                 if (table != null)
120                         table.bindMicroInstructionMemory(memory);
121         }
122
123         private void open(IFile file) throws IOException, MicroInstructionMemoryParseException, CoreException
124         {
125                 bindMicroInstructionMemory(MicroInstructionMemoryParser.parseMemory(
126                                 context.getMachineDefinition().orElseThrow(() -> new MicroInstructionMemoryParseException("No MachineDefinition assigned!"))
127                                                 .getMicroInstructionMemoryDefinition(),
128                                 file.getContents()));
129         }
130
131         private void save(IFile file, IProgressMonitor progressMonitor) throws IOException, CoreException, MicroInstructionMemoryParseException
132         {
133                 if (memory == null)
134                 {
135                         throw new MicroInstructionMemoryParseException(
136                                         "Failed to write MicroprogrammingMemory to File. No MicroprogrammingMemory assigned.");
137                 }
138                 try (InputStream toWrite = MicroInstructionMemoryParser.write(memory))
139                 {
140                         file.setContents(toWrite, 0, progressMonitor);
141                 }
142         }
143
144         @Override
145         public void setFocus()
146         {
147                 table.getTableViewer().getControl().setFocus();
148         }
149
150         @Override
151         public void doSave(IProgressMonitor progressMonitor)
152         {
153                 IEditorInput input = getEditorInput();
154                 if (input instanceof IFileEditorInput)
155                 {
156                         IFileEditorInput pathInput = (IFileEditorInput) input;
157                         try
158                         {
159                                 save(pathInput.getFile(), progressMonitor);
160                                 setDirty(false);
161                         }
162                         catch (Exception e)
163                         {
164                                 e.printStackTrace();
165                                 progressMonitor.setCanceled(true);
166                         }
167                 } else
168                         progressMonitor.setCanceled(true);
169         }
170
171         @Override
172         public void doSaveAs()
173         {
174 //              openSaveAsDialog();
175         }
176
177 //      private void openSaveAsDialog()
178 //      {
179 //              FileDialog d = new FileDialog(table.getTableViewer().getTable().getShell(), SWT.SAVE);
180 //              d.open();
181 //              String filename = d.getFileName();
182 //              if (!filename.equals(""))
183 //              {
184 //                      save(d.getFilterPath() + File.separator + filename);
185 //                      setDirty(false);
186 //              }
187 //      }
188
189         @Override
190         public void init(IEditorSite site, IEditorInput input) throws PartInitException
191         {
192                 setSite(site);
193                 setInput(input);
194                 try
195                 {
196                         if (input instanceof IFileEditorInput)
197                         {
198                                 IFileEditorInput fileInput = (IFileEditorInput) input;
199                                 context = ProjectMachineContext.getMachineContextOf(fileInput.getFile().getProject());
200                                 context.activateMachine();
201                                 setPartName(fileInput.getName());
202                                 open(fileInput.getFile());
203                         }
204                 }
205                 catch (Exception e)
206                 {
207                         throw new PartInitException("Failed to read input!", e);
208                 }
209
210         }
211
212         @Override
213         public boolean isDirty()
214         {
215                 return dirty;
216         }
217
218         @Override
219         public boolean isSaveAsAllowed()
220         {
221                 return false;
222         }
223
224         @Override
225         public void update(long address)
226         {
227                 setDirty(true);
228                 table.refresh();
229         }
230
231         private void setDirty(boolean value)
232         {
233                 dirty = value;
234                 firePropertyChange(PROP_DIRTY);
235         }
236
237         @Override
238         public void activeMicroInstructionChanged(long address)
239         {
240                 highlight((int) (address - memory.getDefinition().getMinimalAddress()));
241         }
242
243         @Override
244         public void dispose()
245         {
246                 table.dispose();
247                 super.dispose();
248         }
249 }