1 package net.mograsim.plugin.editors;
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.math.BigInteger;
6 import java.util.Collection;
7 import java.util.HashSet;
9 import org.eclipse.core.resources.IFile;
10 import org.eclipse.core.runtime.CoreException;
11 import org.eclipse.core.runtime.IProgressMonitor;
12 import org.eclipse.jface.util.IPropertyChangeListener;
13 import org.eclipse.jface.util.SafeRunnable;
14 import org.eclipse.jface.viewers.TableViewerColumn;
15 import org.eclipse.swt.SWT;
16 import org.eclipse.swt.graphics.Font;
17 import org.eclipse.swt.layout.GridData;
18 import org.eclipse.swt.layout.GridLayout;
19 import org.eclipse.swt.widgets.Button;
20 import org.eclipse.swt.widgets.Composite;
21 import org.eclipse.swt.widgets.Control;
22 import org.eclipse.swt.widgets.Label;
23 import org.eclipse.swt.widgets.Table;
24 import org.eclipse.swt.widgets.TableColumn;
25 import org.eclipse.swt.widgets.Text;
26 import org.eclipse.ui.IEditorInput;
27 import org.eclipse.ui.IEditorSite;
28 import org.eclipse.ui.IFileEditorInput;
29 import org.eclipse.ui.PartInitException;
30 import org.eclipse.ui.part.EditorPart;
31 import org.eclipse.ui.themes.ITheme;
32 import org.eclipse.ui.themes.IThemeManager;
34 import net.mograsim.machine.MainMemory;
35 import net.mograsim.machine.MainMemoryDefinition;
36 import net.mograsim.machine.Memory.MemoryCellModifiedListener;
37 import net.mograsim.machine.mi.MicroInstructionMemoryParseException;
38 import net.mograsim.machine.standard.memory.MainMemoryParser;
39 import net.mograsim.plugin.asm.AsmNumberUtil;
40 import net.mograsim.plugin.nature.MachineContext;
41 import net.mograsim.plugin.nature.ProjectMachineContext;
42 import net.mograsim.plugin.tables.AddressLabelProvider;
43 import net.mograsim.plugin.tables.DisplaySettings;
44 import net.mograsim.plugin.tables.LazyTableViewer;
45 import net.mograsim.plugin.tables.NumberColumnLabelProvider;
46 import net.mograsim.plugin.tables.RadixSelector;
47 import net.mograsim.plugin.tables.memory.MemoryCellEditingSupport;
48 import net.mograsim.plugin.tables.memory.MemoryTableContentProvider;
49 import net.mograsim.plugin.tables.memory.MemoryTableRow;
50 import net.mograsim.plugin.tables.memory.NumberVerifyListener;
52 public class MemoryEditor extends EditorPart
54 private MachineContext context;
56 private MainMemory memory;
58 private LazyTableViewer viewer;
59 private MemoryTableContentProvider provider;
60 private DisplaySettings displaySettings;
62 private Collection<Control> fontDependent = new HashSet<>();
64 private boolean dirty;
66 private final MemoryCellModifiedListener memListener;
68 private final static String font = "net.mograsim.plugin.memory.table_font";
69 private IPropertyChangeListener fontChangeListener;
73 memListener = this::cellModified;
77 public void createPartControl(Composite parent)
79 provider = new MemoryTableContentProvider();
80 displaySettings = new DisplaySettings();
82 parent.setLayout(new GridLayout(7, false));
87 displaySettings.addObserver(() -> viewer.refresh());
90 @SuppressWarnings("unused") // RadixSelector and exceptions
91 private void createHeader(Composite parent)
93 Label fromLabel = new Label(parent, SWT.NONE);
94 fromLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
95 fromLabel.setText("Address: ");
97 Text fromText = new Text(parent, SWT.BORDER);
98 fromText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
99 NumberVerifyListener vl = new NumberVerifyListener();
100 fromText.addVerifyListener(vl);
101 fromText.setText("0");
102 fromText.addModifyListener(e ->
106 provider.setLowerBound(AsmNumberUtil.valueOf(fromText.getText()).longValue());
109 catch (NumberFormatException x)
111 // Nothing to do here
114 Label amountLabel = new Label(parent, SWT.NONE);
115 amountLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
116 amountLabel.setText("Number of cells: ");
117 Text amountText = new Text(parent, SWT.BORDER);
118 amountText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
119 amountText.addVerifyListener(vl);
120 amountText.addModifyListener(e ->
124 if (provider != null)
125 provider.setAmount(AsmNumberUtil.valueOf(amountText.getText()).intValue());
129 catch (NumberFormatException x)
131 // Nothing to do here
134 amountText.setText("100");// do this after registering the ModifyListener
135 new RadixSelector(parent, displaySettings);
137 addActivationButton(parent);
140 private void addActivationButton(Composite parent)
142 Button activationButton = new Button(parent, SWT.PUSH);
143 activationButton.setText("Set Active");
144 activationButton.addListener(SWT.Selection, e -> context.getActiveMachine().ifPresent(m -> m.getMainMemory().bind(memory)));
147 private void createViewer(Composite parent)
149 viewer = new LazyTableViewer(parent, SWT.FULL_SELECTION | SWT.BORDER | SWT.VIRTUAL);
150 fontDependent.add(viewer.getTable());
152 Table table = viewer.getTable();
153 table.setHeaderVisible(true);
154 table.setLinesVisible(true);
155 viewer.setUseHashlookup(true);
156 viewer.setContentProvider(provider);
157 getSite().setSelectionProvider(viewer);// TODO what does this do?
158 viewer.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 7, 1));
160 IThemeManager themeManager = getSite().getWorkbenchWindow().getWorkbench().getThemeManager();
161 themeManager.addPropertyChangeListener(fontChangeListener = (e) ->
163 if (IThemeManager.CHANGE_CURRENT_THEME.equals(e.getProperty()) || font.equals(e.getProperty()))
165 updateFont(themeManager.getCurrentTheme());
169 updateFont(themeManager.getCurrentTheme());
172 viewer.setInput(memory);
175 private void updateFont(ITheme theme)
177 Font newFont = theme.getFontRegistry().get(font);
178 // TODO: This is a quick fix! Still have to figure out why the CellEditors do not get the appropriate Font on their own
179 fontDependent.forEach(c -> c.setFont(newFont));
182 private void createColumns()
184 TableViewerColumn addrCol = createTableViewerColumn("Address", 100);
185 addrCol.setLabelProvider(new AddressLabelProvider());
187 TableViewerColumn dataCol = createTableViewerColumn("Data", 100);
188 dataCol.setLabelProvider(new NumberColumnLabelProvider(displaySettings)
191 public BigInteger getAsBigInteger(Object element)
193 MemoryTableRow row = (MemoryTableRow) element;
194 return row.getMemory().getCellAsBigInteger(row.address);
198 public int getBitLength(Object element)
200 return ((MemoryTableRow) element).getMemory().getDefinition().getCellWidth();
203 MemoryCellEditingSupport eSup;
204 dataCol.setEditingSupport(eSup = new MemoryCellEditingSupport(viewer, displaySettings));
205 fontDependent.add(eSup.getCellEditorControl());
208 private TableViewerColumn createTableViewerColumn(String title, int width)
210 TableViewerColumn viewerColumn = new TableViewerColumn(viewer, SWT.NONE);
211 TableColumn column = viewerColumn.getColumn();
212 column.setText(title);
213 column.setWidth(width);
214 column.setResizable(true);
215 column.setMoveable(false);
220 public void init(IEditorSite site, IEditorInput input) throws PartInitException
222 if (input instanceof IFileEditorInput)
224 IFileEditorInput fileInput = (IFileEditorInput) input;
225 context = ProjectMachineContext.getMachineContextOf(fileInput.getFile().getProject());
226 context.activateMachine();
228 setPartName(fileInput.getName());
231 open(fileInput.getFile());
235 throw new PartInitException("Failed to read input!", e);
238 throw new IllegalArgumentException("MemoryEditor can only be used with Files");
245 public void doSave(IProgressMonitor monitor)
247 IEditorInput input = getEditorInput();
248 if (input instanceof IFileEditorInput)
249 SafeRunnable.getRunner().run(() -> save(((IFileEditorInput) input).getFile(), monitor));
252 private void save(IFile file, IProgressMonitor monitor) throws CoreException, IOException
256 throw new MicroInstructionMemoryParseException("Failed to write MainMemory to File. No MainMemory assigned.");
258 try (InputStream toWrite = MainMemoryParser.write(memory))
260 file.setContents(toWrite, 0, monitor);
265 private void open(IFile file) throws IOException, CoreException
267 MainMemoryDefinition memDef = context.getMachineDefinition()
268 .orElseThrow(() -> new MicroInstructionMemoryParseException("No MachineDefinition assigned!")).getMainMemoryDefinition();
269 memory = MainMemoryParser.parseMemory(memDef, file.getContents());
270 memory.registerCellModifiedListener(memListener);
272 viewer.setInput(memory);
275 private void cellModified(@SuppressWarnings("unused") long address)
280 private void setDirty(boolean newDirty)
283 firePropertyChange(PROP_DIRTY);
287 public void doSaveAs()
289 throw new UnsupportedOperationException();
293 public boolean isDirty()
299 public boolean isSaveAsAllowed()
305 public void setFocus()
307 viewer.getTable().setFocus();
311 public void dispose()
313 getSite().getWorkbenchWindow().getWorkbench().getThemeManager().removePropertyChangeListener(fontChangeListener);
315 memory.deregisterCellModifiedListener(memListener);