org.eclipse.pde.internal.ui.shared.target.TargetLocationsGroup.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.pde.internal.ui.shared.target.TargetLocationsGroup.java

Source

/*******************************************************************************
 * Copyright (c) 2009, 2015 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.pde.internal.ui.shared.target;

import java.util.*;
import java.util.List;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.jobs.*;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.viewers.*;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.wizard.IWizard;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.pde.core.target.*;
import org.eclipse.pde.internal.core.PDECore;
import org.eclipse.pde.internal.core.target.*;
import org.eclipse.pde.internal.ui.PDEPlugin;
import org.eclipse.pde.internal.ui.SWTFactory;
import org.eclipse.pde.internal.ui.editor.FormLayoutFactory;
import org.eclipse.pde.internal.ui.editor.targetdefinition.TargetEditor;
import org.eclipse.pde.internal.ui.shared.target.IUContentProvider.IUWrapper;
import org.eclipse.pde.internal.ui.wizards.target.TargetDefinitionContentPage;
import org.eclipse.pde.ui.target.ITargetLocationEditor;
import org.eclipse.pde.ui.target.ITargetLocationUpdater;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.*;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.*;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.progress.UIJob;

/**
 * UI part that can be added to a dialog or to a form editor.  Contains a table displaying
 * the bundle containers of a target definition.  Also has buttons to add, edit and remove
 * bundle containers of varying types.
 * 
 * @see TargetEditor
 * @see TargetDefinitionContentPage
 * @see ITargetDefinition
 * @see ITargetLocation
 */
public class TargetLocationsGroup {

    private TreeViewer fTreeViewer;
    private Button fAddButton;
    private Button fEditButton;
    private Button fRemoveButton;
    private Button fUpdateButton;
    private Button fReloadButton;
    private Button fShowContentButton;

    private ITargetDefinition fTarget;
    private ListenerList fChangeListeners = new ListenerList();

    /**
     * Creates this part using the form toolkit and adds it to the given composite.
     * 
     * @param parent parent composite
     * @param toolkit toolkit to create the widgets with
     * @return generated instance of the table part
     */
    public static TargetLocationsGroup createInForm(Composite parent, FormToolkit toolkit) {
        TargetLocationsGroup contentTable = new TargetLocationsGroup();
        contentTable.createFormContents(parent, toolkit);
        return contentTable;
    }

    /**
     * Creates this part using standard dialog widgets and adds it to the given composite.
     * 
     * @param parent parent composite
     * @return generated instance of the table part
     */
    public static TargetLocationsGroup createInDialog(Composite parent) {
        TargetLocationsGroup contentTable = new TargetLocationsGroup();
        contentTable.createDialogContents(parent);
        return contentTable;
    }

    /**
     * Private constructor, use one of {@link #createTableInDialog(Composite, ITargetChangedListener)}
     * or {@link #createTableInForm(Composite, FormToolkit, ITargetChangedListener)}.
     * 
     * @param reporter reporter implementation that will handle resolving and changes to the containers
     */
    private TargetLocationsGroup() {

    }

    /**
     * Adds a listener to the set of listeners that will be notified when the bundle containers
     * are modified.  This method has no effect if the listener has already been added. 
     * 
     * @param listener target changed listener to add
     */
    public void addTargetChangedListener(ITargetChangedListener listener) {
        fChangeListeners.add(listener);
    }

