Home | History | Annotate | Download | only in sdkman2
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      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
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     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.
     15  */
     16 
     17 package com.android.sdkuilib.internal.repository.sdkman2;
     18 
     19 
     20 import com.android.sdklib.ISdkLog;
     21 import com.android.sdklib.SdkConstants;
     22 import com.android.sdklib.internal.repository.ITaskFactory;
     23 import com.android.sdkuilib.internal.repository.AboutDialog;
     24 import com.android.sdkuilib.internal.repository.MenuBarWrapper;
     25 import com.android.sdkuilib.internal.repository.SettingsController;
     26 import com.android.sdkuilib.internal.repository.SettingsDialog;
     27 import com.android.sdkuilib.internal.repository.UpdaterData;
     28 import com.android.sdkuilib.internal.repository.icons.ImageFactory;
     29 import com.android.sdkuilib.internal.repository.sdkman1.AvdManagerPage;
     30 import com.android.sdkuilib.repository.AvdManagerWindow.AvdInvocationContext;
     31 import com.android.sdkuilib.repository.ISdkChangeListener;
     32 import com.android.sdkuilib.repository.SdkUpdaterWindow;
     33 
     34 import org.eclipse.swt.SWT;
     35 import org.eclipse.swt.events.DisposeEvent;
     36 import org.eclipse.swt.events.DisposeListener;
     37 import org.eclipse.swt.events.SelectionAdapter;
     38 import org.eclipse.swt.events.SelectionEvent;
     39 import org.eclipse.swt.graphics.Point;
     40 import org.eclipse.swt.layout.GridData;
     41 import org.eclipse.swt.layout.GridLayout;
     42 import org.eclipse.swt.widgets.Display;
     43 import org.eclipse.swt.widgets.Menu;
     44 import org.eclipse.swt.widgets.MenuItem;
     45 import org.eclipse.swt.widgets.Shell;
     46 
     47 /**
     48  * This is an intermediate version of the {@link AvdManagerPage}
     49  * wrapped in its own standalone window for use from the SDK Manager 2.
     50  */
     51 public class AvdManagerWindowImpl1 {
     52 
     53     private static final String APP_NAME = "Android Virtual Device Manager";
     54     private static final String APP_NAME_MAC_MENU = "AVD Manager";
     55     private static final String SIZE_POS_PREFIX = "avdman1"; //$NON-NLS-1$
     56 
     57     private final Shell mParentShell;
     58     private final AvdInvocationContext mContext;
     59     /** Internal data shared between the window and its pages. */
     60     private final UpdaterData mUpdaterData;
     61     /** True if this window created the UpdaterData, in which case it needs to dispose it. */
     62     private final boolean mOwnUpdaterData;
     63 
     64     // --- UI members ---
     65 
     66     protected Shell mShell;
     67     private AvdManagerPage mAvdPage;
     68     private SettingsController mSettingsController;
     69 
     70     /**
     71      * Creates a new window. Caller must call open(), which will block.
     72      *
     73      * @param parentShell Parent shell.
     74      * @param sdkLog Logger. Cannot be null.
     75      * @param osSdkRoot The OS path to the SDK root.
     76      * @param context The {@link AvdInvocationContext} to change the behavior depending on who's
     77      *  opening the SDK Manager.
     78      */
     79     public AvdManagerWindowImpl1(
     80             Shell parentShell,
     81             ISdkLog sdkLog,
     82             String osSdkRoot,
     83             AvdInvocationContext context) {
     84         mParentShell = parentShell;
     85         mContext = context;
     86         mUpdaterData = new UpdaterData(osSdkRoot, sdkLog);
     87         mOwnUpdaterData = true;
     88     }
     89 
     90     /**
     91      * Creates a new window. Caller must call open(), which will block.
     92      * <p/>
     93      * This is to be used when the window is opened from {@link SdkUpdaterWindowImpl2}
     94      * to share the same {@link UpdaterData} structure.
     95      *
     96      * @param parentShell Parent shell.
     97      * @param updaterData The parent's updater data.
     98      * @param context The {@link AvdInvocationContext} to change the behavior depending on who's
     99      *  opening the SDK Manager.
    100      */
    101     public AvdManagerWindowImpl1(
    102             Shell parentShell,
    103             UpdaterData updaterData,
    104             AvdInvocationContext context) {
    105         mParentShell = parentShell;
    106         mContext = context;
    107         mUpdaterData = updaterData;
    108         mOwnUpdaterData = false;
    109     }
    110 
    111     /**
    112      * Opens the window.
    113      * @wbp.parser.entryPoint
    114      */
    115     public void open() {
    116         if (mParentShell == null) {
    117             Display.setAppName(APP_NAME); //$hide$ (hide from SWT designer)
    118         }
    119 
    120         createShell();
    121         preCreateContent();
    122         createContents();
    123         createMenuBar();
    124         mShell.open();
    125         mShell.layout();
    126 
    127         boolean ok = postCreateContent();
    128 
    129         if (ok && mContext == AvdInvocationContext.STANDALONE) {
    130             Display display = Display.getDefault();
    131             while (!mShell.isDisposed()) {
    132                 if (!display.readAndDispatch()) {
    133                     display.sleep();
    134                 }
    135             }
    136 
    137             dispose();  //$hide$
    138         }
    139     }
    140 
    141     private void createShell() {
    142         // The AVD Manager must use a shell trim when standalone
    143         // or a dialog trim when invoked from somewhere else.
    144         int style = SWT.SHELL_TRIM;
    145         if (mContext != AvdInvocationContext.STANDALONE) {
    146             style |= SWT.APPLICATION_MODAL;
    147         }
    148 
    149         mShell = new Shell(mParentShell, style);
    150         mShell.addDisposeListener(new DisposeListener() {
    151             @Override
    152             public void widgetDisposed(DisposeEvent e) {
    153                 ShellSizeAndPos.saveSizeAndPos(mShell, SIZE_POS_PREFIX);    //$hide$
    154                 onAndroidSdkUpdaterDispose();                               //$hide$
    155             }
    156         });
    157 
    158         GridLayout glShell = new GridLayout(2, false);
    159         glShell.verticalSpacing = 0;
    160         glShell.horizontalSpacing = 0;
    161         glShell.marginWidth = 0;
    162         glShell.marginHeight = 0;
    163         mShell.setLayout(glShell);
    164 
    165         mShell.setMinimumSize(new Point(500, 300));
    166         mShell.setSize(700, 500);
    167         mShell.setText(APP_NAME);
    168 
    169         ShellSizeAndPos.loadSizeAndPos(mShell, SIZE_POS_PREFIX);
    170     }
    171 
    172     private void createContents() {
    173 
    174         mAvdPage = new AvdManagerPage(mShell, SWT.NONE, mUpdaterData);
    175         mAvdPage.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
    176     }
    177 
    178     @SuppressWarnings("unused") // MenuBarWrapper works using side effects
    179     private void createMenuBar() {
    180 
    181         if (mContext != AvdInvocationContext.STANDALONE) {
    182             return;
    183         }
    184 
    185         Menu menuBar = new Menu(mShell, SWT.BAR);
    186         mShell.setMenuBar(menuBar);
    187 
    188         MenuItem menuBarTools = new MenuItem(menuBar, SWT.CASCADE);
    189         menuBarTools.setText("Tools");
    190 
    191         Menu menuTools = new Menu(menuBarTools);
    192         menuBarTools.setMenu(menuTools);
    193 
    194         MenuItem manageSdk = new MenuItem(menuTools, SWT.NONE);
    195         manageSdk.setText("Manage SDK...");
    196         manageSdk.addSelectionListener(new SelectionAdapter() {
    197             @Override
    198             public void widgetSelected(SelectionEvent event) {
    199                 onSdkManager();
    200             }
    201         });
    202 
    203         if (mContext != AvdInvocationContext.IDE) {
    204             // Note: when invoked from an IDE, the SwtMenuBar library isn't
    205             // available. This means this source should not directly import
    206             // any of SwtMenuBar classes, otherwise the whole window class
    207             // would fail to load. The MenuBarWrapper below helps to make
    208             // that indirection.
    209 
    210             try {
    211                 new MenuBarWrapper(APP_NAME_MAC_MENU, menuTools) {
    212                     @Override
    213                     public void onPreferencesMenuSelected() {
    214                         SettingsDialog sd = new SettingsDialog(mShell, mUpdaterData);
    215                         sd.open();
    216                     }
    217 
    218                     @Override
    219                     public void onAboutMenuSelected() {
    220                         AboutDialog ad = new AboutDialog(mShell, mUpdaterData);
    221                         ad.open();
    222                     }
    223 
    224                     @Override
    225                     public void printError(String format, Object... args) {
    226                         if (mUpdaterData != null) {
    227                             mUpdaterData.getSdkLog().error(null, format, args);
    228                         }
    229                     }
    230                 };
    231             } catch (Exception e) {
    232                 mUpdaterData.getSdkLog().error(e, "Failed to setup menu bar");
    233                 e.printStackTrace();
    234             }
    235         }
    236     }
    237 
    238 
    239     // -- Start of internal part ----------
    240     // Hide everything down-below from SWT designer
    241     //$hide>>$
    242 
    243     // --- Public API -----------
    244 
    245     /**
    246      * Adds a new listener to be notified when a change is made to the content of the SDK.
    247      */
    248     public void addListener(ISdkChangeListener listener) {
    249         mUpdaterData.addListeners(listener);
    250     }
    251 
    252     /**
    253      * Removes a new listener to be notified anymore when a change is made to the content of
    254      * the SDK.
    255      */
    256     public void removeListener(ISdkChangeListener listener) {
    257         mUpdaterData.removeListener(listener);
    258     }
    259 
    260     // --- Internals & UI Callbacks -----------
    261 
    262     /**
    263      * Called before the UI is created.
    264      */
    265     private void preCreateContent() {
    266         mUpdaterData.setWindowShell(mShell);
    267         // We need the UI factory to create the UI
    268         mUpdaterData.setImageFactory(new ImageFactory(mShell.getDisplay()));
    269         // Note: we can't create the TaskFactory yet because we need the UI
    270         // to be created first, so this is done in postCreateContent().
    271     }
    272 
    273     /**
    274      * Once the UI has been created, initializes the content.
    275      * This creates the pages, selects the first one, setup sources and scan for local folders.
    276      *
    277      * Returns true if we should show the window.
    278      */
    279     private boolean postCreateContent() {
    280         setWindowImage(mShell);
    281 
    282         setupSources();
    283         initializeSettings();
    284 
    285         if (mUpdaterData.checkIfInitFailed()) {
    286             return false;
    287         }
    288 
    289         mUpdaterData.broadcastOnSdkLoaded();
    290 
    291         return true;
    292     }
    293 
    294     /**
    295      * Creates the icon of the window shell.
    296      *
    297      * @param shell The shell on which to put the icon
    298      */
    299     private void setWindowImage(Shell shell) {
    300         String imageName = "android_icon_16.png"; //$NON-NLS-1$
    301         if (SdkConstants.currentPlatform() == SdkConstants.PLATFORM_DARWIN) {
    302             imageName = "android_icon_128.png";
    303         }
    304 
    305         if (mUpdaterData != null) {
    306             ImageFactory imgFactory = mUpdaterData.getImageFactory();
    307             if (imgFactory != null) {
    308                 shell.setImage(imgFactory.getImageByName(imageName));
    309             }
    310         }
    311     }
    312 
    313     /**
    314      * Called by the main loop when the window has been disposed.
    315      */
    316     private void dispose() {
    317         mUpdaterData.getSources().saveUserAddons(mUpdaterData.getSdkLog());
    318     }
    319 
    320     /**
    321      * Callback called when the window shell is disposed.
    322      */
    323     private void onAndroidSdkUpdaterDispose() {
    324         if (mOwnUpdaterData && mUpdaterData != null) {
    325             ImageFactory imgFactory = mUpdaterData.getImageFactory();
    326             if (imgFactory != null) {
    327                 imgFactory.dispose();
    328             }
    329         }
    330     }
    331 
    332     /**
    333      * Used to initialize the sources.
    334      */
    335     private void setupSources() {
    336         mUpdaterData.setupDefaultSources();
    337     }
    338 
    339     /**
    340      * Initializes settings.
    341      * This must be called after addExtraPages(), which created a settings page.
    342      * Iterate through all the pages to find the first (and supposedly unique) setting page,
    343      * and use it to load and apply these settings.
    344      */
    345     private void initializeSettings() {
    346         mSettingsController = mUpdaterData.getSettingsController();
    347         mSettingsController.loadSettings();
    348         mSettingsController.applySettings();
    349     }
    350 
    351     private void onSdkManager() {
    352         ITaskFactory oldFactory = mUpdaterData.getTaskFactory();
    353 
    354         try {
    355             SdkUpdaterWindowImpl2 win = new SdkUpdaterWindowImpl2(
    356                     mShell,
    357                     mUpdaterData,
    358                     SdkUpdaterWindow.SdkInvocationContext.AVD_MANAGER);
    359 
    360             win.open();
    361         } catch (Exception e) {
    362             mUpdaterData.getSdkLog().error(e, "SDK Manager window error");
    363         } finally {
    364             mUpdaterData.setTaskFactory(oldFactory);
    365         }
    366     }
    367 }
    368