Merge branch 'development' of
[Mograsim.git] / plugins / net.mograsim.plugin.core / src / net / mograsim / plugin / tables / mi / InstructionView.java
index 3af070f..aa1df4d 100644 (file)
@@ -1,39 +1,46 @@
 package net.mograsim.plugin.tables.mi;
 
+import java.io.BufferedReader;
 import java.io.File;
+import java.io.FileReader;
 import java.io.IOException;
-import java.util.Optional;
+import java.util.Arrays;
 
+import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.jface.viewers.ColumnLabelProvider;
 import org.eclipse.jface.viewers.EditingSupport;
 import org.eclipse.jface.viewers.TableViewerColumn;
 import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.FileDialog;
 import org.eclipse.swt.widgets.Table;
 import org.eclipse.swt.widgets.TableColumn;
-import org.eclipse.ui.part.ViewPart;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.IPathEditorInput;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.part.EditorPart;
 
-import net.mograsim.machine.Machine;
+import net.mograsim.machine.MemoryObserver;
 import net.mograsim.machine.mi.MicroInstructionDefinition;
 import net.mograsim.machine.mi.MicroInstructionMemory;
 import net.mograsim.machine.mi.MicroInstructionMemoryParseException;
 import net.mograsim.machine.mi.MicroInstructionMemoryParser;
+import net.mograsim.machine.mi.parameters.MnemonicFamily;
 import net.mograsim.machine.mi.parameters.ParameterClassification;
 import net.mograsim.plugin.MachineContext;
-import net.mograsim.plugin.MachineContext.ContextObserver;
 import net.mograsim.plugin.tables.AddressLabelProvider;
 import net.mograsim.plugin.tables.DisplaySettings;
 import net.mograsim.plugin.tables.LazyTableViewer;
 import net.mograsim.plugin.tables.RadixSelector;
-import net.mograsim.plugin.util.DropDownMenu;
-import net.mograsim.plugin.util.DropDownMenu.DropDownEntry;
 
-public class InstructionView extends ViewPart implements ContextObserver
+public class InstructionView extends EditorPart implements MemoryObserver
 {
-       private String saveLoc = null;
        private LazyTableViewer viewer;
        private TableViewerColumn[] columns = new TableViewerColumn[0];
        private MicroInstructionDefinition miDef;
@@ -41,6 +48,8 @@ public class InstructionView extends ViewPart implements ContextObserver
        private DisplaySettings displaySettings;
        private InstructionTableContentProvider provider;
        private int highlighted = 0;
+       private boolean dirty = false;
+       private String machineName;
 
        @SuppressWarnings("unused")
        @Override
@@ -48,12 +57,12 @@ public class InstructionView extends ViewPart implements ContextObserver
        {
                provider = new InstructionTableContentProvider();
                GridLayout layout = new GridLayout(3, false);
-               setupMenuButtons(parent);
+               parent.setLayout(layout);
 
                displaySettings = new DisplaySettings();
                new RadixSelector(parent, displaySettings);
 
-               parent.setLayout(layout);
+               addActivationButton(parent);
                viewer = new LazyTableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER | SWT.VIRTUAL);
 
                Table table = viewer.getTable();
@@ -61,6 +70,7 @@ public class InstructionView extends ViewPart implements ContextObserver
                table.setLinesVisible(true);
                viewer.setUseHashlookup(true);
                viewer.setContentProvider(provider);
+               setViewerInput(memory);
                getSite().setSelectionProvider(viewer);
 
                GridData viewerData = new GridData(GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL | GridData.FILL_BOTH);
@@ -68,59 +78,54 @@ public class InstructionView extends ViewPart implements ContextObserver
                viewer.getTable().setLayoutData(viewerData);
 
                displaySettings.addObserver(() -> viewer.refresh());
-               MachineContext.getInstance().registerObserver(this);
-               setMachine(Optional.ofNullable(MachineContext.getInstance().getMachine()));
        }
 
