comparison agent/src/share/classes/sun/jvm/hotspot/ui/MemoryPanel.java @ 0:a61af66fc99e jdk7-b24

Initial load
author duke
date Sat, 01 Dec 2007 00:00:00 +0000
parents
children c18cbe5936b8
comparison
equal deleted inserted replaced
-1:000000000000 0:a61af66fc99e
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 }