com.amazonaws.eclipse.ec2.ui.SelectionTable.java Source code

Java tutorial

Introduction

Here is the source code for com.amazonaws.eclipse.ec2.ui.SelectionTable.java

Source

/*
 * Copyright 2008-2011 Amazon Technologies, Inc.
 *
 * 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://aws.amazon.com/apache2.0
 *
 * This file 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.amazonaws.eclipse.ec2.ui;

import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.layout.TreeColumnLayout;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.swt.widgets.TreeItem;

import com.amazonaws.eclipse.core.AccountInfo;
import com.amazonaws.eclipse.core.AwsToolkitCore;
import com.amazonaws.eclipse.core.regions.Region;
import com.amazonaws.eclipse.core.regions.RegionUtils;
import com.amazonaws.eclipse.core.regions.ServiceAbbreviations;
import com.amazonaws.services.ec2.AmazonEC2;

/**
 * A generic table supporting basic operations (column creation, context menu
 * creation, etc) suitable to use as a base for more complex tables.
 */
public abstract class SelectionTable extends Composite {

    /** The internal table viewer control */
    protected TreeViewer viewer;

    /** An optional listener to notify before and after loading AMIs */
    protected SelectionTableListener selectionTableListener;

    /** The shared user account info */
    private AccountInfo accountInfo = AwsToolkitCore.getDefault().getAccountInfo();

    /** True if this selection table allows multiple items to be selected */
    private final boolean allowMultipleSelections;

    /** True if this table should be virtual because of data sizes */
    private final boolean virtualTable;

    /** An optional comparator to control sorting by columns */
    protected SelectionTableComparator comparator;

    /** An optional account ID to use in EC2 requests, otherwise the default will be used */
    protected String accountIdOverride;

    /**
     * Specifying an EC2 endpoint override will cause the EC2 client for this
     * selection table to always use this overridden endpoint, instead of using
     * the user's currently selected endpoint from the system preferences.
     */
    protected String ec2EndpointOverride;

    /**
     * Creates a new selection table with the specified parent.
     *
     * @param parent
     *            The composite object to contain this new selection table.
     */
    public SelectionTable(Composite parent) {
        this(parent, false, false);
    }

    /**
     * Creates a new selection table with the specified parent.
     *
     * @param parent
     *            The composite object to contain this new selection table.
     * @param allowMultipleSelections
     *            True if this new selection table should allow multiple rows to
     *            be selected at once, otherwise false if only one row should be
     *            selectable at a time.
     * @param virtualTable
     *            True if this new selection table should use the SWT VIRTUAL
     *            style, indicating that it will supply a lazy content provider.
     */
    public SelectionTable(Composite parent, boolean allowMultipleSelections, boolean virtualTable) {
        super(parent, SWT.NONE);
        this.allowMultipleSelections = allowMultipleSelections;
        this.virtualTable = virtualTable;

        createControl();
    }

    /**
     * Adds a selection listener to this selection table.
     *
     * @param listener The selection listener to add to this table.
     */
    public void addSelectionListener(SelectionListener listener) {
        viewer.getTree().addSelectionListener(listener);
    }

    /**
     * Clears the selection in this selection table.
     */
    public void clearSelection() {
        viewer.getTree().setSelection(new TreeItem[0]);
    }

    /**
     * Sets the optional SelectionTableListener that will be notified before
     * and after data is loaded. Loading data can be a long operation, so
     * providing a listener allows another class to receive events as the
     * loading status changes so it can update itself appropriately.
     *
     * @param listener
     *            The listener to notify before and after loading data.
     */
    public void setListener(SelectionTableListener listener) {
        this.selectionTableListener = listener;
    }

    /**
     * Sets the optional EC2 endpoint override for this selection table. Setting
     * this value will cause the EC2 client returned by the getClient method to
     * *always* use this EC2 endpoint, and will completely ignore the EC2 region
     * selected in the system preferences.
     *
     * @param endpoint
     *            The EC2 endpoint to use instead of defaulting to the currently
     *            selected EC2 region in the system preferences.
     */
    public void setEc2EndpointOverride(String endpoint) {
        this.ec2EndpointOverride = endpoint;
    }

    /**
     * Sets the optional EC2 account ID override for this selection table.
     * Setting this will cause the EC2 client to authenticate requests with the
     * specified account, otherwise the default account is used.
     * 
     * @param accountId
     *            The account ID to use for making requests in this selection
     *            table.
     */
    public void setAccountIdOverride(String accountId) {
        this.accountIdOverride = accountId;
    }

    /**
     * Returns the viewer used in this table.
     */
    protected Viewer getViewer() {
        return viewer;
    }

    /**
     * Returns a ready-to-use EC2 client using the currently selected AWS
     * account.
     * 
     * @return A fully configured AWS EC2 client.
     */
    protected AmazonEC2 getAwsEc2Client() {
        if (accountIdOverride != null)
            return getAwsEc2Client(accountIdOverride);
        else
            return getAwsEc2Client(null);
    }

