/* MemoryViewer.java (c) 2009-2015 Edward Swartz All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html */ package v9t9.gui.client.swt.shells.debugger; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Timer; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.resource.FontDescriptor; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.CellEditor; import org.eclipse.jface.viewers.ComboViewer; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.ILazyContentProvider; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TextCellEditor; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StackLayout; import org.eclipse.swt.events.ControlAdapter; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.ControlListener; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.MenuDetectEvent; import org.eclipse.swt.events.MenuDetectListener; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseTrackAdapter; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.layout.RowLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.TableItem; import org.ejs.gui.common.FontUtils; import org.ejs.gui.common.SwtUtils; import v9t9.common.cpu.IBreakpoint; import v9t9.common.cpu.IBreakpointListener; import v9t9.common.machine.IMachine; import v9t9.common.memory.IMemory; import v9t9.common.memory.IMemoryDomain; import v9t9.common.memory.IMemoryEntry; import v9t9.common.memory.IMemoryListener; import v9t9.gui.EmulatorGuiData; import v9t9.gui.client.swt.shells.debugger.CpuViewer.ICpuTracker; import v9t9.gui.common.IMemoryDecoder; import v9t9.gui.common.IMemoryDecoderProvider; import ejs.base.properties.IPersistable; import ejs.base.settings.ISettingSection; import ejs.base.utils.HexUtils; import ejs.base.utils.Pair; /** * @author Ed * */ public class MemoryViewer extends Composite implements IPersistable, ICpuTracker, IBreakpointListener { final int BYTES = 16; private StackLayout tableLayout; private TableViewer byteTableViewer; private TableViewer decodedTableViewer; private ComboViewer entryViewer; private final IMemory memory; protected MemoryRange currentRange; private Button refreshButton; protected boolean autoRefresh; private Button pinButton; private boolean pinMemory; private Button decodeButton; private boolean decodeMemory; private Button filterButton; private boolean filterMemory; private Font tableFont; private IMemoryDecoderProvider memoryDecoderProvider; private ByteMemoryLabelProvider byteMemoryLabelProvider; private IMemoryDecoder memoryDecoder; private Composite tableComposite; private DecodedMemoryContentProvider decodedContentProvider; private ByteMemoryContentProvider byteContentViewer; public MemoryViewer(Composite parent, int style, final IMachine machine, IMemoryDecoderProvider decoderProvider, final Timer timer) { super(parent, style); this.memory = machine.getMemory(); memoryDecoderProvider = decoderProvider; setLayout(new GridLayout(2, false)); createUI(); memory.addListener(new IMemoryListener() { public void physicalMemoryMapChanged(IMemoryEntry entry) { Display.getDefault().asyncExec(new Runnable() { public void run() { if (isDisposed()) return; refreshEntryCombo(); } }); } public void logicalMemoryMapChanged(IMemoryEntry entry) { } }); machine.getExecutor().getBreakpoints().addListener(MemoryViewer.this); addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { tableFont.dispose(); machine.getExecutor().getBreakpoints().removeListener(MemoryViewer.this); } }); } /* (non-Javadoc) * @see ejs.base.properties.IPersistable#saveState(ejs.base.settings.ISettingSection) */ @Override public void saveState(ISettingSection section) { section.put("Range", currentRange != null ? currentRange.toString() : null); section.put("AutoRefresh", autoRefresh); section.put("PinMemory", pinMemory); section.put("FilterMemory", filterMemory); section.put("DecodeMemory", decodeMemory); TableItem item = byteTableViewer.getTable().getItem(new Point(0, 0)); if (item != null && item.getData() instanceof MemoryRow) { section.put("FirstRowAddr", ((MemoryRow) item.getData()).getAddress()); } // I can't seem to directly query the last row in the visible height of the table, // hence this loop... for (int y = 0; y < 256; y++) { item = byteTableViewer.getTable().getItem(new Point(0, byteTableViewer.getTable().getItemHeight() * y)); if (item != null && item.getData() instanceof MemoryRow) { section.put("LastRowAddr", ((MemoryRow) item.getData()).getAddress()); } else { break; } } } /* (non-Javadoc) * @see ejs.base.properties.IPersistable#loadState(ejs.base.settings.ISettingSection) */ @Override public void loadState(ISettingSection section) { if (section == null) return; String range = section.get("Range"); if (range != null) { currentRange = MemoryRange.fromString(memory, range); } autoRefresh = section.getBoolean("AutoRefresh"); pinMemory = section.getBoolean("PinMemory"); filterMemory = section.getBoolean("FilterMemory"); decodeMemory = section.getBoolean("DecodeMemory"); final int visLoAddr = section.getInt("FirstRowAddr"); final int visHiAddr = section.getInt("LastRowAddr"); if (entryViewer != null) { final long timeout = System.currentTimeMillis() + 1000; final ControlListener resetRangeListener = new ControlAdapter() { /* (non-Javadoc) * @see org.eclipse.swt.events.ControlAdapter#controlResized(org.eclipse.swt.events.ControlEvent) */ @Override public void controlResized(ControlEvent e) { if (System.currentTimeMillis() < timeout) scrollByteViewerToActiveRegion(visLoAddr, visHiAddr); else byteTableViewer.getTable().removeControlListener(this); } }; getDisplay().asyncExec(new Runnable() { public void run() { if (isDisposed()) return; refreshButton.setSelection(autoRefresh); pinButton.setSelection(pinMemory); filterButton.setSelection(filterMemory); decodeButton.setSelection(decodeMemory); // apply filter entryViewer.refresh(); if (currentRange != null) { entryViewer.setSelection(new StructuredSelection(currentRange.getEntry())); changeCurrentRange(currentRange); byteTableViewer.getTable().addControlListener(resetRangeListener); } else { tableLayout.topControl = byteTableViewer.getTable(); } } }); } } protected void scrollByteViewerToActiveRegion(int lowRange, int hiRange) { int row = getMemoryRowIndex(lowRange); int visibleRows = byteTableViewer.getTable().getSize().y / byteTableViewer.getTable().getItemHeight(); int endRow = getMemoryRowIndex(hiRange); Object elementAt; if (false) { if (byteTableViewer.getContentProvider() instanceof ILazyContentProvider) { try { ((ILazyContentProvider)byteTableViewer.getContentProvider()).updateElement(row); } catch (Exception e) { // can throw if it's not gonna be visible } } elementAt = byteTableViewer.getElementAt(row); if (elementAt != null) { byteTableViewer.reveal(elementAt); } } if (visibleRows >= endRow - row) { if (byteTableViewer.getContentProvider() instanceof ILazyContentProvider) { try { ((ILazyContentProvider)byteTableViewer.getContentProvider()).updateElement(endRow); } catch (Exception e) { // can throw if it's not gonna be visible } } elementAt = byteTableViewer.getElementAt(endRow); if (elementAt != null) { byteTableViewer.reveal(elementAt); } } } protected final int getMemoryRowIndex(int addr) { return (addr - currentRange.addr) / BYTES; } protected final int getMemoryColumnIndex(int addr) { return (addr - currentRange.addr) % BYTES; } static class MemoryEntryLabelProvider extends LabelProvider { @Override public String getText(Object element) { IMemoryEntry entry = (IMemoryEntry) element; return entry.getName() + " (" + entry.getDomain().getName() + " >" + HexUtils.toHex4((entry.getAddr() + entry.getAddrOffset())) + ")"; } } protected void createUI() { entryViewer = new ComboViewer(this, SWT.DROP_DOWN | SWT.READ_ONLY | SWT.NO_FOCUS); entryViewer.setContentProvider(new ArrayContentProvider()); entryViewer.setLabelProvider(new MemoryEntryLabelProvider()); entryViewer.setComparator(new ViewerComparator() { @Override public int compare(Viewer viewer, Object e1, Object e2) { if (e1 instanceof IMemoryEntry && e2 instanceof IMemoryEntry) { int diff; IMemoryEntry m1 = (IMemoryEntry) e1; IMemoryEntry m2 = (IMemoryEntry) e2; diff = m1.getDomain().getName().compareTo(m2.getDomain().getName()); if (diff != 0) return diff; diff = m1.getAddr() - m2.getAddr(); return diff; } return super.compare(viewer, e1, e2); } }); entryViewer.setFilters(new ViewerFilter[] { new ViewerFilter() { @Override public boolean select(Viewer viewer, Object parentElement, Object element) { IMemoryEntry entry = (IMemoryEntry) element; if (!entry.hasReadAccess()) return false; if (filterMemory && !entry.hasWriteAccess()) return false; return true; } } }); entryViewer.addSelectionChangedListener(new ISelectionChangedListener() { public void selectionChanged(SelectionChangedEvent event) { Object element = ((IStructuredSelection) event.getSelection()).getFirstElement(); MemoryRange range; if (element instanceof IMemoryEntry) { range = new MemoryRange((IMemoryEntry) element); } else if (element instanceof MemoryRange) { range = (MemoryRange) element; } else { return; } changeCurrentRange(range); } }); Composite buttonBar = new Composite(this, SWT.NO_FOCUS); GridDataFactory.swtDefaults().align(SWT.RIGHT, SWT.CENTER).applyTo(buttonBar); buttonBar.setLayout(new RowLayout(SWT.HORIZONTAL)); filterButton = new Button(buttonBar, SWT.TOGGLE); filterButton.setImage(EmulatorGuiData.loadImage(getDisplay(), "icons/filter.png")); filterButton.setSize(24, 24); filterMemory = true; filterButton.setSelection(true); filterButton.setToolTipText("View only RAM entries if set"); filterButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { filterMemory = filterButton.getSelection(); entryViewer.refresh(); } }); refreshButton = new Button(buttonBar, SWT.TOGGLE); refreshButton.setImage(EmulatorGuiData.loadImage(getDisplay(), "icons/refresh.png")); refreshButton.setSize(24, 24); autoRefresh = true; refreshButton.setSelection(true); refreshButton.setToolTipText("Automatically refresh memory view if set"); refreshButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { autoRefresh = refreshButton.getSelection(); } }); decodeButton = new Button(buttonBar, SWT.TOGGLE); decodeButton.setImage(EmulatorGuiData.loadImage(getDisplay(), "icons/decode.png")); decodeButton.setSize(24, 24); decodeMemory = false; decodeButton.setSelection(false); decodeButton.setToolTipText("Decode memory to show underlying structure"); pinButton = new Button(buttonBar, SWT.TOGGLE); pinButton.setImage(EmulatorGuiData.loadImage(getDisplay(), "icons/pin.png")); pinButton.setSize(24, 24); pinMemory = false; pinButton.setSelection(false); pinButton.setToolTipText("Pin view to scroll position if set, else, scroll to active memory"); pinButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { pinMemory = pinButton.getSelection(); } }); refreshEntryCombo(); FontDescriptor fontDescriptor = FontUtils.getFontDescriptor(JFaceResources.getTextFont()); fontDescriptor = fontDescriptor.increaseHeight(-2); tableFont = fontDescriptor.createFont(getDisplay()); tableComposite = new Composite(this, SWT.NONE); tableLayout = new StackLayout(); tableComposite.setLayout(tableLayout); GridDataFactory.fillDefaults().grab(true, true).span(2, 1).applyTo(tableComposite); createByteTableViewer(tableComposite); createDecodedContentTableViewer(tableComposite); tableLayout.topControl = byteTableViewer.getControl(); decodeButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { decodeMemory = decodeButton.getSelection() && memoryDecoder != null; tableLayout.topControl = (decodeMemory ? decodedTableViewer : byteTableViewer).getTable(); tableComposite.layout(true); } }); } protected void createDecodedContentTableViewer(Composite parent) { decodedTableViewer = new TableViewer(parent, SWT.V_SCROLL + SWT.BORDER + SWT.VIRTUAL + SWT.NO_FOCUS + SWT.FULL_SELECTION); final Table table = decodedTableViewer.getTable(); //GridDataFactory.fillDefaults().grab(true, true).span(2, 1).applyTo(table); String[] props = new String[3]; props[0] = "Addr"; new TableColumn(table, SWT.LEFT).setText(props[0]); props[1] = "Memory"; new TableColumn(table, SWT.LEFT).setText(props[1]); props[2] = "Content"; new TableColumn(table, SWT.LEFT).setText(props[2]); GC gc = new GC(table); gc.setFont(tableFont); int width = gc.stringExtent("FFFF").x; gc.dispose(); table.getColumn(0).setWidth(width); table.getColumn(1).setWidth(width * 4); table.getColumn(0).pack(); table.getColumn(1).pack(); table.addControlListener(new ControlAdapter() { @Override public void controlResized(ControlEvent e) { table.getColumn(2).setWidth(table.getSize().x - table.getColumn(0).getWidth() - table.getColumn(1).getWidth()); } }); //for (TableColumn column : table.getColumns()) { // column.pack(); //} table.setHeaderVisible(true); table.setLinesVisible(true); decodedTableViewer.setColumnProperties(props); //byteTableViewer.setCellModifier(new ByteMemoryCellModifier(byteTableViewer)); //byteTableViewer.setCellEditors(editors); table.addMenuDetectListener(new MenuDetectListener() { @Override public void menuDetected(MenuDetectEvent e) { Point pt = getDisplay().map(null, table, e.x, e.y); TableItem item = table.getItem(new Point(pt.x, pt.y)); if (item != null) { DecodedRow row = (DecodedRow) item.getData(); if (row != null && decodedContentProvider != null) { Menu menu = new Menu(table); decodedContentProvider.fillMenu(menu, row); SwtUtils.runMenu(null, e.x, e.y, menu); } } } }); } protected void createByteTableViewer(Composite parent) { byteTableViewer = new TableViewer(parent, SWT.V_SCROLL + SWT.BORDER + SWT.VIRTUAL + SWT.NO_FOCUS + SWT.FULL_SELECTION); byteContentViewer = new ByteMemoryContentProvider(BYTES); byteTableViewer.setContentProvider(byteContentViewer); byteMemoryLabelProvider = new ByteMemoryLabelProvider( new Color(getDisplay(), new RGB(64, 64, 128)), getDisplay().getSystemColor(SWT.COLOR_RED), byteContentViewer ); byteTableViewer.setLabelProvider(byteMemoryLabelProvider); final Table table = byteTableViewer.getTable(); //GridDataFactory.fillDefaults().grab(true, true).span(2, 1).applyTo(table); String[] props = new String[1 + BYTES + 1]; props[0] = "Addr"; new TableColumn(table, SWT.CENTER).setText(props[0]); for (int i = 0; i < BYTES; i++) { String id = Integer.toHexString(i).toUpperCase(); props[i + 1] = id; new TableColumn(table, SWT.CENTER).setText(id + " "); } props[BYTES+1] = "0123456789ABCDEF"; new TableColumn(table, SWT.CENTER).setText(props[BYTES+1]); table.setFont(tableFont); GC gc = new GC(table); gc.setFont(tableFont); int width = gc.stringExtent("FFFF").x; gc.dispose(); table.getColumn(0).setWidth(width); for (int i = 1; i <= BYTES; i++) { table.getColumn(i).setWidth(width / 2); } table.getColumn(BYTES+1).setWidth(width * 2); for (TableColumn column : table.getColumns()) { column.pack(); } table.setHeaderVisible(true); table.setLinesVisible(false); setupByteEditors(table, props); setupByteTableContextMenu(table); setupByteTableHovers(table); } private void setupByteEditors(Table table, String[] props) { final CellEditor[] editors = new CellEditor[1+BYTES+BYTES]; for (int i = 1; i < BYTES+1; i++) { final int column = i; editors[i] = new TextCellEditor(table) { @Override protected void keyReleaseOccured(KeyEvent keyEvent) { if (keyEvent.character == SWT.ESC) { keyEvent.doit = false; // don't close window } else if (keyEvent.keyCode == SWT.ARROW_LEFT) { fireApplyEditorValue(); advanceByteEditor(column, 0, -1); } else if (keyEvent.keyCode == SWT.ARROW_RIGHT || keyEvent.character == '\r' || keyEvent.character == ' ') { fireApplyEditorValue(); advanceByteEditor(column, 0, 1); } else if (keyEvent.keyCode == SWT.ARROW_UP) { fireApplyEditorValue(); advanceByteEditor(column, -1, 0); } else if (keyEvent.keyCode == SWT.PAGE_UP) { fireApplyEditorValue(); advanceByteEditor(column, -16, 0); } else if (keyEvent.keyCode == SWT.ARROW_DOWN) { fireApplyEditorValue(); advanceByteEditor(column, 1, 0); } else if (keyEvent.keyCode == SWT.PAGE_DOWN) { fireApplyEditorValue(); advanceByteEditor(column, 16, 0); } super.keyReleaseOccured(keyEvent); } }; } byteTableViewer.setColumnProperties(props); byteTableViewer.setCellModifier(new ByteMemoryCellModifier(byteTableViewer)); byteTableViewer.setCellEditors(editors); } private void advanceByteEditor(int column, int rowDelta, int colDelta) { MemoryRow row = (MemoryRow) ((IStructuredSelection) byteTableViewer.getSelection()).getFirstElement(); MemoryRow newRow; int newColumn; if (colDelta != 0) { if (column + colDelta > 0 && column + colDelta < BYTES+1) { newRow = row; newColumn = column + colDelta; } else { int nextIndex = getMemoryRowIndex(row.getAddress() + colDelta * BYTES); newRow = byteContentViewer.getElementFor(nextIndex); newColumn = colDelta > 0 ? 1 : BYTES; } } else { int rowIndex = getMemoryRowIndex(row.getAddress() + rowDelta * BYTES); newRow = byteContentViewer.getElementFor(rowIndex); newColumn = column; } if (newRow == null) { newRow = row; } if (newRow != null) { byteTableViewer.editElement(newRow, newColumn); } } private void setupByteTableContextMenu(final Table table) { Menu menu = new Menu(table); MenuItem item; item = new MenuItem(menu, SWT.NONE); item.setText("Set start range"); item.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { if (currentRange == null) return; int addr = table.getSelectionIndex() * BYTES; restrictRange(currentRange.getAddress() + addr, currentRange.getAddress() + currentRange.getSize()); } }); item = new MenuItem(menu, SWT.NONE); item.setText("Set end range"); item.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { if (currentRange == null) return; int endAddr = (table.getSelectionIndex() + 1) * BYTES; restrictRange(currentRange.getAddress(), currentRange.getAddress() + endAddr); } }); item = new MenuItem(menu, SWT.NONE); item.setText("Clear range"); item.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { if (currentRange == null) return; changeCurrentRange(new MemoryRange(currentRange.getEntry())); } }); table.setMenu(menu); } private void setupByteTableHovers(final Table table) { table.addMouseTrackListener(new MouseTrackAdapter() { @Override public void mouseHover(MouseEvent e) { TableItem item = table.getItem(new Point(e.x, e.y)); if (item != null) { for (int i = 0; i <= BYTES; i++) { Rectangle bounds = item.getTextBounds(i); if (e.x >= bounds.x && e.x < bounds.x + bounds.width) { MemoryRange range = (MemoryRange) byteTableViewer.getInput(); MemoryRow row = (MemoryRow) item.getData(); if (row == null) continue; if (i > 0) i--; int addr = row.getAddress() + i; // see if the address's symbol is known String descr = ">" + HexUtils.toHex4(addr); String symbol = getSymbolFor(range, addr); if (symbol != null) { descr += " = " + symbol; } else if ((addr & 1) != 0) { // hovering over byte? addr &= ~1; symbol = getSymbolFor(range, addr); if (symbol != null) { descr += " = " + symbol; } } // see if we can look up the word AT the address addr = range.getEntry().flatReadWord(addr); symbol = getSymbolFor(range, addr); if (symbol != null) { descr += "\n= >" + HexUtils.toHex4(addr) + " = " + symbol; } table.setToolTipText(descr); return; } } } setToolTipText(null); } private String getSymbolFor(MemoryRange range, int addr) { IMemoryEntry entry = range.getEntry(); if (entry.getAddr() <= addr && entry.getAddr() + entry.getSize() > addr) { Pair<String, Short> info = entry.lookupSymbolNear((short) addr, 0x1000); if (info != null) { return info.first + (info.second == addr ? "" : " + " + HexUtils.toHex4(addr - info.second)); } } String symbols = null; for (IMemoryEntry e : entry.getDomain().getFlattenedMemoryEntries()) { Pair<String, Short> info = e.lookupSymbolNear((short) addr, 0x100); if (info != null) { String sym = info.first + (info.second == addr ? "" : " + " + HexUtils.toHex4(addr - info.second)); if (symbols != null) symbols += ", " + sym; else symbols = sym; } } return symbols; } @Override public void mouseEnter(MouseEvent e) { setToolTipText(null); } @Override public void mouseExit(MouseEvent e) { setToolTipText(null); } }); } protected void changeCurrentRange(MemoryRange range) { byteTableViewer.getTable().setLayoutDeferred(true); byteTableViewer.setInput(range); currentRange = range; //for (TableColumn column : byteTableViewer.getTable().getColumns()) // column.pack(); byteTableViewer.getTable().setLayoutDeferred(false); //MemoryViewer.this.getShell().layout(true, true); //MemoryViewer.this.getShell().pack(); memoryDecoder = this.memoryDecoderProvider.getMemoryDecoder(range.getEntry()); if (memoryDecoder == null) { decodeButton.setSelection(false); decodeButton.setEnabled(false); decodeMemory = false; tableLayout.topControl = byteTableViewer.getControl(); tableComposite.layout(true); // decodedTableViewer.setLabelProvider(byteMemoryLabelProvider); // decodedTableViewer.setContentProvider(byteContentViewer); // decodedTableViewer.setInput(range); // decodedTableViewer.refresh(true); return; } decodeButton.setEnabled(true); if (decodedTableViewer.getContentProvider() != null) decodedTableViewer.setInput(null); decodedContentProvider = new DecodedMemoryContentProvider(memoryDecoder); ILabelProvider contentLabelProvider = memoryDecoder.getLabelProvider(); if (contentLabelProvider == null) contentLabelProvider = new LabelProvider() { @Override public String getText(Object element) { return ""; } }; decodedTableViewer.setLabelProvider(new DecodedTableLabelProvider( contentLabelProvider, memoryDecoder.getChunkSize())); decodedTableViewer.setContentProvider(decodedContentProvider); decodedTableViewer.setInput(range); } protected void restrictRange(int addr, int endAddr) { MemoryRange range = new MemoryRange( currentRange.getEntry(), addr, endAddr - addr); changeCurrentRange(range); } private void refreshEntryCombo() { if (!entryViewer.getControl().isDisposed()) { List<IMemoryEntry> allEntries = new ArrayList<IMemoryEntry>(); for (IMemoryDomain domain : memory.getDomains()) { allEntries.addAll(Arrays.asList(domain.getFlattenedMemoryEntries())); } entryViewer.setInput(allEntries.toArray()); } } protected void refreshViewer() { if (!isDisposed() && isVisible() && currentRange != null && !byteTableViewer.isCellEditorActive()) { int lowRange, hiRange; synchronized (currentRange) { byteContentViewer.refresh(); //currentRange.fetchChanges(); MemoryRangeChanges changes = byteContentViewer.getChanges(); if (changes == null || !changes.isTouched(currentRange.getAddress(), currentRange.getSize())) return; lowRange = changes.getLowTouchRange(); hiRange = changes.getHiTouchRange(); if (lowRange <= hiRange) { if (!byteTableViewer.getTable().isDisposed()) { if (pinMemory) { byteTableViewer.setSelection(null); } if (!pinMemory) { scrollByteViewerToActiveRegion(lowRange, hiRange); } //currentRange.clearTouchRange(); } } byteTableViewer.refresh(); if (decodeMemory) { //((DecodedMemoryContentProvider) decodedTableViewer.getContentProvider()).refresh(); if (decodedContentProvider != null) decodedContentProvider.refresh(); decodedTableViewer.refresh(); } } } } /* (non-Javadoc) * @see v9t9.gui.client.swt.shells.debugger.CpuViewer.ICpuTracker#updateForInstruction() */ @Override public void updateForInstruction() { getDisplay().asyncExec(new Runnable() { public void run() { if (isDisposed()) return; refreshViewer(); } }); } /** * @param entry * @param addr * @return */ public boolean contains(IMemoryEntry entry, int addr) { return currentRange != null && currentRange.contains(entry, addr); } /* (non-Javadoc) * @see v9t9.common.cpu.IBreakpointListener#breakpointChanged(v9t9.common.cpu.IBreakpoint, boolean) */ @Override public void breakpointChanged(IBreakpoint bp, boolean added) { Display.getDefault().asyncExec(new Runnable() { public void run() { decodedTableViewer.refresh(); } }); } }