ThreadPanelpublic class ThreadPanel extends TablePanel Base class for our information panels. |
Fields Summary |
---|
private static final String | PREFS_THREAD_COL_ID | private static final String | PREFS_THREAD_COL_TID | private static final String | PREFS_THREAD_COL_STATUS | private static final String | PREFS_THREAD_COL_UTIME | private static final String | PREFS_THREAD_COL_STIME | private static final String | PREFS_THREAD_COL_NAME | private static final String | PREFS_THREAD_SASH | private static final String | PREFS_STACK_COL_CLASS | private static final String | PREFS_STACK_COL_METHOD | private static final String | PREFS_STACK_COL_FILE | private static final String | PREFS_STACK_COL_LINE | private static final String | PREFS_STACK_COL_NATIVE | private org.eclipse.swt.widgets.Display | mDisplay | private org.eclipse.swt.widgets.Composite | mBase | private org.eclipse.swt.widgets.Label | mNotEnabled | private org.eclipse.swt.widgets.Label | mNotSelected | private org.eclipse.swt.widgets.Composite | mThreadBase | private org.eclipse.swt.widgets.Table | mThreadTable | private org.eclipse.jface.viewers.TableViewer | mThreadViewer | private org.eclipse.swt.widgets.Composite | mStackTraceBase | private org.eclipse.swt.widgets.Button | mRefreshStackTraceButton | private org.eclipse.swt.widgets.Label | mStackTraceTimeLabel | private StackTracePanel | mStackTracePanel | private org.eclipse.swt.widgets.Table | mStackTraceTable | private boolean | mMustStopRecurringThreadUpdateIndicates if a timer-based Runnable is current requesting thread updates regularly. | private boolean | mRecurringThreadUpdateRunningFlag to tell the recurring thread update to stop running | private Object | mLock | private static final String[] | THREAD_STATUS |
Methods Summary |
---|
public void | clientChanged(com.android.ddmlib.Client client, int changeMask)Sent when an existing client information changed.
This is sent from a non UI thread.
if (client == getCurrentClient()) {
if ((changeMask & Client.CHANGE_THREAD_MODE) != 0 ||
(changeMask & Client.CHANGE_THREAD_DATA) != 0) {
try {
mThreadTable.getDisplay().asyncExec(new Runnable() {
public void run() {
clientSelected();
}
});
} catch (SWTException e) {
// widget is disposed, we do nothing
}
} else if ((changeMask & Client.CHANGE_THREAD_STACKTRACE) != 0) {
try {
mThreadTable.getDisplay().asyncExec(new Runnable() {
public void run() {
updateThreadStackCall();
}
});
} catch (SWTException e) {
// widget is disposed, we do nothing
}
}
}
| public void | clientSelected()Sent when a new client is selected. The new client can be accessed
with {@link #getCurrentClient()}.
if (mThreadTable.isDisposed()) {
return;
}
Client client = getCurrentClient();
mStackTracePanel.setCurrentClient(client);
if (client != null) {
if (!client.isThreadUpdateEnabled()) {
((StackLayout)mBase.getLayout()).topControl = mNotEnabled;
mThreadViewer.setInput(null);
// if we are currently updating the thread, stop doing it.
mMustStopRecurringThreadUpdate = true;
} else {
((StackLayout)mBase.getLayout()).topControl = mThreadBase;
mThreadViewer.setInput(client);
synchronized (mLock) {
// if we're not updating we start the process
if (mRecurringThreadUpdateRunning == false) {
startRecurringThreadUpdate();
} else if (mMustStopRecurringThreadUpdate) {
// else if there's a runnable that's still going to get called, lets
// simply cancel the stop, and keep going
mMustStopRecurringThreadUpdate = false;
}
}
}
} else {
((StackLayout)mBase.getLayout()).topControl = mNotSelected;
mThreadViewer.setInput(null);
}
mBase.layout();
| protected org.eclipse.swt.widgets.Control | createControl(org.eclipse.swt.widgets.Composite parent)Create our control(s).
mDisplay = parent.getDisplay();
final IPreferenceStore store = DdmUiPreferences.getStore();
mBase = new Composite(parent, SWT.NONE);
mBase.setLayout(new StackLayout());
// UI for thread not enabled
mNotEnabled = new Label(mBase, SWT.CENTER | SWT.WRAP);
mNotEnabled.setText("Thread updates not enabled for selected client\n"
+ "(use toolbar button to enable)");
// UI for not client selected
mNotSelected = new Label(mBase, SWT.CENTER | SWT.WRAP);
mNotSelected.setText("no client is selected");
// base composite for selected client with enabled thread update.
mThreadBase = new Composite(mBase, SWT.NONE);
mThreadBase.setLayout(new FormLayout());
// table above the sash
mThreadTable = new Table(mThreadBase, SWT.MULTI | SWT.FULL_SELECTION);
mThreadTable.setHeaderVisible(true);
mThreadTable.setLinesVisible(true);
TableHelper.createTableColumn(
mThreadTable,
"ID",
SWT.RIGHT,
"888", //$NON-NLS-1$
PREFS_THREAD_COL_ID, store);
TableHelper.createTableColumn(
mThreadTable,
"Tid",
SWT.RIGHT,
"88888", //$NON-NLS-1$
PREFS_THREAD_COL_TID, store);
TableHelper.createTableColumn(
mThreadTable,
"Status",
SWT.LEFT,
"timed-wait", //$NON-NLS-1$
PREFS_THREAD_COL_STATUS, store);
TableHelper.createTableColumn(
mThreadTable,
"utime",
SWT.RIGHT,
"utime", //$NON-NLS-1$
PREFS_THREAD_COL_UTIME, store);
TableHelper.createTableColumn(
mThreadTable,
"stime",
SWT.RIGHT,
"utime", //$NON-NLS-1$
PREFS_THREAD_COL_STIME, store);
TableHelper.createTableColumn(
mThreadTable,
"Name",
SWT.LEFT,
"android.class.ReallyLongClassName.MethodName", //$NON-NLS-1$
PREFS_THREAD_COL_NAME, store);
mThreadViewer = new TableViewer(mThreadTable);
mThreadViewer.setContentProvider(new ThreadContentProvider());
mThreadViewer.setLabelProvider(new ThreadLabelProvider());
mThreadViewer.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
ThreadInfo selectedThread = getThreadSelection(event.getSelection());
updateThreadStackTrace(selectedThread);
}
});
mThreadViewer.addDoubleClickListener(new IDoubleClickListener() {
public void doubleClick(DoubleClickEvent event) {
ThreadInfo selectedThread = getThreadSelection(event.getSelection());
if (selectedThread != null) {
Client client = (Client)mThreadViewer.getInput();
if (client != null) {
client.requestThreadStackTrace(selectedThread.getThreadId());
}
}
}
});
// the separating sash
final Sash sash = new Sash(mThreadBase, SWT.HORIZONTAL);
Color darkGray = parent.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY);
sash.setBackground(darkGray);
// the UI below the sash
mStackTraceBase = new Composite(mThreadBase, SWT.NONE);
mStackTraceBase.setLayout(new GridLayout(2, false));
mRefreshStackTraceButton = new Button(mStackTraceBase, SWT.PUSH);
mRefreshStackTraceButton.setText("Refresh");
mRefreshStackTraceButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
ThreadInfo selectedThread = getThreadSelection(null);
if (selectedThread != null) {
Client currentClient = getCurrentClient();
if (currentClient != null) {
currentClient.requestThreadStackTrace(selectedThread.getThreadId());
}
}
}
});
mStackTraceTimeLabel = new Label(mStackTraceBase, SWT.NONE);
mStackTraceTimeLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
mStackTracePanel = new StackTracePanel();
mStackTraceTable = mStackTracePanel.createPanel(mStackTraceBase,
PREFS_STACK_COL_CLASS,
PREFS_STACK_COL_METHOD,
PREFS_STACK_COL_FILE,
PREFS_STACK_COL_LINE,
PREFS_STACK_COL_NATIVE,
store);
GridData gd;
mStackTraceTable.setLayoutData(gd = new GridData(GridData.FILL_BOTH));
gd.horizontalSpan = 2;
// now setup the sash.
// form layout data
FormData data = new FormData();
data.top = new FormAttachment(0, 0);
data.bottom = new FormAttachment(sash, 0);
data.left = new FormAttachment(0, 0);
data.right = new FormAttachment(100, 0);
mThreadTable.setLayoutData(data);
final FormData sashData = new FormData();
if (store != null && store.contains(PREFS_THREAD_SASH)) {
sashData.top = new FormAttachment(0, store.getInt(PREFS_THREAD_SASH));
} else {
sashData.top = new FormAttachment(50,0); // 50% across
}
sashData.left = new FormAttachment(0, 0);
sashData.right = new FormAttachment(100, 0);
sash.setLayoutData(sashData);
data = new FormData();
data.top = new FormAttachment(sash, 0);
data.bottom = new FormAttachment(100, 0);
data.left = new FormAttachment(0, 0);
data.right = new FormAttachment(100, 0);
mStackTraceBase.setLayoutData(data);
// allow resizes, but cap at minPanelWidth
sash.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event e) {
Rectangle sashRect = sash.getBounds();
Rectangle panelRect = mThreadBase.getClientArea();
int bottom = panelRect.height - sashRect.height - 100;
e.y = Math.max(Math.min(e.y, bottom), 100);
if (e.y != sashRect.y) {
sashData.top = new FormAttachment(0, e.y);
store.setValue(PREFS_THREAD_SASH, e.y);
mThreadBase.layout();
}
}
});
((StackLayout)mBase.getLayout()).topControl = mNotSelected;
return mBase;
| public void | deviceSelected()Sent when a new device is selected. The new device can be accessed
with {@link #getCurrentDevice()}.
// pass
| private com.android.ddmlib.ThreadInfo | getThreadSelection(org.eclipse.jface.viewers.ISelection selection)Returns the current thread selection or null if none is found.
If a {@link ISelection} object is specified, the first {@link ThreadInfo} from this selection
is returned, otherwise, the ISelection returned by
{@link TableViewer#getSelection()} is used.
if (selection == null) {
selection = mThreadViewer.getSelection();
}
if (selection instanceof IStructuredSelection) {
IStructuredSelection structuredSelection = (IStructuredSelection)selection;
Object object = structuredSelection.getFirstElement();
if (object instanceof ThreadInfo) {
return (ThreadInfo)object;
}
}
return null;
| public void | setFocus()Sets the focus to the proper control inside the panel.
mThreadTable.setFocus();
| protected void | setTableFocusListener()
addTableToFocusListener(mThreadTable);
addTableToFocusListener(mStackTraceTable);
| private void | startRecurringThreadUpdate()Initiate recurring events. We use a shorter "initialWait" so we do the
first execution sooner. We don't do it immediately because we want to
give the clients a chance to get set up.
mRecurringThreadUpdateRunning = true;
int initialWait = 1000;
mDisplay.timerExec(initialWait, new Runnable() {
public void run() {
synchronized (mLock) {
// lets check we still want updates.
if (mMustStopRecurringThreadUpdate == false) {
Client client = getCurrentClient();
if (client != null) {
client.requestThreadUpdate();
mDisplay.timerExec(
DdmUiPreferences.getThreadRefreshInterval() * 1000, this);
} else {
// we don't have a Client, which means the runnable is not
// going to be called through the timer. We reset the running flag.
mRecurringThreadUpdateRunning = false;
}
} else {
// else actually stops (don't call the timerExec) and reset the flags.
mRecurringThreadUpdateRunning = false;
mMustStopRecurringThreadUpdate = false;
}
}
}
});
| private void | updateThreadStackCall()Updates the stack call of the currently selected thread.
This must be called from the UI thread.
Client client = getCurrentClient();
if (client != null) {
// get the current selection in the ThreadTable
ThreadInfo selectedThread = getThreadSelection(null);
if (selectedThread != null) {
updateThreadStackTrace(selectedThread);
} else {
updateThreadStackTrace(null);
}
}
| private void | updateThreadStackTrace(com.android.ddmlib.ThreadInfo thread)updates the stackcall of the specified thread. If null the UI is emptied
of current data.
mStackTracePanel.setViewerInput(thread);
if (thread != null) {
mRefreshStackTraceButton.setEnabled(true);
long stackcallTime = thread.getStackCallTime();
if (stackcallTime != 0) {
String label = new Date(stackcallTime).toString();
mStackTraceTimeLabel.setText(label);
} else {
mStackTraceTimeLabel.setText(""); //$NON-NLS-1$
}
} else {
mRefreshStackTraceButton.setEnabled(true);
mStackTraceTimeLabel.setText(""); //$NON-NLS-1$
}
|
|