org.eclipse.oomph.p2.internal.ui.AgentAnalyzerComposite.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.oomph.p2.internal.ui.AgentAnalyzerComposite.java

Source

/*
 * Copyright (c) 2014, 2015 Eike Stepper (Berlin, Germany) 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:
 *    Eike Stepper - initial API and implementation
 */
package org.eclipse.oomph.p2.internal.ui;

import org.eclipse.oomph.p2.core.Agent;
import org.eclipse.oomph.p2.core.Profile;
import org.eclipse.oomph.p2.internal.core.AgentAnalyzer;
import org.eclipse.oomph.p2.internal.core.AgentAnalyzer.AnalyzedArtifact;
import org.eclipse.oomph.p2.internal.core.AgentAnalyzer.AnalyzedBundlePool;
import org.eclipse.oomph.p2.internal.core.AgentAnalyzer.AnalyzedProfile;
import org.eclipse.oomph.p2.internal.core.AgentAnalyzer.Handler;
import org.eclipse.oomph.ui.ErrorDialog;
import org.eclipse.oomph.ui.UIUtil;
import org.eclipse.oomph.util.ObjectUtil;
import org.eclipse.oomph.util.SubMonitor;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.IColorProvider;
import org.eclipse.jface.viewers.ILazyContentProvider;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author Eike Stepper
 */
public class AgentAnalyzerComposite extends Composite {
    private static final int TABLE_STYLE = SWT.BORDER | SWT.FULL_SELECTION | SWT.VIRTUAL | SWT.NO_SCROLL
            | SWT.V_SCROLL;

    private static final String SHOW_ALL = "Show All";

    private static final String SHOW_UNUSED = "Unused";

    private static final String SHOW_DAMAGED = "Damaged";

    private static final String SHOW_BY_ARTIFACT = "By Artifact";

    private final Set<ISelectionProvider> changingSelection = new HashSet<ISelectionProvider>();

    private final Agent agent;

    private boolean initializingAnalyzer;

    private AgentAnalyzer analyzer;

    private AnalyzedBundlePool currentBundlePool;

    private TableViewer bundlePoolViewer;

    private BundlePoolContentProvider bundlePoolContentProvider;

    private Button deleteUnusedProfilesButton;

    private Button deleteUnusedArtifactsButton;

    private Button repairAllArtifactsButton;

    private TableViewer profileViewer;

    private ProfileContentProvider profileContentProvider;

    private String profileFilter = SHOW_ALL;

    private Button selectAllProfilesButton;

    private Button deleteProfilesButton;

    private Button showDetailsButton;

    private TableViewer artifactViewer;

    private ArtifactContentProvider artifactContentProvider;

    private Button selectAllArtifactsButton;

    private Button repairArtifactsButton;

    private Button deleteArtifactsButton;

    private boolean deletingArtifacts;

    public AgentAnalyzerComposite(final Composite parent, int margin, int style, Agent agent)
            throws InvocationTargetException, InterruptedException {
        super(parent, style);
        this.agent = agent;

        setBackground(getDisplay().getSystemColor(SWT.COLOR_TRANSPARENT));

        GridLayout gridLayout = new GridLayout();
        gridLayout.marginWidth = margin;
        gridLayout.marginHeight = margin;
        setLayout(gridLayout);

        createBundlePoolViewer();

        SashForm verticalSashForm = new SashForm(this, SWT.SMOOTH | SWT.VERTICAL);
        verticalSashForm.setLayoutData(new GridData(GridData.FILL_BOTH));

        createProfileViewer(verticalSashForm);
        createArtifactViewer(verticalSashForm);

        verticalSashForm.setWeights(new int[] { 2, 3 });

        addDisposeListener(new DisposeListener() {
            public void widgetDisposed(DisposeEvent e) {
                if (analyzer != null) {
                    analyzer.dispose();
                }
            }
        });

        initAnalyzer();

        bundlePoolContentProvider.setInput(bundlePoolViewer, analyzer);
    }

