Instruction Table Editing Support now uses the correct font
[Mograsim.git] / plugins / net.mograsim.plugin.core / src / net / mograsim / plugin / tables / mi / InstructionTable.java
1 package net.mograsim.plugin.tables.mi;
2
3 import java.util.Arrays;
4
5 import org.eclipse.jface.viewers.ColumnLabelProvider;
6 import org.eclipse.jface.viewers.ColumnViewerEditor;
7 import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent;
8 import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy;
9 import org.eclipse.jface.viewers.EditingSupport;
10 import org.eclipse.jface.viewers.FocusCellOwnerDrawHighlighter;
11 import org.eclipse.jface.viewers.TableViewerColumn;
12 import org.eclipse.jface.viewers.TableViewerEditor;
13 import org.eclipse.jface.viewers.TableViewerFocusCellManager;
14 import org.eclipse.swt.SWT;
15 import org.eclipse.swt.graphics.Color;
16 import org.eclipse.swt.graphics.Font;
17 import org.eclipse.swt.layout.GridData;
18 import org.eclipse.swt.widgets.Composite;
19 import org.eclipse.swt.widgets.Display;
20 import org.eclipse.swt.widgets.Table;
21 import org.eclipse.swt.widgets.TableColumn;
22 import org.eclipse.ui.themes.IThemeManager;
23
24 import net.mograsim.machine.mi.MicroInstructionDefinition;
25 import net.mograsim.machine.mi.MicroInstructionMemory;
26 import net.mograsim.machine.mi.parameters.MnemonicFamily;
27 import net.mograsim.machine.mi.parameters.ParameterClassification;
28 import net.mograsim.plugin.tables.AddressLabelProvider;
29 import net.mograsim.plugin.tables.DisplaySettings;
30 import net.mograsim.plugin.tables.LazyTableViewer;
31
32 public class InstructionTable
33 {
34         protected final DisplaySettings displaySettings;
35         protected final LazyTableViewer viewer;
36         private TableViewerColumn[] columns = new TableViewerColumn[0];
37         private MicroInstructionDefinition miDef;
38         private MicroInstructionMemory memory;
39         private InstructionTableContentProvider provider;
40         private final RowHighlighter highlighter;
41         private final FontAndColorHelper cProv;
42
43         public InstructionTable(Composite parent, DisplaySettings displaySettings, IThemeManager themeManager)
44         {
45                 viewer = new LazyTableViewer(parent, SWT.FULL_SELECTION | SWT.BORDER | SWT.VIRTUAL);
46                 this.displaySettings = displaySettings;
47                 this.cProv = new FontAndColorHelper(viewer, themeManager);
48                 this.highlighter = new RowHighlighter(viewer, cProv);
49
50                 Table table = viewer.getTable();
51                 table.setHeaderVisible(true);
52                 table.setLinesVisible(true);
53                 viewer.setUseHashlookup(true);
54                 table.addDisposeListener(e -> dispose());
55
56                 TableViewerFocusCellManager focusCellManager = new TableViewerFocusCellManager(viewer, new FocusCellOwnerDrawHighlighter(viewer));
57
58                 ColumnViewerEditorActivationStrategy actSupport = new ColumnViewerEditorActivationStrategy(viewer)
59                 {
60                         @Override
61                         protected boolean isEditorActivationEvent(ColumnViewerEditorActivationEvent event)
62                         {
63                                 return event.eventType == ColumnViewerEditorActivationEvent.TRAVERSAL
64                                                 || event.eventType == ColumnViewerEditorActivationEvent.MOUSE_DOUBLE_CLICK_SELECTION
65                                                 || (event.eventType == ColumnViewerEditorActivationEvent.KEY_PRESSED && event.keyCode == SWT.CR)
66                                                 || event.eventType == ColumnViewerEditorActivationEvent.PROGRAMMATIC;
67                         }
68                 };
69                 int features = ColumnViewerEditor.TABBING_HORIZONTAL | ColumnViewerEditor.TABBING_MOVE_TO_ROW_NEIGHBOR
70                                 | ColumnViewerEditor.TABBING_VERTICAL | ColumnViewerEditor.KEYBOARD_ACTIVATION;
71                 TableViewerEditor.create(viewer, focusCellManager, actSupport, features);
72
73                 GridData viewerData = new GridData(GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL | GridData.FILL_BOTH);
74                 viewerData.horizontalSpan = 3;
75                 viewer.getTable().setLayoutData(viewerData);
76
77                 displaySettings.addObserver(() -> viewer.refresh());
78         }
79
80         private void deleteColumns()
81         {
82                 for (TableViewerColumn col : columns)
83                         col.getColumn().dispose();
84         }
85
86         private void createColumns()
87         {
88                 viewer.getTable().setVisible(false);
89
90                 int size = miDef.size();
91                 columns = new TableViewerColumn[size + 1];
92
93                 TableViewerColumn col = createTableViewerColumn("Address");
94                 columns[0] = col;
95                 col.setLabelProvider(new AddressLabelProvider()
96                 {
97                         @Override
98                         public Color getBackground(Object element)
99                         {
100                                 return cProv.getBackground(element, -1);
101                         }
102
103                         @Override
104                         public Color getForeground(Object element)
105                         {
106                                 return cProv.getForeground(element, -1);
107                         }
108
109                         @Override
110                         public Font getFont(Object element)
111                         {
112                                 return cProv.getFont(element, -1);
113                         }
114                 });
115
116                 String[] columnTitles = new String[size];
117
118                 int bit = miDef.sizeInBits();
119                 ParameterClassification[] classes = miDef.getParameterClassifications();
120
121                 for (int i = 0; i < size; i++)
122                 {
123                         int startBit = bit - 1;
124                         int endBit = bit = bit - classes[i].getExpectedBits();
125                         String columnTitle = calculateColumnTitle(startBit, endBit);
126                         columnTitles[i] = columnTitle;
127                         col = createTableViewerColumn(columnTitle);
128                         columns[i + 1] = col;
129                         createEditingAndLabel(col, miDef, i);
130                 }
131
132                 calculateOptimalColumnSize(0, "Address", generateLongestHexStrings(12));
133
134                 for (int i = 0; i < size; i++)
135                 {
136                         String[] longestPossibleContents;
137                         switch (classes[i].getExpectedType())
138                         {
139                         case INTEGER_IMMEDIATE:
140                                 longestPossibleContents = generateLongestHexStrings(classes[i].getExpectedBits());
141                                 break;
142                         case BOOLEAN_IMMEDIATE:
143                         case MNEMONIC:
144                                 longestPossibleContents = ((MnemonicFamily) classes[i]).getStringValues();
145                                 break;
146                         default:
147                                 longestPossibleContents = new String[0];
148                                 break;
149                         }
150                         calculateOptimalColumnSize(i + 1, columnTitles[i], longestPossibleContents);
151                 }
152
153                 viewer.getTable().setVisible(true);
154         }
155
156         private static String calculateColumnTitle(int startBit, int endBit)
157         {
158                 return startBit == endBit ? Integer.toString(startBit) : startBit + "..." + endBit;
159         }
160
161         public void bindMicroInstructionMemory(MicroInstructionMemory memory)
162         {
163                 this.memory = memory;
164                 if (memory != null)
165                 {
166                         this.miDef = memory.getDefinition().getMicroInstructionDefinition();
167                         setViewerInput(memory);
168                 }
169         }
170
171         private static final String[] HEX_DIGITS = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F" };
172
173         private static String[] generateLongestHexStrings(int bitWidth)
174         {
175                 return Arrays.stream(HEX_DIGITS).map(s -> "0x" + s.repeat((bitWidth + 3) / 4)).toArray(String[]::new);
176         }
177
178         private void createEditingAndLabel(TableViewerColumn col, MicroInstructionDefinition miDef, int index)
179         {
180                 ParameterClassification parameterClassification = miDef.getParameterClassifications()[index];
181                 EditingSupport support;
182                 ColumnLabelProvider provider;
183                 switch (parameterClassification.getExpectedType())
184                 {
185                 case BOOLEAN_IMMEDIATE:
186                         support = new BooleanEditingSupport(viewer, miDef, index);
187                         provider = new ParameterLabelProvider(cProv, index);
188                         break;
189                 case INTEGER_IMMEDIATE:
190                         support = new IntegerEditingSupport(viewer, miDef, index, displaySettings, this.provider);
191                         provider = new IntegerColumnLabelProvider(displaySettings, cProv, index);
192                         break;
193                 case MNEMONIC:
194                         support = new MnemonicEditingSupport(viewer, miDef, index, this.provider);
195                         provider = new ParameterLabelProvider(cProv, index);
196                         break;
197                 default:
198                         throw new IllegalStateException(
199                                         "Unable to create EditingSupport for unknown ParameterType " + parameterClassification.getExpectedType());
200                 }
201                 col.setEditingSupport(support);
202                 col.setLabelProvider(provider);
203                 col.getColumn().setToolTipText(miDef.getParameterDescription(index).orElse(""));
204         }
205
206         private TableViewerColumn createTableViewerColumn(String title)
207         {
208                 TableViewerColumn viewerColumn = new TableViewerColumn(viewer, SWT.NONE);
209                 TableColumn column = viewerColumn.getColumn();
210                 column.setText(title);
211                 column.setResizable(true);
212                 column.setMoveable(false);
213                 return viewerColumn;
214         }
215
216         private void calculateOptimalColumnSize(int i, String title, String... longestPossibleContents)
217         {
218                 TableColumn column = viewer.getTable().getColumn(i);
219                 int maxWidth = 0;
220                 for (String s : longestPossibleContents)
221                 {
222                         column.setText(s);
223                         column.pack();
224                         if (column.getWidth() > maxWidth)
225                                 maxWidth = column.getWidth();
226                 }
227                 column.setText(title);
228                 column.pack();
229                 if (column.getWidth() < maxWidth)
230                         column.setWidth(maxWidth);
231         }
232
233         public LazyTableViewer getTableViewer()
234         {
235                 return viewer;
236         }
237
238         public MicroInstructionMemory getMicroInstructionMemory()
239         {
240                 return memory;
241         }
242
243         public void setContentProvider(InstructionTableContentProvider provider)
244         {
245                 this.provider = provider;
246                 viewer.setContentProvider(provider);
247         }
248
249         private void setViewerInput(MicroInstructionMemory memory)
250         {
251                 deleteColumns();
252                 viewer.setInput(memory);
253                 createColumns();
254         }
255
256         public void refresh()
257         {
258                 Display.getDefault().asyncExec(() -> viewer.refresh());
259         }
260
261         private void dispose()
262         {
263                 cProv.dispose();
264                 viewer.getTable().dispose();
265         }
266
267         public void highlight(int row)
268         {
269                 highlighter.highlight(row);
270         }
271 }