    /**
     * Creates the part contents from a toolkit
     * @param parent parent composite
     * @param toolkit form toolkit to create widgets
     */
    private void createFormContents(Composite parent, FormToolkit toolkit) {
        Composite comp = toolkit.createComposite(parent);
        comp.setLayout(FormLayoutFactory.createSectionClientGridLayout(false, 2));
        comp.setLayoutData(new GridData(GridData.FILL_BOTH | GridData.GRAB_VERTICAL));

        Tree atree = toolkit.createTree(comp, SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI);
        atree.setLayout(new GridLayout());
        GridData gd = new GridData(GridData.FILL_BOTH);
        atree.setLayoutData(gd);
        atree.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if (e.keyCode == SWT.DEL && fRemoveButton.getEnabled()) {
                    handleRemove();
                }

            }
        });

        Composite buttonComp = toolkit.createComposite(comp);
        GridLayout layout = new GridLayout();
        layout.marginWidth = layout.marginHeight = 0;
        buttonComp.setLayout(layout);
        buttonComp.setLayoutData(new GridData(GridData.FILL_VERTICAL));

        fAddButton = toolkit.createButton(buttonComp, Messages.BundleContainerTable_0, SWT.PUSH);
        fEditButton = toolkit.createButton(buttonComp, Messages.BundleContainerTable_1, SWT.PUSH);
        fRemoveButton = toolkit.createButton(buttonComp, Messages.BundleContainerTable_2, SWT.PUSH);
        fUpdateButton = toolkit.createButton(buttonComp, Messages.BundleContainerTable_3, SWT.PUSH);
        fReloadButton = toolkit.createButton(buttonComp, Messages.BundleContainerTable_4, SWT.PUSH);

        fShowContentButton = toolkit.createButton(comp, Messages.TargetLocationsGroup_1, SWT.CHECK);

        initializeTreeViewer(atree);
        initializeButtons();

        toolkit.paintBordersFor(comp);
    }

    /**
     * Creates the part contents using SWTFactory
     * @param parent parent composite
     */
    private void createDialogContents(Composite parent) {
        Composite comp = SWTFactory.createComposite(parent, 2, 1, GridData.FILL_BOTH, 0, 0);

        Tree atree = new Tree(comp, SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER | SWT.MULTI);
        atree.setFont(comp.getFont());
        atree.setLayout(new GridLayout());
        GridData gd = new GridData(GridData.FILL_BOTH);
        gd.widthHint = 200;
        atree.setLayoutData(gd);
        atree.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if (e.keyCode == SWT.DEL && fRemoveButton.getEnabled()) {
                    handleRemove();
                }
            }
        });

        Composite buttonComp = SWTFactory.createComposite(comp, 2, 1, GridData.FILL_BOTH);
        GridLayout layout = new GridLayout();
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        buttonComp.setLayout(layout);
        buttonComp.setLayoutData(new GridData(GridData.FILL_VERTICAL));

        fAddButton = SWTFactory.createPushButton(buttonComp, Messages.BundleContainerTable_0, null);
        fEditButton = SWTFactory.createPushButton(buttonComp, Messages.BundleContainerTable_1, null);
        fRemoveButton = SWTFactory.createPushButton(buttonComp, Messages.BundleContainerTable_2, null);
        fUpdateButton = SWTFactory.createPushButton(buttonComp, Messages.BundleContainerTable_3, null);
        fReloadButton = SWTFactory.createPushButton(buttonComp, Messages.BundleContainerTable_4, null);

        fShowContentButton = SWTFactory.createCheckButton(comp, Messages.TargetLocationsGroup_1, null, false, 2);

        initializeTreeViewer(atree);
        initializeButtons();
    }

    /**
     * Sets up the tree viewer using the given tree
     * @param tree
     */
    private void initializeTreeViewer(Tree tree) {
        fTreeViewer = new TreeViewer(tree);
        fTreeViewer.setContentProvider(new TargetLocationContentProvider());
        fTreeViewer.setLabelProvider(new TargetLocationLabelProvider(true, false));
        fTreeViewer.setComparator(new ViewerComparator() {
            @Override
            public int compare(Viewer viewer, Object e1, Object e2) {
                // Status at the end of the list
                if (e1 instanceof IStatus && !(e2 instanceof IStatus)) {
                    return 1;
                }
                if (e2 instanceof IStatus && !(e1 instanceof IStatus)) {
                    return -1;
                }
                return super.compare(viewer, e1, e2);
            }
        });
        fTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
            public void selectionChanged(SelectionChangedEvent event) {
                updateButtons();
            }
        });
        fTreeViewer.addDoubleClickListener(new IDoubleClickListener() {
            public void doubleClick(DoubleClickEvent event) {
                if (!event.getSelection().isEmpty()) {
                    handleEdit();
                }
            }
        });
        fTreeViewer.setAutoExpandLevel(AbstractTreeViewer.ALL_LEVELS);
    }

    /**
     * Sets up the buttons, the button fields must already be created before calling this method
     */
    private void initializeButtons() {
        fAddButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                handleAdd();
            }
        });
        fAddButton.setLayoutData(new GridData());
        SWTFactory.setButtonDimensionHint(fAddButton);

        fEditButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                handleEdit();
            }
        });
        fEditButton.setLayoutData(new GridData());
        fEditButton.setEnabled(false);
        SWTFactory.setButtonDimensionHint(fEditButton);

        fRemoveButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                handleRemove();
            }
        });
        fRemoveButton.setLayoutData(new GridData());
        fRemoveButton.setEnabled(false);
        SWTFactory.setButtonDimensionHint(fRemoveButton);

        fUpdateButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                handleUpdate();
            }
        });
        fUpdateButton.setLayoutData(new GridData());
        fUpdateButton.setEnabled(false);
        SWTFactory.setButtonDimensionHint(fUpdateButton);

        fReloadButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                handleReload();
            }
        });
        fReloadButton.setLayoutData(new GridData());
        fReloadButton.setEnabled(true);
        SWTFactory.setButtonDimensionHint(fReloadButton);

        fShowContentButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                ((TargetLocationContentProvider) fTreeViewer.getContentProvider())
                        .setShowLocationContent(fShowContentButton.getSelection());
                fTreeViewer.refresh();
                fTreeViewer.expandAll();
            }
        });
        fShowContentButton.setLayoutData(new GridData());
        SWTFactory.setButtonDimensionHint(fShowContentButton);
    }

    /**
     * Sets the target definition model to use as input for the tree, can be called with different
     * models to change the tree's input.
     * @param target target model
     */
    public void setInput(ITargetDefinition target) {
        fTarget = target;
        fTreeViewer.setInput(fTarget);
        updateButtons();
    }

    private void handleAdd() {
        AddBundleContainerWizard wizard = new AddBundleContainerWizard(fTarget);
        Shell parent = fTreeViewer.getTree().getShell();
        WizardDialog dialog = new WizardDialog(parent, wizard);
        if (dialog.open() != Window.CANCEL) {
            contentsChanged(false);
            fTreeViewer.refresh();
            updateButtons();
        }
    }

    private void handleEdit() {
        IStructuredSelection selection = (IStructuredSelection) fTreeViewer.getSelection();
        for (Iterator<?> iterator = selection.iterator(); iterator.hasNext();) {
            Object currentSelection = iterator.next();
            if (currentSelection instanceof ITargetLocation) {
                ITargetLocation location = (ITargetLocation) currentSelection;
                ITargetLocationEditor editor = (ITargetLocationEditor) Platform.getAdapterManager()
                        .getAdapter(location, ITargetLocationEditor.class);
                if (editor != null) {
                    if (editor.canEdit(fTarget, location)) {
                        IWizard editWizard = editor.getEditWizard(fTarget, location);
                        if (editWizard != null) {
                            Shell parent = fTreeViewer.getTree().getShell();
                            WizardDialog wizard = new WizardDialog(parent, editWizard);
                            if (wizard.open() == Window.OK) {
                                // Update the table
                                // TODO Do we need to force a resolve for IUBundleContainers?
                                contentsChanged(false);
                                fTreeViewer.refresh();
                                updateButtons();
                                // TODO We can't restore selection if they replace the location
                                fTreeViewer.setSelection(new StructuredSelection(location), true);
                            }
                        }
                        break; //Only open for one selected item
                    }
                } else if (location instanceof AbstractBundleContainer) {
                    // TODO Custom code for locations that don't use adapters yet
                    Shell parent = fTreeViewer.getTree().getShell();
                    EditBundleContainerWizard wizard = new EditBundleContainerWizard(fTarget, location);
                    WizardDialog dialog = new WizardDialog(parent, wizard);
                    if (dialog.open() == Window.OK) {
                        contentsChanged(false);
                        fTreeViewer.refresh();
                        updateButtons();
                        // TODO We can't restore selection if they replace the location
                        fTreeViewer.setSelection(new StructuredSelection(location), true);
                    }
                    break; //Only open for one selected item
                }
            } else if (currentSelection instanceof IUWrapper) {
                // TODO Custom code to allow editing of individual IUs
                IUWrapper wrapper = (IUWrapper) currentSelection;
                Shell parent = fTreeViewer.getTree().getShell();
                EditBundleContainerWizard editWizard = new EditBundleContainerWizard(fTarget, wrapper.getParent());
                WizardDialog wizard = new WizardDialog(parent, editWizard);
                if (wizard.open() == Window.OK) {
                    // Update the table
                    // TODO Do we need to force a resolve for IUBundleContainers?
                    contentsChanged(false);
                    fTreeViewer.refresh();
                    updateButtons();
                    // TODO We can't restore selection if they replace the location
                    fTreeViewer.setSelection(new StructuredSelection(wrapper.getParent()), true);
                }
                break; //Only open for one selected item
            }
        }
    }

    private void handleRemove() {
        // TODO Contains custom code to remove individual IUWrappers
        // TODO Contains custom code to force re-resolve if IUBundleContainer removed

        IStructuredSelection selection = (IStructuredSelection) fTreeViewer.getSelection();
        ITargetLocation[] containers = fTarget.getTargetLocations();
        if (!selection.isEmpty() && containers != null && containers.length > 0) {
            List<Object> toRemove = new ArrayList<Object>();
            boolean removedSite = false;
            boolean removedContainer = false;
            for (Iterator<?> iterator = selection.iterator(); iterator.hasNext();) {
                Object currentSelection = iterator.next();
                if (currentSelection instanceof ITargetLocation) {
                    if (currentSelection instanceof IUBundleContainer) {
                        removedSite = true;
                    }
                    removedContainer = true;
                    toRemove.add(currentSelection);
                }
                if (currentSelection instanceof IUWrapper) {
                    toRemove.add(currentSelection);
                }
            }

            if (removedContainer) {
                Set<ITargetLocation> newContainers = new HashSet<ITargetLocation>();
                newContainers.addAll(Arrays.asList(fTarget.getTargetLocations()));
                newContainers.removeAll(toRemove);
                if (newContainers.size() > 0) {
                    fTarget.setTargetLocations(newContainers.toArray(new ITargetLocation[newContainers.size()]));
                } else {
                    fTarget.setTargetLocations(null);
                }

                // If we remove a site container, the content change update must force a re-resolve bug 275458 / bug 275401
                contentsChanged(removedSite);
                fTreeViewer.refresh(false);
                updateButtons();
            } else {
                for (Iterator<Object> iterator = toRemove.iterator(); iterator.hasNext();) {
                    Object current = iterator.next();
                    if (current instanceof IUWrapper) {
                        ((IUWrapper) current).getParent().removeInstallableUnit(((IUWrapper) current).getIU());
                    }
                }
                contentsChanged(removedSite);
                fTreeViewer.refresh(true);
                updateButtons();
            }
        }
    }

    private void handleUpdate() {
        // TODO Only IUWrapper children are added to the map for special update processing
        IStructuredSelection selection = (IStructuredSelection) fTreeViewer.getSelection();
        Map<ITargetLocation, Set<Object>> toUpdate = new HashMap<ITargetLocation, Set<Object>>();
        for (Iterator<?> iterator = selection.iterator(); iterator.hasNext();) {
            Object currentSelection = iterator.next();
            if (currentSelection instanceof ITargetLocation)
                toUpdate.put((ITargetLocation) currentSelection, new HashSet<Object>(0));
            else if (currentSelection instanceof IUWrapper) {
                IUWrapper wrapper = (IUWrapper) currentSelection;
                Set<Object> iuSet = toUpdate.get(wrapper.getParent());
                if (iuSet == null) {
                    iuSet = new HashSet<Object>();
                    iuSet.add(wrapper.getIU().getId());
                    toUpdate.put(wrapper.getParent(), iuSet);
                } else if (!iuSet.isEmpty())
                    iuSet.add(wrapper.getIU().getId());
            }
        }
        if (toUpdate.isEmpty())
            return;

        JobChangeAdapter listener = new JobChangeAdapter() {
            @Override
            public void done(final IJobChangeEvent event) {
                UIJob job = new UIJob(Messages.UpdateTargetJob_UpdateJobName) {
                    @Override
                    public IStatus runInUIThread(IProgressMonitor monitor) {
                        IStatus result = event.getJob().getResult();
                        if (!result.isOK()) {
                            if (!fTreeViewer.getControl().isDisposed()) {
                                ErrorDialog.openError(fTreeViewer.getTree().getShell(),
                                        Messages.TargetLocationsGroup_TargetUpdateErrorDialog, result.getMessage(),
                                        result);
                            }
                        } else if (result.getCode() != ITargetLocationUpdater.STATUS_CODE_NO_CHANGE) {
                            // Update was successful and changed the target, if dialog/editor still open, update it
                            if (!fTreeViewer.getControl().isDisposed()) {
                                contentsChanged(true);
                                fTreeViewer.refresh(true);
                                updateButtons();
                            }

                            // If the target is the current platform, run a load job for the user
                            try {
                                ITargetPlatformService service = (ITargetPlatformService) PDECore.getDefault()
                                        .acquireService(ITargetPlatformService.class.getName());
                                if (service != null) {
                                    ITargetHandle currentTarget = service.getWorkspaceTargetHandle();
                                    if (fTarget.getHandle().equals(currentTarget))
                                        LoadTargetDefinitionJob.load(fTarget);
                                }
                            } catch (CoreException e) {
                                // do nothing if we could not set the current target.
                            }
                        }
                        return Status.OK_STATUS;
                    }
                };
                job.schedule();
            }
        };
        UpdateTargetJob.update(fTarget, toUpdate, listener);
    }

    private void updateButtons() {

        IStructuredSelection selection = (IStructuredSelection) fTreeViewer.getSelection();
        if (selection.isEmpty()) {
            fRemoveButton.setEnabled(false);
            fUpdateButton.setEnabled(false);
            fEditButton.setEnabled(false);
        }

        boolean canRemove = false;
        boolean canEdit = false;
        boolean canUpdate = false;
        for (Iterator<?> iterator = selection.iterator(); iterator.hasNext();) {

            Object currentSelection = iterator.next();
            if (currentSelection instanceof ITargetLocation) {
                canRemove = true;
                if (!canEdit) {
                    ITargetLocation location = (ITargetLocation) currentSelection;
                    ITargetLocationEditor editor = (ITargetLocationEditor) Platform.getAdapterManager()
                            .getAdapter(location, ITargetLocationEditor.class);
                    if (editor != null) {
                        canEdit = editor.canEdit(fTarget, location);
                    }
                    if (location instanceof AbstractBundleContainer) {
                        // TODO Custom code for locations that don't use adapters yet
                        canEdit = true;
                    }
                }
                if (!canUpdate) {
                    ITargetLocation location = (ITargetLocation) currentSelection;
                    ITargetLocationUpdater updater = (ITargetLocationUpdater) Platform.getAdapterManager()
                            .getAdapter(location, ITargetLocationUpdater.class);
                    if (updater != null) {
                        canUpdate = updater.canUpdate(fTarget, location);
                    }
                }

            } else if (currentSelection instanceof IUWrapper) {
                // TODO Custom code to support editing/updating/removal of individual IUs
                canRemove = true;
                canEdit = true;
                canUpdate = true;
            }
            if (canRemove && canEdit && canUpdate) {
                break;
            }

        }
        fRemoveButton.setEnabled(canRemove);
        fEditButton.setEnabled(canEdit);
        fUpdateButton.setEnabled(canUpdate);

        // TODO Some code to find the parent location of items in the tree
        // For each selected item, find it's parent location and add it to the set
        //      for (int i = 0; i < treeSelection.length; i++) {
        //         TreeItem current = treeSelection[i];
        //         while (current != null){
        //            if (current instanceof ITargetLocation){
        //               selectedLocations.add(current);
        //               break;
        //            }
        //            current = current.getParentItem();
        //         }
        //      }

    }

    private void handleReload() {

        //delete profile
        try {
            P2TargetUtils.deleteProfile(fTarget.getHandle());
        } catch (CoreException e) {
            PDEPlugin.log(e);
        }

        // increase sequence number
        if (fTarget instanceof TargetDefinition)
            ((TargetDefinition) fTarget).incrementSequenceNumber();

        Job job = new UIJob("Reloading...") { //$NON-NLS-1$
            @Override
            public IStatus runInUIThread(IProgressMonitor monitor) {
                contentsChanged(true);
                return Status.OK_STATUS;
            }
        };
        job.schedule();

    }

    /**
     * Informs the reporter for this table that something has changed
     * and is dirty.
     */
    private void contentsChanged(boolean force) {
        Object[] listeners = fChangeListeners.getListeners();
        for (int i = 0; i < listeners.length; i++) {
            ((ITargetChangedListener) listeners[i]).contentsChanged(fTarget, this, true, force);
        }
    }

}