    /**
     * Returns a ready-to-use EC2 client for the account ID given.
     * 
     * TODO: move the account ID into a member variable, deprecate this method
     */
    protected AmazonEC2 getAwsEc2Client(String accountId) {
        if (ec2EndpointOverride != null) {
            return AwsToolkitCore.getClientFactory(accountId).getEC2ClientByEndpoint(ec2EndpointOverride);
        }

        Region defaultRegion = RegionUtils.getCurrentRegion();
        String regionEndpoint = defaultRegion.getServiceEndpoints().get(ServiceAbbreviations.EC2);
        return AwsToolkitCore.getClientFactory(accountId).getEC2ClientByEndpoint(regionEndpoint);
    }

    /**
     * Returns the current selection in this table.
     *
     * @return The current selection in this table.
     */
    protected Object getSelection() {
        StructuredSelection selection = (StructuredSelection) viewer.getSelection();
        return selection.getFirstElement();
    }

    /**
     * Packs the columns in this selection table.
     */
    protected void packColumns() {
        if (viewer == null)
            return;

        Tree table = viewer.getTree();
        for (TreeColumn col : table.getColumns()) {
            col.pack();
        }
    }

    /**
     * Creates a new column with the specified text and weight.
     *
     * @param columnText
     *            The text for the column header.
     * @param weight
     *            The weight of the new column, relative to the other columns.
     *
     * @return The new TableColum that was created.
     */
    protected TreeColumn newColumn(String columnText, int weight) {
        Tree table = viewer.getTree();
        TreeColumn column = new TreeColumn(table, SWT.NONE);
        column.setText(columnText);

        TreeColumnLayout tableColumnLayout = (TreeColumnLayout) getLayout();
        tableColumnLayout.setColumnData(column, new ColumnWeightData(weight));

        return column;
    }

    /**
     * Creates and configures the actual tree control.
     */
    protected void createControl() {
        TreeColumnLayout treeColumnLayout = new TreeColumnLayout();
        setLayout(treeColumnLayout);

        int style = SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER;

        if (allowMultipleSelections) {
            style |= SWT.MULTI;
        } else {
            style |= SWT.SINGLE;
        }

        if (virtualTable) {
            style |= SWT.VIRTUAL;
        }

        viewer = new TreeViewer(this, style);

        if (virtualTable)
            viewer.setUseHashlookup(true);

        Tree tree = viewer.getTree();
        tree.setLinesVisible(true);
        tree.setHeaderVisible(true);

        createColumns();
        makeActions();
        hookContextMenu();
    }

    /**
     * Subclasses must implement this to set up the table's columns.
     */
    protected abstract void createColumns();

    /**
     * Subclasses must implement this to create any needed actions.
     */
    protected abstract void makeActions();

    /**
     * Subclasses must implement this to provide any context menu contributions.
     *
     * @param manager
     *            The manager for the table's context menu.
     */
    protected abstract void fillContextMenu(IMenuManager manager);

    /**
     * Hooks a context (popup) menu for the table control.
     */
    private void hookContextMenu() {
        MenuManager menuMgr = new MenuManager("#PopupMenu");
        menuMgr.setRemoveAllWhenShown(true);
        menuMgr.addMenuListener(new AcountValidatingMenuListener());
        Menu menu = menuMgr.createContextMenu(viewer.getControl());
        viewer.getControl().setMenu(menu);

        menuMgr.createContextMenu(this);
    }

    /**
     * Sets the comparator used to control sorting by columns in this selection
     * table and adds a selection listener to each column in this table that will
     * update the sorting information on the comparator.
     *
     * @param comparator
     *            The comparator used to control sorting by columns in this
     *            selection table.
     */
    protected void setComparator(SelectionTableComparator comparator) {
        this.comparator = comparator;

        viewer.setComparator(comparator);
        viewer.getTree().setSortColumn(viewer.getTree().getColumn(comparator.getColumn()));
        viewer.getTree().setSortDirection(comparator.getDirection());

        int i = 0;
        for (TreeColumn column : viewer.getTree().getColumns()) {
            column.addSelectionListener(new SelectionTableColumnClickListener(i++, viewer, comparator));
        }
    }

    /**
     * A MenuListener that checks to see if the user's AWS account information has
     * been entered. If it hasn't, the user will be directed to the plugin
     * preferences so they can enter it and start using the tools.
     */
    private final class AcountValidatingMenuListener implements IMenuListener {

        /* (non-Javadoc)
         * @see org.eclipse.jface.action.IMenuListener#menuAboutToShow(org.eclipse.jface.action.IMenuManager)
         */
        public void menuAboutToShow(IMenuManager manager) {
            if (accountInfo != null && accountInfo.isValid()) {
                fillContextMenu(manager);
                return;
            }

            manager.add(new SetupAwsAccountAction());
        }
    }

    /**
     * A simple interface that objects can implement if they want to register
     * themselves as a listener for data loading events in this SelectionTable.
     */
    public interface SelectionTableListener {
        /**
         * This method is called to notify the listener that this selection
         * table is currently reloading its data.
         */
        public void loadingData();

        /**
         * This method is called to notify the listener that this selection
         * table has finished loading all data. This doesn't necessarily mean
         * that they were loaded successfully, just that this selection table is
         * no longer querying for data.
         * Will also pass along the number of records that got loaded
         */
        public void finishedLoadingData(int recordCount);
    }
}