-       public void highlight(int index)
+       private void addActivationButton(Composite parent)
        {
-               viewer.highlightRow(highlighted, false);
-               viewer.highlightRow(index, true);
-               viewer.getTable().setTopIndex(index);
-       }
-
-       @SuppressWarnings("unused")
-       private void setupMenuButtons(Composite parent)
-       {
-               DropDownEntry open = new DropDownEntry("Open", (e) ->
+               Button activationButton = new Button(parent, SWT.PUSH);
+               activationButton.setText("Set Active");
+               activationButton.addSelectionListener(new SelectionListener()
                {
-                       FileDialog d = new FileDialog(parent.getShell(), SWT.NONE);
-                       d.open();
-                       String filename = d.getFileName();
-                       if (!filename.equals(""))
-                               open(d.getFilterPath() + File.separator + filename);
-               });
 
-               DropDownEntry save = new DropDownEntry("Save", (e) ->
-               {
-                       if (saveLoc == null)
-                               openSaveAsDialog(parent);
-                       save(saveLoc);
-               });
-               DropDownEntry saveAs = new DropDownEntry("SaveAs", (e) ->
-               {
-                       openSaveAsDialog(parent);
-                       save(saveLoc);
+                       @Override
+                       public void widgetSelected(SelectionEvent e)
+                       {
+                               if (e.detail == SWT.PUSH)
+                                       MachineContext.getInstance().getMachine().getMicroInstructionMemory().bind(memory);
+                               // TODO register this in project context
+                       }
+
+                       @Override
+                       public void widgetDefaultSelected(SelectionEvent e)
+                       {
+                               widgetSelected(e);
+                       }
                });
-               new DropDownMenu(parent, "File", open, save, saveAs);
        }
 
-       private void openSaveAsDialog(Composite parent)
+       public void highlight(int index)
        {
-               FileDialog d = new FileDialog(parent.getShell(), SWT.SAVE);
-               d.open();
-               String filename = d.getFileName();
-               if (!filename.equals(""))
-                       saveLoc = d.getFilterPath() + File.separator + filename;
+               viewer.highlightRow(highlighted, false);
+               viewer.highlightRow(index, true);
+               viewer.getTable().setTopIndex(index);
        }
 
        public void bindMicroInstructionMemory(MicroInstructionMemory memory)
        {
-               deleteColumns();
                this.memory = memory;
-               viewer.setInput(memory);
                this.miDef = memory.getDefinition().getMicroInstructionDefinition();
-               createColumns();
+               this.memory.registerObserver(this);
+               setViewerInput(memory);
+       }
+
+       private void setViewerInput(MicroInstructionMemory memory)
+       {
+               if (viewer != null)
+               {
+                       deleteColumns();
+                       viewer.setInput(memory);
+                       createColumns();
+               }
        }
 
        private void deleteColumns()
@@ -134,26 +139,47 @@ public class InstructionView extends ViewPart implements ContextObserver
                int size = miDef.size();
                columns = new TableViewerColumn[size + 1];
 
-               TableViewerColumn col = createTableViewerColumn("Address", 200);
+               TableViewerColumn col = createTableViewerColumn("Address", generateLongestHexStrings(12));
                columns[0] = col;
                col.setLabelProvider(new AddressLabelProvider());
 
-               int bit = 0;
+               int bit = miDef.sizeInBits();
                ParameterClassification[] classes = miDef.getParameterClassifications();
 
                for (int i = 0; i < size; i++)
                {
-                       int startBit = bit;
-                       int endBit = (bit = bit + classes[i].getExpectedBits()) - 1;
+                       int startBit = bit - 1;
+                       int endBit = bit = bit - classes[i].getExpectedBits();
                        String name = startBit == endBit ? Integer.toString(startBit) : startBit + "..." + endBit;
-                       int bounds = 20 + 20 * classes[i].getExpectedBits();
 
-                       col = createTableViewerColumn(name, bounds);
+                       String[] longestPossibleContents;
+                       switch (classes[i].getExpectedType())
+                       {
+                       case INTEGER_IMMEDIATE:
+                               longestPossibleContents = generateLongestHexStrings(classes[i].getExpectedBits());
+                               break;
+                       case BOOLEAN_IMMEDIATE:
+                       case MNEMONIC:
+                               longestPossibleContents = ((MnemonicFamily) classes[i]).getStringValues();
+                               break;
+                       default:
+                               longestPossibleContents = new String[0];
+                               break;
+                       }
+
+                       col = createTableViewerColumn(name, longestPossibleContents);
                        columns[i + 1] = col;
                        createEditingAndLabel(col, miDef, i);
                }
        }
 
+       private static final String[] HEX_DIGITS = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F" };
+
+       private static String[] generateLongestHexStrings(int bitWidth)
+       {
+               return Arrays.stream(HEX_DIGITS).map(s -> "0x" + s.repeat((bitWidth + 3) / 4)).toArray(String[]::new);
+       }
+
        private void createEditingAndLabel(TableViewerColumn col, MicroInstructionDefinition miDef, int index)
        {
                ParameterClassification parameterClassification = miDef.getParameterClassifications()[index];
@@ -182,12 +208,22 @@ public class InstructionView extends ViewPart implements ContextObserver
                col.getColumn().setToolTipText(miDef.getParameterDescription(index).orElse(""));
        }
 
