OSDN Git Service

Save/Restore the width of all columns in the LogCatPanel table.
[android-x86/sdk.git] / ddms / app / src / com / android / ddms / UIThread.java
index 1c33613..0149739 100644 (file)
@@ -21,19 +21,19 @@ import com.android.ddmlib.Client;
 import com.android.ddmlib.ClientData;
 import com.android.ddmlib.IDevice;
 import com.android.ddmlib.Log;
+import com.android.ddmlib.SyncException;
 import com.android.ddmlib.SyncService;
 import com.android.ddmlib.AndroidDebugBridge.IClientChangeListener;
 import com.android.ddmlib.ClientData.IHprofDumpHandler;
 import com.android.ddmlib.ClientData.MethodProfilingStatus;
 import com.android.ddmlib.Log.ILogOutput;
 import com.android.ddmlib.Log.LogLevel;
-import com.android.ddmlib.SyncService.SyncResult;
 import com.android.ddmuilib.AllocationPanel;
+import com.android.ddmuilib.DdmUiPreferences;
 import com.android.ddmuilib.DevicePanel;
 import com.android.ddmuilib.EmulatorControlPanel;
 import com.android.ddmuilib.HeapPanel;
 import com.android.ddmuilib.ITableFocusListener;
-import com.android.ddmuilib.ImageHelper;
 import com.android.ddmuilib.ImageLoader;
 import com.android.ddmuilib.InfoPanel;
 import com.android.ddmuilib.NativeHeapPanel;
@@ -47,10 +47,16 @@ import com.android.ddmuilib.explorer.DeviceExplorer;
 import com.android.ddmuilib.handler.BaseFileHandler;
 import com.android.ddmuilib.handler.MethodProfilingHandler;
 import com.android.ddmuilib.log.event.EventLogPanel;
+import com.android.ddmuilib.logcat.LogCatPanel;
+import com.android.ddmuilib.logcat.LogCatReceiver;
 import com.android.ddmuilib.logcat.LogColors;
 import com.android.ddmuilib.logcat.LogFilter;
 import com.android.ddmuilib.logcat.LogPanel;
 import com.android.ddmuilib.logcat.LogPanel.ILogFilterStorageManager;
+import com.android.menubar.IMenuBarCallback;
+import com.android.menubar.IMenuBarEnhancer;
+import com.android.menubar.IMenuBarEnhancer.MenuBarMode;
+import com.android.menubar.MenuBarEnhancer;
 
 import org.eclipse.jface.dialogs.MessageDialog;
 import org.eclipse.jface.preference.IPreferenceStore;
@@ -85,7 +91,6 @@ import org.eclipse.swt.widgets.Label;
 import org.eclipse.swt.widgets.Listener;
 import org.eclipse.swt.widgets.Menu;
 import org.eclipse.swt.widgets.MenuItem;
-import org.eclipse.swt.widgets.MessageBox;
 import org.eclipse.swt.widgets.Sash;
 import org.eclipse.swt.widgets.Shell;
 import org.eclipse.swt.widgets.TabFolder;
