com.microsoft.azureexplorer.views.ServiceExplorerView.java Source code

Java tutorial

Introduction

Here is the source code for com.microsoft.azureexplorer.views.ServiceExplorerView.java

Source

/**
 * Copyright (c) Microsoft Corporation
 * 
 * All rights reserved. 
 * 
 * MIT License
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files 
 * (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, 
 * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 
 * subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH 
 * THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
package com.microsoft.azureexplorer.views;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;

import com.microsoft.azureexplorer.Activator;
import com.microsoft.tooling.msservices.helpers.azure.AzureCmdException;
import com.microsoft.tooling.msservices.helpers.azure.AzureManagerImpl;
import com.microsoft.tooling.msservices.helpers.collections.ListChangeListener;
import com.microsoft.tooling.msservices.helpers.collections.ListChangedEvent;
import com.microsoft.tooling.msservices.helpers.collections.ObservableList;
import com.microsoft.tooling.msservices.model.Subscription;
import com.microsoft.tooling.msservices.serviceexplorer.Node;
import com.microsoft.tooling.msservices.serviceexplorer.NodeAction;
import com.microsoft.tooling.msservices.serviceexplorer.azure.AzureServiceModule;
import com.microsoft.tooling.msservices.serviceexplorer.azure.storage.StorageModule;
import com.microsoftopentechnologies.wacommon.commoncontrols.ManageSubscriptionDialog;

public class ServiceExplorerView extends ViewPart implements PropertyChangeListener {

    /**
     * The ID of the view as specified by the extension.
     */
    public static final String ID = "ServiceExplorerView";

    private TreeViewer viewer;
    private Action refreshAction;
    private Action manageSubscriptionAction;
    private Action doubleClickAction;

    private AzureServiceModule azureServiceModule;

    /*
      * The content provider class is responsible for
     * providing objects to the view. It can wrap
     * existing objects in adapters or simply return
     * objects as-is. These objects may be sensitive
     * to the current input of the view, or ignore
     * it and always show the same content 
     * (like Task List, for example).
     */
    class ViewContentProvider implements IStructuredContentProvider, ITreeContentProvider {
        private TreeNode invisibleRoot;

        public void inputChanged(Viewer v, Object oldInput, Object newInput) {
        }

        public void dispose() {
        }

        public Object[] getElements(Object parent) {
            if (parent.equals(getViewSite())) {
                if (invisibleRoot == null)
                    initialize();
                return getChildren(invisibleRoot);
            }
            return getChildren(parent);
        }

        public Object getParent(Object child) {
            if (child instanceof TreeNode) {
                return (((TreeNode) child).node).getParent().getViewData();
            }
            return null;
        }

        public Object[] getChildren(Object parent) {
            if (parent instanceof TreeNode) {
                return ((TreeNode) parent).getChildNodes().toArray();
            }
            return new Object[0];
        }

        public boolean hasChildren(Object parent) {
            if (parent instanceof TreeNode)
                return ((TreeNode) parent).getChildNodes().size() > 0;
            return false;
        }

        private void initialize() {
            azureServiceModule = new AzureServiceModule(null, true);

            invisibleRoot = new TreeNode(null);
            invisibleRoot.add(createTreeNode(azureServiceModule));

            // kick-off asynchronous load of child nodes on all the modules
            azureServiceModule.load();
        }
    }

    private class TreeNode {
        Node node;
        List<TreeNode> childNodes = new ArrayList<TreeNode>();

        public TreeNode(Node node) {
            this.node = node;
        }

        public void add(TreeNode treeNode) {
            childNodes.add(treeNode);
        }

        public List<TreeNode> getChildNodes() {
            return childNodes;
        }

        public void remove(TreeNode treeNode) {
            childNodes.remove(treeNode);
        }

        @Override
        public String toString() {
            return node.getName();
        }
    }

    private TreeNode createTreeNode(Node node) {
        TreeNode treeNode = new TreeNode(node);

        // associate the TreeNode with the Node via it's "viewData"
        // property; this allows us to quickly retrieve the DefaultMutableTreeNode
        // object associated with a Node
        node.setViewData(treeNode);

        // listen for property change events on the node
        node.addPropertyChangeListener(this);

        // listen for structure changes on the node, i.e. when child nodes are
        // added or removed
        node.getChildNodes().addChangeListener(new NodeListChangeListener(treeNode));

        // create child tree nodes for each child node
        if (node.hasChildNodes()) {
            for (Node childNode : node.getChildNodes()) {
                treeNode.add(createTreeNode(childNode));
                //                treeNode.add(createTreeNode(childNode));
            }
        }
        return treeNode;
    }

    private void removeEventHandlers(Node node) {
        node.removePropertyChangeListener(this);

        ObservableList<Node> childNodes = node.getChildNodes();
        childNodes.removeAllChangeListeners();
        //
        if (node.hasChildNodes()) {
            // this remove call should cause the NodeListChangeListener object
            // registered on it's child nodes to fire which should recursively
            // clean up event handlers on it's children
            node.removeAllChildNodes();
        }
    }

    @Override
    public void propertyChange(final PropertyChangeEvent evt) {
        // if we are not running on the dispatch thread then switch
        // to dispatch thread
        //        if(!ApplicationManager.getApplication().isDispatchThread()) {
        //            ApplicationManager.getApplication().invokeAndWait(new Runnable() {
        //                @Override
        //                public void run() {
        //                    propertyChange(evt);
        //                }
        //            }, ModalityState.any());
        //
        //            return;
        //        }

        // this event is fired whenever a property on a node in the
        // model changes; we respond by triggering a node change
        // event in the tree's model
        final Node node = (Node) evt.getSource();

        // the treeModel object can be null before it is initialized
        // from createToolWindowContent; we ignore property change
        // notifications till we have a valid model object
        //        if(treeModel != null) {
        //            treeModel.nodeChanged((TreeNode) node.getViewData());
        //        }
        Display.getDefault().asyncExec(new Runnable() {
            @Override
            public void run() {
                viewer.refresh((TreeNode) node.getViewData());
            }
        });
    }

    private class NodeListChangeListener implements ListChangeListener {
        private TreeNode treeNode;

        public NodeListChangeListener(TreeNode treeNode) {
            this.treeNode = treeNode;
        }

        @Override
        public void listChanged(final ListChangedEvent e) {
            switch (e.getAction()) {
            case add:
                // create child tree nodes for the new nodes
                for (Node childNode : (Collection<Node>) e.getNewItems()) {
                    treeNode.add(createTreeNode(childNode));
                }
                break;
            case remove:
                // unregister all event handlers recursively and remove
                // child nodes from the tree
                for (Node childNode : (Collection<Node>) e.getOldItems()) {
                    removeEventHandlers(childNode);

                    // remove this node from the tree
                    treeNode.remove((TreeNode) childNode.getViewData());
                }
                break;
            }
            Display.getDefault().asyncExec(new Runnable() {
                @Override
                public void run() {
                    viewer.refresh(treeNode);
                }
            });
        }
    }

    class ViewLabelProvider extends LabelProvider {

        public String getText(Object obj) {
            return obj.toString();
        }

        public Image getImage(Object obj) {
            if (obj instanceof TreeNode) {
                String iconPath = ((TreeNode) obj).node.getIconPath();
                if (iconPath != null) {
                    return Activator.getImageDescriptor("icons/" + iconPath).createImage();//Activator.getDefault().getImageRegistry().get((((Node) obj).getIconPath()));
                }
            }
            return super.getImage(obj);
        }
    }

    class NameSorter extends ViewerSorter {
    }

    /**
     * The constructor.
     */
    public ServiceExplorerView() {
    }

    /**
     * This is a callback that will allow us
     * to create the viewer and initialize it.
     */
    public void createPartControl(Composite parent) {
        viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
        viewer.setContentProvider(new ViewContentProvider());
        viewer.setLabelProvider(new ViewLabelProvider());
        viewer.setSorter(new NameSorter());
        viewer.setInput(getViewSite());

        // Create the help context id for the viewer's control
        PlatformUI.getWorkbench().getHelpSystem().setHelp(viewer.getControl(),
                "com.microsoft.azureexplorer.viewer");
        makeActions();
        hookContextMenu();
        hookMouseActions();
        contributeToActionBars();
    }

    private void hookContextMenu() {
        MenuManager menuMgr = new MenuManager("#PopupMenu");
        menuMgr.setRemoveAllWhenShown(true);
        menuMgr.addMenuListener(new IMenuListener() {
            public void menuAboutToShow(IMenuManager manager) {
                if (viewer.getSelection().isEmpty()) {
                    return;
                }
                if (viewer.getSelection() instanceof IStructuredSelection) {
                    IStructuredSelection selection = (IStructuredSelection) viewer.getSelection();
                    Node node = ((TreeNode) selection.getFirstElement()).node;
                    if (node.hasNodeActions()) {
                        for (final NodeAction nodeAction : node.getNodeActions()) {
                            Action action = new Action(nodeAction.getName()) {
                                public void run() {
                                    nodeAction.fireNodeActionEvent();
                                }
                            };
                            action.setEnabled(nodeAction.isEnabled());
                            manager.add(action);
                        }
                    }
                }
            }
        });
        Menu menu = menuMgr.createContextMenu(viewer.getControl());
        viewer.getControl().setMenu(menu);
    }

    private void contributeToActionBars() {
        IActionBars bars = getViewSite().getActionBars();
        fillLocalPullDown(bars.getMenuManager());
        fillLocalToolBar(bars.getToolBarManager());
    }

    private void fillLocalPullDown(IMenuManager manager) {
        manager.add(refreshAction);
        manager.add(new Separator());
        manager.add(manageSubscriptionAction);
    }

    private void fillLocalToolBar(IToolBarManager manager) {
        manager.add(refreshAction);
        manager.add(manageSubscriptionAction);
        manager.add(new Separator());
    }

    private void makeActions() {
        refreshAction = new Action("Refresh", Activator.getImageDescriptor("icons/refresh.png")) {
            public void run() {
                azureServiceModule.load();
            }
        };
        refreshAction.setToolTipText("Refresh Service List");

        manageSubscriptionAction = new Action("Manage Subscriptions",
                Activator.getImageDescriptor("icons/azure_explorer.png")) {
            public void run() {
                ManageSubscriptionDialog subscriptionDialog = new ManageSubscriptionDialog(new Shell(), true,
                        false);
                subscriptionDialog.open();
                azureServiceModule.load();

            }
        };
        manageSubscriptionAction.setToolTipText("Manage Subscriptions");
        doubleClickAction = new Action() {
            public void run() {
                ISelection selection = viewer.getSelection();
                Object obj = ((IStructuredSelection) selection).getFirstElement();
                viewer.expandToLevel(obj, 1);
                try {
                    List<Subscription> subscriptions = AzureManagerImpl.getManager().getFullSubscriptionList();
                    if ((subscriptions == null || subscriptions.isEmpty())
                            && (((TreeNode) obj).node instanceof StorageModule
                                    || ((TreeNode) obj).node instanceof AzureServiceModule)) {
                        ManageSubscriptionDialog subscriptionsDialog = new ManageSubscriptionDialog(
                                getSite().getShell(), true, false);
                        subscriptionsDialog.open();
                    }
                } catch (AzureCmdException e) {
                    Activator.getDefault().log(e.getMessage(), e);
                }
            }
        };
    }

    private void hookMouseActions() {
        viewer.addDoubleClickListener(new IDoubleClickListener() {
            public void doubleClick(DoubleClickEvent event) {
                doubleClickAction.run();
            }
        });
        Tree tree = (Tree) viewer.getControl();
        tree.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                TreeItem item = (TreeItem) e.item;
                Node node = ((TreeNode) item.getData()).node;
                // if the node in question is in a "loading" state then we
                // do not propagate the click event to it
                if (!node.isLoading()) {
                    node.getClickAction().fireNodeActionEvent();
                }
            }
        });
    }

    /**
     * Passing the focus request to the viewer's control.
     */
    public void setFocus() {
        viewer.getControl().setFocus();
    }
}