2 * Copyright (C) 2007 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.ddms;
19 import com.android.ddmlib.AndroidDebugBridge;
20 import com.android.ddmlib.Client;
21 import com.android.ddmlib.IDevice;
22 import com.android.ddmlib.Log;
23 import com.android.ddmlib.Log.ILogOutput;
24 import com.android.ddmlib.Log.LogLevel;
25 import com.android.ddmuilib.AllocationPanel;
26 import com.android.ddmuilib.DevicePanel;
27 import com.android.ddmuilib.DevicePanel.IUiSelectionListener;
28 import com.android.ddmuilib.EmulatorControlPanel;
29 import com.android.ddmuilib.HeapPanel;
30 import com.android.ddmuilib.ITableFocusListener;
31 import com.android.ddmuilib.ImageHelper;
32 import com.android.ddmuilib.ImageLoader;
33 import com.android.ddmuilib.InfoPanel;
34 import com.android.ddmuilib.NativeHeapPanel;
35 import com.android.ddmuilib.ScreenShotDialog;
36 import com.android.ddmuilib.SysinfoPanel;
37 import com.android.ddmuilib.TablePanel;
38 import com.android.ddmuilib.ThreadPanel;
39 import com.android.ddmuilib.actions.ToolItemAction;
40 import com.android.ddmuilib.explorer.DeviceExplorer;
41 import com.android.ddmuilib.log.event.EventLogPanel;
42 import com.android.ddmuilib.logcat.LogColors;
43 import com.android.ddmuilib.logcat.LogFilter;
44 import com.android.ddmuilib.logcat.LogPanel;
45 import com.android.ddmuilib.logcat.LogPanel.ILogFilterStorageManager;
47 import org.eclipse.jface.dialogs.MessageDialog;
48 import org.eclipse.jface.preference.IPreferenceStore;
49 import org.eclipse.jface.preference.PreferenceStore;
50 import org.eclipse.swt.SWT;
51 import org.eclipse.swt.SWTError;
52 import org.eclipse.swt.SWTException;
53 import org.eclipse.swt.dnd.Clipboard;
54 import org.eclipse.swt.events.ControlEvent;
55 import org.eclipse.swt.events.ControlListener;
56 import org.eclipse.swt.events.MenuAdapter;
57 import org.eclipse.swt.events.MenuEvent;
58 import org.eclipse.swt.events.SelectionAdapter;
59 import org.eclipse.swt.events.SelectionEvent;
60 import org.eclipse.swt.events.ShellEvent;
61 import org.eclipse.swt.events.ShellListener;
62 import org.eclipse.swt.graphics.Color;
63 import org.eclipse.swt.graphics.Font;
64 import org.eclipse.swt.graphics.FontData;
65 import org.eclipse.swt.graphics.Rectangle;
66 import org.eclipse.swt.layout.FillLayout;
67 import org.eclipse.swt.layout.FormAttachment;
68 import org.eclipse.swt.layout.FormData;
69 import org.eclipse.swt.layout.FormLayout;
70 import org.eclipse.swt.layout.GridData;
71 import org.eclipse.swt.layout.GridLayout;
72 import org.eclipse.swt.widgets.Composite;
73 import org.eclipse.swt.widgets.Display;
74 import org.eclipse.swt.widgets.Event;
75 import org.eclipse.swt.widgets.Label;
76 import org.eclipse.swt.widgets.Listener;
77 import org.eclipse.swt.widgets.Menu;
78 import org.eclipse.swt.widgets.MenuItem;
79 import org.eclipse.swt.widgets.MessageBox;
80 import org.eclipse.swt.widgets.Sash;
81 import org.eclipse.swt.widgets.Shell;
82 import org.eclipse.swt.widgets.TabFolder;
83 import org.eclipse.swt.widgets.TabItem;
84 import org.eclipse.swt.widgets.ToolBar;
85 import org.eclipse.swt.widgets.ToolItem;
88 import java.util.ArrayList;
91 * This acts as the UI builder. This cannot be its own thread since this prevent using AWT in an
92 * SWT application. So this class mainly builds the ui, and manages communication between the panels
93 * when {@link IDevice} / {@link Client} selection changes.
95 public class UIThread implements IUiSelectionListener {
97 * UI tab panel definitions. The constants here must match up with the array
98 * indices in mPanels. PANEL_CLIENT_LIST is a "virtual" panel representing
101 public static final int PANEL_CLIENT_LIST = -1;
103 public static final int PANEL_INFO = 0;
105 public static final int PANEL_THREAD = 1;
107 public static final int PANEL_HEAP = 2;
109 public static final int PANEL_NATIVE_HEAP = 3;
111 private static final int PANEL_ALLOCATIONS = 4;
113 private static final int PANEL_SYSINFO = 5;
115 private static final int PANEL_COUNT = 6;
117 /** Content is setup in the constructor */
118 private static TablePanel[] mPanels = new TablePanel[PANEL_COUNT];
120 private static final String[] mPanelNames = new String[] {
121 "Info", "Threads", "VM Heap", "Native Heap", "Allocation Tracker", "Sysinfo"
124 private static final String[] mPanelTips = new String[] {
125 "Client information", "Thread status", "VM heap status",
126 "Native heap status", "Allocation Tracker", "Sysinfo graphs"
129 private static final String PREFERENCE_LOGSASH =
130 "logSashLocation"; //$NON-NLS-1$
131 private static final String PREFERENCE_SASH =
132 "sashLocation"; //$NON-NLS-1$
134 private static final String PREFS_COL_TIME =
135 "logcat.time"; //$NON-NLS-1$
136 private static final String PREFS_COL_LEVEL =
137 "logcat.level"; //$NON-NLS-1$
138 private static final String PREFS_COL_PID =
139 "logcat.pid"; //$NON-NLS-1$
140 private static final String PREFS_COL_TAG =
141 "logcat.tag"; //$NON-NLS-1$
142 private static final String PREFS_COL_MESSAGE =
143 "logcat.message"; //$NON-NLS-1$
145 private static final String PREFS_FILTERS = "logcat.filter"; //$NON-NLS-1$
147 // singleton instance
148 private static UIThread mInstance = new UIThread();
151 private Display mDisplay;
153 // the table we show in the left-hand pane
154 private DevicePanel mDevicePanel;
156 private IDevice mCurrentDevice = null;
157 private Client mCurrentClient = null;
159 // status line at the bottom of the app window
160 private Label mStatusLine;
162 // some toolbar items we need to update
163 private ToolItem mTBShowThreadUpdates;
164 private ToolItem mTBShowHeapUpdates;
165 private ToolItem mTBHalt;
166 private ToolItem mTBCauseGc;
168 private ImageLoader mDdmsImageLoader;
169 private ImageLoader mDdmuiLibImageLoader;
171 private final class FilterStorage implements ILogFilterStorageManager {
173 public LogFilter[] getFilterFromStore() {
174 String filterPrefs = PrefsDialog.getStore().getString(
177 // split in a string per filter
178 String[] filters = filterPrefs.split("\\|"); //$NON-NLS-1$
180 ArrayList<LogFilter> list =
181 new ArrayList<LogFilter>(filters.length);
183 for (String f : filters) {
184 if (f.length() > 0) {
185 LogFilter logFilter = new LogFilter();
186 if (logFilter.loadFromString(f)) {
192 return list.toArray(new LogFilter[list.size()]);
195 public void saveFilters(LogFilter[] filters) {
196 StringBuilder sb = new StringBuilder();
197 for (LogFilter f : filters) {
198 String filterString = f.toString();
199 sb.append(filterString);
203 PrefsDialog.getStore().setValue(PREFS_FILTERS, sb.toString());
206 public boolean requiresDefaultFilter() {
212 private LogPanel mLogPanel;
214 private ToolItemAction mCreateFilterAction;
215 private ToolItemAction mDeleteFilterAction;
216 private ToolItemAction mEditFilterAction;
217 private ToolItemAction mExportAction;
218 private ToolItemAction mClearAction;
220 private ToolItemAction[] mLogLevelActions;
221 private String[] mLogLevelIcons = {
222 "v.png", //$NON-NLS-1S
223 "d.png", //$NON-NLS-1S
224 "i.png", //$NON-NLS-1S
225 "w.png", //$NON-NLS-1S
226 "e.png", //$NON-NLS-1S
229 protected Clipboard mClipboard;
231 private MenuItem mCopyMenuItem;
233 private MenuItem mSelectAllMenuItem;
235 private TableFocusListener mTableListener;
237 private DeviceExplorer mExplorer = null;
238 private Shell mExplorerShell = null;
240 private EmulatorControlPanel mEmulatorPanel;
242 private EventLogPanel mEventLogPanel;
244 private class TableFocusListener implements ITableFocusListener {
246 private IFocusedTableActivator mCurrentActivator;
248 public void focusGained(IFocusedTableActivator activator) {
249 mCurrentActivator = activator;
250 if (mCopyMenuItem.isDisposed() == false) {
251 mCopyMenuItem.setEnabled(true);
252 mSelectAllMenuItem.setEnabled(true);
256 public void focusLost(IFocusedTableActivator activator) {
257 // if we move from one table to another, it's unclear
258 // if the old table lose its focus before the new
259 // one gets the focus, so we need to check.
260 if (activator == mCurrentActivator) {
262 if (mCopyMenuItem.isDisposed() == false) {
263 mCopyMenuItem.setEnabled(false);
264 mSelectAllMenuItem.setEnabled(false);
269 public void copy(Clipboard clipboard) {
270 if (mCurrentActivator != null) {
271 mCurrentActivator.copy(clipboard);
275 public void selectAll() {
276 if (mCurrentActivator != null) {
277 mCurrentActivator.selectAll();
285 * Generic constructor.
288 mPanels[PANEL_INFO] = new InfoPanel();
289 mPanels[PANEL_THREAD] = new ThreadPanel();
290 mPanels[PANEL_HEAP] = new HeapPanel();
291 if (PrefsDialog.getStore().getBoolean(PrefsDialog.SHOW_NATIVE_HEAP)) {
292 mPanels[PANEL_NATIVE_HEAP] = new NativeHeapPanel();
294 mPanels[PANEL_NATIVE_HEAP] = null;
296 mPanels[PANEL_ALLOCATIONS] = new AllocationPanel();
297 mPanels[PANEL_SYSINFO] = new SysinfoPanel();
301 * Get singleton instance of the UI thread.
303 public static UIThread getInstance() {
308 * Return the Display. Don't try this unless you're in the UI thread.
310 public Display getDisplay() {
314 public void asyncExec(Runnable r) {
315 if (mDisplay != null && mDisplay.isDisposed() == false) {
316 mDisplay.asyncExec(r);
320 /** returns the IPreferenceStore */
321 public IPreferenceStore getStore() {
322 return PrefsDialog.getStore();
326 * Create SWT objects and drive the user interface event loop.
328 public void runUI() {
329 Display.setAppName("ddms");
330 mDisplay = new Display();
331 Shell shell = new Shell(mDisplay);
333 // create the image loaders for DDMS and DDMUILIB
334 mDdmsImageLoader = new ImageLoader(this.getClass());
335 mDdmuiLibImageLoader = new ImageLoader(DevicePanel.class);
337 shell.setImage(ImageHelper.loadImage(mDdmsImageLoader, mDisplay,
338 "ddms-icon.png", //$NON-NLS-1$
341 Log.setLogOutput(new ILogOutput() {
342 public void printAndPromptLog(final LogLevel logLevel, final String tag,
343 final String message) {
344 Log.printLog(logLevel, tag, message);
345 // dialog box only run in UI thread..
346 mDisplay.asyncExec(new Runnable() {
348 Shell shell = mDisplay.getActiveShell();
349 if (logLevel == LogLevel.ERROR) {
350 MessageDialog.openError(shell, tag, message);
352 MessageDialog.openWarning(shell, tag, message);
358 public void printLog(LogLevel logLevel, String tag, String message) {
359 Log.printLog(logLevel, tag, message);
363 // [try to] ensure ADB is running
364 String adbLocation = System.getProperty("com.android.ddms.bindir"); //$NON-NLS-1$
365 if (adbLocation != null && adbLocation.length() != 0) {
366 adbLocation += File.separator + "adb"; //$NON-NLS-1$
368 adbLocation = "adb"; //$NON-NLS-1$
371 AndroidDebugBridge.init(true /* debugger support */);
372 AndroidDebugBridge.createBridge(adbLocation, true /* forceNewBridge */);
374 shell.setText("Dalvik Debug Monitor");
375 setConfirmClose(shell);
377 createWidgets(shell);
380 setSizeAndPosition(shell);
383 Log.d("ddms", "UI is up");
385 while (!shell.isDisposed()) {
386 if (!mDisplay.readAndDispatch())
389 mLogPanel.stopLogCat(true);
391 mDevicePanel.dispose();
392 for (TablePanel panel : mPanels) {
399 Log.d("ddms", "UI is down");
403 * Set the size and position of the main window from the preference, and
404 * setup listeners for control events (resize/move of the window)
406 private void setSizeAndPosition(final Shell shell) {
407 shell.setMinimumSize(400, 200);
409 // get the x/y and w/h from the prefs
410 PreferenceStore prefs = PrefsDialog.getStore();
411 int x = prefs.getInt(PrefsDialog.SHELL_X);
412 int y = prefs.getInt(PrefsDialog.SHELL_Y);
413 int w = prefs.getInt(PrefsDialog.SHELL_WIDTH);
414 int h = prefs.getInt(PrefsDialog.SHELL_HEIGHT);
416 // check that we're not out of the display area
417 Rectangle rect = mDisplay.getClientArea();
418 // first check the width/height
419 if (w > rect.width) {
421 prefs.setValue(PrefsDialog.SHELL_WIDTH, rect.width);
423 if (h > rect.height) {
425 prefs.setValue(PrefsDialog.SHELL_HEIGHT, rect.height);
427 // then check x. Make sure the left corner is in the screen
430 prefs.setValue(PrefsDialog.SHELL_X, rect.x);
431 } else if (x >= rect.x + rect.width) {
432 x = rect.x + rect.width - w;
433 prefs.setValue(PrefsDialog.SHELL_X, rect.x);
435 // then check y. Make sure the left corner is in the screen
438 prefs.setValue(PrefsDialog.SHELL_Y, rect.y);
439 } else if (y >= rect.y + rect.height) {
440 y = rect.y + rect.height - h;
441 prefs.setValue(PrefsDialog.SHELL_Y, rect.y);
444 // now we can set the location/size
445 shell.setBounds(x, y, w, h);
447 // add listener for resize/move
448 shell.addControlListener(new ControlListener() {
449 public void controlMoved(ControlEvent e) {
451 Rectangle rect = shell.getBounds();
452 // store in pref file
453 PreferenceStore prefs = PrefsDialog.getStore();
454 prefs.setValue(PrefsDialog.SHELL_X, rect.x);
455 prefs.setValue(PrefsDialog.SHELL_Y, rect.y);
458 public void controlResized(ControlEvent e) {
460 Rectangle rect = shell.getBounds();
461 // store in pref file
462 PreferenceStore prefs = PrefsDialog.getStore();
463 prefs.setValue(PrefsDialog.SHELL_WIDTH, rect.width);
464 prefs.setValue(PrefsDialog.SHELL_HEIGHT, rect.height);
470 * Set the size and position of the file explorer window from the
471 * preference, and setup listeners for control events (resize/move of
474 private void setExplorerSizeAndPosition(final Shell shell) {
475 shell.setMinimumSize(400, 200);
477 // get the x/y and w/h from the prefs
478 PreferenceStore prefs = PrefsDialog.getStore();
479 int x = prefs.getInt(PrefsDialog.EXPLORER_SHELL_X);
480 int y = prefs.getInt(PrefsDialog.EXPLORER_SHELL_Y);
481 int w = prefs.getInt(PrefsDialog.EXPLORER_SHELL_WIDTH);
482 int h = prefs.getInt(PrefsDialog.EXPLORER_SHELL_HEIGHT);
484 // check that we're not out of the display area
485 Rectangle rect = mDisplay.getClientArea();
486 // first check the width/height
487 if (w > rect.width) {
489 prefs.setValue(PrefsDialog.EXPLORER_SHELL_WIDTH, rect.width);
491 if (h > rect.height) {
493 prefs.setValue(PrefsDialog.EXPLORER_SHELL_HEIGHT, rect.height);
495 // then check x. Make sure the left corner is in the screen
498 prefs.setValue(PrefsDialog.EXPLORER_SHELL_X, rect.x);
499 } else if (x >= rect.x + rect.width) {
500 x = rect.x + rect.width - w;
501 prefs.setValue(PrefsDialog.EXPLORER_SHELL_X, rect.x);
503 // then check y. Make sure the left corner is in the screen
506 prefs.setValue(PrefsDialog.EXPLORER_SHELL_Y, rect.y);
507 } else if (y >= rect.y + rect.height) {
508 y = rect.y + rect.height - h;
509 prefs.setValue(PrefsDialog.EXPLORER_SHELL_Y, rect.y);
512 // now we can set the location/size
513 shell.setBounds(x, y, w, h);
515 // add listener for resize/move
516 shell.addControlListener(new ControlListener() {
517 public void controlMoved(ControlEvent e) {
519 Rectangle rect = shell.getBounds();
520 // store in pref file
521 PreferenceStore prefs = PrefsDialog.getStore();
522 prefs.setValue(PrefsDialog.EXPLORER_SHELL_X, rect.x);
523 prefs.setValue(PrefsDialog.EXPLORER_SHELL_Y, rect.y);
526 public void controlResized(ControlEvent e) {
528 Rectangle rect = shell.getBounds();
529 // store in pref file
530 PreferenceStore prefs = PrefsDialog.getStore();
531 prefs.setValue(PrefsDialog.EXPLORER_SHELL_WIDTH, rect.width);
532 prefs.setValue(PrefsDialog.EXPLORER_SHELL_HEIGHT, rect.height);
538 * Set the confirm-before-close dialog. TODO: enable/disable in prefs. TODO:
539 * is there any point in having this?
541 private void setConfirmClose(final Shell shell) {
545 shell.addListener(SWT.Close, new Listener() {
546 public void handleEvent(Event event) {
547 int style = SWT.APPLICATION_MODAL | SWT.YES | SWT.NO;
548 MessageBox msgBox = new MessageBox(shell, style);
549 msgBox.setText("Confirm...");
550 msgBox.setMessage("Close DDM?");
551 event.doit = (msgBox.open() == SWT.YES);
557 * Create the menu bar and items.
559 private void createMenus(final Shell shell) {
561 Menu menuBar = new Menu(shell, SWT.BAR);
563 // create top-level items
564 MenuItem fileItem = new MenuItem(menuBar, SWT.CASCADE);
565 fileItem.setText("&File");
566 MenuItem editItem = new MenuItem(menuBar, SWT.CASCADE);
567 editItem.setText("&Edit");
568 MenuItem actionItem = new MenuItem(menuBar, SWT.CASCADE);
569 actionItem.setText("&Actions");
570 MenuItem deviceItem = new MenuItem(menuBar, SWT.CASCADE);
571 deviceItem.setText("&Device");
572 MenuItem helpItem = new MenuItem(menuBar, SWT.CASCADE);
573 helpItem.setText("&Help");
575 // create top-level menus
576 Menu fileMenu = new Menu(menuBar);
577 fileItem.setMenu(fileMenu);
578 Menu editMenu = new Menu(menuBar);
579 editItem.setMenu(editMenu);
580 Menu actionMenu = new Menu(menuBar);
581 actionItem.setMenu(actionMenu);
582 Menu deviceMenu = new Menu(menuBar);
583 deviceItem.setMenu(deviceMenu);
584 Menu helpMenu = new Menu(menuBar);
585 helpItem.setMenu(helpMenu);
589 // create File menu items
590 item = new MenuItem(fileMenu, SWT.NONE);
591 item.setText("&Preferences...");
592 item.addSelectionListener(new SelectionAdapter() {
594 public void widgetSelected(SelectionEvent e) {
595 PrefsDialog.run(shell);
599 item = new MenuItem(fileMenu, SWT.NONE);
600 item.setText("&Static Port Configuration...");
601 item.addSelectionListener(new SelectionAdapter() {
603 public void widgetSelected(SelectionEvent e) {
604 StaticPortConfigDialog dlg = new StaticPortConfigDialog(shell);
609 new MenuItem(fileMenu, SWT.SEPARATOR);
611 item = new MenuItem(fileMenu, SWT.NONE);
612 item.setText("E&xit\tCtrl-Q");
613 item.setAccelerator('Q' | SWT.CONTROL);
614 item.addSelectionListener(new SelectionAdapter() {
616 public void widgetSelected(SelectionEvent e) {
621 // create edit menu items
622 mCopyMenuItem = new MenuItem(editMenu, SWT.NONE);
623 mCopyMenuItem.setText("&Copy\tCtrl-C");
624 mCopyMenuItem.setAccelerator('C' | SWT.COMMAND);
625 mCopyMenuItem.addSelectionListener(new SelectionAdapter() {
627 public void widgetSelected(SelectionEvent e) {
628 mTableListener.copy(mClipboard);
632 new MenuItem(editMenu, SWT.SEPARATOR);
634 mSelectAllMenuItem = new MenuItem(editMenu, SWT.NONE);
635 mSelectAllMenuItem.setText("Select &All\tCtrl-A");
636 mSelectAllMenuItem.setAccelerator('A' | SWT.COMMAND);
637 mSelectAllMenuItem.addSelectionListener(new SelectionAdapter() {
639 public void widgetSelected(SelectionEvent e) {
640 mTableListener.selectAll();
644 // create Action menu items
645 // TODO: this should come with a confirmation dialog
646 final MenuItem actionHaltItem = new MenuItem(actionMenu, SWT.NONE);
647 actionHaltItem.setText("&Halt VM");
648 actionHaltItem.addSelectionListener(new SelectionAdapter() {
650 public void widgetSelected(SelectionEvent e) {
651 mDevicePanel.killSelectedClient();
655 final MenuItem actionCauseGcItem = new MenuItem(actionMenu, SWT.NONE);
656 actionCauseGcItem.setText("Cause &GC");
657 actionCauseGcItem.addSelectionListener(new SelectionAdapter() {
659 public void widgetSelected(SelectionEvent e) {
660 mDevicePanel.forceGcOnSelectedClient();
664 // configure Action items based on current state
665 actionMenu.addMenuListener(new MenuAdapter() {
667 public void menuShown(MenuEvent e) {
668 actionHaltItem.setEnabled(mTBHalt.getEnabled());
669 actionCauseGcItem.setEnabled(mTBCauseGc.getEnabled());
673 // create Device menu items
674 item = new MenuItem(deviceMenu, SWT.NONE);
675 item.setText("&Screen capture...\tCTrl-S");
676 item.setAccelerator('S' | SWT.CONTROL);
677 item.addSelectionListener(new SelectionAdapter() {
679 public void widgetSelected(SelectionEvent e) {
680 if (mCurrentDevice != null) {
681 ScreenShotDialog dlg = new ScreenShotDialog(shell);
682 dlg.open(mCurrentDevice);
687 new MenuItem(deviceMenu, SWT.SEPARATOR);
689 item = new MenuItem(deviceMenu, SWT.NONE);
690 item.setText("File Explorer...");
691 item.addSelectionListener(new SelectionAdapter() {
693 public void widgetSelected(SelectionEvent e) {
694 createFileExplorer();
698 new MenuItem(deviceMenu, SWT.SEPARATOR);
700 item = new MenuItem(deviceMenu, SWT.NONE);
701 item.setText("Show &process status...");
702 item.addSelectionListener(new SelectionAdapter() {
704 public void widgetSelected(SelectionEvent e) {
705 DeviceCommandDialog dlg;
706 dlg = new DeviceCommandDialog("ps -x", "ps-x.txt", shell);
707 dlg.open(mCurrentDevice);
711 item = new MenuItem(deviceMenu, SWT.NONE);
712 item.setText("Dump &device state...");
713 item.addSelectionListener(new SelectionAdapter() {
715 public void widgetSelected(SelectionEvent e) {
716 DeviceCommandDialog dlg;
717 dlg = new DeviceCommandDialog("/system/bin/dumpstate /proc/self/fd/0",
718 "device-state.txt", shell);
719 dlg.open(mCurrentDevice);
723 item = new MenuItem(deviceMenu, SWT.NONE);
724 item.setText("Dump &app state...");
725 item.setEnabled(false);
726 item.addSelectionListener(new SelectionAdapter() {
728 public void widgetSelected(SelectionEvent e) {
729 DeviceCommandDialog dlg;
730 dlg = new DeviceCommandDialog("dumpsys", "app-state.txt", shell);
731 dlg.open(mCurrentDevice);
735 item = new MenuItem(deviceMenu, SWT.NONE);
736 item.setText("Dump &radio state...");
737 item.addSelectionListener(new SelectionAdapter() {
739 public void widgetSelected(SelectionEvent e) {
740 DeviceCommandDialog dlg;
741 dlg = new DeviceCommandDialog(
742 "cat /data/logs/radio.4 /data/logs/radio.3"
743 + " /data/logs/radio.2 /data/logs/radio.1"
744 + " /data/logs/radio",
745 "radio-state.txt", shell);
746 dlg.open(mCurrentDevice);
750 item = new MenuItem(deviceMenu, SWT.NONE);
751 item.setText("Run &logcat...");
752 item.addSelectionListener(new SelectionAdapter() {
754 public void widgetSelected(SelectionEvent e) {
755 DeviceCommandDialog dlg;
756 dlg = new DeviceCommandDialog("logcat '*:d jdwp:w'", "log.txt",
758 dlg.open(mCurrentDevice);
762 // create Help menu items
763 item = new MenuItem(helpMenu, SWT.NONE);
764 item.setText("&Contents...");
765 item.addSelectionListener(new SelectionAdapter() {
767 public void widgetSelected(SelectionEvent e) {
768 int style = SWT.APPLICATION_MODAL | SWT.OK;
769 MessageBox msgBox = new MessageBox(shell, style);
770 msgBox.setText("Help!");
771 msgBox.setMessage("Help wanted.");
776 new MenuItem(helpMenu, SWT.SEPARATOR);
778 item = new MenuItem(helpMenu, SWT.NONE);
779 item.setText("&About...");
780 item.addSelectionListener(new SelectionAdapter() {
782 public void widgetSelected(SelectionEvent e) {
783 AboutDialog dlg = new AboutDialog(shell);
788 // tell the shell to use this menu
789 shell.setMenuBar(menuBar);
793 * Create the widgets in the main application window. The basic layout is a
794 * two-panel sash, with a scrolling list of VMs on the left and detailed
795 * output for a single VM on the right.
797 private void createWidgets(final Shell shell) {
798 Color darkGray = shell.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY);
801 * Create three areas: tool bar, split panels, status line
803 shell.setLayout(new GridLayout(1, false));
806 final Composite panelArea = new Composite(shell, SWT.BORDER);
808 // make the panel area absorb all space
809 panelArea.setLayoutData(new GridData(GridData.FILL_BOTH));
812 mStatusLine = new Label(shell, SWT.NONE);
814 // make status line extend all the way across
815 mStatusLine.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
817 mStatusLine.setText("Initializing...");
820 * Configure the split-panel area.
822 final PreferenceStore prefs = PrefsDialog.getStore();
824 Composite topPanel = new Composite(panelArea, SWT.NONE);
825 final Sash sash = new Sash(panelArea, SWT.HORIZONTAL);
826 sash.setBackground(darkGray);
827 Composite bottomPanel = new Composite(panelArea, SWT.NONE);
829 panelArea.setLayout(new FormLayout());
831 createTopPanel(topPanel, darkGray);
832 createBottomPanel(bottomPanel);
835 FormData data = new FormData();
836 data.top = new FormAttachment(0, 0);
837 data.bottom = new FormAttachment(sash, 0);
838 data.left = new FormAttachment(0, 0);
839 data.right = new FormAttachment(100, 0);
840 topPanel.setLayoutData(data);
842 final FormData sashData = new FormData();
843 if (prefs != null && prefs.contains(PREFERENCE_LOGSASH)) {
844 sashData.top = new FormAttachment(0, prefs.getInt(
845 PREFERENCE_LOGSASH));
847 sashData.top = new FormAttachment(50,0); // 50% across
849 sashData.left = new FormAttachment(0, 0);
850 sashData.right = new FormAttachment(100, 0);
851 sash.setLayoutData(sashData);
853 data = new FormData();
854 data.top = new FormAttachment(sash, 0);
855 data.bottom = new FormAttachment(100, 0);
856 data.left = new FormAttachment(0, 0);
857 data.right = new FormAttachment(100, 0);
858 bottomPanel.setLayoutData(data);
860 // allow resizes, but cap at minPanelWidth
861 sash.addListener(SWT.Selection, new Listener() {
862 public void handleEvent(Event e) {
863 Rectangle sashRect = sash.getBounds();
864 Rectangle panelRect = panelArea.getClientArea();
865 int bottom = panelRect.height - sashRect.height - 100;
866 e.y = Math.max(Math.min(e.y, bottom), 100);
867 if (e.y != sashRect.y) {
868 sashData.top = new FormAttachment(0, e.y);
869 prefs.setValue(PREFERENCE_LOGSASH, e.y);
875 // add a global focus listener for all the tables
876 mTableListener = new TableFocusListener();
878 // now set up the listener in the various panels
879 mLogPanel.setTableFocusListener(mTableListener);
880 mEventLogPanel.setTableFocusListener(mTableListener);
881 for (TablePanel p : mPanels) {
883 p.setTableFocusListener(mTableListener);
887 mStatusLine.setText("");
891 * Populate the tool bar.
893 private void createDevicePanelToolBar(ToolBar toolBar) {
894 Display display = toolBar.getDisplay();
896 // add "show thread updates" button
897 mTBShowThreadUpdates = new ToolItem(toolBar, SWT.CHECK);
898 mTBShowThreadUpdates.setImage(ImageHelper.loadImage(mDdmuiLibImageLoader, display,
899 DevicePanel.ICON_THREAD, DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null));
900 mTBShowThreadUpdates.setToolTipText("Show thread updates");
901 mTBShowThreadUpdates.setEnabled(false);
902 mTBShowThreadUpdates.addSelectionListener(new SelectionAdapter() {
904 public void widgetSelected(SelectionEvent e) {
905 if (mCurrentClient != null) {
906 // boolean status = ((ToolItem)e.item).getSelection();
907 // invert previous state
908 boolean enable = !mCurrentClient.isThreadUpdateEnabled();
910 mCurrentClient.setThreadUpdateEnabled(enable);
912 e.doit = false; // this has no effect?
917 // add "show heap updates" button
918 mTBShowHeapUpdates = new ToolItem(toolBar, SWT.CHECK);
919 mTBShowHeapUpdates.setImage(ImageHelper.loadImage(mDdmuiLibImageLoader, display,
920 DevicePanel.ICON_HEAP, DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null));
921 mTBShowHeapUpdates.setToolTipText("Show heap updates");
922 mTBShowHeapUpdates.setEnabled(false);
923 mTBShowHeapUpdates.addSelectionListener(new SelectionAdapter() {
925 public void widgetSelected(SelectionEvent e) {
926 if (mCurrentClient != null) {
927 // boolean status = ((ToolItem)e.item).getSelection();
928 // invert previous state
929 boolean enable = !mCurrentClient.isHeapUpdateEnabled();
930 mCurrentClient.setHeapUpdateEnabled(enable);
932 e.doit = false; // this has no effect?
937 new ToolItem(toolBar, SWT.SEPARATOR);
939 // add "kill VM" button; need to make this visually distinct from
940 // the status update buttons
941 mTBHalt = new ToolItem(toolBar, SWT.PUSH);
942 mTBHalt.setToolTipText("Halt the target VM");
943 mTBHalt.setEnabled(false);
944 mTBHalt.setImage(ImageHelper.loadImage(mDdmuiLibImageLoader, display,
945 DevicePanel.ICON_HALT, DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null));
946 mTBHalt.addSelectionListener(new SelectionAdapter() {
948 public void widgetSelected(SelectionEvent e) {
949 mDevicePanel.killSelectedClient();
953 new ToolItem(toolBar, SWT.SEPARATOR);
955 // add "cause GC" button
956 mTBCauseGc = new ToolItem(toolBar, SWT.PUSH);
957 mTBCauseGc.setToolTipText("Cause an immediate GC in the target VM");
958 mTBCauseGc.setEnabled(false);
959 mTBCauseGc.setImage(ImageHelper.loadImage(mDdmuiLibImageLoader, display,
960 DevicePanel.ICON_GC, DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null));
961 mTBCauseGc.addSelectionListener(new SelectionAdapter() {
963 public void widgetSelected(SelectionEvent e) {
964 mDevicePanel.forceGcOnSelectedClient();
971 private void createTopPanel(final Composite comp, Color darkGray) {
972 final PreferenceStore prefs = PrefsDialog.getStore();
974 comp.setLayout(new FormLayout());
976 Composite leftPanel = new Composite(comp, SWT.NONE);
977 final Sash sash = new Sash(comp, SWT.VERTICAL);
978 sash.setBackground(darkGray);
979 Composite rightPanel = new Composite(comp, SWT.NONE);
981 createLeftPanel(leftPanel);
982 createRightPanel(rightPanel);
984 FormData data = new FormData();
985 data.top = new FormAttachment(0, 0);
986 data.bottom = new FormAttachment(100, 0);
987 data.left = new FormAttachment(0, 0);
988 data.right = new FormAttachment(sash, 0);
989 leftPanel.setLayoutData(data);
991 final FormData sashData = new FormData();
992 sashData.top = new FormAttachment(0, 0);
993 sashData.bottom = new FormAttachment(100, 0);
994 if (prefs != null && prefs.contains(PREFERENCE_SASH)) {
995 sashData.left = new FormAttachment(0, prefs.getInt(
998 // position the sash 380 from the right instead of x% (done by using
999 // FormAttachment(x, 0)) in order to keep the sash at the same
1001 // from the left when the window is resized.
1002 // 380px is just enough to display the left table with no horizontal
1003 // scrollbar with the default font.
1004 sashData.left = new FormAttachment(0, 380);
1006 sash.setLayoutData(sashData);
1008 data = new FormData();
1009 data.top = new FormAttachment(0, 0);
1010 data.bottom = new FormAttachment(100, 0);
1011 data.left = new FormAttachment(sash, 0);
1012 data.right = new FormAttachment(100, 0);
1013 rightPanel.setLayoutData(data);
1015 final int minPanelWidth = 60;
1017 // allow resizes, but cap at minPanelWidth
1018 sash.addListener(SWT.Selection, new Listener() {
1019 public void handleEvent(Event e) {
1020 Rectangle sashRect = sash.getBounds();
1021 Rectangle panelRect = comp.getClientArea();
1022 int right = panelRect.width - sashRect.width - minPanelWidth;
1023 e.x = Math.max(Math.min(e.x, right), minPanelWidth);
1024 if (e.x != sashRect.x) {
1025 sashData.left = new FormAttachment(0, e.x);
1026 prefs.setValue(PREFERENCE_SASH, e.x);
1033 private void createBottomPanel(final Composite comp) {
1034 final PreferenceStore prefs = PrefsDialog.getStore();
1037 Display display = comp.getDisplay();
1038 mClipboard = new Clipboard(display);
1040 LogColors colors = new LogColors();
1042 colors.infoColor = new Color(display, 0, 127, 0);
1043 colors.debugColor = new Color(display, 0, 0, 127);
1044 colors.errorColor = new Color(display, 255, 0, 0);
1045 colors.warningColor = new Color(display, 255, 127, 0);
1046 colors.verboseColor = new Color(display, 0, 0, 0);
1048 // set the preferences names
1049 LogPanel.PREFS_TIME = PREFS_COL_TIME;
1050 LogPanel.PREFS_LEVEL = PREFS_COL_LEVEL;
1051 LogPanel.PREFS_PID = PREFS_COL_PID;
1052 LogPanel.PREFS_TAG = PREFS_COL_TAG;
1053 LogPanel.PREFS_MESSAGE = PREFS_COL_MESSAGE;
1055 comp.setLayout(new GridLayout(1, false));
1057 ToolBar toolBar = new ToolBar(comp, SWT.HORIZONTAL);
1059 mCreateFilterAction = new ToolItemAction(toolBar, SWT.PUSH);
1060 mCreateFilterAction.item.setToolTipText("Create Filter");
1061 mCreateFilterAction.item.setImage(ImageHelper.loadImage(mDdmuiLibImageLoader, mDisplay,
1062 "add.png", //$NON-NLS-1$
1063 DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null));
1064 mCreateFilterAction.item.addSelectionListener(new SelectionAdapter() {
1066 public void widgetSelected(SelectionEvent e) {
1067 mLogPanel.addFilter();
1071 mEditFilterAction = new ToolItemAction(toolBar, SWT.PUSH);
1072 mEditFilterAction.item.setToolTipText("Edit Filter");
1073 mEditFilterAction.item.setImage(ImageHelper.loadImage(mDdmuiLibImageLoader, mDisplay,
1074 "edit.png", //$NON-NLS-1$
1075 DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null));
1076 mEditFilterAction.item.addSelectionListener(new SelectionAdapter() {
1078 public void widgetSelected(SelectionEvent e) {
1079 mLogPanel.editFilter();
1083 mDeleteFilterAction = new ToolItemAction(toolBar, SWT.PUSH);
1084 mDeleteFilterAction.item.setToolTipText("Delete Filter");
1085 mDeleteFilterAction.item.setImage(ImageHelper.loadImage(mDdmuiLibImageLoader, mDisplay,
1086 "delete.png", //$NON-NLS-1$
1087 DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null));
1088 mDeleteFilterAction.item.addSelectionListener(new SelectionAdapter() {
1090 public void widgetSelected(SelectionEvent e) {
1091 mLogPanel.deleteFilter();
1096 new ToolItem(toolBar, SWT.SEPARATOR);
1098 LogLevel[] levels = LogLevel.values();
1099 mLogLevelActions = new ToolItemAction[mLogLevelIcons.length];
1100 for (int i = 0 ; i < mLogLevelActions.length; i++) {
1101 String name = levels[i].getStringValue();
1102 final ToolItemAction newAction = new ToolItemAction(toolBar, SWT.CHECK);
1103 mLogLevelActions[i] = newAction;
1104 //newAction.item.setText(name);
1105 newAction.item.addSelectionListener(new SelectionAdapter() {
1107 public void widgetSelected(SelectionEvent e) {
1108 // disable the other actions and record current index
1109 for (int i = 0 ; i < mLogLevelActions.length; i++) {
1110 ToolItemAction a = mLogLevelActions[i];
1111 if (a == newAction) {
1114 // set the log level
1115 mLogPanel.setCurrentFilterLogLevel(i+2);
1117 a.setChecked(false);
1123 newAction.item.setToolTipText(name);
1124 newAction.item.setImage(ImageHelper.loadImage(mDdmuiLibImageLoader, mDisplay,
1126 DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null));
1129 new ToolItem(toolBar, SWT.SEPARATOR);
1131 mClearAction = new ToolItemAction(toolBar, SWT.PUSH);
1132 mClearAction.item.setToolTipText("Clear Log");
1134 mClearAction.item.setImage(ImageHelper.loadImage(mDdmuiLibImageLoader, mDisplay,
1135 "clear.png", //$NON-NLS-1$
1136 DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null));
1137 mClearAction.item.addSelectionListener(new SelectionAdapter() {
1139 public void widgetSelected(SelectionEvent e) {
1144 new ToolItem(toolBar, SWT.SEPARATOR);
1146 mExportAction = new ToolItemAction(toolBar, SWT.PUSH);
1147 mExportAction.item.setToolTipText("Export Selection As Text...");
1148 mExportAction.item.setImage(ImageHelper.loadImage(mDdmuiLibImageLoader, mDisplay,
1149 "save.png", //$NON-NLS-1$
1150 DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null));
1151 mExportAction.item.addSelectionListener(new SelectionAdapter() {
1153 public void widgetSelected(SelectionEvent e) {
1161 // now create the log view
1162 mLogPanel = new LogPanel(new ImageLoader(LogPanel.class), colors, new FilterStorage(),
1163 LogPanel.FILTER_MANUAL);
1165 mLogPanel.setActions(mDeleteFilterAction, mEditFilterAction, mLogLevelActions);
1167 String colMode = prefs.getString(PrefsDialog.LOGCAT_COLUMN_MODE);
1168 if (PrefsDialog.LOGCAT_COLUMN_MODE_AUTO.equals(colMode)) {
1169 mLogPanel.setColumnMode(LogPanel.COLUMN_MODE_AUTO);
1172 String fontStr = PrefsDialog.getStore().getString(PrefsDialog.LOGCAT_FONT);
1173 if (fontStr != null) {
1175 FontData fdat = new FontData(fontStr);
1176 mLogPanel.setFont(new Font(display, fdat));
1177 } catch (IllegalArgumentException e) {
1178 // Looks like fontStr isn't a valid font representation.
1179 // We do nothing in this case, the logcat view will use the default font.
1180 } catch (SWTError e2) {
1181 // Looks like the Font() constructor failed.
1182 // We do nothing in this case, the logcat view will use the default font.
1186 mLogPanel.createPanel(comp);
1188 // and start the logcat
1189 mLogPanel.startLogCat(mCurrentDevice);
1193 * Create the contents of the left panel: a table of VMs.
1195 private void createLeftPanel(final Composite comp) {
1196 comp.setLayout(new GridLayout(1, false));
1197 ToolBar toolBar = new ToolBar(comp, SWT.HORIZONTAL | SWT.RIGHT | SWT.WRAP);
1198 toolBar.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
1199 createDevicePanelToolBar(toolBar);
1201 Composite c = new Composite(comp, SWT.NONE);
1202 c.setLayoutData(new GridData(GridData.FILL_BOTH));
1204 mDevicePanel = new DevicePanel(new ImageLoader(DevicePanel.class), true /* showPorts */);
1205 mDevicePanel.createPanel(c);
1207 // add ourselves to the device panel selection listener
1208 mDevicePanel.addSelectionListener(this);
1212 * Create the contents of the right panel: tabs with VM information.
1214 private void createRightPanel(final Composite comp) {
1216 TabFolder tabFolder;
1218 comp.setLayout(new FillLayout());
1220 tabFolder = new TabFolder(comp, SWT.NONE);
1222 for (int i = 0; i < mPanels.length; i++) {
1223 if (mPanels[i] != null) {
1224 item = new TabItem(tabFolder, SWT.NONE);
1225 item.setText(mPanelNames[i]);
1226 item.setToolTipText(mPanelTips[i]);
1227 item.setControl(mPanels[i].createPanel(tabFolder));
1231 // add the emulator control panel to the folders.
1232 item = new TabItem(tabFolder, SWT.NONE);
1233 item.setText("Emulator Control");
1234 item.setToolTipText("Emulator Control Panel");
1235 mEmulatorPanel = new EmulatorControlPanel(mDdmuiLibImageLoader);
1236 item.setControl(mEmulatorPanel.createPanel(tabFolder));
1238 // add the event log panel to the folders.
1239 item = new TabItem(tabFolder, SWT.NONE);
1240 item.setText("Event Log");
1241 item.setToolTipText("Event Log");
1243 // create the composite that will hold the toolbar and the event log panel.
1244 Composite eventLogTopComposite = new Composite(tabFolder, SWT.NONE);
1245 item.setControl(eventLogTopComposite);
1246 eventLogTopComposite.setLayout(new GridLayout(1, false));
1248 // create the toolbar and the actions
1249 ToolBar toolbar = new ToolBar(eventLogTopComposite, SWT.HORIZONTAL);
1250 toolbar.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
1252 ToolItemAction optionsAction = new ToolItemAction(toolbar, SWT.PUSH);
1253 optionsAction.item.setToolTipText("Opens the options panel");
1254 optionsAction.item.setImage(ImageHelper.loadImage(mDdmuiLibImageLoader, comp.getDisplay(),
1255 "edit.png", //$NON-NLS-1$
1256 DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null));
1258 ToolItemAction clearAction = new ToolItemAction(toolbar, SWT.PUSH);
1259 clearAction.item.setToolTipText("Clears the event log");
1260 clearAction.item.setImage(ImageHelper.loadImage(mDdmuiLibImageLoader, comp.getDisplay(),
1261 "clear.png", //$NON-NLS-1$
1262 DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null));
1264 new ToolItem(toolbar, SWT.SEPARATOR);
1266 ToolItemAction saveAction = new ToolItemAction(toolbar, SWT.PUSH);
1267 saveAction.item.setToolTipText("Saves the event log");
1268 saveAction.item.setImage(ImageHelper.loadImage(mDdmuiLibImageLoader, comp.getDisplay(),
1269 "save.png", //$NON-NLS-1$
1270 DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null));
1272 ToolItemAction loadAction = new ToolItemAction(toolbar, SWT.PUSH);
1273 loadAction.item.setToolTipText("Loads an event log");
1274 loadAction.item.setImage(ImageHelper.loadImage(mDdmuiLibImageLoader, comp.getDisplay(),
1275 "load.png", //$NON-NLS-1$
1276 DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null));
1278 ToolItemAction importBugAction = new ToolItemAction(toolbar, SWT.PUSH);
1279 importBugAction.item.setToolTipText("Imports a bug report");
1280 importBugAction.item.setImage(ImageHelper.loadImage(mDdmuiLibImageLoader, comp.getDisplay(),
1281 "importBug.png", //$NON-NLS-1$
1282 DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null));
1284 // create the event log panel
1285 mEventLogPanel = new EventLogPanel(mDdmuiLibImageLoader);
1287 // set the external actions
1288 mEventLogPanel.setActions(optionsAction, clearAction, saveAction, loadAction,
1292 mEventLogPanel.createPanel(eventLogTopComposite);
1295 private void createFileExplorer() {
1296 if (mExplorer == null) {
1297 mExplorerShell = new Shell(mDisplay);
1300 mExplorerShell.setLayout(new GridLayout(1, false));
1303 ToolBar toolBar = new ToolBar(mExplorerShell, SWT.HORIZONTAL);
1304 toolBar.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
1306 ToolItemAction pullAction = new ToolItemAction(toolBar, SWT.PUSH);
1307 pullAction.item.setToolTipText("Pull File from Device");
1308 pullAction.item.setImage(mDdmuiLibImageLoader.loadImage("pull.png", mDisplay)); //$NON-NLS-1$
1310 ToolItemAction pushAction = new ToolItemAction(toolBar, SWT.PUSH);
1311 pushAction.item.setToolTipText("Push file onto Device");
1312 pushAction.item.setImage(mDdmuiLibImageLoader.loadImage("push.png", mDisplay)); //$NON-NLS-1$
1314 ToolItemAction deleteAction = new ToolItemAction(toolBar, SWT.PUSH);
1315 deleteAction.item.setToolTipText("Delete");
1316 deleteAction.item.setImage(mDdmuiLibImageLoader.loadImage("delete.png", mDisplay)); //$NON-NLS-1$
1319 mExplorer = new DeviceExplorer();
1321 mExplorer.setImages(mDdmuiLibImageLoader.loadImage("file.png", mDisplay), //$NON-NLS-1$
1322 mDdmuiLibImageLoader.loadImage("folder.png", mDisplay), //$NON-NLS-1$
1323 mDdmuiLibImageLoader.loadImage("android.png", mDisplay), //$NON-NLS-1$
1325 mExplorer.setActions(pushAction, pullAction, deleteAction);
1327 pullAction.item.addSelectionListener(new SelectionAdapter() {
1329 public void widgetSelected(SelectionEvent e) {
1330 mExplorer.pullSelection();
1333 pullAction.setEnabled(false);
1335 pushAction.item.addSelectionListener(new SelectionAdapter() {
1337 public void widgetSelected(SelectionEvent e) {
1338 mExplorer.pushIntoSelection();
1341 pushAction.setEnabled(false);
1343 deleteAction.item.addSelectionListener(new SelectionAdapter() {
1345 public void widgetSelected(SelectionEvent e) {
1346 mExplorer.deleteSelection();
1349 deleteAction.setEnabled(false);
1351 Composite parent = new Composite(mExplorerShell, SWT.NONE);
1352 parent.setLayoutData(new GridData(GridData.FILL_BOTH));
1354 mExplorer.createPanel(parent);
1355 mExplorer.switchDevice(mCurrentDevice);
1357 mExplorerShell.addShellListener(new ShellListener() {
1358 public void shellActivated(ShellEvent e) {
1362 public void shellClosed(ShellEvent e) {
1364 mExplorerShell = null;
1367 public void shellDeactivated(ShellEvent e) {
1371 public void shellDeiconified(ShellEvent e) {
1375 public void shellIconified(ShellEvent e) {
1380 mExplorerShell.pack();
1381 setExplorerSizeAndPosition(mExplorerShell);
1382 mExplorerShell.open();
1384 if (mExplorerShell != null) {
1385 mExplorerShell.forceActive();
1391 * Set the status line. TODO: make this a stack, so we can safely have
1392 * multiple things trying to set it all at once. Also specify an expiration?
1394 public void setStatusLine(final String str) {
1396 mDisplay.asyncExec(new Runnable() {
1398 doSetStatusLine(str);
1401 } catch (SWTException swte) {
1402 if (!mDisplay.isDisposed())
1407 private void doSetStatusLine(String str) {
1408 if (mStatusLine.isDisposed())
1411 if (!mStatusLine.getText().equals(str)) {
1412 mStatusLine.setText(str);
1414 // try { Thread.sleep(100); }
1415 // catch (InterruptedException ie) {}
1419 public void displayError(final String msg) {
1421 mDisplay.syncExec(new Runnable() {
1423 MessageDialog.openError(mDisplay.getActiveShell(), "Error",
1427 } catch (SWTException swte) {
1428 if (!mDisplay.isDisposed())
1433 private void enableButtons() {
1434 if (mCurrentClient != null) {
1435 mTBShowThreadUpdates.setSelection(mCurrentClient.isThreadUpdateEnabled());
1436 mTBShowThreadUpdates.setEnabled(true);
1437 mTBShowHeapUpdates.setSelection(mCurrentClient.isHeapUpdateEnabled());
1438 mTBShowHeapUpdates.setEnabled(true);
1439 mTBHalt.setEnabled(true);
1440 mTBCauseGc.setEnabled(true);
1442 // list is empty, disable these
1443 mTBShowThreadUpdates.setSelection(false);
1444 mTBShowThreadUpdates.setEnabled(false);
1445 mTBShowHeapUpdates.setSelection(false);
1446 mTBShowHeapUpdates.setEnabled(false);
1447 mTBHalt.setEnabled(false);
1448 mTBCauseGc.setEnabled(false);
1453 * Sent when a new {@link IDevice} and {@link Client} are selected.
1454 * @param selectedDevice the selected device. If null, no devices are selected.
1455 * @param selectedClient The selected client. If null, no clients are selected.
1457 * @see IUiSelectionListener
1459 public void selectionChanged(IDevice selectedDevice, Client selectedClient) {
1460 if (mCurrentDevice != selectedDevice) {
1461 mCurrentDevice = selectedDevice;
1462 for (TablePanel panel : mPanels) {
1463 if (panel != null) {
1464 panel.deviceSelected(mCurrentDevice);
1468 mEmulatorPanel.deviceSelected(mCurrentDevice);
1469 mLogPanel.deviceSelected(mCurrentDevice);
1470 if (mEventLogPanel != null) {
1471 mEventLogPanel.deviceSelected(mCurrentDevice);
1474 if (mExplorer != null) {
1475 mExplorer.switchDevice(mCurrentDevice);
1479 if (mCurrentClient != selectedClient) {
1480 AndroidDebugBridge.getBridge().setSelectedClient(selectedClient);
1481 mCurrentClient = selectedClient;
1482 for (TablePanel panel : mPanels) {
1483 if (panel != null) {
1484 panel.clientSelected(mCurrentClient);