0
|
1 /*
|
|
2 * Copyright 2001-2002 Sun Microsystems, Inc. All Rights Reserved.
|
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
4 *
|
|
5 * This code is free software; you can redistribute it and/or modify it
|
|
6 * under the terms of the GNU General Public License version 2 only, as
|
|
7 * published by the Free Software Foundation.
|
|
8 *
|
|
9 * This code is distributed in the hope that it will be useful, but WITHOUT
|
|
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
12 * version 2 for more details (a copy is included in the LICENSE file that
|
|
13 * accompanied this code).
|
|
14 *
|
|
15 * You should have received a copy of the GNU General Public License version
|
|
16 * 2 along with this work; if not, write to the Free Software Foundation,
|
|
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
18 *
|
|
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
|
20 * CA 95054 USA or visit www.sun.com if you need additional information or
|
|
21 * have any questions.
|
|
22 *
|
|
23 */
|
|
24
|
|
25 package sun.jvm.hotspot.ui;
|
|
26
|
|
27 import java.awt.*;
|
|
28 import java.awt.datatransfer.*;
|
|
29 import java.awt.event.*;
|
|
30 import java.io.IOException;
|
|
31 import java.math.*;
|
|
32 import java.util.*;
|
|
33 import javax.swing.*;
|
|
34 import javax.swing.event.*;
|
|
35 import javax.swing.table.*;
|
|
36 import sun.jvm.hotspot.debugger.*;
|
|
37 import sun.jvm.hotspot.ui.*;
|
|
38
|
|
39 public class MemoryPanel extends JPanel {
|
|
40 private boolean is64Bit;
|
|
41 private Debugger debugger;
|
|
42 private int addressSize;
|
|
43 private String unmappedAddrString;
|
|
44 private HighPrecisionJScrollBar scrollBar;
|
|
45 private AbstractTableModel model;
|
|
46 private JTable table;
|
|
47 private BigInteger startVal;
|
|
48 // Includes any partially-visible row at the bottom
|
|
49 private int numVisibleRows;
|
|
50 // Frequently-used subexpression
|
|
51 private int numUsableRows;
|
|
52 // Multi-row (and multi-column) selection. Have to duplicate state
|
|
53 // from UI so this can work as we scroll off the screen.
|
|
54 private boolean haveAnchor;
|
|
55 private int rowAnchorIndex;
|
|
56 private int colAnchorIndex;
|
|
57 private boolean haveLead;
|
|
58 private int rowLeadIndex;
|
|
59 private int colLeadIndex;
|
|
60
|
|
61 abstract class ActionWrapper extends AbstractAction {
|
|
62 private Action parent;
|
|
63 ActionWrapper() {
|
|
64 }
|
|
65
|
|
66 void setParent(Action parent) {
|
|
67 this.parent = parent;
|
|
68 }
|
|
69
|
|
70 Action getParent() {
|
|
71 return parent;
|
|
72 }
|
|
73
|
|
74 public void actionPerformed(ActionEvent e) {
|
|
75 if (getParent() != null) {
|
|
76 getParent().actionPerformed(e);
|
|
77 }
|
|
78 }
|
|
79 }
|
|
80
|
|
81 public MemoryPanel(final Debugger debugger, boolean is64Bit) {
|
|
82 super();
|
|
83 this.debugger = debugger;
|
|
84 this.is64Bit = is64Bit;
|
|
85 if (is64Bit) {
|
|
86 addressSize = 8;
|
|
87 unmappedAddrString = "??????????????????";
|
|
88 } else {
|
|
89 addressSize = 4;
|
|
90 unmappedAddrString = "??????????";
|
|
91 }
|
|
92 setLayout(new BorderLayout());
|
|
93 setupScrollBar();
|
|
94 add(scrollBar, BorderLayout.EAST);
|
|
95
|
|
96 model = new AbstractTableModel() {
|
|
97 public int getRowCount() {
|
|
98 return numVisibleRows;
|
|
99 }
|
|
100 public int getColumnCount() {
|
|
101 return 2;
|
|
102 }
|
|
103 public Object getValueAt(int row, int column) {
|
|
104 switch (column) {
|
|
105 case 0: return bigIntToHexString(startVal.add(new BigInteger(Integer.toString((row * addressSize)))));
|
|
106 case 1: {
|
|
107 try {
|
|
108 Address addr = bigIntToAddress(startVal.add(new BigInteger(Integer.toString((row * addressSize)))));
|
|
109 if (addr != null) {
|
|
110 return addressToString(addr.getAddressAt(0));
|
|
111 }
|
|
112 return unmappedAddrString;
|
|
113 } catch (UnmappedAddressException e) {
|
|
114 return unmappedAddrString;
|
|
115 }
|
|
116 }
|
|
117 default: throw new RuntimeException("Column " + column + " out of bounds");
|
|
118 }
|
|
119 }
|
|
120 public boolean isCellEditable(int row, int col) {
|
|
121 return false;
|
|
122 }
|
|
123 };
|
|
124
|
|
125 // View with JTable with no header
|
|
126 table = new JTable(model);
|
|
127 table.setTableHeader(null);
|
|
128 table.setShowGrid(false);
|
|
129 table.setIntercellSpacing(new Dimension(0, 0));
|
|
130 table.setCellSelectionEnabled(true);
|
|
131 table.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
|
|
132 table.setDragEnabled(true);
|
|
133 Font font = GraphicsUtilities.lookupFont("Courier");
|
|
134 if (font == null) {
|
|
135 throw new RuntimeException("Error looking up monospace font Courier");
|
|
136 }
|
|
137 table.setFont(font);
|
|
138
|
|
139 // Export proper data.
|
|
140 // We need to keep our own notion of the selection in order to
|
|
141 // properly export data, since the selection can go beyond the
|
|
142 // visible area on the screen (and since the table's model doesn't
|
|
143 // back all of those slots).
|
|
144 // Code thanks to Shannon.Hickey@sfbay
|
|
145 table.setTransferHandler(new TransferHandler() {
|
|
146 protected Transferable createTransferable(JComponent c) {
|
|
147 JTable table = (JTable)c;
|
|
148 if (haveSelection()) {
|
|
149 StringBuffer buf = new StringBuffer();
|
|
150 int iDir = (getRowAnchor() < getRowLead() ? 1 : -1);
|
|
151 int jDir = (getColAnchor() < getColLead() ? 1 : -1);
|
|
152
|
|
153 for (int i = getRowAnchor(); i != getRowLead() + iDir; i += iDir) {
|
|
154 for (int j = getColAnchor(); j != getColLead() + jDir; j += jDir) {
|
|
155 Object val = model.getValueAt(i, j);
|
|
156 buf.append(val == null ? "" : val.toString());
|
|
157 if (j != getColLead()) {
|
|
158 buf.append("\t");
|
|
159 }
|
|
160 }
|
|
161 if (i != getRowLead()) {
|
|
162 buf.append("\n");
|
|
163 }
|
|
164 }
|
|
165
|
|
166 return new StringTransferable(buf.toString());
|
|
167 }
|
|
168 return null;
|
|
169 }
|
|
170
|
|
171 public int getSourceActions(JComponent c) {
|
|
172 return COPY;
|
|
173 }
|
|
174
|
|
175 public boolean importData(JComponent c, Transferable t) {
|
|
176 if (canImport(c, t.getTransferDataFlavors())) {
|
|
177 try {
|
|
178 String str = (String)t.getTransferData(DataFlavor.stringFlavor);
|
|
179 handleImport(c, str);
|
|
180 return true;
|
|
181 } catch (UnsupportedFlavorException ufe) {
|
|
182 } catch (IOException ioe) {
|
|
183 }
|
|
184 }
|
|
185
|
|
186 return false;
|
|
187 }
|
|
188
|
|
189 public boolean canImport(JComponent c, DataFlavor[] flavors) {
|
|
190 for (int i = 0; i < flavors.length; i++) {
|
|
191 if (DataFlavor.stringFlavor.equals(flavors[i])) {
|
|
192 return true;
|
|
193 }
|
|
194 }
|
|
195 return false;
|
|
196 }
|
|
197
|
|
198 private void handleImport(JComponent c, String str) {
|
|
199 // do whatever you want with the string here
|
|
200 try {
|
|
201 makeVisible(debugger.parseAddress(str));
|
|
202 clearSelection();
|
|
203 table.clearSelection();
|
|
204 } catch (NumberFormatException e) {
|
|
205 System.err.println("Unable to parse address \"" + str + "\"");
|
|
206 }
|
|
207 }
|
|
208 });
|
|
209
|
|
210 // Supporting keyboard scrolling
|
|
211 // See src/share/classes/javax/swing/plaf/metal/MetalLookAndFeel.java,
|
|
212 // search for Table.AncestorInputMap
|
|
213
|
|
214 // Actions to override:
|
|
215 // selectPreviousRow, selectNextRow,
|
|
216 // scrollUpChangeSelection, scrollDownChangeSelection,
|
|
217 // selectPreviousRowExtendSelection, selectNextRowExtendSelection,
|
|
218 // scrollDownExtendSelection, scrollUpExtendSelection (Shift-PgDn/PgUp)
|
|
219
|
|
220 ActionMap map = table.getActionMap();
|
|
221
|
|
222 // Up arrow
|
|
223 installActionWrapper(map, "selectPreviousRow", new ActionWrapper() {
|
|
224 public void actionPerformed(ActionEvent e) {
|
|
225 beginUpdate();
|
|
226 clearSelection();
|
|
227 if (table.getSelectedRow() == 0) {
|
|
228 scrollBar.scrollUpOrLeft();
|
|
229 table.setRowSelectionInterval(0, 0);
|
|
230 } else {
|
|
231 super.actionPerformed(e);
|
|
232 }
|
|
233 maybeGrabSelection();
|
|
234 endUpdate();
|
|
235 }
|
|
236 });
|
|
237 // Down arrow
|
|
238 installActionWrapper(map, "selectNextRow", new ActionWrapper() {
|
|
239 public void actionPerformed(ActionEvent e) {
|
|
240 beginUpdate();
|
|
241 clearSelection();
|
|
242 int row = table.getSelectedRow();
|
|
243 if (row >= numUsableRows) {
|
|
244 scrollBar.scrollDownOrRight();
|
|
245 table.setRowSelectionInterval(row, row);
|
|
246 } else {
|
|
247 super.actionPerformed(e);
|
|
248 }
|
|
249 maybeGrabSelection();
|
|
250 endUpdate();
|
|
251 }
|
|
252 });
|
|
253 // Page up
|
|
254 installActionWrapper(map, "scrollUpChangeSelection", new ActionWrapper() {
|
|
255 public void actionPerformed(ActionEvent e) {
|
|
256 beginUpdate();
|
|
257 clearSelection();
|
|
258 int row = table.getSelectedRow();
|
|
259 scrollBar.pageUpOrLeft();
|
|
260 if (row >= 0) {
|
|
261 table.setRowSelectionInterval(row, row);
|
|
262 }
|
|
263 maybeGrabSelection();
|
|
264 endUpdate();
|
|
265 }
|
|
266 });
|
|
267 // Page down
|
|
268 installActionWrapper(map, "scrollDownChangeSelection", new ActionWrapper() {
|
|
269 public void actionPerformed(ActionEvent e) {
|
|
270 beginUpdate();
|
|
271 clearSelection();
|
|
272 int row = table.getSelectedRow();
|
|
273 scrollBar.pageDownOrRight();
|
|
274 if (row >= 0) {
|
|
275 table.setRowSelectionInterval(row, row);
|
|
276 }
|
|
277 maybeGrabSelection();
|
|
278 endUpdate();
|
|
279 }
|
|
280 });
|
|
281 // Shift + Up arrow
|
|
282 installActionWrapper(map, "selectPreviousRowExtendSelection", new ActionWrapper() {
|
|
283 public void actionPerformed(ActionEvent e) {
|
|
284 beginUpdate();
|
|
285 if (!haveAnchor()) {
|
|
286 setAnchorFromTable();
|
|
287 setLeadFromTable();
|
|
288 // setAnchor(table.getSelectedRow());
|
|
289 // setLead(table.getSelectedRow());
|
|
290 }
|
|
291 int newLead = getRowLead() - 1;
|
|
292 int newAnchor = getRowAnchor();
|
|
293 if (newLead < 0) {
|
|
294 scrollBar.scrollUpOrLeft();
|
|
295 ++newLead;
|
|
296 ++newAnchor;
|
|
297 }
|
|
298 setSelection(newAnchor, newLead, getColAnchor(), getColLead());
|
|
299 // printSelection();
|
|
300 endUpdate();
|
|
301 }
|
|
302 });
|
|
303 // Shift + Left arrow
|
|
304 installActionWrapper(map, "selectPreviousColumnExtendSelection", new ActionWrapper() {
|
|
305 public void actionPerformed(ActionEvent e) {
|
|
306 beginUpdate();
|
|
307 if (!haveAnchor()) {
|
|
308 setAnchorFromTable();
|
|
309 setLeadFromTable();
|
|
310 }
|
|
311 int newLead = Math.max(0, getColLead() - 1);
|
|
312 setSelection(getRowAnchor(), getRowLead(), getColAnchor(), newLead);
|
|
313 // printSelection();
|
|
314 endUpdate();
|
|
315 }
|
|
316 });
|
|
317 // Shift + Down arrow
|
|
318 installActionWrapper(map, "selectNextRowExtendSelection", new ActionWrapper() {
|
|
319 public void actionPerformed(ActionEvent e) {
|
|
320 beginUpdate();
|
|
321 if (!haveAnchor()) {
|
|
322 setAnchorFromTable();
|
|
323 setLeadFromTable();
|
|
324 // setAnchor(table.getSelectedRow());
|
|
325 // setLead(table.getSelectedRow());
|
|
326 }
|
|
327 int newLead = getRowLead() + 1;
|
|
328 int newAnchor = getRowAnchor();
|
|
329 if (newLead > numUsableRows) {
|
|
330 scrollBar.scrollDownOrRight();
|
|
331 --newLead;
|
|
332 --newAnchor;
|
|
333 }
|
|
334 setSelection(newAnchor, newLead, getColAnchor(), getColLead());
|
|
335 // printSelection();
|
|
336 endUpdate();
|
|
337 }
|
|
338 });
|
|
339 // Shift + Right arrow
|
|
340 installActionWrapper(map, "selectNextColumnExtendSelection", new ActionWrapper() {
|
|
341 public void actionPerformed(ActionEvent e) {
|
|
342 beginUpdate();
|
|
343 if (!haveAnchor()) {
|
|
344 setAnchorFromTable();
|
|
345 setLeadFromTable();
|
|
346 }
|
|
347 int newLead = Math.min(model.getColumnCount() - 1, getColLead() + 1);
|
|
348 setSelection(getRowAnchor(), getRowLead(), getColAnchor(), newLead);
|
|
349 // printSelection();
|
|
350 endUpdate();
|
|
351 }
|
|
352 });
|
|
353 // Shift + Page up
|
|
354 installActionWrapper(map, "scrollUpExtendSelection", new ActionWrapper() {
|
|
355 public void actionPerformed(ActionEvent e) {
|
|
356 beginUpdate();
|
|
357 if (!haveAnchor()) {
|
|
358 setAnchorFromTable();
|
|
359 setLeadFromTable();
|
|
360 // setAnchor(table.getSelectedRow());
|
|
361 // setLead(table.getSelectedRow());
|
|
362 }
|
|
363 int newLead = getRowLead() - numUsableRows;
|
|
364 int newAnchor = getRowAnchor();
|
|
365 if (newLead < 0) {
|
|
366 scrollBar.pageUpOrLeft();
|
|
367 newLead += numUsableRows;
|
|
368 newAnchor += numUsableRows;
|
|
369 }
|
|
370 setSelection(newAnchor, newLead, getColAnchor(), getColLead());
|
|
371 // printSelection();
|
|
372 endUpdate();
|
|
373 }
|
|
374 });
|
|
375 // Shift + Page down
|
|
376 installActionWrapper(map, "scrollDownExtendSelection", new ActionWrapper() {
|
|
377 public void actionPerformed(ActionEvent e) {
|
|
378 beginUpdate();
|
|
379 if (!haveAnchor()) {
|
|
380 setAnchorFromTable();
|
|
381 setLeadFromTable();
|
|
382 // setAnchor(table.getSelectedRow());
|
|
383 // setLead(table.getSelectedRow());
|
|
384 }
|
|
385 int newLead = getRowLead() + numUsableRows;
|
|
386 int newAnchor = getRowAnchor();
|
|
387 if (newLead > numUsableRows) {
|
|
388 scrollBar.pageDownOrRight();
|
|
389 newLead -= numUsableRows;
|
|
390 newAnchor -= numUsableRows;
|
|
391 }
|
|
392 setSelection(newAnchor, newLead, getColAnchor(), getColLead());
|
|
393 // printSelection();
|
|
394 endUpdate();
|
|
395 }
|
|
396 });
|
|
397
|
|
398 // Clear our notion of selection upon mouse press
|
|
399 table.addMouseListener(new MouseAdapter() {
|
|
400 public void mousePressed(MouseEvent e) {
|
|
401 if (shouldIgnore(e)) {
|
|
402 return;
|
|
403 }
|
|
404 // Make shift-clicking work properly
|
|
405 if (e.isShiftDown()) {
|
|
406 maybeGrabSelection();
|
|
407 return;
|
|
408 }
|
|
409 // System.err.println(" Clearing selection on mouse press");
|
|
410 clearSelection();
|
|
411 }
|
|
412 });
|
|
413
|
|
414 // Watch for mouse going out of bounds
|
|
415 table.addMouseMotionListener(new MouseMotionAdapter() {
|
|
416 public void mouseDragged(MouseEvent e) {
|
|
417 if (shouldIgnore(e)) {
|
|
418 // System.err.println(" (Ignoring consumed mouse event)");
|
|
419 return;
|
|
420 }
|
|
421
|
|
422 // Look for drag events outside table and scroll if necessary
|
|
423 Point p = e.getPoint();
|
|
424 if (table.rowAtPoint(p) == -1) {
|
|
425 // See whether we are above or below the table
|
|
426 Rectangle rect = new Rectangle();
|
|
427 getBounds(rect);
|
|
428 beginUpdate();
|
|
429 if (p.y < rect.y) {
|
|
430 // System.err.println(" Scrolling up due to mouse event");
|
|
431 // Scroll up
|
|
432 scrollBar.scrollUpOrLeft();
|
|
433 setSelection(getRowAnchor(), 0, getColAnchor(), getColLead());
|
|
434 } else {
|
|
435 // System.err.println(" Scrolling down due to mouse event");
|
|
436 // Scroll down
|
|
437 scrollBar.scrollDownOrRight();
|
|
438 setSelection(getRowAnchor(), numUsableRows, getColAnchor(), getColLead());
|
|
439 }
|
|
440 // printSelection();
|
|
441 endUpdate();
|
|
442 } else {
|
|
443 maybeGrabSelection();
|
|
444 }
|
|
445 }
|
|
446 });
|
|
447
|
|
448
|
|
449 add(table, BorderLayout.CENTER);
|
|
450
|
|
451 // Make sure we recompute number of visible rows
|
|
452 addComponentListener(new ComponentAdapter() {
|
|
453 public void componentResized(ComponentEvent e) {
|
|
454 recomputeNumVisibleRows();
|
|
455 constrain();
|
|
456 }
|
|
457 });
|
|
458 addHierarchyListener(new HierarchyListener() {
|
|
459 public void hierarchyChanged(HierarchyEvent e) {
|
|
460 recomputeNumVisibleRows();
|
|
461 constrain();
|
|
462 }
|
|
463 });
|
|
464 updateFromScrollBar();
|
|
465 }
|
|
466
|
|
467 /** Makes the given address visible somewhere in the window */
|
|
468 public void makeVisible(Address addr) {
|
|
469 BigInteger bi = addressToBigInt(addr);
|
|
470 scrollBar.setValueHP(bi);
|
|
471 }
|
|
472
|
|
473 //----------------------------------------------------------------------
|
|
474 // Internals only below this point
|
|
475 //
|
|
476
|
|
477 private void setupScrollBar() {
|
|
478 if (is64Bit) {
|
|
479 // 64-bit mode
|
|
480 scrollBar =
|
|
481 new HighPrecisionJScrollBar(
|
|
482 Scrollbar.VERTICAL,
|
|
483 new BigInteger(1, new byte[] {
|
|
484 (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00,
|
|
485 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00}),
|
|
486 new BigInteger(1, new byte[] {
|
|
487 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
|
|
488 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00}),
|
|
489 new BigInteger(1, new byte[] {
|
|
490 (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
|
|
491 (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFC}));
|
|
492 scrollBar.setUnitIncrementHP(new BigInteger(1, new byte[] {
|
|
493 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
|
|
494 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x08}));
|
|
495 scrollBar.setBlockIncrementHP(new BigInteger(1, new byte[] {
|
|
496 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
|
|
497 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x40}));
|
|
498 } else {
|
|
499 // 32-bit mode
|
|
500 scrollBar=
|
|
501 new HighPrecisionJScrollBar(
|
|
502 Scrollbar.VERTICAL,
|
|
503 new BigInteger(1, new byte[] {
|
|
504 (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00}),
|
|
505 new BigInteger(1, new byte[] {
|
|
506 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00}),
|
|
507 new BigInteger(1, new byte[] {
|
|
508 (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFC}));
|
|
509 scrollBar.setUnitIncrementHP(new BigInteger(1, new byte[] {
|
|
510 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x04}));
|
|
511 scrollBar.setBlockIncrementHP(new BigInteger(1, new byte[] {
|
|
512 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x20}));
|
|
513 }
|
|
514 scrollBar.addChangeListener(new ChangeListener() {
|
|
515 public void stateChanged(ChangeEvent e) {
|
|
516 updateFromScrollBar();
|
|
517 }
|
|
518 });
|
|
519 }
|
|
520
|
|
521 private void updateFromScrollBar() {
|
|
522 beginUpdate();
|
|
523 BigInteger oldStartVal = startVal;
|
|
524 startVal = scrollBar.getValueHP();
|
|
525 constrain();
|
|
526 model.fireTableDataChanged();
|
|
527 if (oldStartVal != null) {
|
|
528 modifySelection(oldStartVal.subtract(startVal).intValue() / addressSize);
|
|
529 }
|
|
530 endUpdate();
|
|
531 }
|
|
532
|
|
533 private void constrain() {
|
|
534 BigInteger offset = new BigInteger(Integer.toString(addressSize * (numUsableRows)));
|
|
535 BigInteger endVal = startVal.add(offset);
|
|
536 if (endVal.compareTo(scrollBar.getMaximumHP()) > 0) {
|
|
537 startVal = scrollBar.getMaximumHP().subtract(offset);
|
|
538 endVal = scrollBar.getMaximumHP();
|
|
539 scrollBar.setValueHP(startVal);
|
|
540 model.fireTableDataChanged();
|
|
541 }
|
|
542 }
|
|
543
|
|
544 private void recomputeNumVisibleRows() {
|
|
545 Rectangle rect = new Rectangle();
|
|
546 getBounds(rect);
|
|
547 int h = table.getRowHeight();
|
|
548 numVisibleRows = (rect.height + (h - 1)) / h;
|
|
549 numUsableRows = numVisibleRows - 2;
|
|
550 scrollBar.setBlockIncrementHP(new BigInteger(Integer.toString(addressSize * (numUsableRows))));
|
|
551 model.fireTableDataChanged();
|
|
552 // FIXME: refresh selection
|
|
553 }
|
|
554
|
|
555 private String bigIntToHexString(BigInteger bi) {
|
|
556 StringBuffer buf = new StringBuffer();
|
|
557 buf.append("0x");
|
|
558 String val = bi.toString(16);
|
|
559 for (int i = 0; i < ((2 * addressSize) - val.length()); i++) {
|
|
560 buf.append('0');
|
|
561 }
|
|
562 buf.append(val);
|
|
563 return buf.toString();
|
|
564 }
|
|
565
|
|
566 private Address bigIntToAddress(BigInteger i) {
|
|
567 String s = bigIntToHexString(i);
|
|
568 return debugger.parseAddress(s);
|
|
569 }
|
|
570
|
|
571 private BigInteger addressToBigInt(Address a) {
|
|
572 String s = addressToString(a);
|
|
573 if (!s.startsWith("0x")) {
|
|
574 throw new NumberFormatException(s);
|
|
575 }
|
|
576 return new BigInteger(s.substring(2), 16);
|
|
577 }
|
|
578
|
|
579 private String addressToString(Address a) {
|
|
580 if (a == null) {
|
|
581 if (is64Bit) {
|
|
582 return "0x0000000000000000";
|
|
583 } else {
|
|
584 return "0x00000000";
|
|
585 }
|
|
586 }
|
|
587 return a.toString();
|
|
588 }
|
|
589
|
|
590 private static void installActionWrapper(ActionMap map,
|
|
591 String actionName,
|
|
592 ActionWrapper wrapper) {
|
|
593 wrapper.setParent(map.get(actionName));
|
|
594 map.put(actionName, wrapper);
|
|
595 }
|
|
596
|
|
597 private boolean shouldIgnore(MouseEvent e) {
|
|
598 return e.isConsumed() || (!(SwingUtilities.isLeftMouseButton(e) && table.isEnabled()));
|
|
599 }
|
|
600
|
|
601 private void clearSelection() {
|
|
602 haveAnchor = false;
|
|
603 haveLead = false;
|
|
604 }
|
|
605
|
|
606 private int updateLevel;
|
|
607 private boolean updating() { return updateLevel > 0; }
|
|
608 private void beginUpdate() { ++updateLevel; }
|
|
609 private void endUpdate() { --updateLevel; }
|
|
610
|
|
611 private boolean haveAnchor() { return haveAnchor; }
|
|
612 private boolean haveLead() { return haveLead; }
|
|
613 private boolean haveSelection() { return haveAnchor() && haveLead(); }
|
|
614 private int getRowAnchor() { return rowAnchorIndex; }
|
|
615 private int getColAnchor() { return colAnchorIndex; }
|
|
616 private int getRowLead() { return rowLeadIndex; }
|
|
617 private int getColLead() { return colLeadIndex; }
|
|
618
|
|
619 private void setAnchorFromTable() {
|
|
620 setAnchor(table.getSelectionModel().getAnchorSelectionIndex(),
|
|
621 table.getColumnModel().getSelectionModel().getAnchorSelectionIndex());
|
|
622 }
|
|
623 private void setLeadFromTable() {
|
|
624 setLead(table.getSelectionModel().getAnchorSelectionIndex(),
|
|
625 table.getColumnModel().getSelectionModel().getAnchorSelectionIndex());
|
|
626 }
|
|
627 private void setAnchor(int row, int col) {
|
|
628 rowAnchorIndex = row;
|
|
629 colAnchorIndex = col;
|
|
630 haveAnchor = true;
|
|
631 }
|
|
632 private void setLead(int row, int col) {
|
|
633 rowLeadIndex = row;
|
|
634 colLeadIndex = col;
|
|
635 haveLead = true;
|
|
636 }
|
|
637 private int clamp(int val, int min, int max) {
|
|
638 return Math.max(Math.min(val, max), min);
|
|
639 }
|
|
640 private void maybeGrabSelection() {
|
|
641 if (table.getSelectedRow() != -1) {
|
|
642 // Grab selection
|
|
643 ListSelectionModel rowSel = table.getSelectionModel();
|
|
644 ListSelectionModel colSel = table.getColumnModel().getSelectionModel();
|
|
645 if (!haveAnchor()) {
|
|
646 // System.err.println("Updating from table's selection");
|
|
647 setSelection(rowSel.getAnchorSelectionIndex(), rowSel.getLeadSelectionIndex(),
|
|
648 colSel.getAnchorSelectionIndex(), colSel.getLeadSelectionIndex());
|
|
649 } else {
|
|
650 // System.err.println("Updating lead from table's selection");
|
|
651 setSelection(getRowAnchor(), rowSel.getLeadSelectionIndex(),
|
|
652 getColAnchor(), colSel.getLeadSelectionIndex());
|
|
653 }
|
|
654 // printSelection();
|
|
655 }
|
|
656 }
|
|
657 private void setSelection(int rowAnchor, int rowLead, int colAnchor, int colLead) {
|
|
658 setAnchor(rowAnchor, colAnchor);
|
|
659 setLead(rowLead, colLead);
|
|
660 table.setRowSelectionInterval(clamp(rowAnchor, 0, numUsableRows),
|
|
661 clamp(rowLead, 0, numUsableRows));
|
|
662 table.setColumnSelectionInterval(colAnchor, colLead);
|
|
663 }
|
|
664 private void modifySelection(int amount) {
|
|
665 if (haveSelection()) {
|
|
666 setSelection(getRowAnchor() + amount, getRowLead() + amount,
|
|
667 getColAnchor(), getColLead());
|
|
668 }
|
|
669 }
|
|
670 private void printSelection() {
|
|
671 System.err.println("Selection updated to (" +
|
|
672 model.getValueAt(getRowAnchor(), getColAnchor()) +
|
|
673 ", " +
|
|
674 model.getValueAt(getRowLead(), getColLead()) + ") [(" +
|
|
675 getRowAnchor() + ", " + getColAnchor() + "), (" +
|
|
676 getRowLead() + ", " + getColLead() + ")]");
|
|
677 }
|
|
678 }
|