Revert "Revert "Bug 577207 - Migrate bundle spy""
This reverts commit 33882ac3c2ff848fc1acf301d91f61ef1f2df336.
Reason for revert: planned for 4.23
Change-Id: I243bdb79926a46e8b6c887962a15746771eedb43
Reviewed-on: https://git.eclipse.org/r/c/pde/eclipse.pde.ui/+/187129
Tested-by: PDE Bot <pde-bot@eclipse.org>
Reviewed-by: Lars Vogel <Lars.Vogel@vogella.com>
diff --git a/pom.xml b/pom.xml
index 55378e6..151460d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -74,6 +74,7 @@
<module>ui/org.eclipse.pde.ui.tests</module>
<module>ui/org.eclipse.pde.ui.tests.smartimport</module>
<module>ui/org.eclipse.pde.spy.core</module>
+ <module>ui/org.eclipse.pde.spy.bundle</module>
<module>ui/org.eclipse.pde.spy.css</module>
<module>ui/org.eclipse.pde.spy.model</module>
<module>ui/org.eclipse.pde.spy.preferences</module>
diff --git a/ui/org.eclipse.pde.spy.bundle/.classpath b/ui/org.eclipse.pde.spy.bundle/.classpath
new file mode 100644
index 0000000..4a00bec
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/.classpath
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
+ <attributes>
+ <attribute name="module" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/ui/org.eclipse.pde.spy.bundle/.project b/ui/org.eclipse.pde.spy.bundle/.project
new file mode 100644
index 0000000..405de65
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.pde.spy.bundle</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ </natures>
+</projectDescription>
diff --git a/ui/org.eclipse.pde.spy.bundle/.settings/org.eclipse.jdt.core.prefs b/ui/org.eclipse.pde.spy.bundle/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..f2525a8
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,14 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=11
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=11
diff --git a/ui/org.eclipse.pde.spy.bundle/META-INF/MANIFEST.MF b/ui/org.eclipse.pde.spy.bundle/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..c417cb0
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/META-INF/MANIFEST.MF
@@ -0,0 +1,20 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %name
+Bundle-SymbolicName: org.eclipse.pde.spy.bundle;singleton:=true
+Bundle-Version: 0.12.100.qualifier
+Bundle-RequiredExecutionEnvironment: JavaSE-11
+Automatic-Module-Name: org.eclipse.pde.spy.bundle
+Require-Bundle: org.eclipse.core.runtime;bundle-version="3.10.0",
+ org.eclipse.jface;bundle-version="3.10.1",
+ org.eclipse.e4.ui.model.workbench,
+ org.eclipse.e4.core.contexts,
+ org.eclipse.e4.ui.di,
+ org.eclipse.e4.core.di,
+ org.eclipse.e4.core.services,
+ org.eclipse.pde.spy.core;bundle-version="1.0.0"
+Bundle-Localization: plugin
+Import-Package: javax.annotation;version="1.3.5",
+ javax.inject;version="1.0.0"
+Bundle-Vendor: %provider-name
+Bundle-ActivationPolicy: lazy
diff --git a/ui/org.eclipse.pde.spy.bundle/about.html b/ui/org.eclipse.pde.spy.bundle/about.html
new file mode 100644
index 0000000..164f781
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/about.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<title>About</title>
+</head>
+<body lang="EN-US">
+ <h2>About This Content</h2>
+
+ <p>November 30, 2017</p>
+ <h3>License</h3>
+
+ <p>
+ The Eclipse Foundation makes available all content in this plug-in
+ ("Content"). Unless otherwise indicated below, the Content
+ is provided to you under the terms and conditions of the Eclipse
+ Public License Version 2.0 ("EPL"). A copy of the EPL is
+ available at <a href="http://www.eclipse.org/legal/epl-2.0">http://www.eclipse.org/legal/epl-2.0</a>.
+ For purposes of the EPL, "Program" will mean the Content.
+ </p>
+
+ <p>
+ If you did not receive this Content directly from the Eclipse
+ Foundation, the Content is being redistributed by another party
+ ("Redistributor") and different terms and conditions may
+ apply to your use of any object code in the Content. Check the
+ Redistributor's license that was provided with the Content. If no such
+ license exists, contact the Redistributor. Unless otherwise indicated
+ below, the terms and conditions of the EPL still apply to any source
+ code in the Content and such source code may be obtained at <a
+ href="http://www.eclipse.org/">http://www.eclipse.org</a>.
+ </p>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/ui/org.eclipse.pde.spy.bundle/build.properties b/ui/org.eclipse.pde.spy.bundle/build.properties
new file mode 100644
index 0000000..a9b12c8
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/build.properties
@@ -0,0 +1,8 @@
+source.. = src/
+bin.includes = META-INF/,\
+ .,\
+ plugin.properties,\
+ plugin.xml,\
+ icons/,\
+ about.html
+src.includes = about.html
diff --git a/ui/org.eclipse.pde.spy.bundle/icons/osgi.png b/ui/org.eclipse.pde.spy.bundle/icons/osgi.png
new file mode 100644
index 0000000..15cf6e3
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/icons/osgi.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.bundle/icons/osgi@2x.png b/ui/org.eclipse.pde.spy.bundle/icons/osgi@2x.png
new file mode 100644
index 0000000..5656bcf
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/icons/osgi@2x.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.bundle/icons/refresh.png b/ui/org.eclipse.pde.spy.bundle/icons/refresh.png
new file mode 100644
index 0000000..bee8fe7
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/icons/refresh.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.bundle/icons/refresh@2x.png b/ui/org.eclipse.pde.spy.bundle/icons/refresh@2x.png
new file mode 100644
index 0000000..89d4d48
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/icons/refresh@2x.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.bundle/icons/start.png b/ui/org.eclipse.pde.spy.bundle/icons/start.png
new file mode 100644
index 0000000..c06ce07
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/icons/start.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.bundle/icons/start@2x.png b/ui/org.eclipse.pde.spy.bundle/icons/start@2x.png
new file mode 100644
index 0000000..d1a4b91
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/icons/start@2x.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.bundle/icons/state_active.png b/ui/org.eclipse.pde.spy.bundle/icons/state_active.png
new file mode 100644
index 0000000..a9be929
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/icons/state_active.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.bundle/icons/state_active@2x.png b/ui/org.eclipse.pde.spy.bundle/icons/state_active@2x.png
new file mode 100644
index 0000000..fefe4e7
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/icons/state_active@2x.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.bundle/icons/state_installed.png b/ui/org.eclipse.pde.spy.bundle/icons/state_installed.png
new file mode 100644
index 0000000..cc3a72d
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/icons/state_installed.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.bundle/icons/state_installed@2x.png b/ui/org.eclipse.pde.spy.bundle/icons/state_installed@2x.png
new file mode 100644
index 0000000..65b2922
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/icons/state_installed@2x.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.bundle/icons/state_resolved.png b/ui/org.eclipse.pde.spy.bundle/icons/state_resolved.png
new file mode 100644
index 0000000..2edf65f
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/icons/state_resolved.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.bundle/icons/state_resolved@2x.png b/ui/org.eclipse.pde.spy.bundle/icons/state_resolved@2x.png
new file mode 100644
index 0000000..5411cac
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/icons/state_resolved@2x.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.bundle/icons/state_starting.png b/ui/org.eclipse.pde.spy.bundle/icons/state_starting.png
new file mode 100644
index 0000000..f2e6a03
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/icons/state_starting.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.bundle/icons/state_starting@2x.png b/ui/org.eclipse.pde.spy.bundle/icons/state_starting@2x.png
new file mode 100644
index 0000000..8e26ea4
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/icons/state_starting@2x.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.bundle/icons/state_stopping.png b/ui/org.eclipse.pde.spy.bundle/icons/state_stopping.png
new file mode 100644
index 0000000..9fcc646
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/icons/state_stopping.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.bundle/icons/state_stopping@2x.png b/ui/org.eclipse.pde.spy.bundle/icons/state_stopping@2x.png
new file mode 100644
index 0000000..d46b3a0
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/icons/state_stopping@2x.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.bundle/icons/state_uninstalled.png b/ui/org.eclipse.pde.spy.bundle/icons/state_uninstalled.png
new file mode 100644
index 0000000..fb407df
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/icons/state_uninstalled.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.bundle/icons/state_uninstalled@2x.png b/ui/org.eclipse.pde.spy.bundle/icons/state_uninstalled@2x.png
new file mode 100644
index 0000000..f0dc98a
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/icons/state_uninstalled@2x.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.bundle/icons/stop.png b/ui/org.eclipse.pde.spy.bundle/icons/stop.png
new file mode 100644
index 0000000..fe4c275
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/icons/stop.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.bundle/icons/stop@2x.png b/ui/org.eclipse.pde.spy.bundle/icons/stop@2x.png
new file mode 100644
index 0000000..0787f19
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/icons/stop@2x.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.bundle/plugin.properties b/ui/org.eclipse.pde.spy.bundle/plugin.properties
new file mode 100644
index 0000000..a230739
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/plugin.properties
@@ -0,0 +1,18 @@
+###############################################################################
+# Copyright (c) 2021, vogella GmbH Corporation and others.
+#
+# This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License 2.0
+# which accompanies this distribution, and is available at
+# https://www.eclipse.org/legal/epl-2.0/
+#
+# SPDX-License-Identifier: EPL-2.0
+#
+# Contributors:
+# Lars Vogel - initial API and implementation
+###############################################################################
+#
+#
+name = Bundle Spy
+provider-name = Eclipse.org
+description = Bundle Spy to display all bundles and their states
\ No newline at end of file
diff --git a/ui/org.eclipse.pde.spy.bundle/plugin.xml b/ui/org.eclipse.pde.spy.bundle/plugin.xml
new file mode 100644
index 0000000..6c1460d
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/plugin.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plugin>
+ <extension point="org.eclipse.pde.spy.core.spyPart">
+ <spyPart
+ description="%description"
+ icon="$nl$/icons/osgi.png"
+ name="%name"
+ part="org.eclipse.pde.spy.bundle.BundleSpyPart"
+ shortcut="M2+M3+F12">
+ </spyPart>
+ </extension>
+</plugin>
diff --git a/ui/org.eclipse.pde.spy.bundle/pom.xml b/ui/org.eclipse.pde.spy.bundle/pom.xml
new file mode 100644
index 0000000..ed10982
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/pom.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2012, 2019 Eclipse Foundation and others.
+ All rights reserved. This program and the accompanying materials
+ are made available under the terms of the Eclipse Distribution License v1.0
+ which accompanies this distribution, and is available at
+ http://www.eclipse.org/org/documents/edl-v10.php
+
+ Contributors:
+ Igor Fedorenko - initial implementation
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>eclipse.pde.ui</artifactId>
+ <groupId>eclipse.pde.ui</groupId>
+ <version>4.23.0-SNAPSHOT</version>
+ <relativePath>../../</relativePath>
+ </parent>
+
+ <properties>
+ <skipAPIAnalysis>true</skipAPIAnalysis>
+ </properties>
+
+
+ <groupId>org.pde.ui</groupId>
+ <artifactId>org.eclipse.pde.spy.bundle</artifactId>
+ <version>0.12.100-SNAPSHOT</version>
+ <packaging>eclipse-plugin</packaging>
+</project>
diff --git a/ui/org.eclipse.pde.spy.bundle/src/org/eclipse/pde/spy/bundle/BundleSpyPart.java b/ui/org.eclipse.pde.spy.bundle/src/org/eclipse/pde/spy/bundle/BundleSpyPart.java
new file mode 100644
index 0000000..cf808b9
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/src/org/eclipse/pde/spy/bundle/BundleSpyPart.java
@@ -0,0 +1,317 @@
+/*******************************************************************************
+ * Copyright (c) 2015 OPCoach and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Olivier Prouvost <olivier.prouvost@opcoach.com> - initial API and implementation (bug #451116)
+ * Simon Scholz <simon.scholz@vogella.com> - Bug 466785
+ *******************************************************************************/
+package org.eclipse.pde.spy.bundle;
+
+import java.util.Iterator;
+
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.di.Focus;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.pde.spy.bundle.internal.BundleDataFilter;
+import org.eclipse.pde.spy.bundle.internal.BundleDataProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.Text;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.FrameworkUtil;
+
+/**
+ * This class is the main part of the bundle spy. It displays a tableviewer with
+ * all bundles
+ */
+public class BundleSpyPart {
+
+ private static final String ICON_REFRESH = "icons/refresh.png";
+ public static final String ICON_STATE_ACTIVE = "icons/state_active.png";
+ public static final String ICON_STATE_STARTING = "icons/state_starting.png";
+ public static final String ICON_STATE_STOPPING = "icons/state_stopping.png";
+ public static final String ICON_STATE_RESOLVED = "icons/state_resolved.png";
+ public static final String ICON_STATE_INSTALLED = "icons/state_installed.png";
+ public static final String ICON_STATE_UNINSTALLED = "icons/state_uninstalled.png";
+ public static final String ICON_START = "icons/start.png";
+ public static final String ICON_STOP = "icons/stop.png";
+
+ private TableViewer bundlesTableViewer;
+
+ private Text filterText;
+
+ private Button showOnlyFilteredElements;
+
+ private BundleDataFilter bundleFilter;
+
+ @Inject
+ private IEclipseContext ctx;
+
+ /** Store the values to set it when it is reopened */
+ private static String lastFilterText = null;
+ private static boolean lastShowFiltered = false;
+
+ /**
+ * Create contents of the view part.
+ */
+ @PostConstruct
+ public void createControls(Composite parent) {
+ ImageRegistry imgReg = initializeImageRegistry();
+
+ // Set a filter in context (-> null at the begining).
+ bundleFilter = new BundleDataFilter();
+ ctx.set(BundleDataFilter.class, bundleFilter);
+
+ parent.setLayout(new GridLayout(1, false));
+
+ final Composite comp = new Composite(parent, SWT.NONE);
+ comp.setLayout(new GridLayout(5, false));
+
+ Button refreshButton = new Button(comp, SWT.FLAT);
+ refreshButton.setImage(imgReg.get(ICON_REFRESH));
+ refreshButton.setToolTipText("Refresh the contexts");
+ refreshButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ bundlesTableViewer.refresh(true);
+ }
+ });
+
+ filterText = new Text(comp, SWT.SEARCH | SWT.ICON_SEARCH | SWT.ICON_CANCEL);
+ GridDataFactory.fillDefaults().hint(200, SWT.DEFAULT).applyTo(filterText);
+ filterText.setMessage("Search data");
+ filterText.setToolTipText(
+ "Highlight the bundles where the contained objects contains this string.\n" + "Case is ignored.");
+ if (lastFilterText != null)
+ filterText.setText(lastFilterText);
+ bundleFilter.setPattern(lastFilterText);
+ filterText.addKeyListener(new KeyAdapter() {
+ @Override
+ public void keyReleased(KeyEvent e) {
+ String textToSearch = filterText.getText();
+ lastFilterText = textToSearch;
+ boolean enableButton = textToSearch.length() > 0;
+ // Enable/disable button for filtering
+ showOnlyFilteredElements.setEnabled(enableButton);
+
+ // Then update filters and viewers
+ bundleFilter.setPattern(textToSearch);
+ setFilter();
+ bundlesTableViewer.refresh(true);
+ }
+
+ });
+
+ showOnlyFilteredElements = new Button(comp, SWT.CHECK);
+ showOnlyFilteredElements.setText("Show Only Filtered");
+ showOnlyFilteredElements.setToolTipText("Show only the filtered items in the bundle table ");
+ showOnlyFilteredElements.setEnabled((lastFilterText != null) && (lastFilterText.length() > 0));
+ showOnlyFilteredElements.setSelection(lastShowFiltered);
+ showOnlyFilteredElements.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ lastShowFiltered = showOnlyFilteredElements.getSelection();
+ setFilter();
+ }
+ });
+
+ startButton = new Button(comp, SWT.FLAT);
+ startButton.setImage(imgReg.get(ICON_START));
+ startButton.setToolTipText("Start the selected bundles not yet started");
+ startButton.setEnabled(false);
+ startButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ IStructuredSelection sel = (IStructuredSelection) bundlesTableViewer.getSelection();
+ Iterator<?> iter = sel.iterator();
+ while (iter.hasNext()) {
+ Bundle b = (Bundle) iter.next();
+ try {
+ b.start();
+ } catch (BundleException e1) {
+ e1.printStackTrace();
+ }
+ }
+ bundlesTableViewer.refresh();
+ updateButtonStatuses(sel);
+ }
+ });
+
+ stopButton = new Button(comp, SWT.FLAT);
+ stopButton.setImage(imgReg.get(ICON_STOP));
+ stopButton.setToolTipText("Stop the selected bundles not yet stopped");
+ stopButton.setEnabled(false);
+ stopButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (MessageDialog.openConfirm(((Control) e.getSource()).getShell(), "Confirm Bundle Stop",
+ "Stopping a bundle may cause problems in your current application.\nUse this button only for your bundles under testing\n\nDo you confirm you want to stop the selected started bundle(s) ? ")) {
+ IStructuredSelection sel = (IStructuredSelection) bundlesTableViewer.getSelection();
+ Iterator<?> iter = sel.iterator();
+ while (iter.hasNext()) {
+ Bundle b = (Bundle) iter.next();
+ try {
+ b.stop();
+ } catch (BundleException e1) {
+ e1.printStackTrace();
+ }
+ }
+ bundlesTableViewer.refresh();
+ updateButtonStatuses(sel);
+ }
+ }
+ });
+
+ // Create the customer table with 2 columns: firstname and name
+ bundlesTableViewer = new TableViewer(parent);
+ final Table cTable = bundlesTableViewer.getTable();
+ cTable.setHeaderVisible(true);
+ cTable.setLinesVisible(true);
+ GridData gd_cTable = new GridData(SWT.FILL, SWT.FILL, true, true);
+ // gd_cTable.verticalAlignment = SWT.TOP;
+ cTable.setLayoutData(gd_cTable);
+
+ // Create the first column for bundle name
+ addColumn(bundlesTableViewer, 35, "State", BundleDataProvider.COL_STATE);
+ addColumn(bundlesTableViewer, 200, "Bundle Name", BundleDataProvider.COL_NAME);
+ addColumn(bundlesTableViewer, 200, "Version", BundleDataProvider.COL_VERSION);
+
+ // Set input data and content provider (default ArrayContentProvider)
+ bundlesTableViewer.setContentProvider(ArrayContentProvider.getInstance());
+
+ // Get the list of bundles in platform using bundle context...
+ BundleContext bc = FrameworkUtil.getBundle(BundleSpyPart.class).getBundleContext();
+ bundlesTableViewer.setInput(bc.getBundles());
+
+ bundlesTableViewer.addSelectionChangedListener(event -> updateButtonStatuses((IStructuredSelection) event.getSelection()));
+
+ ColumnViewerToolTipSupport.enableFor(bundlesTableViewer);
+
+ }
+
+ /** Update the stop and start buttons depending on current selection */
+ protected void updateButtonStatuses(IStructuredSelection selection) {
+ // startButton is enabled if at least one bundle is not active
+ // stopButton is enabled if at least one bundle is active
+ boolean oneBundleIsActive = false;
+ boolean oneBundleIsNotActive = false;
+
+ Iterator<?> iter = selection.iterator();
+ while (iter.hasNext()) {
+ Bundle b = (Bundle) iter.next();
+ oneBundleIsActive = oneBundleIsActive || (b.getState() == Bundle.ACTIVE);
+ oneBundleIsNotActive = oneBundleIsNotActive || (b.getState() != Bundle.ACTIVE);
+ }
+ startButton.setEnabled(oneBundleIsNotActive);
+ stopButton.setEnabled(oneBundleIsActive);
+
+ }
+
+ private void addColumn(final TableViewer parentTable, int width, String title, final int column) {
+ TableViewerColumn col = new TableViewerColumn(bundlesTableViewer, SWT.NONE);
+ col.getColumn().setWidth(width);
+ col.getColumn().setText(title);
+
+ final BundleDataProvider bdp = ContextInjectionFactory.make(BundleDataProvider.class, ctx);
+ bdp.setColumn(column);
+ col.setLabelProvider(bdp);
+
+ col.getColumn().addSelectionListener(new SelectionAdapter() {
+
+ private int turnAround = 1;
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ turnAround *= -1;
+ parentTable.setComparator(new ViewerComparator() {
+ @Override
+ public int compare(Viewer viewer, Object e1, Object e2) {
+ if (BundleDataProvider.COL_STATE == column) {
+ Bundle b1 = (Bundle) e1;
+ Bundle b2 = (Bundle) e2;
+ return turnAround(Integer.compare(b1.getState(), b2.getState()));
+ }
+
+ return turnAround(bdp.getText(e1).compareTo(bdp.getText(e2)));
+ }
+ });
+ }
+
+ private int turnAround(int compare) {
+ return compare * turnAround;
+ }
+ });
+
+ }
+
+ private static final ViewerFilter[] NO_FILTER = new ViewerFilter[0];
+ private Button stopButton;
+ private Button startButton;
+
+ /** Set the filter on table */
+ public void setFilter() {
+
+ if (showOnlyFilteredElements.isEnabled() && showOnlyFilteredElements.getSelection()) {
+ bundlesTableViewer.setFilters(bundleFilter);
+ } else {
+ bundlesTableViewer.setFilters(NO_FILTER);
+ }
+ }
+
+ @Focus
+ public void setFocus() {
+ bundlesTableViewer.getControl().setFocus();
+ }
+
+ private ImageRegistry initializeImageRegistry() {
+ Bundle b = FrameworkUtil.getBundle(this.getClass());
+ ImageRegistry imgReg = new ImageRegistry();
+ imgReg.put(ICON_REFRESH, ImageDescriptor.createFromURL(b.getEntry(ICON_REFRESH)));
+ imgReg.put(ICON_STATE_ACTIVE, ImageDescriptor.createFromURL(b.getEntry(ICON_STATE_ACTIVE)));
+ imgReg.put(ICON_STATE_RESOLVED, ImageDescriptor.createFromURL(b.getEntry(ICON_STATE_RESOLVED)));
+ imgReg.put(ICON_STATE_STARTING, ImageDescriptor.createFromURL(b.getEntry(ICON_STATE_STARTING)));
+ imgReg.put(ICON_STATE_STOPPING, ImageDescriptor.createFromURL(b.getEntry(ICON_STATE_STOPPING)));
+ imgReg.put(ICON_STATE_INSTALLED, ImageDescriptor.createFromURL(b.getEntry(ICON_STATE_INSTALLED)));
+ imgReg.put(ICON_STATE_UNINSTALLED, ImageDescriptor.createFromURL(b.getEntry(ICON_STATE_UNINSTALLED)));
+ imgReg.put(ICON_START, ImageDescriptor.createFromURL(b.getEntry(ICON_START)));
+ imgReg.put(ICON_STOP, ImageDescriptor.createFromURL(b.getEntry(ICON_STOP)));
+
+ ctx.set(ImageRegistry.class, imgReg);
+
+ return imgReg;
+ }
+
+}
diff --git a/ui/org.eclipse.pde.spy.bundle/src/org/eclipse/pde/spy/bundle/internal/BundleDataFilter.java b/ui/org.eclipse.pde.spy.bundle/src/org/eclipse/pde/spy/bundle/internal/BundleDataFilter.java
new file mode 100644
index 0000000..28ece26
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/src/org/eclipse/pde/spy/bundle/internal/BundleDataFilter.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2015 OPCoach.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Olivier Prouvost <olivier.prouvost@opcoach.com> - initial API and implementation (bug #451116)
+ *******************************************************************************/
+package org.eclipse.pde.spy.bundle.internal;
+
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.osgi.framework.Bundle;
+
+public class BundleDataFilter extends ViewerFilter {
+ private String pattern;
+
+ // Implements the filter for the data table content
+ @Override
+ public boolean select(Viewer viewer, Object parentElement, Object element) {
+ Bundle b = (Bundle) element;
+
+ // Must only select objects matching the pattern -> get all text for one
+ // element and
+ // check if values are in pattern.
+ TableViewer tv = (TableViewer) viewer;
+ String bstring = getBundleStrings(b, tv.getTable().getColumnCount());
+
+ return matchText(bstring);
+
+ }
+
+ public String getBundleStrings(Bundle b, int nbColumn) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < nbColumn; i++)
+ sb.append(BundleDataProvider.getText(b, i)).append(" ");
+
+ return sb.toString();
+ }
+
+ /** Set the pattern and use it as lowercase */
+ public void setPattern(String newPattern) {
+ if ((newPattern == null) || (newPattern.length() == 0))
+ pattern = null;
+ else
+ pattern = newPattern.toLowerCase();
+ }
+
+ public boolean matchText(String text) {
+ return ((text == null) || (pattern == null)) ? false : text.toLowerCase().contains(pattern);
+ }
+
+}
diff --git a/ui/org.eclipse.pde.spy.bundle/src/org/eclipse/pde/spy/bundle/internal/BundleDataProvider.java b/ui/org.eclipse.pde.spy.bundle/src/org/eclipse/pde/spy/bundle/internal/BundleDataProvider.java
new file mode 100644
index 0000000..0c901a8
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.bundle/src/org/eclipse/pde/spy/bundle/internal/BundleDataProvider.java
@@ -0,0 +1,153 @@
+/*******************************************************************************
+ * Copyright (c) 2015 OPCoach.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Olivier Prouvost <olivier.prouvost@opcoach.com> - initial API and implementation (bug #451116)
+ *******************************************************************************/
+package org.eclipse.pde.spy.bundle.internal;
+
+import javax.inject.Inject;
+
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.pde.spy.bundle.BundleSpyPart;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+import org.osgi.framework.Bundle;
+
+/**
+ * The column Label and content Provider used to display information in context
+ * data TreeViewer. Two instances for label provider are created : one for key,
+ * one for values
+ *
+ * @see ContextDataPart
+ */
+public class BundleDataProvider extends ColumnLabelProvider {
+
+ public static final int COL_NAME = 0;
+ public static final int COL_VERSION = 1;
+ public static final int COL_STATE = 2;
+
+ private static final Color COLOR_IF_FOUND = Display.getCurrent().getSystemColor(SWT.COLOR_BLUE);
+
+ @Inject
+ private ImageRegistry imgReg;
+
+ // Only one bundle filter, injected for all columns.
+ @Inject
+ private BundleDataFilter bundleFilter;
+
+ // The column number this provider manages.
+ private int column;
+
+ @Inject
+ public BundleDataProvider() {
+ super();
+ }
+
+ @Override
+ public String getText(Object element) {
+ // Received element is a bundle...Text depends on column.
+ Bundle b = (Bundle) element;
+ String result = getText(b, column);
+ return (result == null) ? super.getText(element) : result;
+
+ }
+
+ public static String getText(Bundle b, int col) {
+ switch (col) {
+ case COL_NAME:
+ return b.getSymbolicName();
+ case COL_VERSION:
+ return b.getVersion().toString();
+ case COL_STATE:
+ return ""; // No text for state (see tooltip)
+
+ }
+ return null;
+ }
+
+ @Override
+ public Color getForeground(Object element) {
+ // Return magenta color if the value could not be yet computed (for
+ // context functions)
+ String s = getText(element);
+
+ // Return blue color if the string matches the search
+ return ((bundleFilter != null) && (bundleFilter.matchText(s))) ? COLOR_IF_FOUND : null;
+ }
+
+ @Override
+ public Image getImage(Object element) {
+ Bundle b = (Bundle) element;
+ if (column == COL_STATE) {
+
+ switch (b.getState()) {
+ case Bundle.ACTIVE:
+ return imgReg.get(BundleSpyPart.ICON_STATE_ACTIVE);
+ case Bundle.INSTALLED:
+ return imgReg.get(BundleSpyPart.ICON_STATE_INSTALLED);
+ case Bundle.RESOLVED:
+ return imgReg.get(BundleSpyPart.ICON_STATE_RESOLVED);
+ case Bundle.STARTING:
+ return imgReg.get(BundleSpyPart.ICON_STATE_STARTING);
+ case Bundle.STOPPING:
+ return imgReg.get(BundleSpyPart.ICON_STATE_STOPPING);
+ case Bundle.UNINSTALLED:
+ return imgReg.get(BundleSpyPart.ICON_STATE_UNINSTALLED);
+
+ }
+ }
+ return null;
+
+ }
+
+ @Override
+ public String getToolTipText(Object element) {
+ Bundle b = (Bundle) element;
+
+ switch (b.getState()) {
+ case Bundle.ACTIVE:
+ return "This bundle is Active";
+ case Bundle.INSTALLED:
+ return "This bundle is Installed";
+ case Bundle.RESOLVED:
+ return "This bundle is Resolved";
+ case Bundle.STARTING:
+ return "This bundle is Starting";
+ case Bundle.STOPPING:
+ return "This bundle is Stopping";
+ case Bundle.UNINSTALLED:
+ return "This bundle is Uninstalled";
+
+ }
+
+ return "This bundle is in state : " + b.getState();
+
+ }
+
+ @Override
+ public Image getToolTipImage(Object object) {
+ return getImage(object);
+ }
+
+ @Override
+ public int getToolTipStyle(Object object) {
+ return SWT.SHADOW_OUT;
+ }
+
+ public void setColumn(int col) {
+ column = col;
+
+ }
+
+}