-       private TableViewerColumn createTableViewerColumn(String title, int bound)
+       private TableViewerColumn createTableViewerColumn(String title, String... longestPossibleContents)
        {
                TableViewerColumn viewerColumn = new TableViewerColumn(viewer, SWT.NONE);
                TableColumn column = viewerColumn.getColumn();
+               int maxWidth = 0;
+               for (String s : longestPossibleContents)
+               {
+                       column.setText(s);
+                       column.pack();
+                       if (column.getWidth() > maxWidth)
+                               maxWidth = column.getWidth();
+               }
                column.setText(title);
-               column.setWidth(bound);
+               column.pack();
+               if (column.getWidth() < maxWidth)
+                       column.setWidth(maxWidth);
                column.setResizable(true);
                column.setMoveable(false);
                return viewerColumn;
@@ -195,16 +231,10 @@ public class InstructionView extends ViewPart implements ContextObserver
 
        private void open(String file)
        {
-               if (miDef == null)
-               {
-                       System.err.println("Failed to parse MicroprogrammingMemory from File. No MicroInstructionDefinition assigned.");
-                       return;
-               }
-               try
+               try (BufferedReader bf = new BufferedReader(new FileReader(file)))
                {
-                       MicroInstructionMemoryParser.parseMemory(memory, file);
-                       viewer.refresh();
-                       saveLoc = file;
+                       machineName = bf.readLine();
+                       bindMicroInstructionMemory(MicroInstructionMemoryParser.parseMemory(machineName, bf));
                }
                catch (IOException | MicroInstructionMemoryParseException e)
                {
@@ -217,17 +247,15 @@ public class InstructionView extends ViewPart implements ContextObserver
                if (memory == null)
                {
                        System.err.println("Failed to write MicroprogrammingMemory to File. No MicroprogrammingMemory assigned.");
+                       return;
                }
-               if (saveLoc != null)
+               try
                {
-                       try
-                       {
-                               MicroInstructionMemoryParser.write(memory, file);
-                       }
-                       catch (IOException e)
-                       {
-                               e.printStackTrace();
-                       }
+                       MicroInstructionMemoryParser.write(memory, machineName, file);
+               }
+               catch (IOException e)
+               {
+                       e.printStackTrace();
                }
        }
 
@@ -238,12 +266,69 @@ public class InstructionView extends ViewPart implements ContextObserver
        }
 
        @Override
-       public void setMachine(Optional<Machine> machine)
+       public void doSave(IProgressMonitor progressMonitor)
+       {
+               IEditorInput input = getEditorInput();
+               if (input instanceof IPathEditorInput)
+               {
+                       IPathEditorInput pathInput = (IPathEditorInput) input;
+                       save(pathInput.getPath().toOSString());
+                       setDirty(false);
+               }
+       }
+
+       @Override
+       public void doSaveAs()
        {
-               if (machine.isPresent())
+               openSaveAsDialog();
+       }
+
+       private void openSaveAsDialog()
+       {
+               FileDialog d = new FileDialog(viewer.getTable().getShell(), SWT.SAVE);
+               d.open();
+               String filename = d.getFileName();
+               if (!filename.equals(""))
                {
-                       Machine actualMachine = machine.get();
-                       bindMicroInstructionMemory(actualMachine.getMicroInstructionMemory());
+                       save(d.getFilterPath() + File.separator + filename);
+                       setDirty(false);
                }
        }
+
+       @Override
+       public void init(IEditorSite site, IEditorInput input) throws PartInitException
+       {
+               setSite(site);
+               setInput(input);
+               if (input instanceof IPathEditorInput)
+               {
+                       IPathEditorInput pathInput = (IPathEditorInput) input;
+                       setPartName(pathInput.getName());
+                       open(pathInput.getPath().toOSString());
+               }
+       }
+
+       @Override
+       public boolean isDirty()
+       {
+               return dirty;
+       }
+
+       @Override
+       public boolean isSaveAsAllowed()
+       {
+               return true;
+       }
+
+       @Override
+       public void update(long address)
+       {
+               setDirty(true);
+       }
+
+       private void setDirty(boolean value)
+       {
+               dirty = value;
+               firePropertyChange(PROP_DIRTY);
+       }
 }