1/*
2 * Copyright (c) 2001, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25package sun.jvm.hotspot.ui;
26
27import java.awt.*;
28import java.awt.event.*;
29import java.util.*;
30import javax.swing.*;
31import javax.swing.event.*;
32import javax.swing.table.*;
33
34import sun.jvm.hotspot.debugger.*;
35
36public class ProcessListPanel extends JPanel {
37  private Debugger           dbg;
38  private AbstractTableModel dataModel;
39  private java.util.List     els;
40  private boolean            sortByName   = true;
41  private boolean            sortReversed = false;
42  private javax.swing.Timer  timer;
43  private JTable             table;
44
45  /** Takes a Debugger in constructor. Updates the list once during
46      construction; list can be updated automatically by "starting"
47      the panel. */
48  public ProcessListPanel(Debugger dbg) {
49    super();
50
51    this.dbg = dbg;
52
53    update();
54
55    dataModel = new AbstractTableModel() {
56        public int getColumnCount() { return 2;          }
57        public int getRowCount()    { return els.size(); }
58        public String getColumnName(int col) {
59          switch (col) {
60          case 0:
61            return "Process Name";
62          case 1:
63            return "Process ID";
64          default:
65            throw new RuntimeException("Index " + col + " out of bounds");
66          }
67        }
68
69        public Object getValueAt(int row, int col) {
70          ProcessInfo info = (ProcessInfo) els.get(row);
71
72          switch (col) {
73          case 0:
74            return info.getName();
75          case 1:
76            return new Integer(info.getPid());
77          default:
78            throw new RuntimeException("Index (" + col + ", " + row + ") out of bounds");
79          }
80        }
81      };
82
83    // Create user interface
84    setLayout(new BorderLayout());
85    table = new JTable(dataModel);
86    table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
87    JTableHeader header = table.getTableHeader();
88    header.setReorderingAllowed(false);
89    table.setRowSelectionAllowed(true);
90    table.setColumnSelectionAllowed(false);
91    // Provide sorting in similar fashion to Task Manager
92    header.addMouseListener(new MouseAdapter() {
93        public void mousePressed(MouseEvent e) {
94          int viewColumn = table.getColumnModel().getColumnIndexAtX(e.getX());
95          int column = table.convertColumnIndexToModel(viewColumn);
96          if (column != -1) {
97            boolean newSortByName = (column == 0);
98            if (newSortByName == sortByName) {
99              // Switch sense of "reversed" instead
100              sortReversed = !sortReversed;
101            } else {
102              sortByName = newSortByName;
103              sortReversed = false;
104            }
105
106            // Keep the current selection if possible
107            int i = table.getSelectedRow();
108            int pid = getPid(els, i);
109            sort(els);
110            i = findPid(els, pid);
111            dataModel.fireTableDataChanged();
112            if ((i >= 0) || (els.size() > 0)) {
113              if (i >= 0) {
114                table.setRowSelectionInterval(i, i);
115              } else {
116                table.setRowSelectionInterval(0, 0);
117              }
118            }
119          }
120        }
121      });
122
123    JScrollPane scrollPane = new JScrollPane(table);
124    add(scrollPane, BorderLayout.CENTER);
125
126    if (els.size() > 0) {
127      table.setRowSelectionInterval(0, 0);
128    }
129  }
130
131  /** Set update interval for automatic updating of the process list */
132
133  public void setAutoUpdateInterval(int millis) {
134    getTimer().setDelay(millis);
135  }
136
137  /** Start auto updating of the panel */
138  public void start() {
139    getTimer().start();
140  }
141
142  /** Stop auto updating of the panel */
143  public void stop() {
144    getTimer().stop();
145  }
146
147  /** Call this to update the panel's notion of the process list */
148  public synchronized void update() {
149    if (!dbg.hasProcessList()) {
150      throw new RuntimeException("ProcessListPanel requires that debugger supports getProcessList()");
151    }
152    java.util.List newEls = dbg.getProcessList();
153    sort(newEls);
154    if (table != null) {
155      // Keep the current selection if possible
156      int i = table.getSelectedRow();
157      int pid = getPid(els, i);
158      i = findPid(newEls, pid);
159      els = newEls;
160      dataModel.fireTableDataChanged();
161      if ((i >= 0) || (els.size() > 0)) {
162        if (i >= 0) {
163          table.setRowSelectionInterval(i, i);
164        } else {
165          table.setRowSelectionInterval(0, 0);
166        }
167      }
168    } else {
169      els = newEls;
170    }
171  }
172
173  /** Call this to get the selected ProcessInfo, or null if none selected */
174  public synchronized ProcessInfo getSelectedProcess() {
175    int i = table.getSelectedRow();
176    if (i < 0) {
177      return null;
178    }
179    return (ProcessInfo) els.get(i);
180  }
181
182  private synchronized void sort(java.util.List els) {
183    Comparator c;
184    if (sortByName) {
185      c = new Comparator() {
186          public int compare(Object o1, Object o2) {
187            int scale = (sortReversed ? -1 : 1);
188            return scale * ((ProcessInfo) o1).getName().compareToIgnoreCase(((ProcessInfo) o2).getName());
189          }
190        };
191    } else {
192      c = new Comparator() {
193          public int compare(Object o1, Object o2) {
194            int scale = (sortReversed ? -1 : 1);
195            int pid1 = ((ProcessInfo) o1).getPid();
196            int pid2 = ((ProcessInfo) o2).getPid();
197            int ret;
198            if      (pid1 <  pid2) ret = -1;
199            else if (pid1 == pid2) ret = 0;
200            else ret = 1;
201            return ret * scale;
202          }
203        };
204    }
205    Collections.sort(els, c);
206  }
207
208  private javax.swing.Timer getTimer() {
209    if (timer == null) {
210      timer = new javax.swing.Timer(1000, new ActionListener() {
211          public void actionPerformed(ActionEvent e) {
212            update();
213          }
214        });
215    }
216    return timer;
217  }
218
219  private synchronized int getPid(java.util.List els, int index) {
220    return ((ProcessInfo) els.get(index)).getPid();
221  }
222
223  private synchronized int findPid(java.util.List els, int pid) {
224    for (int i = 0; i < els.size(); i++) {
225      ProcessInfo info = (ProcessInfo) els.get(i);
226      if (info.getPid() == pid) {
227        return i;
228      }
229    }
230    return -1;
231  }
232}
233