@@ -102,6 +107,8 @@ import java.util.ArrayList;
  * when {@link IDevice} / {@link Client} selection changes.
  */
 public class UIThread implements IUiSelectionListener, IClientChangeListener {
+    private static final String APP_NAME = "DDMS";
+
     /*
      * UI tab panel definitions. The constants here must match up with the array
      * indices in mPanels. PANEL_CLIENT_LIST is a "virtual" panel representing
@@ -176,9 +183,6 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
     private ToolItem mTBDumpHprof;
     private ToolItem mTBProfiling;
 
-    private ImageLoader mDdmsImageLoader;
-    private ImageLoader mDdmuiLibImageLoader;
-
     private final class FilterStorage implements ILogFilterStorageManager {
 
         public LogFilter[] getFilterFromStore() {
@@ -220,7 +224,18 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
     }
 
 
-    private LogPanel mLogPanel;
+    /**
+     * Flag to indicate whether to use the old or the new logcat view. This is a
+     * temporary workaround that will be removed once the new view is complete.
+     */
+    private static final String USE_NEW_LOGCAT_VIEW =
+            System.getenv("ANDROID_USE_NEW_LOGCAT_VIEW");
+    private boolean useOldLogCatView() {
+        return USE_NEW_LOGCAT_VIEW == null;
+    }
+
+    private LogPanel mLogPanel; /* only valid when useOldLogCatView() == true */
+    private LogCatPanel mLogCatPanel; /* only valid when useOldLogCatView() == false */
 
     private ToolItemAction mCreateFilterAction;
     private ToolItemAction mDeleteFilterAction;
@@ -256,6 +271,8 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
 
     private Image mTracingStopImage;
 
+    private ImageLoader mDdmUiLibLoader;
+
     private class TableFocusListener implements ITableFocusListener {
 
         private IFocusedTableActivator mCurrentActivator;
@@ -330,18 +347,20 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
                         // get the sync service to pull the HPROF file
                         final SyncService sync = client.getDevice().getSyncService();
                         if (sync != null) {
-                            SyncResult result = promptAndPull(sync,
+                            promptAndPull(sync,
                                     client.getClientData().getClientDescription() + ".hprof",
                                     remoteFilePath, "Save HPROF file");
-                            if (result != null && result.getCode() != SyncService.RESULT_OK) {
-                                displayErrorFromUiThread(
-                                        "Unable to download HPROF file from device '%1$s'.\n\n%2$s",
-                                        device.getSerialNumber(), result.getMessage());
-                            }
                         } else {
-                            displayErrorFromUiThread("Unable to download HPROF file from device '%1$s'.",
+                            displayErrorFromUiThread(
+                                    "Unable to download HPROF file from device '%1$s'.",
                                     device.getSerialNumber());
                         }
+                    } catch (SyncException e) {
+                        if (e.wasCanceled() == false) {
+                            displayErrorFromUiThread(
+                                    "Unable to download HPROF file from device '%1$s'.\n\n%2$s",
+                                    device.getSerialNumber(), e.getMessage());
+                        }
                     } catch (Exception e) {
                         displayErrorFromUiThread("Unable to download HPROF file from device '%1$s'.",
                                 device.getSerialNumber());
@@ -414,19 +433,18 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
 
     /**
      * Create SWT objects and drive the user interface event loop.
-     * @param location location of the folder that contains ddms.
+     * @param ddmsParentLocation location of the folder that contains ddms.
      */
     public void runUI(String ddmsParentLocation) {
-        Display.setAppName("ddms");
+        Display.setAppName(APP_NAME);
         mDisplay = new Display();
         final Shell shell = new Shell(mDisplay);
 
         // create the image loaders for DDMS and DDMUILIB
-        mDdmsImageLoader = new ImageLoader(this.getClass());
-        mDdmuiLibImageLoader = new ImageLoader(DevicePanel.class);
+        mDdmUiLibLoader = ImageLoader.getDdmUiLibLoader();
 
-        shell.setImage(ImageHelper.loadImage(mDdmsImageLoader, mDisplay,
-                "ddms-icon.png", //$NON-NLS-1$
+        shell.setImage(ImageLoader.getLoader(this.getClass()).loadImage(mDisplay,
+                "ddms-128.png", //$NON-NLS-1$
                 100, 50, null));
 
         Log.setLogOutput(new ILogOutput() {
@@ -436,11 +454,11 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
                 // dialog box only run in UI thread..
                 mDisplay.asyncExec(new Runnable() {
                     public void run() {
-                        Shell shell = mDisplay.getActiveShell();
+                        Shell activeShell = mDisplay.getActiveShell();
                         if (logLevel == LogLevel.ERROR) {
-                            MessageDialog.openError(shell, tag, message);
+                            MessageDialog.openError(activeShell, tag, message);
                         } else {
-                            MessageDialog.openWarning(shell, tag, message);
+                            MessageDialog.openWarning(activeShell, tag, message);
                         }
                     }
                 });
@@ -456,9 +474,18 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
         ClientData.setMethodProfilingHandler(new MethodProfilingHandler(shell));
 
         // [try to] ensure ADB is running
+        // in the new SDK, adb is in the platform-tools, but when run from the command line
+        // in the Android source tree, then adb is next to ddms.
         String adbLocation;
         if (ddmsParentLocation != null && ddmsParentLocation.length() != 0) {
-            adbLocation = ddmsParentLocation + File.separator + "adb"; //$NON-NLS-1$
+            // check if there's a platform-tools folder
+            File platformTools = new File(new File(ddmsParentLocation).getParent(),
+                    "platform-tools");  //$NON-NLS-1$
+            if (platformTools.isDirectory()) {
+                adbLocation = platformTools.getAbsolutePath() + File.separator + "adb"; //$NON-NLS-1$
+            } else {
+                adbLocation = ddmsParentLocation + File.separator + "adb"; //$NON-NLS-1$
+            }
         } else {
             adbLocation = "adb"; //$NON-NLS-1$
         }
@@ -484,7 +511,9 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
             if (!mDisplay.readAndDispatch())
                 mDisplay.sleep();
         }
-        mLogPanel.stopLogCat(true);
+        if (useOldLogCatView()) {
+            mLogPanel.stopLogCat(true);
+        }
 
         mDevicePanel.dispose();
         for (TablePanel panel : mPanels) {
@@ -493,6 +522,8 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
             }
         }
 
+        ImageLoader.dispose();
+
         mDisplay.dispose();
         Log.d("ddms", "UI is down");
     }
@@ -546,20 +577,20 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
         shell.addControlListener(new ControlListener() {
             public void controlMoved(ControlEvent e) {
                 // get the new x/y
-                Rectangle rect = shell.getBounds();
+                Rectangle controlBounds = shell.getBounds();
                 // store in pref file
-                PreferenceStore prefs = PrefsDialog.getStore();
-                prefs.setValue(PrefsDialog.SHELL_X, rect.x);
-                prefs.setValue(PrefsDialog.SHELL_Y, rect.y);
+                PreferenceStore currentPrefs = PrefsDialog.getStore();
+                currentPrefs.setValue(PrefsDialog.SHELL_X, controlBounds.x);
+                currentPrefs.setValue(PrefsDialog.SHELL_Y, controlBounds.y);
             }
 
             public void controlResized(ControlEvent e) {
                 // get the new w/h
-                Rectangle rect = shell.getBounds();
+                Rectangle controlBounds = shell.getBounds();
                 // store in pref file
-                PreferenceStore prefs = PrefsDialog.getStore();
-                prefs.setValue(PrefsDialog.SHELL_WIDTH, rect.width);
-                prefs.setValue(PrefsDialog.SHELL_HEIGHT, rect.height);
+                PreferenceStore currentPrefs = PrefsDialog.getStore();
+                currentPrefs.setValue(PrefsDialog.SHELL_WIDTH, controlBounds.width);
+                currentPrefs.setValue(PrefsDialog.SHELL_HEIGHT, controlBounds.height);
             }
         });
     }
@@ -614,41 +645,31 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
         shell.addControlListener(new ControlListener() {
             public void controlMoved(ControlEvent e) {
                 // get the new x/y
-                Rectangle rect = shell.getBounds();
+                Rectangle controlBounds = shell.getBounds();
                 // store in pref file
-                PreferenceStore prefs = PrefsDialog.getStore();
-                prefs.setValue(PrefsDialog.EXPLORER_SHELL_X, rect.x);
-                prefs.setValue(PrefsDialog.EXPLORER_SHELL_Y, rect.y);
+                PreferenceStore currentPrefs = PrefsDialog.getStore();
+                currentPrefs.setValue(PrefsDialog.EXPLORER_SHELL_X, controlBounds.x);
+                currentPrefs.setValue(PrefsDialog.EXPLORER_SHELL_Y, controlBounds.y);
             }
 
             public void controlResized(ControlEvent e) {
                 // get the new w/h
-                Rectangle rect = shell.getBounds();
+                Rectangle controlBounds = shell.getBounds();
                 // store in pref file
-                PreferenceStore prefs = PrefsDialog.getStore();
-                prefs.setValue(PrefsDialog.EXPLORER_SHELL_WIDTH, rect.width);
-                prefs.setValue(PrefsDialog.EXPLORER_SHELL_HEIGHT, rect.height);
+                PreferenceStore currentPrefs = PrefsDialog.getStore();
+                currentPrefs.setValue(PrefsDialog.EXPLORER_SHELL_WIDTH, controlBounds.width);
+                currentPrefs.setValue(PrefsDialog.EXPLORER_SHELL_HEIGHT, controlBounds.height);
             }
         });
     }
 
     /*
-     * Set the confirm-before-close dialog. TODO: enable/disable in prefs. TODO:
-     * is there any point in having this?
+     * Set the confirm-before-close dialog.
      */
     private void setConfirmClose(final Shell shell) {
-        if (true)
-            return;
-
-        shell.addListener(SWT.Close, new Listener() {
-            public void handleEvent(Event event) {
-                int style = SWT.APPLICATION_MODAL | SWT.YES | SWT.NO;
-                MessageBox msgBox = new MessageBox(shell, style);
-                msgBox.setText("Confirm...");
-                msgBox.setMessage("Close DDM?");
-                event.doit = (msgBox.open() == SWT.YES);
-            }
-        });
+        // Note: there was some commented out code to display a confirmation box
+        // when closing. The feature seems unnecessary and the code was not being
+        // used, so it has been removed.
     }
 
     /*
@@ -667,8 +688,6 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
         actionItem.setText("&Actions");
         MenuItem deviceItem = new MenuItem(menuBar, SWT.CASCADE);
         deviceItem.setText("&Device");
-        MenuItem helpItem = new MenuItem(menuBar, SWT.CASCADE);
-        helpItem.setText("&Help");
 
         // create top-level menus
         Menu fileMenu = new Menu(menuBar);
@@ -679,22 +698,11 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
         actionItem.setMenu(actionMenu);
         Menu deviceMenu = new Menu(menuBar);
         deviceItem.setMenu(deviceMenu);
-        Menu helpMenu = new Menu(menuBar);
-        helpItem.setMenu(helpMenu);
 
         MenuItem item;
 
         // create File menu items
         item = new MenuItem(fileMenu, SWT.NONE);
-        item.setText("&Preferences...");
-        item.addSelectionListener(new SelectionAdapter() {
-            @Override
-            public void widgetSelected(SelectionEvent e) {
-                PrefsDialog.run(shell);
-            }
-        });
-
-        item = new MenuItem(fileMenu, SWT.NONE);
         item.setText("&Static Port Configuration...");
         item.addSelectionListener(new SelectionAdapter() {
             @Override
@@ -704,18 +712,36 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
             }
         });
 
-        new MenuItem(fileMenu, SWT.SEPARATOR);
+        IMenuBarEnhancer enhancer = MenuBarEnhancer.setupMenu(APP_NAME, fileMenu,
+                new IMenuBarCallback() {
+            public void printError(String format, Object... args) {
+                Log.e("DDMS Menu Bar", String.format(format, args));
+            }
 
-        item = new MenuItem(fileMenu, SWT.NONE);
-        item.setText("E&xit\tCtrl-Q");
-        item.setAccelerator('Q' | SWT.CONTROL);
-        item.addSelectionListener(new SelectionAdapter() {
-            @Override
-            public void widgetSelected(SelectionEvent e) {
-                shell.close();
+            public void onPreferencesMenuSelected() {
+                PrefsDialog.run(shell);
+            }
+
+            public void onAboutMenuSelected() {
+                AboutDialog dlg = new AboutDialog(shell);
+                dlg.open();
             }
         });
 
+        if (enhancer.getMenuBarMode() == MenuBarMode.GENERIC) {
+            new MenuItem(fileMenu, SWT.SEPARATOR);
+
+            item = new MenuItem(fileMenu, SWT.NONE);
+            item.setText("E&xit\tCtrl-Q");
+            item.setAccelerator('Q' | (Main.isMac() ? SWT.COMMAND : SWT.CONTROL));
+            item.addSelectionListener(new SelectionAdapter() {
+                @Override
+                public void widgetSelected(SelectionEvent e) {
+                    shell.close();
+                }
+            });
+        }
+
         // create edit menu items
         mCopyMenuItem = new MenuItem(editMenu, SWT.NONE);
         mCopyMenuItem.setText("&Copy\tCtrl-C");
@@ -759,19 +785,37 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
             }
         });
 
+        final MenuItem actionResetAdb = new MenuItem(actionMenu, SWT.NONE);
+        actionResetAdb.setText("&Reset adb");
+        actionResetAdb.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                AndroidDebugBridge bridge = AndroidDebugBridge.getBridge();
+                if (bridge != null) {
+                    bridge.restart();
+                }
+            }
+        });
+
         // configure Action items based on current state
         actionMenu.addMenuListener(new MenuAdapter() {
             @Override
             public void menuShown(MenuEvent e) {
                 actionHaltItem.setEnabled(mTBHalt.getEnabled() && mCurrentClient != null);
                 actionCauseGcItem.setEnabled(mTBCauseGc.getEnabled() && mCurrentClient != null);
+                actionResetAdb.setEnabled(true);
             }
         });
 
         // create Device menu items
         final MenuItem screenShotItem = new MenuItem(deviceMenu, SWT.NONE);
+
+        // The \tCtrl-S "keybinding text" here isn't right for the Mac - but
+        // it's stripped out and replaced by the proper keyboard accelerator
+        // text (e.g. the unicode symbol for the command key + S) anyway
+        // so it's fine to leave it there for the other platforms.
         screenShotItem.setText("&Screen capture...\tCtrl-S");
-        screenShotItem.setAccelerator('S' | SWT.CONTROL);
+        screenShotItem.setAccelerator('S' | (Main.isMac() ? SWT.COMMAND : SWT.CONTROL));
         screenShotItem.addSelectionListener(new SelectionAdapter() {
             @Override
             public void widgetSelected(SelectionEvent e) {
@@ -872,32 +916,6 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
             }
         });
 
-        // create Help menu items
-        item = new MenuItem(helpMenu, SWT.NONE);
-        item.setText("&Contents...");
-        item.addSelectionListener(new SelectionAdapter() {
-            @Override
-            public void widgetSelected(SelectionEvent e) {
-                int style = SWT.APPLICATION_MODAL | SWT.OK;
-                MessageBox msgBox = new MessageBox(shell, style);
-                msgBox.setText("Help!");
-                msgBox.setMessage("Help wanted.");
-                msgBox.open();
-            }
-        });
-
-        new MenuItem(helpMenu, SWT.SEPARATOR);
-
-        item = new MenuItem(helpMenu, SWT.NONE);
-        item.setText("&About...");
-        item.addSelectionListener(new SelectionAdapter() {
-            @Override
-            public void widgetSelected(SelectionEvent e) {
-                AboutDialog dlg = new AboutDialog(shell);
-                dlg.open();
-            }
-        });
-
         // tell the shell to use this menu
         shell.setMenuBar(menuBar);
     }
@@ -942,7 +960,12 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
         panelArea.setLayout(new FormLayout());
 
         createTopPanel(topPanel, darkGray);
-        createBottomPanel(bottomPanel);
+
+        if (useOldLogCatView()) {
+            createBottomPanel(bottomPanel);
+        } else {
+            createLogCatView(bottomPanel);
+        }
 
         // form layout data
         FormData data = new FormData();
@@ -979,7 +1002,9 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
                 e.y = Math.max(Math.min(e.y, bottom), 100);
                 if (e.y != sashRect.y) {
                     sashData.top = new FormAttachment(0, e.y);
-                    prefs.setValue(PREFERENCE_LOGSASH, e.y);
+                    if (prefs != null) {
+                        prefs.setValue(PREFERENCE_LOGSASH, e.y);
+                    }
                     panelArea.layout();
                 }
             }
@@ -989,7 +1014,9 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
         mTableListener = new TableFocusListener();
 
         // now set up the listener in the various panels
-        mLogPanel.setTableFocusListener(mTableListener);
+        if (useOldLogCatView()) {
+            mLogPanel.setTableFocusListener(mTableListener);
+        }
         mEventLogPanel.setTableFocusListener(mTableListener);
         for (TablePanel p : mPanels) {
             if (p != null) {
@@ -1008,7 +1035,7 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
 
         // add "show heap updates" button
         mTBShowHeapUpdates = new ToolItem(toolBar, SWT.CHECK);
-        mTBShowHeapUpdates.setImage(ImageHelper.loadImage(mDdmuiLibImageLoader, display,
+        mTBShowHeapUpdates.setImage(mDdmUiLibLoader.loadImage(display,
                 DevicePanel.ICON_HEAP, DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null));
         mTBShowHeapUpdates.setToolTipText("Show heap updates");
         mTBShowHeapUpdates.setEnabled(false);
@@ -1030,7 +1057,7 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
         mTBDumpHprof = new ToolItem(toolBar, SWT.PUSH);
         mTBDumpHprof.setToolTipText("Dump HPROF file");
         mTBDumpHprof.setEnabled(false);
-        mTBDumpHprof.setImage(ImageHelper.loadImage(mDdmuiLibImageLoader, display,
+        mTBDumpHprof.setImage(mDdmUiLibLoader.loadImage(display,
                 DevicePanel.ICON_HPROF, DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null));
         mTBDumpHprof.addSelectionListener(new SelectionAdapter() {
             @Override
@@ -1047,7 +1074,7 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
         mTBCauseGc = new ToolItem(toolBar, SWT.PUSH);
         mTBCauseGc.setToolTipText("Cause an immediate GC");
         mTBCauseGc.setEnabled(false);
-        mTBCauseGc.setImage(ImageHelper.loadImage(mDdmuiLibImageLoader, display,
+        mTBCauseGc.setImage(mDdmUiLibLoader.loadImage(display,
                 DevicePanel.ICON_GC, DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null));
         mTBCauseGc.addSelectionListener(new SelectionAdapter() {
             @Override
@@ -1060,7 +1087,7 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
 
         // add "show thread updates" button
         mTBShowThreadUpdates = new ToolItem(toolBar, SWT.CHECK);
-        mTBShowThreadUpdates.setImage(ImageHelper.loadImage(mDdmuiLibImageLoader, display,
+        mTBShowThreadUpdates.setImage(mDdmUiLibLoader.loadImage(display,
                 DevicePanel.ICON_THREAD, DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null));
         mTBShowThreadUpdates.setToolTipText("Show thread updates");
         mTBShowThreadUpdates.setEnabled(false);
@@ -1080,10 +1107,10 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
         });
 
         // add a start/stop method tracing
-        mTracingStartImage = ImageHelper.loadImage(mDdmuiLibImageLoader, display,
+        mTracingStartImage = mDdmUiLibLoader.loadImage(display,
                 DevicePanel.ICON_TRACING_START,
                 DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null);
-        mTracingStopImage = ImageHelper.loadImage(mDdmuiLibImageLoader, display,
+        mTracingStopImage = mDdmUiLibLoader.loadImage(display,
                 DevicePanel.ICON_TRACING_STOP,
                 DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null);
         mTBProfiling = new ToolItem(toolBar, SWT.PUSH);
@@ -1104,7 +1131,7 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
         mTBHalt = new ToolItem(toolBar, SWT.PUSH);
         mTBHalt.setToolTipText("Halt the target VM");
         mTBHalt.setEnabled(false);
-        mTBHalt.setImage(ImageHelper.loadImage(mDdmuiLibImageLoader, display,
+        mTBHalt.setImage(mDdmUiLibLoader.loadImage(display,
                 DevicePanel.ICON_HALT, DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null));
         mTBHalt.addSelectionListener(new SelectionAdapter() {
             @Override
@@ -1171,7 +1198,9 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
                 e.x = Math.max(Math.min(e.x, right), minPanelWidth);
                 if (e.x != sashRect.x) {
                     sashData.left = new FormAttachment(0, e.x);
-                    prefs.setValue(PREFERENCE_SASH, e.x);
+                    if (prefs != null) {
+                        prefs.setValue(PREFERENCE_SASH, e.x);
+                    }
                     comp.layout();
                 }
             }
@@ -1206,7 +1235,7 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
 
         mCreateFilterAction = new ToolItemAction(toolBar, SWT.PUSH);
         mCreateFilterAction.item.setToolTipText("Create Filter");
-        mCreateFilterAction.item.setImage(ImageHelper.loadImage(mDdmuiLibImageLoader, mDisplay,
+        mCreateFilterAction.item.setImage(mDdmUiLibLoader.loadImage(mDisplay,
                 "add.png", //$NON-NLS-1$
                 DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null));
         mCreateFilterAction.item.addSelectionListener(new SelectionAdapter() {
@@ -1218,7 +1247,7 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
 
         mEditFilterAction = new ToolItemAction(toolBar, SWT.PUSH);
         mEditFilterAction.item.setToolTipText("Edit Filter");
-        mEditFilterAction.item.setImage(ImageHelper.loadImage(mDdmuiLibImageLoader, mDisplay,
+        mEditFilterAction.item.setImage(mDdmUiLibLoader.loadImage(mDisplay,
                 "edit.png", //$NON-NLS-1$
                 DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null));
         mEditFilterAction.item.addSelectionListener(new SelectionAdapter() {
@@ -1230,7 +1259,7 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
 
         mDeleteFilterAction = new ToolItemAction(toolBar, SWT.PUSH);
         mDeleteFilterAction.item.setToolTipText("Delete Filter");
-        mDeleteFilterAction.item.setImage(ImageHelper.loadImage(mDdmuiLibImageLoader, mDisplay,
+        mDeleteFilterAction.item.setImage(mDdmUiLibLoader.loadImage(mDisplay,
                 "delete.png", //$NON-NLS-1$
                 DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null));
         mDeleteFilterAction.item.addSelectionListener(new SelectionAdapter() {
@@ -1254,13 +1283,13 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
                 @Override
                 public void widgetSelected(SelectionEvent e) {
                     // disable the other actions and record current index
-                    for (int i = 0 ; i < mLogLevelActions.length; i++) {
-                        ToolItemAction a = mLogLevelActions[i];
+                    for (int k = 0 ; k < mLogLevelActions.length; k++) {
+                        ToolItemAction a = mLogLevelActions[k];
                         if (a == newAction) {
                             a.setChecked(true);
 
                             // set the log level
-                            mLogPanel.setCurrentFilterLogLevel(i+2);
+                            mLogPanel.setCurrentFilterLogLevel(k+2);
                         } else {
                             a.setChecked(false);
                         }
@@ -1269,7 +1298,7 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
             });
 
             newAction.item.setToolTipText(name);
-            newAction.item.setImage(ImageHelper.loadImage(mDdmuiLibImageLoader, mDisplay,
+            newAction.item.setImage(mDdmUiLibLoader.loadImage(mDisplay,
                     mLogLevelIcons[i],
                     DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null));
         }
@@ -1279,7 +1308,7 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
         mClearAction = new ToolItemAction(toolBar, SWT.PUSH);
         mClearAction.item.setToolTipText("Clear Log");
 
-        mClearAction.item.setImage(ImageHelper.loadImage(mDdmuiLibImageLoader, mDisplay,
+        mClearAction.item.setImage(mDdmUiLibLoader.loadImage(mDisplay,
                 "clear.png", //$NON-NLS-1$
                 DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null));
         mClearAction.item.addSelectionListener(new SelectionAdapter() {
@@ -1293,7 +1322,7 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
 
         mExportAction = new ToolItemAction(toolBar, SWT.PUSH);
         mExportAction.item.setToolTipText("Export Selection As Text...");
-        mExportAction.item.setImage(ImageHelper.loadImage(mDdmuiLibImageLoader, mDisplay,
+        mExportAction.item.setImage(mDdmUiLibLoader.loadImage(mDisplay,
                 "save.png", //$NON-NLS-1$
                 DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null));
         mExportAction.item.addSelectionListener(new SelectionAdapter() {
@@ -1307,8 +1336,7 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
         toolBar.pack();
 
         // now create the log view
-        mLogPanel = new LogPanel(new ImageLoader(LogPanel.class), colors, new FilterStorage(),
-                LogPanel.FILTER_MANUAL);
+        mLogPanel = new LogPanel(colors, new FilterStorage(), LogPanel.FILTER_MANUAL);
 
         mLogPanel.setActions(mDeleteFilterAction, mEditFilterAction, mLogLevelActions);
 
@@ -1337,6 +1365,15 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
         mLogPanel.startLogCat(mCurrentDevice);
     }
 
+    private void createLogCatView(Composite parent) {
+        mLogCatPanel = new LogCatPanel(new LogCatReceiver(), DdmUiPreferences.getStore());
+        mLogCatPanel.createPanel(parent);
+
+        if (mCurrentDevice != null) {
+            mLogCatPanel.deviceSelected(mCurrentDevice);
+        }
+    }
+
     /*
      * Create the contents of the left panel: a table of VMs.
      */
@@ -1349,7 +1386,7 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
         Composite c = new Composite(comp, SWT.NONE);
         c.setLayoutData(new GridData(GridData.FILL_BOTH));
 
-        mDevicePanel = new DevicePanel(new ImageLoader(DevicePanel.class), true /* showPorts */);
+        mDevicePanel = new DevicePanel(true /* showPorts */);
         mDevicePanel.createPanel(c);
 
         // add ourselves to the device panel selection listener
@@ -1380,7 +1417,7 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
         item = new TabItem(tabFolder, SWT.NONE);
         item.setText("Emulator Control");
         item.setToolTipText("Emulator Control Panel");
-        mEmulatorPanel = new EmulatorControlPanel(mDdmuiLibImageLoader);
+        mEmulatorPanel = new EmulatorControlPanel();
         item.setControl(mEmulatorPanel.createPanel(tabFolder));
 
         // add the event log panel to the folders.
@@ -1399,13 +1436,13 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
 
         ToolItemAction optionsAction = new ToolItemAction(toolbar, SWT.PUSH);
         optionsAction.item.setToolTipText("Opens the options panel");
-        optionsAction.item.setImage(ImageHelper.loadImage(mDdmuiLibImageLoader, comp.getDisplay(),
+        optionsAction.item.setImage(mDdmUiLibLoader.loadImage(comp.getDisplay(),
                 "edit.png", //$NON-NLS-1$
                 DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null));
 
         ToolItemAction clearAction = new ToolItemAction(toolbar, SWT.PUSH);
         clearAction.item.setToolTipText("Clears the event log");
-        clearAction.item.setImage(ImageHelper.loadImage(mDdmuiLibImageLoader, comp.getDisplay(),
+        clearAction.item.setImage(mDdmUiLibLoader.loadImage(comp.getDisplay(),
                 "clear.png", //$NON-NLS-1$
                 DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null));
 
@@ -1413,24 +1450,24 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
 
         ToolItemAction saveAction = new ToolItemAction(toolbar, SWT.PUSH);
         saveAction.item.setToolTipText("Saves the event log");
-        saveAction.item.setImage(ImageHelper.loadImage(mDdmuiLibImageLoader, comp.getDisplay(),
+        saveAction.item.setImage(mDdmUiLibLoader.loadImage(comp.getDisplay(),
                 "save.png", //$NON-NLS-1$
                 DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null));
 
         ToolItemAction loadAction = new ToolItemAction(toolbar, SWT.PUSH);
         loadAction.item.setToolTipText("Loads an event log");
-        loadAction.item.setImage(ImageHelper.loadImage(mDdmuiLibImageLoader, comp.getDisplay(),
+        loadAction.item.setImage(mDdmUiLibLoader.loadImage(comp.getDisplay(),
                 "load.png", //$NON-NLS-1$
                 DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null));
 
         ToolItemAction importBugAction = new ToolItemAction(toolbar, SWT.PUSH);
         importBugAction.item.setToolTipText("Imports a bug report");
-        importBugAction.item.setImage(ImageHelper.loadImage(mDdmuiLibImageLoader, comp.getDisplay(),
+        importBugAction.item.setImage(mDdmUiLibLoader.loadImage(comp.getDisplay(),
                 "importBug.png", //$NON-NLS-1$
                 DevicePanel.ICON_WIDTH, DevicePanel.ICON_WIDTH, null));
 
         // create the event log panel
-        mEventLogPanel = new EventLogPanel(mDdmuiLibImageLoader);
+        mEventLogPanel = new EventLogPanel();
 
         // set the external actions
         mEventLogPanel.setActions(optionsAction, clearAction, saveAction, loadAction,
@@ -1453,7 +1490,7 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
 
             ToolItemAction pullAction = new ToolItemAction(toolBar, SWT.PUSH);
             pullAction.item.setToolTipText("Pull File from Device");
-            Image image = mDdmuiLibImageLoader.loadImage("pull.png", mDisplay); //$NON-NLS-1$
+            Image image = mDdmUiLibLoader.loadImage("pull.png", mDisplay); //$NON-NLS-1$
             if (image != null) {
                 pullAction.item.setImage(image);
             } else {
@@ -1463,7 +1500,7 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
 
             ToolItemAction pushAction = new ToolItemAction(toolBar, SWT.PUSH);
             pushAction.item.setToolTipText("Push file onto Device");
-            image = mDdmuiLibImageLoader.loadImage("push.png", mDisplay); //$NON-NLS-1$
+            image = mDdmUiLibLoader.loadImage("push.png", mDisplay); //$NON-NLS-1$
             if (image != null) {
                 pushAction.item.setImage(image);
             } else {
@@ -1473,7 +1510,7 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
 
             ToolItemAction deleteAction = new ToolItemAction(toolBar, SWT.PUSH);
             deleteAction.item.setToolTipText("Delete");
-            image = mDdmuiLibImageLoader.loadImage("delete.png", mDisplay); //$NON-NLS-1$
+            image = mDdmUiLibLoader.loadImage("delete.png", mDisplay); //$NON-NLS-1$
             if (image != null) {
                 deleteAction.item.setImage(image);
             } else {
@@ -1481,14 +1518,19 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
                 deleteAction.item.setText("Delete"); //$NON-NLS-1$
             }
 
+            ToolItemAction createNewFolderAction = new ToolItemAction(toolBar, SWT.PUSH);
+            createNewFolderAction.item.setToolTipText("New Folder");
+            image = mDdmUiLibLoader.loadImage("add.png", mDisplay); //$NON-NLS-1$
+            if (image != null) {
+                createNewFolderAction.item.setImage(image);
+            } else {
+                // this is for debugging purpose when the icon is missing
+                createNewFolderAction.item.setText("New Folder"); //$NON-NLS-1$
+            }
+
             // device explorer
             mExplorer = new DeviceExplorer();
-
-            mExplorer.setImages(mDdmuiLibImageLoader.loadImage("file.png", mDisplay), //$NON-NLS-1$
-                    mDdmuiLibImageLoader.loadImage("folder.png", mDisplay), //$NON-NLS-1$
-                    mDdmuiLibImageLoader.loadImage("android.png", mDisplay), //$NON-NLS-1$
-                    null);
-            mExplorer.setActions(pushAction, pullAction, deleteAction);
+            mExplorer.setActions(pushAction, pullAction, deleteAction, createNewFolderAction);
 
             pullAction.item.addSelectionListener(new SelectionAdapter() {
                 @Override
@@ -1514,6 +1556,14 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
             });
             deleteAction.setEnabled(false);
 
+            createNewFolderAction.item.addSelectionListener(new SelectionAdapter() {
+                @Override
+                public void widgetSelected(SelectionEvent e) {
+                    mExplorer.createNewFolderInSelection();
+                }
+            });
+            createNewFolderAction.setEnabled(false);
+
             Composite parent = new Composite(mExplorerShell, SWT.NONE);
             parent.setLayoutData(new GridData(GridData.FILL_BOTH));
 
@@ -1664,7 +1714,11 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener {
             }
 
             mEmulatorPanel.deviceSelected(mCurrentDevice);
-            mLogPanel.deviceSelected(mCurrentDevice);
+            if (useOldLogCatView()) {
+                mLogPanel.deviceSelected(mCurrentDevice);
+            } else {
+                mLogCatPanel.deviceSelected(mCurrentDevice);
+            }
             if (mEventLogPanel != null) {
                 mEventLogPanel.deviceSelected(mCurrentDevice);
             }