/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.motorola.studio.android.emulator.ui.perspective; import static com.motorola.studio.android.common.log.StudioLogger.error; import static com.motorola.studio.android.common.log.StudioLogger.warn; import java.util.Collection; import java.util.TreeSet; import org.eclipse.ui.IFolderLayout; import org.eclipse.ui.IPageLayout; import org.eclipse.ui.IPerspectiveFactory; import org.eclipse.ui.PartInitException; import com.motorola.studio.android.common.utilities.EclipseUtils; import com.motorola.studio.android.emulator.ui.perspective.extension.AndroidPerspectiveExtensionBean; import com.motorola.studio.android.emulator.ui.perspective.extension.AndroidPerspectiveExtensionBean.PerspectiveAreas; import com.motorola.studio.android.emulator.ui.perspective.extension.AndroidPerspectiveExtensionReader; import com.motorola.studio.android.emulator.ui.perspective.extension.IAndroidPerspectiveExtensionConstants; import com.motorola.studio.android.emulator.ui.view.AndroidView; import com.motorola.studio.android.emulator.ui.view.MainDisplayView; /** * DESCRIPTION: * This class represents the Android Emulator perspective. * * RESPONSIBILITY: * Create the Android Emulator perspective. * * COLABORATORS: * None * * USAGE: * This class is referenced by the plugin.xml file of this plugin. */ public class AndroidEmulatorPerspective implements IPerspectiveFactory { private static String LAUNCH_COOLBAR_SHORTCUT = "org.eclipse.debug.ui.launchActionSet"; /** * Creates the initial layout for a page. * * @param layout the page layout * * @see IPerspectiveFactory#createInitialLayout(IPageLayout) */ public void createInitialLayout(IPageLayout layout) { // ---------------HOW THE PERSPECTIVE IS LAID OUT--------------- // // The Android Perspective will be dynamically populated according to // the contributions declared to it through the androidPerspectiveExtension // extension point. // The perspective consists of three areas: // - the area where the Android Emulator View is placed, on the right side // - the area where device management related views are placed, on the left side // - the area for emulation views, on the middle // The areas that are dynamically populated are the two last ones, and they will // be referred to as 'dynamic areas' by methods. // // The first area is filled by the code on this method by itself, and the two other // ones are filled depending on what is found for the extension point. // The following drawing illustrates the position of each area on the workbench: // // ____________________________________ // | | | | // | | | | // | Dev | | Moto | // | Mgt | | magx | // | Views | Emu Views Area | Emu | // | Area | | View | // | | | Area | // | | | | // |_______|___________________|_______| // // Device Management views are placed atop of each other on their respective area. // Emulation views are laid out depending on the number of views declared. If there // is only one emulation view, it is placed occupying the entire emulation views area. // If there are two emulation views, they divide the emulation views area in half and // occupy the area from bottom to top, as seen on the following drawing: // // ____________________________________ // | | | | // | | | | // | Dev | Emu Views part 2 | Moto | // | Mgt | | magx | // | Views |___________________| Emu | // | Area | | View | // | | Emu Views part 1 | Area | // | | | | // |_______|___________________|_______| // // If there are three emulation views or more, they divide the emulation views area in // three parts, which are occupied from bottom to top, as seen on the following drawing: // // ____________________________________ // | | | | // | | Emu Views part 3 | | // | Dev |___________________| Moto | // | Mgt | | magx | // | Views | Emu Views part 2 | Emu | // | Area |___________________| View | // | | | Area | // | | Emu Views part 1 | | // |_______|___________________|_______| // // If there are no device management or no emulation views (or both), their folders are // always created so that the workbench is always divided into the correct areas for // better user experience. // // ------------------------------------------------------------- addEmulatorView(layout); addRunCoolbar(layout); createAndPopulateDynamicAreas(layout); // hide the editor area (not necessary on this perspective) layout.setEditorAreaVisible(false); } private void addEmulatorView(IPageLayout layout) { // emulator view is a sticky view, no place holder is necessary (only open it) try { EclipseUtils.showView(AndroidView.ANDROID_VIEW_ID); } catch (PartInitException e) { error("Unable to open Android Emulator View on Android Emulator Perspective."); } layout.addShowViewShortcut(AndroidView.ANDROID_VIEW_ID); layout.addShowViewShortcut(MainDisplayView.EMULATOR_MAIN_DISPLAY_VIEW_ID); } private void addRunCoolbar(IPageLayout layout) { layout.addActionSet(LAUNCH_COOLBAR_SHORTCUT); } private void createAndPopulateDynamicAreas(IPageLayout layout) { // read the extensions for this perspective, as declared by the androidPerspectiveExtension // extension point Collection<AndroidPerspectiveExtensionBean> perspectiveExtensionBeans = AndroidPerspectiveExtensionReader.readAndroidPerspectiveExtensions(); // the folder for placing device management related views IFolderLayout devMgtArea = createDeviceMgtViewsArea(layout); // collection of emuy area view ids for later placement // it is alphabetically ordered (so that a group of defined // views always open on the same location) Collection<String> emuAreaViewIds = new TreeSet<String>(); for (AndroidPerspectiveExtensionBean extensionBean : perspectiveExtensionBeans) { if (PerspectiveAreas.DEVICE_MANAGEMENT_VIEWS_AREA.equals(extensionBean.getArea())) { // put dev mgt views atop of each other on the folder devMgtArea.addView(extensionBean.getViewId()); } else if (PerspectiveAreas.EMULATION_VIEWS_AREA.equals(extensionBean.getArea())) { // collect emu views for later placement emuAreaViewIds.add(extensionBean.getViewId()); } else { // in case of something not expected, log the problem warn("View of id " + extensionBean.getViewId() + " could not be added to Android Emulator perspective"); } } // the number of emu views, for defining the number of folders necessary int numEmuViews = emuAreaViewIds.size(); // create the emu area folders, which will be at most size 3 IFolderLayout[] emuAreaFolders = createEmuArea(layout, numEmuViews); // place the views on the correct folder by using the leftover of dividing the // number of the current view by number of maximum folders (3) int i = 0; for (String viewId : emuAreaViewIds) { emuAreaFolders[i % 3].addView(viewId); i++; // next view } } private IFolderLayout createDeviceMgtViewsArea(IPageLayout layout) { return layout.createFolder(IAndroidPerspectiveExtensionConstants.ATT_AREA_DEVMGT_VALUE, IPageLayout.LEFT, 0.30f, IPageLayout.ID_EDITOR_AREA); } private IFolderLayout[] createEmuArea(IPageLayout layout, int numEmuViews) { // at most 3 folders are necessary IFolderLayout[] emuAreaFolders = new IFolderLayout[3]; // the number of divisions the emu views area will be divided into int div = (numEmuViews >= 3 ? 3 : (numEmuViews == 2 ? 2 : 1)); // the ratio for the first folder to be placed (the bottom one, which may turn // to be the only one if div is equal to 1) float ratio = 1.00f / div; // the bottom folder (#1) is always necessary // for 3 folders, ratio = 0.33f; for 2 folders, ratio = 0.5f emuAreaFolders[0] = layout.createFolder("emuAreaBottom", IPageLayout.BOTTOM, ratio, IPageLayout.ID_EDITOR_AREA); // create folder #2 only if necessary if (numEmuViews >= 2) { // adjust ratio depending on the number of folders in total: // for 3 folders, ratio = 0.67f; for 2 folders, ratio = 0.5f if (numEmuViews > 2) { ratio = 2 * ratio; } emuAreaFolders[1] = layout.createFolder("emuAreaMiddle", IPageLayout.TOP, ratio, "emuAreaBottom"); } // create folder #3 only if necessary if (numEmuViews >= 3) { // ratio is always half of folder #2 space emuAreaFolders[2] = layout.createFolder("emuAreaTop", IPageLayout.TOP, 0.50f, "emuAreaMiddle"); } return emuAreaFolders; } }