    private void createBundlePoolViewer() {
        Composite bundlePoolComposite = new Composite(this, SWT.NONE);
        GridLayout bundlePoolLayout = new GridLayout();
        bundlePoolLayout.marginWidth = 0;
        bundlePoolLayout.marginHeight = 0;
        bundlePoolComposite.setLayout(bundlePoolLayout);
        bundlePoolComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));

        bundlePoolViewer = new TableViewer(bundlePoolComposite, TABLE_STYLE);
        Table bundlePoolTable = bundlePoolViewer.getTable();
        bundlePoolTable.setHeaderVisible(true);
        GridData bundlePoolData = new GridData(SWT.FILL, SWT.FILL, true, false);
        bundlePoolData.heightHint = 84;
        bundlePoolTable.setLayoutData(bundlePoolData);

        TableColumn bundlePoolColumn = new TableViewerColumn(bundlePoolViewer, SWT.NONE).getColumn();
        bundlePoolColumn.setText("Bundle Pool");
        bundlePoolColumn.setWidth(305);
        bundlePoolColumn.setResizable(false);

        TableColumn profilesColumn = new TableViewerColumn(bundlePoolViewer, SWT.NONE).getColumn();
        profilesColumn.setText("Profiles");
        profilesColumn.setAlignment(SWT.RIGHT);
        profilesColumn.setWidth(55);

        TableColumn unusedProfilesColumn = new TableViewerColumn(bundlePoolViewer, SWT.NONE).getColumn();
        unusedProfilesColumn.setText("Unused Profiles");
        unusedProfilesColumn.setAlignment(SWT.RIGHT);
        unusedProfilesColumn.setWidth(97);

        TableColumn artifactsColumn = new TableViewerColumn(bundlePoolViewer, SWT.NONE).getColumn();
        artifactsColumn.setText("Artifacts");
        artifactsColumn.setAlignment(SWT.RIGHT);
        artifactsColumn.setWidth(63);

        TableColumn unusedArtifactsColumn = new TableViewerColumn(bundlePoolViewer, SWT.NONE).getColumn();
        unusedArtifactsColumn.setText("Unused Artifacts");
        unusedArtifactsColumn.setAlignment(SWT.RIGHT);
        unusedArtifactsColumn.setWidth(105);

        TableColumn damagedArtifactsColumn = new TableViewerColumn(bundlePoolViewer, SWT.NONE).getColumn();
        damagedArtifactsColumn.setText("Damaged Artifacts");
        damagedArtifactsColumn.setAlignment(SWT.RIGHT);
        damagedArtifactsColumn.setWidth(125);

        bundlePoolContentProvider = new BundlePoolContentProvider();
        bundlePoolViewer.setContentProvider(bundlePoolContentProvider);
        bundlePoolViewer.setLabelProvider(new TableLabelProvider(getDisplay()));
        bundlePoolViewer.addSelectionChangedListener(new SelectionChangedListener() {
            @Override
            protected void doSelectionChanged(SelectionChangedEvent event) {
                currentBundlePool = (AnalyzedBundlePool) ((IStructuredSelection) event.getSelection())
                        .getFirstElement();

                profileViewer.setSelection(StructuredSelection.EMPTY);
                profileContentProvider.setInput(profileViewer, currentBundlePool);

                artifactViewer.setSelection(StructuredSelection.EMPTY);
                artifactContentProvider.setInput(artifactViewer, currentBundlePool);

                updateBundlePoolButtons();
            }
        });

        Composite bundlePoolButtonBar = new Composite(bundlePoolComposite, SWT.NONE);
        bundlePoolButtonBar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
        GridLayout bundlePoolButtonBarLayout = new GridLayout(4, false);
        bundlePoolButtonBarLayout.marginWidth = 0;
        bundlePoolButtonBarLayout.marginHeight = 0;
        bundlePoolButtonBar.setLayout(bundlePoolButtonBarLayout);

        new Label(bundlePoolButtonBar, SWT.NONE).setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));

        deleteUnusedProfilesButton = new Button(bundlePoolButtonBar, SWT.NONE);
        deleteUnusedProfilesButton.setText("Delete Unused Profiles");
        deleteUnusedProfilesButton.setEnabled(false);
        deleteUnusedProfilesButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                AnalyzedProfile[] profiles = currentBundlePool.getUnusedProfiles();
                deleteProfiles(profiles);
                updateBundlePoolButtons();
            }
        });

        deleteUnusedArtifactsButton = new Button(bundlePoolButtonBar, SWT.NONE);
        deleteUnusedArtifactsButton.setText("Delete Unused Artifacts");
        deleteUnusedArtifactsButton.setEnabled(false);
        deleteUnusedArtifactsButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                AnalyzedArtifact[] artifacts = currentBundlePool.getUnusedArtifacts();
                deleteArtifacts(artifacts);
                updateBundlePoolButtons();
            }
        });

        repairAllArtifactsButton = new Button(bundlePoolButtonBar, SWT.NONE);
        repairAllArtifactsButton.setText("Repair Damaged Artifacts");
        repairAllArtifactsButton.setEnabled(false);
        repairAllArtifactsButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                AnalyzedArtifact[] artifacts = currentBundlePool.getDamagedArtifacts();
                repairArtifacts(artifacts);
                updateBundlePoolButtons();
            }
        });

        new Label(bundlePoolComposite, SWT.NONE);
        bundlePoolContentProvider.setInput(bundlePoolViewer, null); // trigger resizeColumns
    }

    private void createProfileViewer(Composite parent) {
        Composite profileComposite = new Composite(parent, SWT.NONE);
        GridLayout profileLayout = new GridLayout();
        profileLayout.marginWidth = 0;
        profileLayout.marginHeight = 0;
        profileComposite.setLayout(profileLayout);

        profileViewer = new TableViewer(profileComposite, TABLE_STYLE | SWT.MULTI);
        Table profileTable = profileViewer.getTable();
        profileTable.setHeaderVisible(true);
        profileTable.setLayoutData(new GridData(GridData.FILL_BOTH));
        new SelectAllAdapter(profileViewer);

        TableColumn profileColumn = new TableViewerColumn(profileViewer, SWT.NONE).getColumn();
        profileColumn.setText("Profile");
        profileColumn.setWidth(447);
        profileColumn.setResizable(false);

        TableColumn artifactsColumn = new TableViewerColumn(profileViewer, SWT.NONE).getColumn();
        artifactsColumn.setText("Artifacts");
        artifactsColumn.setAlignment(SWT.RIGHT);
        artifactsColumn.setWidth(62);

        TableColumn damagedArtifactsColumn = new TableViewerColumn(profileViewer, SWT.NONE).getColumn();
        damagedArtifactsColumn.setText("Damaged Artifacts");
        damagedArtifactsColumn.setAlignment(SWT.RIGHT);
        damagedArtifactsColumn.setWidth(120);

        TableColumn rootsColumn = new TableViewerColumn(profileViewer, SWT.NONE).getColumn();
        rootsColumn.setText("Roots");
        rootsColumn.setAlignment(SWT.RIGHT);
        rootsColumn.setWidth(50);

        TableColumn repositoriesColumn = new TableViewerColumn(profileViewer, SWT.NONE).getColumn();
        repositoriesColumn.setText("Repositories");
        repositoriesColumn.setAlignment(SWT.RIGHT);
        repositoriesColumn.setWidth(82);

        profileContentProvider = new ProfileContentProvider();
        profileViewer.setContentProvider(profileContentProvider);
        profileViewer.setLabelProvider(new TableLabelProvider(getDisplay()));
        profileViewer.addSelectionChangedListener(new SelectionChangedListener() {
            @Override
            protected void doSelectionChanged(SelectionChangedEvent event) {
                updateProfileButtons();
            }

            @Override
            protected void triggerOtherSelections(SelectionChangedEvent event) {
                if (!changingSelection.contains(artifactViewer)) {
                    Set<AnalyzedArtifact> artifacts = new HashSet<AnalyzedArtifact>();
                    for (AnalyzedProfile profile : getSelectedProfiles()) {
                        artifacts.addAll(profile.getArtifacts());
                    }

                    artifactViewer
                            .setSelection(new StructuredSelection(new ArrayList<AnalyzedArtifact>(artifacts)));
                }
            }
        });

        profileTable.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseDoubleClick(MouseEvent e) {
                showProfileDetails();
            }
        });

        Composite profileButtonBar = new Composite(profileComposite, SWT.NONE);
        profileButtonBar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
        profileButtonBar.setLayout(UIUtil.createGridLayout(5));

        final Combo filterCombo = new Combo(profileButtonBar, SWT.READ_ONLY);
        filterCombo.add(SHOW_ALL);
        filterCombo.add(SHOW_UNUSED);
        filterCombo.add(SHOW_BY_ARTIFACT);
        filterCombo.select(0);
        filterCombo.pack();
        filterCombo.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                profileFilter = filterCombo.getText();
                profileContentProvider.setFilter(profileFilter);
            }
        });

        selectAllProfilesButton = new Button(profileButtonBar, SWT.NONE);
        selectAllProfilesButton.setText("Select All");
        selectAllProfilesButton.setEnabled(false);
        selectAllProfilesButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                profileViewer.setSelection(new StructuredSelection(currentBundlePool.getProfiles()));
            }
        });

        new Label(profileButtonBar, SWT.NONE).setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));

        deleteProfilesButton = new Button(profileButtonBar, SWT.NONE);
        deleteProfilesButton.setText("Delete Selected...");
        deleteProfilesButton.setEnabled(false);
        deleteProfilesButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                AnalyzedProfile[] profiles = getSelectedProfiles();
                deleteProfiles(profiles);
            }
        });

        showDetailsButton = new Button(profileButtonBar, SWT.NONE);
        showDetailsButton.setText("Details...");
        showDetailsButton.setEnabled(false);
        showDetailsButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                showProfileDetails();
            }
        });

        new Label(profileComposite, SWT.NONE);
        profileContentProvider.setInput(profileViewer, null); // trigger resizeColumns
    }

    private void createArtifactViewer(Composite parent) {
        Composite artifactComposite = new Composite(parent, SWT.NONE);
        GridLayout artifactLayout = new GridLayout();
        artifactLayout.marginWidth = 0;
        artifactLayout.marginHeight = 0;
        artifactComposite.setLayout(artifactLayout);

        artifactViewer = new TableViewer(artifactComposite, TABLE_STYLE | SWT.MULTI);
        Table artifactTable = artifactViewer.getTable();
        artifactTable.setHeaderVisible(true);
        artifactTable.setLayoutData(new GridData(GridData.FILL_BOTH));
        new SelectAllAdapter(artifactViewer);

        TableColumn artifactColumn = new TableViewerColumn(artifactViewer, SWT.NONE).getColumn();
        artifactColumn.setText("Artifact");
        artifactColumn.setWidth(365);
        artifactColumn.setResizable(false);

        TableColumn versionVersion = new TableViewerColumn(artifactViewer, SWT.NONE).getColumn();
        versionVersion.setText("Version");
        versionVersion.setWidth(205);

        TableColumn profilesColumn = new TableViewerColumn(artifactViewer, SWT.NONE).getColumn();
        profilesColumn.setText("Profiles");
        profilesColumn.setAlignment(SWT.RIGHT);
        profilesColumn.setWidth(56);

        artifactContentProvider = new ArtifactContentProvider();
        artifactViewer.setContentProvider(artifactContentProvider);
        artifactViewer.setLabelProvider(new TableLabelProvider(getDisplay()));
        artifactViewer.addSelectionChangedListener(new SelectionChangedListener() {
            @Override
            protected void doSelectionChanged(SelectionChangedEvent event) {
                updateArtifactButtons();

                if (SHOW_BY_ARTIFACT.equals(profileFilter)) {
                    profileContentProvider.refresh();
                }
            }

            @Override
            protected void triggerOtherSelections(SelectionChangedEvent event) {
                if (!SHOW_BY_ARTIFACT.equals(profileFilter)) {
                    if (!changingSelection.contains(profileViewer)) {
                        Set<AnalyzedProfile> profiles = new HashSet<AnalyzedProfile>();
                        for (AnalyzedArtifact artifact : getSelectedArtifacts()) {
                            profiles.addAll(artifact.getProfiles());
                        }

                        profileViewer.setSelection(new StructuredSelection(profiles.toArray()));
                    }
                }
            }
        });

        Composite artifactButtonBar = new Composite(artifactComposite, SWT.NONE);
        artifactButtonBar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
        GridLayout artifactButtonBarLayout = new GridLayout(5, false);
        artifactButtonBarLayout.marginWidth = 0;
        artifactButtonBarLayout.marginHeight = 0;
        artifactButtonBar.setLayout(artifactButtonBarLayout);

        final Combo filterCombo = new Combo(artifactButtonBar, SWT.READ_ONLY);
        filterCombo.add(SHOW_ALL);
        filterCombo.add(SHOW_UNUSED);
        filterCombo.add(SHOW_DAMAGED);
        filterCombo.select(0);
        filterCombo.pack();
        filterCombo.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                String selection = filterCombo.getText();
                artifactContentProvider.setFilter(selection);
            }
        });

        selectAllArtifactsButton = new Button(artifactButtonBar, SWT.NONE);
        selectAllArtifactsButton.setText("Select All");
        selectAllArtifactsButton.setEnabled(false);
        selectAllArtifactsButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                artifactViewer.setSelection(new StructuredSelection(currentBundlePool.getArtifacts()));
            }
        });

        new Label(artifactButtonBar, SWT.NONE).setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));

        deleteArtifactsButton = new Button(artifactButtonBar, SWT.NONE);
        deleteArtifactsButton.setText("Delete Selected...");
        deleteArtifactsButton.setEnabled(false);
        deleteArtifactsButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                AnalyzedArtifact[] artifacts = getSelectedArtifacts();
                deleteArtifacts(artifacts);
            }
        });

        repairArtifactsButton = new Button(artifactButtonBar, SWT.NONE);
        repairArtifactsButton.setText("Repair Selected");
        repairArtifactsButton.setEnabled(false);
        repairArtifactsButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                AnalyzedArtifact[] artifacts = getSelectedArtifacts();
                repairArtifacts(artifacts);
            }
        });

        artifactContentProvider.setInput(artifactViewer, null); // trigger resizeColumns
    }

    private void initAnalyzer() throws InvocationTargetException, InterruptedException {
        initializingAnalyzer = true;

        try {
            ProgressMonitorDialog dialog = new ProgressMonitorDialog(getShell());
            dialog.run(true, true, new IRunnableWithProgress() {
                public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
                    analyzer = new AgentAnalyzer(agent, true, new Handler() {
                        public void analyzerChanged(final AgentAnalyzer analyzer) {
                            if (analyzer == AgentAnalyzerComposite.this.analyzer) {
                                asyncExec(new Runnable() {
                                    public void run() {
                                        bundlePoolContentProvider.refresh();

                                        if (!deletingArtifacts) {
                                            artifactContentProvider.refresh();
                                            profileContentProvider.refresh();
                                        }

                                        getDisplay().asyncExec(new Runnable() {
                                            public void run() {
                                                Object[] elements = bundlePoolContentProvider.getElements(analyzer);
                                                if (elements.length != 0) {
                                                    bundlePoolViewer
                                                            .setSelection(new StructuredSelection(elements[0]));
                                                }
                                            }
                                        });
                                    }
                                });
                            }
                        }

                        public void bundlePoolChanged(final AnalyzedBundlePool bundlePool, final boolean artifacts,
                                final boolean profiles) {
                            asyncExec(new Runnable() {
                                public void run() {
                                    bundlePoolViewer.update(bundlePool, null);

                                    if (bundlePool == currentBundlePool) {
                                        if (!artifacts && !profiles) {
                                            updateBundlePoolButtons();
                                        } else {
                                            if (artifacts) {
                                                artifactContentProvider.refresh();
                                            }

                                            if (profiles) {
                                                profileContentProvider.refresh();
                                            }
                                        }
                                    }
                                }
                            });
                        }

                        public void profileChanged(final AnalyzedProfile profile) {
                            if (deletingArtifacts) {
                                return;
                            }

                            if (profile.getBundlePool() == currentBundlePool) {
                                asyncExec(new Runnable() {
                                    public void run() {
                                        profileViewer.update(profile, null);
                                    }
                                });
                            }
                        }

                        public void artifactChanged(final AnalyzedArtifact artifact) {
                            if (deletingArtifacts) {
                                return;
                            }

                            if (artifact == null || artifact.getBundlePool() == currentBundlePool) {
                                asyncExec(new Runnable() {
                                    public void run() {
                                        if (artifact != null && ObjectUtil
                                                .equals(artifactContentProvider.getFilter(), SHOW_ALL)) {
                                            artifactViewer.update(artifact, null);
                                        } else {
                                            artifactContentProvider.refresh();
                                        }
                                    }
                                });
                            }
                        }
                    }, monitor);
                }
            });
        } finally {
            initializingAnalyzer = false;
        }
    }

    private void asyncExec(Runnable runnable) {
        if (!isDisposed()) {
            Display display = getDisplay();
            UIUtil.asyncExec(display, runnable);
        }
    }

    private AnalyzedProfile[] getSelectedProfiles() {
        IStructuredSelection selection = (IStructuredSelection) profileViewer.getSelection();

        @SuppressWarnings("unchecked")
        List<AnalyzedProfile> profiles = (List<AnalyzedProfile>) (List<?>) selection.toList();
        return profiles.toArray(new AnalyzedProfile[profiles.size()]);
    }

    private AnalyzedArtifact[] getSelectedArtifacts() {
        IStructuredSelection selection = (IStructuredSelection) artifactViewer.getSelection();

        @SuppressWarnings("unchecked")
        List<AnalyzedArtifact> artifacts = (List<AnalyzedArtifact>) (List<?>) selection.toList();
        return artifacts.toArray(new AnalyzedArtifact[artifacts.size()]);
    }

    private boolean updateButton(Button button, String text, int count, String suffix) {
        button.setEnabled(count != 0);
        if (count != 0) {
            text += " " + count;
        }

        text += suffix;

        if (!button.getText().equals(text)) {
            button.setText(text);
            return true;
        }

        return false;
    }

    private void updateBundlePoolButtons() {
        boolean changed = false;

        if (currentBundlePool != null) {
            changed |= updateButton(deleteUnusedProfilesButton, "Delete",
                    currentBundlePool.getUnusedProfilesCount(), " Unused Profiles...");
            if (initializingAnalyzer && deleteUnusedProfilesButton.isEnabled()) {
                deleteUnusedProfilesButton.setEnabled(false);
            }

            changed |= updateButton(deleteUnusedArtifactsButton, "Delete",
                    currentBundlePool.getUnusedArtifactsCount(), " Unused Artifacts...");
            if (initializingAnalyzer && deleteUnusedArtifactsButton.isEnabled()) {
                deleteUnusedArtifactsButton.setEnabled(false);
            }

            changed |= updateButton(repairAllArtifactsButton, "Repair",
                    currentBundlePool.getDamagedArtifactsCount(), " Damaged Artifacts");

            if (currentBundlePool.isAnalyzingDamage() && repairAllArtifactsButton.isEnabled()) {
                repairAllArtifactsButton.setEnabled(false);
            }
        }

        if (changed) {
            Composite parent = deleteUnusedProfilesButton.getParent();
            parent.pack();
            parent.getParent().layout();
        }
    }

    private void updateProfileButtons() {
        boolean changed = false;

        if (currentBundlePool != null) {
            Object[] elements = profileContentProvider.getElements(currentBundlePool);
            changed |= updateButton(selectAllProfilesButton, "Select All", elements.length, "");
        }

        AnalyzedProfile[] profiles = getSelectedProfiles();
        int count = profiles.length;

        changed |= updateButton(deleteProfilesButton, "Delete", count, " Selected...");

        showDetailsButton.setEnabled(count == 1);

        if (count != 0) {
            boolean enabled = true;
            for (int i = 0; i < count; i++) {
                AnalyzedProfile profile = profiles[i];
                if (!profile.isUnused()) {
                    enabled = false;
                    break;
                }
            }

            deleteProfilesButton.setEnabled(enabled);
        }

        if (changed) {
            Composite parent = deleteProfilesButton.getParent();
            parent.pack();
            parent.getParent().layout();
        }
    }

    private void updateArtifactButtons() {
        boolean changed = false;

        if (currentBundlePool != null) {
            Object[] elements = artifactContentProvider.getElements(currentBundlePool);
            changed |= updateButton(selectAllArtifactsButton, "Select All", elements.length, "");
        }

        AnalyzedArtifact[] artifacts = getSelectedArtifacts();
        int count = artifacts.length;

        changed |= updateButton(repairArtifactsButton, "Repair", count, " Selected");
        changed |= updateButton(deleteArtifactsButton, "Delete", count, " Selected...");

        if (changed) {
            Composite parent = repairArtifactsButton.getParent();
            parent.pack();
            parent.getParent().layout();
        }
    }

    private void deleteProfiles(final AnalyzedProfile[] profiles) {
        int len = profiles.length;
        String message = "Do you really want to delete " + len + " profile" + (len == 1 ? "" : "s") + "?";

        if (MessageDialog.openQuestion(getShell(), AgentAnalyzerDialog.TITLE, message)) {
            try {
                UIUtil.runInProgressDialog(getShell(), new IRunnableWithProgress() {
                    public void run(IProgressMonitor monitor)
                            throws InvocationTargetException, InterruptedException {
                        SubMonitor progress = SubMonitor.convert(monitor, "Deleting profiles", profiles.length)
                                .detectCancelation();

                        for (AnalyzedProfile profile : profiles) {
                            profile.delete(progress.newChild());
                        }
                    }
                });

                profileContentProvider.refresh();
                profileViewer.setSelection(StructuredSelection.EMPTY);
            } catch (InvocationTargetException ex) {
                ErrorDialog.open(ex);
            } catch (InterruptedException ex) {
                // Ignore.
            }
        }
    }

    private void showProfileDetails() {
        AnalyzedProfile[] selectedProfiles = getSelectedProfiles();
        if (selectedProfiles.length == 1) {
            Profile profile = selectedProfiles[0].getP2Profile();

            ProfileDetailsDialog dialog = new ProfileDetailsDialog(getShell(), profile);
            dialog.open();
        }
    }

    private void deleteArtifacts(final AnalyzedArtifact[] artifacts) {
        int len = artifacts.length;
        String message = "Do you really want to delete " + len + " artifact" + (len == 1 ? "" : "s") + "?\n\n"
                + "Note 1: Unused artifacts can always safely be deleted. "
                + "They will be deleted physically from your disk and logically from your bundle pool.\n\n"
                + "Note 2: Artifacts used in your profiles will be deleted only physically from your disk. "
                + "Repairing them is possible if they are still available for download from a p2 repository.";

        if (MessageDialog.openQuestion(getShell(), AgentAnalyzerDialog.TITLE, message)) {
            try {
                deletingArtifacts = true;
                UIUtil.runInProgressDialog(getShell(), new IRunnableWithProgress() {
                    public void run(IProgressMonitor monitor)
                            throws InvocationTargetException, InterruptedException {
                        SubMonitor progress = SubMonitor.convert(monitor, "Deleting artifacts...", artifacts.length)
                                .detectCancelation();

                        for (AnalyzedArtifact artifact : artifacts) {
                            artifact.delete(progress.newChild());
                        }
                    }
                });

                profileViewer.refresh();
                profileViewer.setSelection(StructuredSelection.EMPTY);

                artifactContentProvider.refresh();
                artifactViewer.setSelection(StructuredSelection.EMPTY);
            } catch (InvocationTargetException ex) {
                ErrorDialog.open(ex);
            } catch (InterruptedException ex) {
                // Ignore.
            } finally {
                deletingArtifacts = false;
            }
        }
    }

    private void repairArtifacts(final AnalyzedArtifact[] artifacts) {
        try {
            final List<AnalyzedArtifact> remainingArtifacts = new ArrayList<AnalyzedArtifact>();

            UIUtil.runInProgressDialog(getShell(), new IRunnableWithProgress() {
                public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
                    SubMonitor progress = SubMonitor
                            .convert(monitor, AnalyzedArtifact.REPAIR_TASK_NAME, artifacts.length)
                            .detectCancelation();

                    for (AnalyzedArtifact artifact : artifacts) {
                        if (!artifact.repair(null, progress.newChild())) {
                            remainingArtifacts.add(artifact);
                        }
                    }
                }
            });

            artifactContentProvider.refresh();
            artifactViewer.setSelection(StructuredSelection.EMPTY);

            boolean firstTime = true;
            Set<URI> repositories = new HashSet<URI>(analyzer.getRepositoryURIs());

            while (!remainingArtifacts.isEmpty()) {
                AdditionalURIPrompterDialog dialog = new AdditionalURIPrompterDialog(getShell(), firstTime,
                        remainingArtifacts, repositories);
                if (dialog.open() == AdditionalURIPrompterDialog.CANCEL) {
                    break;
                }

                firstTime = false;
                analyzer.getRepositoryURIs().addAll(repositories);

                final Set<URI> checkedRepositories = dialog.getCheckedRepositories();
                UIUtil.runInProgressDialog(getShell(), new IRunnableWithProgress() {
                    public void run(IProgressMonitor monitor)
                            throws InvocationTargetException, InterruptedException {
                        SubMonitor progress = SubMonitor
                                .convert(monitor, AnalyzedArtifact.REPAIR_TASK_NAME, artifacts.length)
                                .detectCancelation();

                        for (Iterator<AnalyzedArtifact> it = remainingArtifacts.iterator(); it.hasNext();) {
                            AnalyzedArtifact artifact = it.next();
                            if (artifact.repair(checkedRepositories, progress.newChild())) {
                                it.remove();
                            }
                        }
                    }
                });

                repositories.removeAll(checkedRepositories);
                artifactContentProvider.refresh();
            }
        } catch (InvocationTargetException ex) {
            ErrorDialog.open(ex);
        } catch (InterruptedException ex) {
            // Ignore.
        }
    }

    /**
     * @author Eike Stepper
     */
    private abstract class SelectionChangedListener implements ISelectionChangedListener {
        public final void selectionChanged(SelectionChangedEvent event) {
            doSelectionChanged(event);

            if (changingSelection.add(event.getSelectionProvider())) {
                try {
                    triggerOtherSelections(event);
                } finally {
                    changingSelection.remove(event.getSelectionProvider());
                }
            }
        }

        protected abstract void doSelectionChanged(SelectionChangedEvent event);

        protected void triggerOtherSelections(SelectionChangedEvent event) {
            // Subclasses may override
        }
    }

    /**
     * @author Eike Stepper
     */
    private static final class SelectAllAdapter extends KeyAdapter {
        private final StructuredViewer viewer;

        public SelectAllAdapter(StructuredViewer viewer) {
            this.viewer = viewer;
            viewer.getControl().addKeyListener(this);
        }

        @Override
        public void keyPressed(KeyEvent e) {
            if ((e.stateMask & SWT.CONTROL) != 0 && e.keyCode == 'a') {
                IStructuredContentProvider contentProvider = (IStructuredContentProvider) viewer
                        .getContentProvider();
                viewer.setSelection(new StructuredSelection(contentProvider.getElements(viewer.getInput())));
            }
        }
    }

    /**
     * @author Eike Stepper
     */
    public static final class TableLabelProvider extends LabelProvider
            implements ITableLabelProvider, IColorProvider {
        private final Color gray;

        private boolean singleColumn;

        public TableLabelProvider(Display display, boolean singleColumn) {
            this.singleColumn = singleColumn;
            gray = display.getSystemColor(SWT.COLOR_DARK_GRAY);
        }

        public TableLabelProvider(Display display) {
            this(display, false);
        }

        public String getColumnText(Object element, int columnIndex) {
            if (element instanceof AnalyzedBundlePool) {
                AnalyzedBundlePool bundlePool = (AnalyzedBundlePool) element;
                switch (columnIndex) {
                case 0:
                    return bundlePool.getLocation().getAbsolutePath();
                case 1:
                    return Integer.toString(bundlePool.getProfilesCount());
                case 2:
                    return Integer.toString(bundlePool.getUnusedProfilesCount());
                case 3:
                    return Integer.toString(bundlePool.getArtifactCount());
                case 4:
                    return Integer.toString(bundlePool.getUnusedArtifactsCount());
                case 5:
                    int percent = bundlePool.getDamagedArtifactsPercent();
                    return Integer.toString(bundlePool.getDamagedArtifactsCount())
                            + (percent == 100 ? "" : " (" + percent + "%)");
                }
            } else if (element instanceof AnalyzedProfile) {
                AnalyzedProfile profile = (AnalyzedProfile) element;
                switch (columnIndex) {
                case 0:
                    return profile.getID();
                case 1:
                    return Integer.toString(profile.getArtifacts().size());
                case 2:
                    return Integer.toString(profile.getDamagedArtifactsCount());
                case 3:
                    return Integer.toString(profile.getRoots());
                case 4:
                    return Integer.toString(profile.getRepositoryURIs().size());
                }
            } else if (element instanceof AnalyzedArtifact) {
                AnalyzedArtifact artifact = (AnalyzedArtifact) element;
                switch (columnIndex) {
                case 0:
                    if (singleColumn) {
                        return artifact.getID() + " " + artifact.getVersion();
                    }

                    return artifact.getID();
                case 1:
                    return artifact.getVersion();
                case 2:
                    return Integer.toString(artifact.getProfiles().size());
                }
            }

            return String.valueOf(element);
        }

        public Image getColumnImage(Object element, int columnIndex) {
            if (columnIndex == 0) {
                if (element instanceof AnalyzedBundlePool) {
                    AnalyzedBundlePool bundlePool = (AnalyzedBundlePool) element;
                    String key = "bundlePool";
                    if (bundlePool.getDamagedArtifactsCount() != 0) {
                        key += "Damaged";
                    }

                    return getPluginImage(key);
                }

                if (element instanceof AnalyzedArtifact) {
                    AnalyzedArtifact artifact = (AnalyzedArtifact) element;
                    String key = "artifact" + artifact.getType();
                    if (artifact.isDamaged()) {
                        key += "Damaged";
                    }

                    return getPluginImage(key);
                }

                if (element instanceof AnalyzedProfile) {
                    AnalyzedProfile profile = (AnalyzedProfile) element;
                    String key = "profile" + profile.getType();
                    if (profile.isDamaged()) {
                        key += "Damaged";
                    }

                    return getPluginImage(key);
                }

                if (element instanceof URI) {
                    return getPluginImage("repository");
                }
            }

            return null;
        }

        public Color getForeground(Object element) {
            if (element instanceof AnalyzedArtifact) {
                AnalyzedArtifact artifact = (AnalyzedArtifact) element;
                if (artifact.isUnused()) {
                    return gray;
                }
            }

            if (element instanceof AnalyzedProfile) {
                AnalyzedProfile profile = (AnalyzedProfile) element;
                if (profile.isUnused()) {
                    return gray;
                }
            }

            return null;
        }

        public Color getBackground(Object element) {
            return null;
        }

        static Set<String> keys = new HashSet<String>();

        private static Image getPluginImage(String key) {
            return P2UIPlugin.INSTANCE.getSWTImage("obj16/" + key + "");
        }
    }

    /**
     * @author Eike Stepper
     */
    private static abstract class TableContentProvider extends ControlAdapter
            implements IStructuredContentProvider, ILazyContentProvider {
        private static final int FIRST_TIME = -1;

        private final ControlListener columnListener = new ControlAdapter() {
            @Override
            public void controlResized(ControlEvent e) {
                resizeColumns(true);
            }
        };

        private TableViewer tableViewer;

        private Object input;

        private String filter = SHOW_ALL;

        private int lastWidth = FIRST_TIME;

        public void setInput(TableViewer viewer, Object input) {
            if (tableViewer == null) {
                tableViewer = viewer;
                tableViewer.getTable().addControlListener(this);
            }

            if (input != null) {
                tableViewer.setInput(input);
                refresh();
            }

            ScrollBar verticalBar = tableViewer.getTable().getVerticalBar();
            if (verticalBar != null) {
                verticalBar.setSelection(verticalBar.getMinimum());
            }

            resizeColumns();
        }

        public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
            input = newInput;
        }

        public void dispose() {
            input = null;
            tableViewer = null;
        }

        public void updateElement(int index) {
            Object[] elements = getElements(input);
            Object element = index < elements.length ? elements[index] : null;
            tableViewer.replace(element, index);
        }

        public void refresh() {
            if (tableViewer != null && input != null) {
                tableViewer.refresh();
                tableViewer.setItemCount(getElements(input).length);
            }
        }

        public String getFilter() {
            return filter;
        }

        public void setFilter(String filter) {
            this.filter = filter;
            UIUtil.asyncExec(tableViewer.getTable().getDisplay(), new Runnable() {
                public void run() {
                    tableViewer.setSelection(StructuredSelection.EMPTY);
                    refresh();
                    resizeColumns();
                }
            });
        }

        @Override
        public void controlResized(ControlEvent e) {
            resizeColumns(false);
        }

        public void resizeColumns() {
            Table table = tableViewer.getTable();
            if (!table.isDisposed()) {
                UIUtil.asyncExec(table.getDisplay(), new Runnable() {
                    public void run() {
                        resizeColumns(true);
                    }
                });
            }
        }

        private void resizeColumns(boolean force) {
            Table table = tableViewer.getTable();
            int tableWidth = table.getSize().x;
            if (force || tableWidth != lastWidth) {
                boolean firstTime = lastWidth == FIRST_TIME;
                lastWidth = tableWidth;

                ScrollBar bar = table.getVerticalBar();
                if (bar != null && bar.isVisible()) {
                    tableWidth -= bar.getSize().x;
                }

                final TableColumn[] columns = table.getColumns();
                for (int i = 1; i < columns.length; i++) {
                    TableColumn column = columns[i];
                    tableWidth -= column.getWidth();

                    if (firstTime) {
                        column.addControlListener(columnListener);
                    }
                }

                columns[0].setWidth(tableWidth);
            }
        }
    }

    /**
     * @author Eike Stepper
     */
    private final class BundlePoolContentProvider extends TableContentProvider {
        public Object[] getElements(Object input) {
            Map<File, AnalyzedBundlePool> map = ((AgentAnalyzer) input).getBundlePools();
            AnalyzedBundlePool[] bundlePools = map.values().toArray(new AnalyzedBundlePool[map.size()]);
            Arrays.sort(bundlePools);
            return bundlePools;
        }

        @Override
        public void refresh() {
            super.refresh();
            updateBundlePoolButtons();
        }
    }

    /**
     * @author Eike Stepper
     */
    private final class ProfileContentProvider extends TableContentProvider {
        public Object[] getElements(Object input) {
            String filter = getFilter();
            if (ObjectUtil.equals(filter, SHOW_UNUSED)) {
                return ((AnalyzedBundlePool) input).getUnusedProfiles();
            }

            if (ObjectUtil.equals(filter, SHOW_BY_ARTIFACT)) {
                Set<AnalyzedProfile> profiles = new HashSet<AnalyzedProfile>();
                for (AnalyzedArtifact artifact : getSelectedArtifacts()) {
                    profiles.addAll(artifact.getProfiles());
                }

                AnalyzedProfile[] array = profiles.toArray(new AnalyzedProfile[profiles.size()]);
                Arrays.sort(array);
                return array;
            }

            return ((AnalyzedBundlePool) input).getProfiles();
        }

        @Override
        public void refresh() {
            super.refresh();
            updateProfileButtons();
        }
    }

    /**
     * @author Eike Stepper
     */
    private final class ArtifactContentProvider extends TableContentProvider {
        public Object[] getElements(Object input) {
            String filter = getFilter();
            if (ObjectUtil.equals(filter, SHOW_UNUSED)) {
                return ((AnalyzedBundlePool) input).getUnusedArtifacts();
            }

            if (ObjectUtil.equals(filter, SHOW_DAMAGED)) {
                return ((AnalyzedBundlePool) input).getDamagedArtifacts();
            }

            return ((AnalyzedBundlePool) input).getArtifacts();
        }

        @Override
        public void refresh() {
            super.refresh();
            updateArtifactButtons();
        }
    }
}