=UTF-8
diff --git a/ui/org.eclipse.pde.spy.adapter/.settings/org.eclipse.jdt.core.prefs b/ui/org.eclipse.pde.spy.adapter/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000000..306cb687c4f
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.adapter/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,15 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=21
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=21
+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=21
+encoding/org.eclipse.pde.spy.adapter=UTF-8
\ No newline at end of file
diff --git a/ui/org.eclipse.pde.spy.adapter/META-INF/MANIFEST.MF b/ui/org.eclipse.pde.spy.adapter/META-INF/MANIFEST.MF
new file mode 100644
index 00000000000..9386a2517af
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.adapter/META-INF/MANIFEST.MF
@@ -0,0 +1,25 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %name
+Bundle-SymbolicName: org.eclipse.pde.spy.adapter;singleton:=true
+Bundle-Version: 0.1.0.qualifier
+Require-Bundle: org.eclipse.core.runtime,
+ org.eclipse.swt,
+ org.eclipse.e4.core.contexts,
+ org.eclipse.e4.core.di,
+ org.eclipse.e4.core.services,
+ org.eclipse.e4.ui.di,
+ org.eclipse.e4.ui.workbench,
+ org.eclipse.emf.ecore,
+ org.eclipse.jface,
+ org.eclipse.equinox.common,
+ org.eclipse.e4.ui.services
+Bundle-RequiredExecutionEnvironment: JavaSE-21
+Automatic-Module-Name: org.eclipse.pde.spy.adapter
+Bundle-ActivationPolicy: lazy
+Bundle-Vendor: %provider-name
+Import-Package: jakarta.annotation;version="[2.1.0,3.0.0)",
+ jakarta.inject;version="[2.0.0,3.0.0)"
+Bundle-Localization: plugin
+Export-Package: org.eclipse.pde.spy.adapter
+Require-Capability: eclipse.swt;filter:="(image.format=svg)"
diff --git a/ui/org.eclipse.pde.spy.adapter/about.html b/ui/org.eclipse.pde.spy.adapter/about.html
new file mode 100644
index 00000000000..3c90a2af4be
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.adapter/about.html
@@ -0,0 +1,31 @@
+
+
+
+
+About
+
+
+About This Content
+
+January 30, 2014
+License
+
+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 http://www.eclipse.org/legal/epl-v20.html.
+For purposes of the EPL, "Program" will mean the Content.
+
+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 http://www.eclipse.org.
+
+
+
+
+
+
diff --git a/ui/org.eclipse.pde.spy.adapter/build.properties b/ui/org.eclipse.pde.spy.adapter/build.properties
new file mode 100644
index 00000000000..639937d9fc7
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.adapter/build.properties
@@ -0,0 +1,7 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ icons/,\
+ plugin.xml,\
+ plugin.properties
diff --git a/ui/org.eclipse.pde.spy.adapter/icons/ext_point_obj.png b/ui/org.eclipse.pde.spy.adapter/icons/ext_point_obj.png
new file mode 100644
index 00000000000..60f8dce5bba
Binary files /dev/null and b/ui/org.eclipse.pde.spy.adapter/icons/ext_point_obj.png differ
diff --git a/ui/org.eclipse.pde.spy.adapter/icons/ext_point_obj@2x.png b/ui/org.eclipse.pde.spy.adapter/icons/ext_point_obj@2x.png
new file mode 100644
index 00000000000..b8cd13b201e
Binary files /dev/null and b/ui/org.eclipse.pde.spy.adapter/icons/ext_point_obj@2x.png differ
diff --git a/ui/org.eclipse.pde.spy.adapter/icons/from_type.png b/ui/org.eclipse.pde.spy.adapter/icons/from_type.png
new file mode 100644
index 00000000000..bc915da4420
Binary files /dev/null and b/ui/org.eclipse.pde.spy.adapter/icons/from_type.png differ
diff --git a/ui/org.eclipse.pde.spy.adapter/icons/innerinterface_public_obj.png b/ui/org.eclipse.pde.spy.adapter/icons/innerinterface_public_obj.png
new file mode 100644
index 00000000000..e091ec43dbd
Binary files /dev/null and b/ui/org.eclipse.pde.spy.adapter/icons/innerinterface_public_obj.png differ
diff --git a/ui/org.eclipse.pde.spy.adapter/icons/osgi.png b/ui/org.eclipse.pde.spy.adapter/icons/osgi.png
new file mode 100644
index 00000000000..15cf6e3af70
Binary files /dev/null and b/ui/org.eclipse.pde.spy.adapter/icons/osgi.png differ
diff --git a/ui/org.eclipse.pde.spy.adapter/icons/to_type.png b/ui/org.eclipse.pde.spy.adapter/icons/to_type.png
new file mode 100644
index 00000000000..ab848c24925
Binary files /dev/null and b/ui/org.eclipse.pde.spy.adapter/icons/to_type.png differ
diff --git a/ui/org.eclipse.pde.spy.adapter/notice.html b/ui/org.eclipse.pde.spy.adapter/notice.html
new file mode 100644
index 00000000000..f19c483b9c8
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.adapter/notice.html
@@ -0,0 +1,108 @@
+
+
+
+
+
+Eclipse Foundation Software User Agreement
+
+
+
+Eclipse Foundation Software User Agreement
+February 1, 2011
+
+Usage Of Content
+
+THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS
+ (COLLECTIVELY "CONTENT"). USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND
+ CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE
+ OF THE CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR
+ NOTICES INDICATED OR REFERENCED BELOW. IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND
+ CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.
+
+Applicable Licenses
+
+Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the Eclipse Public License Version 1.0
+ ("EPL"). A copy of the EPL is provided with this Content and is also available at http://www.eclipse.org/legal/epl-v10.html.
+ For purposes of the EPL, "Program" will mean the Content.
+
+Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code
+ repository ("Repository") in software modules ("Modules") and made available as downloadable archives ("Downloads").
+
+
+ - Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content. Typical modules may include plug-ins ("Plug-ins"), plug-in fragments ("Fragments"), and features ("Features").
+ - Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java™ ARchive) in a directory named "plugins".
+ - A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material. Each Feature may be packaged as a sub-directory in a directory named "features". Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of the Plug-ins
+ and/or Fragments associated with that Feature.
+ - Features may also include other Features ("Included Features"). Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of Included Features.
+
+
+The terms and conditions governing Plug-ins and Fragments should be contained in files named "about.html" ("Abouts"). The terms and conditions governing Features and
+Included Features should be contained in files named "license.html" ("Feature Licenses"). Abouts and Feature Licenses may be located in any directory of a Download or Module
+including, but not limited to the following locations:
+
+
+ - The top-level (root) directory
+ - Plug-in and Fragment directories
+ - Inside Plug-ins and Fragments packaged as JARs
+ - Sub-directories of the directory named "src" of certain Plug-ins
+ - Feature directories
+
+
+Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license ("Feature Update License") during the
+installation process. If the Feature contains Included Features, the Feature Update License should either provide you with the terms and conditions governing the Included Features or
+inform you where you can locate them. Feature Update Licenses may be found in the "license" property of files named "feature.properties" found within a Feature.
+Such Abouts, Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in
+that directory.
+
+THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. SOME OF THESE
+OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):
+
+
+
+IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License is provided, please
+contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.
+
+
+Use of Provisioning Technology
+
+The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse
+ Update Manager ("Provisioning Technology") for the purpose of allowing users to install software, documentation, information and/or
+ other materials (collectively "Installable Software"). This capability is provided with the intent of allowing such users to
+ install, extend and update Eclipse-based products. Information about packaging Installable Software is available at http://eclipse.org/equinox/p2/repository_packaging.html
+ ("Specification").
+
+You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the
+ applicable license agreements relating to the Installable Software to be presented to, and accepted by, the users of the Provisioning Technology
+ in accordance with the Specification. By using Provisioning Technology in such a manner and making it available in accordance with the
+ Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:
+
+
+ - A series of actions may occur ("Provisioning Process") in which a user may execute the Provisioning Technology
+ on a machine ("Target Machine") with the intent of installing, extending or updating the functionality of an Eclipse-based
+ product.
+ - During the Provisioning Process, the Provisioning Technology may cause third party Installable Software or a portion thereof to be
+ accessed and copied to the Target Machine.
+ - Pursuant to the Specification, you will provide to the user the terms and conditions that govern the use of the Installable
+ Software ("Installable Software Agreement") and such Installable Software Agreement shall be accessed from the Target
+ Machine in accordance with the Specification. Such Installable Software Agreement must inform the user of the terms and conditions that govern
+ the Installable Software and must solicit acceptance by the end user in the manner prescribed in such Installable Software Agreement. Upon such
+ indication of agreement by the user, the provisioning Technology will complete installation of the Installable Software.
+
+
+Cryptography
+
+Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to
+ another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import,
+ possession, or use, and re-export of encryption software, to see if this is permitted.
+
+Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.
+
+
diff --git a/ui/org.eclipse.pde.spy.adapter/plugin.properties b/ui/org.eclipse.pde.spy.adapter/plugin.properties
new file mode 100644
index 00000000000..959be25e3a6
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.adapter/plugin.properties
@@ -0,0 +1,18 @@
+###############################################################################
+# Copyright (c) Lacherp.
+#
+# 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:
+# Lacherp - initial API and implementation
+###############################################################################
+#
+#
+name = Adapter Spy
+provider-name = Eclipse.org
+description = Adapter spy to display the adapter hierarchy
\ No newline at end of file
diff --git a/ui/org.eclipse.pde.spy.adapter/plugin.xml b/ui/org.eclipse.pde.spy.adapter/plugin.xml
new file mode 100644
index 00000000000..4ace6694510
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.adapter/plugin.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
diff --git a/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/AdapterSpyPart.java b/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/AdapterSpyPart.java
new file mode 100644
index 00000000000..3250205d1f1
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/AdapterSpyPart.java
@@ -0,0 +1,421 @@
+/*******************************************************************************
+ * Copyright (c) Lacherp.
+ *
+ * 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:
+ * Lacherp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.pde.spy.adapter;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.di.annotations.Optional;
+import org.eclipse.e4.ui.di.UISynchronize;
+import org.eclipse.e4.ui.services.IServiceConstants;
+import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.EditingSupport;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.TreeViewerColumn;
+import org.eclipse.pde.spy.adapter.model.AdapterData;
+import org.eclipse.pde.spy.adapter.model.AdapterRepository;
+import org.eclipse.pde.spy.adapter.tools.AdapterHelper;
+import org.eclipse.pde.spy.adapter.viewer.AdapterContentProvider;
+import org.eclipse.pde.spy.adapter.viewer.AdapterDataComparator;
+import org.eclipse.pde.spy.adapter.viewer.AdapterFilter;
+import org.eclipse.pde.spy.adapter.viewer.ColumnViewerToolTipSupportCustom;
+import org.eclipse.pde.spy.adapter.viewer.FilterData;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.dnd.Clipboard;
+import org.eclipse.swt.dnd.TextTransfer;
+import org.eclipse.swt.dnd.Transfer;
+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.Text;
+import org.eclipse.swt.widgets.Tree;
+
+import jakarta.annotation.PostConstruct;
+import jakarta.annotation.PreDestroy;
+import jakarta.inject.Inject;
+import jakarta.inject.Named;
+
+
+/**
+ * Adapter Spy part
+ * @author pascal
+ *
+ */
+public class AdapterSpyPart {
+
+ private TreeViewer adapterTreeViewer;
+
+ private AdapterContentProvider adapterContentProvider;
+
+ private static final String NAMED_UPDATE_TREE_SOURCE_TO_DESTINATION = "updateTreeSourceToDestination";
+ private static final String NAMED_UPDATE_TREE_DESTINATION_TO_SOURCE = "updateTreeDestinationToSource";
+ private static final String SOURCE_TYPE = "Source Type";
+ private static final String DESTINATION_TYPE = "Destination Type";
+ private static final String DISPLAY_SOURCE_TYPE = "Display " + SOURCE_TYPE;
+ private static final String DISPLAY_DESTINATION_TYPE = "Display " + DESTINATION_TYPE;
+ private static final String TOOLTIP_SOURCE_TYPE = "Display the source type first, and list\nall destination types derived from that source as child elements.";
+ private static final String TOOLTIP_DESTINATION_TYPE = "Display the destination type first, and list\nall source types that can adapt to it as child elements.";
+
+ @Inject
+ UISynchronize uisync;
+
+ @Inject
+ IEclipseContext context;
+
+
+ @Inject
+ AdapterRepository adapterRepo;
+
+ @Inject
+ ESelectionService selectService;
+
+ AdapterFilter adapterFilter;
+
+ boolean sourceToDestination = true;
+
+ private TreeViewerColumn sourceOrDestinationTvc;
+
+ private AdapterDataComparator comparator;
+
+ @Inject
+ public AdapterSpyPart(IEclipseContext context) {
+ // wrap eclipse adapter
+ AdapterHelper.wrapperEclipseAdapter();
+ adapterFilter = ContextInjectionFactory.make(AdapterFilter.class, context);
+ context.set(ImageRegistry.class, AdapterHelper.getImageRegistry(this));
+ }
+
+ @PostConstruct
+ public void createControls(Composite parent, IExtensionRegistry extensionRegistry, ImageRegistry imgr) {
+
+ parent.setLayout(new GridLayout(1, false));
+ createToolBarZone(parent, imgr);
+
+ SashForm sashForm = new SashForm(parent, SWT.VERTICAL | SWT.V_SCROLL | SWT.H_SCROLL);
+ sashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ AdapterHelper.getServicesContext().set(AdapterRepository.class, adapterRepo);
+ adapterRepo.clear();
+
+ Collection adapterDatalist = adapterRepo.getAdapters();
+
+ // Adapter TreeViewer
+ adapterTreeViewer = new TreeViewer(sashForm);
+ adapterContentProvider = ContextInjectionFactory.make(AdapterContentProvider.class, context);
+ adapterContentProvider.setColumnIndex(0);
+ adapterTreeViewer.setContentProvider(adapterContentProvider);
+ adapterTreeViewer.setLabelProvider(adapterContentProvider);
+ adapterTreeViewer.setFilters(adapterFilter);
+
+ // add comparator
+ comparator = new AdapterDataComparator(0);
+ adapterTreeViewer.setComparator(comparator);
+
+ // define columns
+ final Tree cTree = adapterTreeViewer.getTree();
+ cTree.setHeaderVisible(true);
+ cTree.setLinesVisible(true);
+ cTree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ sourceOrDestinationTvc = new TreeViewerColumn(adapterTreeViewer, SWT.NONE);
+ sourceOrDestinationTvc.getColumn().setText("Source Type");
+ sourceOrDestinationTvc.getColumn().setWidth(500);
+ sourceOrDestinationTvc.setLabelProvider(adapterContentProvider);
+ cTree.setSortColumn(sourceOrDestinationTvc.getColumn());
+ sourceOrDestinationTvc.getColumn().addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ comparator.setColumn(0);
+ adapterTreeViewer.getTree().setSortDirection(comparator.getDirection());
+ adapterTreeViewer.refresh();
+ }
+ });
+ sourceOrDestinationTvc.setEditingSupport(new EditingSupport(adapterTreeViewer) {
+
+ @Override
+ protected void setValue(Object element, Object value) {
+ }
+
+ @Override
+ protected Object getValue(Object element) {
+ return null;
+ }
+
+ @Override
+ protected CellEditor getCellEditor(Object element) {
+ return null;
+ }
+ @Override
+ protected boolean canEdit(Object element) {
+ if(element instanceof AdapterData)
+ {
+ ((AdapterData)element).setSelectedColumn(0);
+ selectService.setSelection(element);
+ }
+ return false;
+ }
+ });
+
+
+ TreeViewerColumn adapterFactoryClassTvc = new TreeViewerColumn(adapterTreeViewer, SWT.NONE);
+ adapterFactoryClassTvc.getColumn().setText("AdapterFactory");
+ adapterFactoryClassTvc.getColumn().setWidth(700);
+ AdapterContentProvider adapterContentProvider2 = ContextInjectionFactory.make(AdapterContentProvider.class, context);
+ adapterContentProvider2.setColumnIndex(1);
+ adapterFactoryClassTvc.setLabelProvider(adapterContentProvider2);
+ adapterFactoryClassTvc.setEditingSupport(new EditingSupport(adapterTreeViewer) {
+
+ @Override
+ protected void setValue(Object element, Object value) {
+ }
+ @Override
+ protected Object getValue(Object element) {
+ return null;
+ }
+ @Override
+ protected CellEditor getCellEditor(Object element) {
+ return null;
+ }
+
+ @Override
+ protected boolean canEdit(Object element) {
+ if(element instanceof AdapterData)
+ {
+ ((AdapterData)element).setSelectedColumn(1);
+ selectService.setSelection(element);
+ }
+ return false;
+ }
+ });
+
+
+ ColumnViewerToolTipSupportCustom.enableFor(adapterTreeViewer);
+ context.set(NAMED_UPDATE_TREE_SOURCE_TO_DESTINATION, adapterDatalist);
+
+ }
+
+ @Inject
+ @Optional
+ private void updateAdapterTreeViewerSourceToType(
+ @Named(NAMED_UPDATE_TREE_SOURCE_TO_DESTINATION) Collection adapaters) {
+ if (adapaters == null) {
+ return;
+ }
+ refreshAdapterTree(NAMED_UPDATE_TREE_SOURCE_TO_DESTINATION, adapaters);
+ }
+
+ @Inject
+ @Optional
+ private void updateAdapterTreeViewTypeToSource(
+ @Named(NAMED_UPDATE_TREE_DESTINATION_TO_SOURCE) Collection adapaters) {
+ if (adapaters == null) {
+ return;
+ }
+ // reduce source Type
+ Collection reduceresult = reduceType(adapaters);
+ refreshAdapterTree(NAMED_UPDATE_TREE_SOURCE_TO_DESTINATION, reduceresult);
+ }
+
+ @PreDestroy
+ public void dispose() {
+ adapterTreeViewer = null;
+ if (adapterContentProvider != null) {
+ ContextInjectionFactory.uninject(adapterContentProvider, context);
+ }
+ if (adapterFilter != null) {
+ ContextInjectionFactory.uninject(adapterFilter, context);
+ }
+ AdapterHelper.restoreOriginalEclipseAdapter();
+ context.set(AdapterFilter.UPDATE_CTX_FILTER, null);
+ adapterRepo.clear();
+
+ }
+
+ @Inject
+ @Optional
+ public void handleSelection(@Named(IServiceConstants.ACTIVE_SELECTION) AdapterData adapterDataSelected) {
+ if (adapterDataSelected == null) {
+ return;
+ }
+ String toCopy ="";
+ if( adapterDataSelected.getSelectedColumn() == 0 && adapterDataSelected.getParent() == null ) {
+ toCopy = ((sourceToDestination)? adapterDataSelected.getSourceType():adapterDataSelected.getDestinationType());
+ }
+ if( adapterDataSelected.getSelectedColumn() == 0 && adapterDataSelected.getParent() != null ) {
+ toCopy = ((sourceToDestination)? adapterDataSelected.getDestinationType():adapterDataSelected.getSourceType());
+ }
+ if( adapterDataSelected.getSelectedColumn() == 1 ) {
+ if (!sourceToDestination)
+ toCopy = adapterDataSelected.getAdapterDataParent().getAdapterClassName();
+ else
+ toCopy = adapterDataSelected.getAdapterClassName();
+ }
+ Clipboard clipboard = new Clipboard(null);
+ try {
+ TextTransfer textTransfer = TextTransfer.getInstance();
+ Transfer[] transfers = new Transfer[] { textTransfer };
+ Object[] data = new Object[] { toCopy };
+ clipboard.setContents(data, transfers);
+ } finally {
+ clipboard.dispose();
+ }
+
+ }
+
+ private void createToolBarZone(Composite parent, ImageRegistry imgr) {
+ final Composite comp = new Composite(parent, SWT.NONE);
+ comp.setLayout(new GridLayout(4, false));
+
+ Text filterText = new Text(comp, SWT.SEARCH | SWT.ICON_SEARCH | SWT.ICON_CANCEL);
+ GridDataFactory.swtDefaults().align(SWT.CENTER, SWT.CENTER).hint(250, SWT.DEFAULT).applyTo(filterText);
+
+ filterText.setMessage("Search data");
+ filterText.setToolTipText("Find any element in tree");
+
+ filterText.addModifyListener(e -> {
+ FilterData fdata = getFilterData();
+ if (filterText.getText().isEmpty()) {
+ fdata.setTxtSearchFilter("");
+ } else {
+ fdata.setTxtSearchFilter(filterText.getText());
+ }
+ context.set(AdapterFilter.UPDATE_CTX_FILTER, fdata);
+ adapterTreeViewer.refresh(true);
+
+ });
+
+ Button showPackageFilter = new Button(comp, SWT.CHECK);
+ showPackageFilter.setText("Show package");
+
+ showPackageFilter.setToolTipText("Show source type with packages name");
+ showPackageFilter.setEnabled(true);
+ showPackageFilter.setSelection(true);
+ showPackageFilter.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ FilterData fdata = getFilterData();
+ fdata.setShowPackage(!fdata.getShowPackage());
+ context.set(AdapterFilter.UPDATE_CTX_FILTER, fdata);
+ adapterTreeViewer.refresh(true);
+ }
+ });
+
+ // --- Vertical radio buttons to choose display direction ---
+ Composite radioGroup = new Composite(comp, SWT.NONE);
+ radioGroup.setLayout(new GridLayout(1, false));
+
+ Button rbSource = new Button(radioGroup, SWT.RADIO);
+ rbSource.setText(DISPLAY_SOURCE_TYPE);
+ rbSource.setToolTipText(TOOLTIP_SOURCE_TYPE);
+
+ Button rbDestination = new Button(radioGroup, SWT.RADIO);
+ rbDestination.setText(DISPLAY_DESTINATION_TYPE);
+ rbDestination.setToolTipText(TOOLTIP_DESTINATION_TYPE);
+
+ rbSource.setSelection(sourceToDestination);
+ rbDestination.setSelection(!sourceToDestination);
+
+ // Factorized refresh logic
+ Runnable refreshView = () -> {
+ FilterData fdata = getFilterData();
+ fdata.setSourceToDestination(sourceToDestination);
+ context.set(AdapterFilter.UPDATE_CTX_FILTER, fdata);
+
+ if (sourceToDestination) {
+ sourceOrDestinationTvc.getColumn().setText(SOURCE_TYPE);
+ context.set(NAMED_UPDATE_TREE_SOURCE_TO_DESTINATION, adapterRepo.getAdapters());
+ } else {
+ sourceOrDestinationTvc.getColumn().setText(DESTINATION_TYPE);
+ context.set(NAMED_UPDATE_TREE_DESTINATION_TO_SOURCE, adapterRepo.revertSourceToType());
+ }
+ adapterTreeViewer.refresh(true);
+ };
+
+ // Listeners
+ rbSource.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (rbSource.getSelection()) {
+ sourceToDestination = true;
+ refreshView.run();
+ }
+ }
+ });
+
+ rbDestination.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (rbDestination.getSelection()) {
+ sourceToDestination = false;
+ refreshView.run();
+ }
+ }
+ });
+
+ uisync.asyncExec(() -> comp.pack());
+
+ }
+
+ private FilterData getFilterData() {
+ if (context.get(AdapterFilter.UPDATE_CTX_FILTER) == null) {
+ return new FilterData();
+ }
+ return new FilterData((FilterData) context.get(AdapterFilter.UPDATE_CTX_FILTER));
+ }
+
+
+
+ private Collection reduceType(Collection originalList) {
+ Collection reduceresult = originalList;
+
+ Map> resultmap = groupBy(originalList);
+ reduceresult.clear();
+ resultmap.forEach((k, v) -> {
+ AdapterData firstElem = v.get(0);
+ reduceresult.add(firstElem);
+ for (int idx = 1; idx < v.size(); idx++) {
+ firstElem.getChildrenList().addAll(v.get(idx).getChildrenList());
+ }
+ });
+
+ return reduceresult;
+ }
+
+ private Map> groupBy(Collection originalList) {
+ return originalList.stream().collect(Collectors.groupingBy(AdapterData::getDestinationType));
+ }
+
+
+ private void refreshAdapterTree(String namedContext, Collection result) {
+ uisync.syncExec(() -> {
+ if (adapterTreeViewer != null) {
+ adapterTreeViewer.setInput(result);
+ context.set(namedContext, null);
+ }
+ });
+ }
+
+}
diff --git a/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/Messages.java b/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/Messages.java
new file mode 100644
index 00000000000..1f26ba8f76d
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/Messages.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) Lacherp.
+ *
+ * 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:
+ * Lacherp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.pde.spy.adapter;
+
+import org.eclipse.pde.spy.adapter.tools.AdapterHelper;
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Messages constant class
+ * @author pascal
+ *
+ */
+public class Messages extends NLS {
+
+ public static String rootSourceTypeTooltip;
+ public static String rootDestinationTypeToolTip;
+ public static String childSourceTypeToolTip;
+ public static String childDestinationTypeToolTip;
+ public static String adapterFactory;
+
+
+ static {
+ // load message values from bundle file
+ reloadMessages();
+ }
+
+ public static void reloadMessages() {
+ NLS.initializeMessages(AdapterHelper.BUNDLE_ID+ ".Messages", Messages.class);
+ }
+}
diff --git a/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/Messages.properties b/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/Messages.properties
new file mode 100644
index 00000000000..d50b4ba52e6
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/Messages.properties
@@ -0,0 +1,25 @@
+################################################################################
+# Copyright (c) Lacherp.
+#
+# 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:
+# Lacherp - initial API and implementation
+################################################################################
+
+# root node tooltip
+rootSourceTypeTooltip = expand this node to know the types in which \"{0}\" can be adapted
+rootDestinationTypeToolTip = expand this node to know the types that can be adapted to \"{0}\"
+
+# child node tooltip
+childSourceTypeToolTip = \"{0}\" can be adapted to \"{1}\"\n by the \"{2}\"
+childDestinationTypeToolTip = \"{0}\" can be obtained from \"{1}\" using \"{2}\" adapter factory
+
+# Adapter Factory column
+adapterFactory = \"{0}\" adapter factory can transform \"{1}\" to \"{2}\"
+
diff --git a/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/hook/EclipseAdapterHook.java b/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/hook/EclipseAdapterHook.java
new file mode 100644
index 00000000000..588cb99ff88
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/hook/EclipseAdapterHook.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) Lacherp.
+ *
+ * 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:
+ * Lacherp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.pde.spy.adapter.hook;
+
+import org.eclipse.e4.core.internal.services.EclipseAdapter;
+
+@SuppressWarnings("restriction")
+public class EclipseAdapterHook extends EclipseAdapter {
+
+
+ @Override
+ public T adapt(Object element, Class adapterType) {
+ return super.adapt(element, adapterType);
+ }
+
+
+}
diff --git a/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/model/AdapterData.java b/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/model/AdapterData.java
new file mode 100644
index 00000000000..ebd079cfdf2
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/model/AdapterData.java
@@ -0,0 +1,464 @@
+/*******************************************************************************
+ * Copyright (c) Lacherp.
+ *
+ * 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:
+ * Lacherp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.pde.spy.adapter.model;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.eclipse.pde.spy.adapter.Messages;
+import org.eclipse.pde.spy.adapter.tools.AdapterHelper;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyleRange;
+import org.eclipse.swt.widgets.Display;
+import org.osgi.framework.Bundle;
+
+/**
+ * Adapter data model Object This class is used to store ConfigurationElement
+ * elements which use an adapter
+ *
+ * @author pascal
+ *
+ */
+public class AdapterData implements Comparable {
+
+ String sourceType;
+ String destinationType;
+ String adapterClassName;
+ boolean isInterface = false;
+ boolean checkInterfaceClass = false;
+ AdapterData parent;
+ List children = new ArrayList<>();
+ AdapterElementType elemType;
+ boolean visibilityFilter = true;
+ Boolean showPackage;
+
+ int selectedColumn;
+
+ /**
+ * @return the selectedColumn
+ */
+ public int getSelectedColumn() {
+ return selectedColumn;
+ }
+
+ /**
+ * @param selectedColumn the selectedColumn to set
+ */
+ public void setSelectedColumn(int selectedColumn) {
+ this.selectedColumn = selectedColumn;
+ }
+
+ /**
+ * Ctor
+ *
+ * @param elemType
+ */
+ public AdapterData(AdapterElementType elemType) {
+ this.elemType = elemType;
+ showPackage = Boolean.TRUE;
+ }
+
+ public AdapterData(AdapterData adapterData) {
+ this.elemType = adapterData.getAdapterElementType();
+ this.showPackage = Boolean.TRUE;
+ this.destinationType = adapterData.getDestinationType();
+ this.adapterClassName = adapterData.getAdapterClassName();
+ this.sourceType = adapterData.getSourceType();
+ }
+
+ /**
+ * propagate visibility to children
+ */
+ public void propagateVisibility() {
+ children.forEach(d -> {
+ d.setVisibilityFilter(isVisibilityFilter());
+ d.propagateVisibility();
+ });
+ }
+
+ public void textSearch(String txtSearch, AtomicBoolean bfound) {
+
+ if (bfound.get()) {
+ return;
+ }
+ String txt = this.toString();
+ bfound.set(txt.contains(txtSearch));
+ // check in adapter class
+ children.forEach(d -> {
+ d.textSearch(txtSearch, bfound);
+ });
+
+ }
+
+ /**
+ * @return the sourceType
+ */
+ public String getSourceType() {
+ return checkNull(sourceType);
+ }
+
+ /**
+ * @param sourceType the sourceType to set
+ */
+ public void setSourceType(String sourceType) {
+ this.sourceType = sourceType;
+ }
+
+ /**
+ * @return the destinationType
+ */
+ public String getDestinationType() {
+ return checkNull(destinationType);
+ }
+
+ /**
+ * @param destinationType the destinationType to set
+ */
+ public void setDestinationType(String destinationType) {
+ this.destinationType = destinationType;
+ }
+
+ /**
+ * @return the adapterClassName
+ */
+ public String getAdapterClassName() {
+ return checkNull(adapterClassName);
+ }
+
+ /**
+ * @param adapterClassName the adapterClassName to set
+ */
+ public void setAdapterClassName(String adapterClassName) {
+ this.adapterClassName = adapterClassName;
+ }
+
+ public boolean hasChildren() {
+ return !children.isEmpty();
+ }
+
+ public List getChildrenList() {
+ return this.children;
+ }
+
+ public Object getChildren(boolean sourceToDestination) {
+ if (!children.isEmpty()) {
+ Collections.sort(children);
+ if( sourceToDestination) {
+ Map> childs = children.stream().collect(Collectors.groupingBy(AdapterData::getDestinationType));
+ children.clear();
+ childs.values().forEach(ls-> children.add(ls.get(0)));
+ return children.toArray();
+ }else {
+ Map> childs = children.stream().collect(Collectors.groupingBy(AdapterData::getSourceType));
+ children.clear();
+ childs.values().forEach(ls-> children.add(ls.get(0)));
+ return children.toArray();
+ }
+ }
+ return new AdapterData[0];
+ }
+
+ public Object getParent() {
+ return this.parent;
+ }
+
+ public AdapterData getAdapterDataParent() {
+ return (AdapterData) this.parent;
+ }
+
+ public void setParent(AdapterData parent) {
+ this.parent = parent;
+ }
+
+ public AdapterElementType getAdapterElementType() {
+ return this.elemType;
+ }
+
+ /**
+ * @return the isInterface
+ */
+ public boolean isInterface() {
+ return isInterface;
+ }
+
+ /**
+ * @param isInterface the isInterface to set
+ */
+ public void setInterface(boolean isInterface) {
+ this.isInterface = isInterface;
+ }
+
+ /**
+ * @return the showPackage
+ */
+ public boolean isShowPackage() {
+ return showPackage;
+ }
+
+ /**
+ * @param showPackage the showPackage to set
+ */
+ public void setShowPackage(boolean showPackage) {
+ this.showPackage = showPackage;
+ }
+
+ public String getText(int columnIndex) {
+ if (columnIndex == 0) {
+ return elemType.equals(AdapterElementType.SOURCE_TYPE) ? displayPackage(getSourceType())
+ : displayPackage(getDestinationType());
+ }
+ if (columnIndex == 1 && getParent() != null) {
+
+ return elemType.equals(AdapterElementType.DESTINATION_TYPE) ? displayPackage(getAdapterClassName())
+ : displayPackage(((AdapterData) getParent()).getAdapterClassName());
+ }
+ return "";
+ }
+
+ public String getImageName() {
+ String className = elemType.equals(AdapterElementType.SOURCE_TYPE) ? getSourceType():getDestinationType();
+ if (elemType.equals(AdapterElementType.DESTINATION_TYPE)) {
+ return AdapterHelper.DESTINATION_TYPE_IMG_KEY;
+ }
+ if(!checkInterfaceClass) {
+ Bundle bundle = AdapterHelper.getBundleForClassName(className);
+ if (bundle != null)
+ setInterface(AdapterHelper.isInterfaceTypeClass(bundle, className));
+ else {
+ // may be it's an interface
+ if (subStringPackage(className).startsWith("I")) {
+ return AdapterHelper.INTERFACE_IMG_KEY;
+ }
+ return AdapterHelper.SOURCE_TYPE_IMG_KEY;
+ }
+ checkInterfaceClass = true;
+ }
+ if (elemType.equals(AdapterElementType.SOURCE_TYPE)) {
+ if( isInterface()) {
+ return AdapterHelper.INTERFACE_IMG_KEY;
+ }
+ return AdapterHelper.SOURCE_TYPE_IMG_KEY;
+ }
+
+ return null;
+
+ }
+
+ /**
+ * @return the visibilityFilter
+ */
+ public boolean isVisibilityFilter() {
+ return visibilityFilter;
+ }
+
+ /**
+ * @param visibilityFilter the visibilityFilter to set
+ */
+ public void setVisibilityFilter(boolean visibilityFilter) {
+ this.visibilityFilter = visibilityFilter;
+ }
+
+ public Stream convertSourceToType() {
+ final ArrayList result = new ArrayList<>();
+ this.getChildrenList().forEach(child -> {
+ AdapterData newAdapterData = new AdapterData(child);
+ AdapterData soon = new AdapterData(this);
+ soon.setParent(child);
+ newAdapterData.getChildrenList().add(soon);
+
+ result.add(newAdapterData);
+ });
+ return result.stream();
+ }
+
+ @Override
+ public String toString() {
+ return getSourceType() + "@" + getDestinationType() + getAdapterClassName();
+ }
+
+
+ @Override
+ public int compareTo(AdapterData o) {
+ return this.getText(0).compareTo(o.getText(0));
+ }
+
+ public String getToolTipText(boolean sourceToDestination, int columnIndex) {
+
+ if (columnIndex == 1) {
+ return getAdapterClassName().isEmpty() ? "" : getAdapterFactorySourceTooltip();
+ }
+ // column 0
+ if (sourceToDestination && getParent() == null) {
+ return getRootSourceTypeTooltip();
+ }
+ if (!sourceToDestination && getParent() == null) {
+ return getRootDesinationTypeTooltip();
+ }
+ if (sourceToDestination && getParent() != null) {
+ return getChildSourceTypeToolTip();
+ }
+ return getChildDestinationTypeToolTip();
+
+ }
+
+ public StyleRange[] getToolTipStyleRanges(Boolean sourceToDestination, int columnIndex) {
+ if (columnIndex == 1) {
+ return getAdapterClassName().isEmpty() ? null : getAdapterFactorySourceTooltipStyleRanges();
+ }
+ // column 0
+ if (sourceToDestination && getParent() == null) {
+ return getRootSourceTypeTooltipStyleRanges();
+ }
+ if (!sourceToDestination && getParent() == null) {
+ return getRootDesinationTypeTooltipStyleRanges();
+ }
+ if (sourceToDestination && getParent() != null) {
+ return getChildSourceTypeToolTipStyleRanges();
+ }
+ return getChildDestinationTypeToolTipStyleRanges();
+
+ }
+
+ private String getRootSourceTypeTooltip() {
+ return NLS.bind(Messages.rootSourceTypeTooltip, subStringPackage(getSourceType()));
+ }
+
+ private String getRootDesinationTypeTooltip() {
+ return NLS.bind(Messages.rootDestinationTypeToolTip, subStringPackage(getDestinationType()));
+ }
+
+ private String getAdapterFactorySourceTooltip() {
+ List bindings = Arrays.asList(subStringPackage(getAdapterClassName()),
+ subStringPackage(((AdapterData) getParent()).getSourceType()), concatChildren(true));
+ return NLS.bind(Messages.adapterFactory, bindings.toArray());
+ }
+
+ private String getChildDestinationTypeToolTip() {
+ List bindings = Arrays.asList(subStringPackage(getSourceType()),
+ subStringPackage(((AdapterData) getParent()).getDestinationType()),
+ subStringPackage(((AdapterData) getParent()).getAdapterClassName()));
+ return NLS.bind(Messages.childDestinationTypeToolTip, bindings.toArray());
+ }
+
+ private String getChildSourceTypeToolTip() {
+ List bindings = Arrays.asList(subStringPackage(((AdapterData) getParent()).getSourceType()),
+ subStringPackage(getDestinationType()), subStringPackage(getAdapterClassName()));
+ return NLS.bind(Messages.childSourceTypeToolTip, bindings.toArray());
+ }
+
+ private StyleRange[] getAdapterFactorySourceTooltipStyleRanges() {
+ int length0 = subStringPackage(getAdapterClassName()).length();
+ int length1 =subStringPackage(((AdapterData) getParent()).getSourceType()).length();
+ int length2 = concatChildren(true).length();
+
+ StyleRange [] styleRanges = new StyleRange[4];
+ styleRanges[0] = getBoldStyle(0, length0);
+ styleRanges[1] = getStandard(length0+1, 30);
+ styleRanges[2] = getBoldStyle(length0+31, length1);
+ styleRanges[3] = getBoldStyle(length0+35+length1, length2);
+
+ return styleRanges;
+ }
+
+ private StyleRange[] getRootSourceTypeTooltipStyleRanges() {
+ StyleRange [] styleRanges = new StyleRange[2];
+ styleRanges[0] = getStandard(0, 43);
+ styleRanges[1] = getBoldStyle(44, subStringPackage(getSourceType()).length());
+ return styleRanges;
+ }
+
+ private StyleRange[] getRootDesinationTypeTooltipStyleRanges() {
+ StyleRange [] styleRanges = new StyleRange[2];
+ styleRanges[0] = getStandard(0, 57);
+ styleRanges[1] = getBoldStyle(58, subStringPackage(getDestinationType()).length());
+ return styleRanges;
+ }
+
+ private StyleRange[] getChildSourceTypeToolTipStyleRanges() {
+
+ int length0 = subStringPackage(((AdapterData) getParent()).getSourceType()).length();
+ int length1 = subStringPackage(getDestinationType()).length();
+ int length2 = subStringPackage(getAdapterClassName()).length();
+ StyleRange [] styleRanges = new StyleRange[4];
+ styleRanges[0] = getBoldStyle(0, length0);
+ styleRanges[1] = getStandard(length0+1, 18);
+ styleRanges[2] = getBoldStyle(length0+19, length1);
+ styleRanges[3] = getBoldStyle(length0+28+length1, length2);
+ return styleRanges;
+ }
+
+ private StyleRange[] getChildDestinationTypeToolTipStyleRanges() {
+
+ int length0 = subStringPackage(getSourceType()).length();
+ int length1 = subStringPackage(((AdapterData) getParent()).getDestinationType()).length();
+ int length2 = subStringPackage(((AdapterData) getParent()).getAdapterClassName()).length();
+ StyleRange [] styleRanges = new StyleRange[4];
+ styleRanges[0] = getBoldStyle(0, length0);
+ styleRanges[1] = getStandard(length0+1, 20);
+ styleRanges[2] = getBoldStyle(length0+22, length1);
+ styleRanges[3] = getBoldStyle(length0+28+length1, length2);
+ return styleRanges;
+ }
+
+ private StyleRange getStandard(int start,int length) {
+ StyleRange styleRange = new StyleRange();
+ styleRange.start = start;
+ styleRange.length = length;
+ styleRange.fontStyle = SWT.NORMAL;
+ styleRange.foreground = Display.getDefault().getSystemColor(SWT.COLOR_BLACK);
+ return styleRange;
+ }
+
+ private StyleRange getBoldStyle(int start,int length) {
+ StyleRange styleRange = new StyleRange();
+ styleRange.start = start;
+ styleRange.length = length;
+ styleRange.fontStyle = SWT.BOLD;
+ styleRange.foreground = Display.getDefault().getSystemColor(SWT.COLOR_BLUE);
+ return styleRange;
+ }
+
+ private String checkNull(String val) {
+ return (val == null) ? "" : val;
+ }
+
+ private String displayPackage(String value) {
+ if (Boolean.TRUE.equals(showPackage)) {
+ return value;
+ }
+ return subStringPackage(value);
+ }
+
+
+
+ private String subStringPackage(String value) {
+ return value.substring(value.lastIndexOf(".") + 1, value.length());
+ }
+
+ private String concatChildren(boolean sourceToDestination) {
+ if (sourceToDestination)
+ return ((AdapterData) getParent()).children.stream().map((a) -> a.subStringPackage(a.getDestinationType()))
+ .collect(Collectors.joining(", "));
+ else
+ return "";
+ }
+
+}
diff --git a/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/model/AdapterElementType.java b/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/model/AdapterElementType.java
new file mode 100644
index 00000000000..018284e31ee
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/model/AdapterElementType.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ * Copyright (c) Lacherp.
+ *
+ * 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:
+ * Lacherp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.pde.spy.adapter.model;
+
+public enum AdapterElementType {
+ PLUGIN,
+ SOURCE_TYPE,
+ DESTINATION_TYPE;
+}
diff --git a/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/model/AdapterRepository.java b/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/model/AdapterRepository.java
new file mode 100644
index 00000000000..534fe416ad9
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/model/AdapterRepository.java
@@ -0,0 +1,133 @@
+/*******************************************************************************
+ * Copyright (c) Lacherp.
+ *
+ * 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:
+ * Lacherp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.pde.spy.adapter.model;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
+
+import org.eclipse.core.internal.runtime.AdapterManager;
+import org.eclipse.core.internal.runtime.IAdapterFactoryExt;
+import org.eclipse.core.runtime.IAdapterFactory;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.e4.core.di.annotations.Creatable;
+import org.eclipse.pde.spy.adapter.tools.AdapterHelper;
+
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+
+
+@SuppressWarnings("restriction")
+@Creatable
+@Singleton
+public class AdapterRepository {
+
+ @Inject
+ IExtensionRegistry extensionRegistry;
+
+ Map sourceTypeToAdapterDataMap = new HashMap<>();
+ Map destinationTypeToAdapterDataMap = new HashMap<>();
+ List configEleme;
+
+ public Collection getAdapters() {
+
+ if(!sourceTypeToAdapterDataMap.isEmpty()) {
+ return sourceTypeToAdapterDataMap.values();
+ }
+
+ Map> factories = Collections.synchronizedMap(AdapterManager.getDefault().getFactories());
+ AtomicReference refAdapterData= new AtomicReference<>();
+ factories.forEach( (k,v) -> {
+
+ if (!sourceTypeToAdapterDataMap.containsKey(k))
+ {
+ AdapterData adapData = new AdapterData(AdapterElementType.SOURCE_TYPE);
+ adapData.setSourceType(k);
+ sourceTypeToAdapterDataMap.put(k, adapData);
+ }
+ refAdapterData.set(sourceTypeToAdapterDataMap.get(k));
+ final List configsForSourceType = getAdapterFactoryClassFromExtension(k);
+ v.forEach(l -> {
+ if( l instanceof IAdapterFactoryExt) {
+
+ IAdapterFactoryExt adapfext = (IAdapterFactoryExt) l;
+ AtomicReference refClassName = new AtomicReference<>();
+ for( String targetType :adapfext.getAdapterNames()) {
+ AdapterData adapData = new AdapterData(AdapterElementType.DESTINATION_TYPE);
+ adapData.setParent(refAdapterData.get());
+ adapData.setDestinationType(targetType);
+ destinationTypeToAdapterDataMap.put(targetType, adapData);
+ refClassName.set("");
+ configsForSourceType.forEach( config -> {
+ for ( IConfigurationElement child :config.getChildren()) {
+ String type = child.getAttribute(AdapterHelper.EXT_POINT_ATTR_TYPE);
+ if( type.equals(targetType))
+ {
+ refClassName.set(config.getAttribute(AdapterHelper.EXT_POINT_ATTR_CLASS));
+ }
+ }
+ });
+ adapData.setAdapterClassName(refClassName.get());
+ refAdapterData.get().getChildrenList().add(adapData);
+ }
+ }
+ });
+
+ });
+ destinationTypeToAdapterDataMap.values().forEach( ad -> {
+ String destType = ad.getDestinationType();
+ Optional found = sourceTypeToAdapterDataMap.values().stream().filter( ads -> ads.getSourceType().equals(destType)).findAny();
+ if(found.isPresent()) {
+ found.get().getChildrenList().forEach( adchild -> {
+ if (((AdapterData)ad.getParent()).getSourceType().equals(adchild.getDestinationType())) {
+ AdapterData adpd=new AdapterData(adchild);
+ ad.getChildrenList().add(adpd);
+ return;
+ }
+ ad.getChildrenList().add(adchild);
+ });
+ }
+ });
+ return sourceTypeToAdapterDataMap.values();
+ }
+
+
+ public List revertSourceToType(){
+ return sourceTypeToAdapterDataMap.values().stream().flatMap(AdapterData::convertSourceToType)
+ .collect(Collectors.toList());
+ }
+
+
+ public void clear() {
+ sourceTypeToAdapterDataMap.clear();
+ destinationTypeToAdapterDataMap.clear();
+ }
+
+
+ private List getAdapterFactoryClassFromExtension(String sourceType) {
+ if( configEleme ==null) {
+ configEleme = Arrays.asList(extensionRegistry.getConfigurationElementsFor(AdapterHelper.EXT_POINT_ID));
+ }
+ return configEleme.stream().filter( config-> config.getAttribute(AdapterHelper.EXT_POINT_ATTR_ADAPTABLE_TYPE).equals(sourceType)).collect(Collectors.toList());
+
+ }
+
+}
diff --git a/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/tools/AdapterHelper.java b/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/tools/AdapterHelper.java
new file mode 100644
index 00000000000..f5acdc8b0c0
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/tools/AdapterHelper.java
@@ -0,0 +1,148 @@
+/*******************************************************************************
+ * Copyright (c) Lacherp.
+ *
+ * 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:
+ * Lacherp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.pde.spy.adapter.tools;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.contexts.EclipseContextFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.internal.services.EclipseAdapter;
+import org.eclipse.e4.core.services.adapter.Adapter;
+import org.eclipse.pde.spy.adapter.hook.EclipseAdapterHook;
+import org.eclipse.pde.spy.adapter.model.AdapterRepository;
+import org.eclipse.e4.ui.internal.workbench.E4Workbench;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.widgets.Display;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+/**
+ * Helper class
+ * @author pascal
+ *
+ */
+@SuppressWarnings("restriction")
+public final class AdapterHelper {
+
+ // Bundle ID
+ public static final String BUNDLE_ID ="org.eclipse.pde.spy.adapter";
+
+ // Image keys constants
+ public static final String BUNDLE_IMG_KEY = "icons/osgi.png";
+ public static final String SOURCE_TYPE_IMG_KEY = "icons/from_type.png";
+ public static final String DESTINATION_TYPE_IMG_KEY = "icons/to_type.png";
+ public static final String INTERFACE_IMG_KEY = "icons/innerinterface_public_obj.png";
+
+ // extension constant string
+ public static final String EXT_POINT_ID = "org.eclipse.core.runtime.adapters";
+ public static final String EXT_POINT_ATTR_ADAPTABLE_TYPE = "adaptableType";
+ public static final String EXT_POINT_ATTR_CLASS = "class";
+ public static final String EXT_POINT_ATTR_ADAPTER = "adapter";
+ public static final String EXT_POINT_ATTR_TYPE = "type";
+
+ private static final Map classNameToBundleMap =new HashMap<>();
+ private static List bundlesList = new ArrayList<>();
+ private static final BundleContext bc = FrameworkUtil.getBundle(AdapterRepository.class).getBundleContext();
+
+ private static EclipseAdapter originalEclipseAdapter;
+
+ private static BundleContext bcontext;
+
+ private static Color TOOLTIP_BACKGROUND;
+
+ private AdapterHelper() {
+ // do nothing
+ }
+
+
+
+ public static void wrapperEclipseAdapter() {
+ IEclipseContext serviceContext = E4Workbench.getServiceContext();
+ if (serviceContext == null) {
+ System.err.println("service context is null, unable to wrap eclipse adapter");
+ return;
+ }
+ EclipseAdapter eclipseAdapter = (EclipseAdapter) serviceContext.get(Adapter.class);
+ if (originalEclipseAdapter == null) {
+ originalEclipseAdapter = (EclipseAdapter) serviceContext.get(Adapter.class);
+ }
+ if (!(eclipseAdapter instanceof EclipseAdapterHook)) {
+ serviceContext.set(Adapter.class, ContextInjectionFactory.make(EclipseAdapterHook.class, serviceContext));
+ }
+ }
+
+ public static void restoreOriginalEclipseAdapter() {
+ IEclipseContext serviceContext = E4Workbench.getServiceContext();
+ if (serviceContext != null && originalEclipseAdapter != null) {
+ serviceContext.set(Adapter.class, originalEclipseAdapter);
+ }
+ }
+
+ public static IEclipseContext getServicesContext() {
+ return EclipseContextFactory.getServiceContext(bcontext);
+ }
+
+ public static ImageRegistry getImageRegistry(Object instance) {
+ Bundle b = FrameworkUtil.getBundle(instance.getClass());
+ bcontext = b.getBundleContext();
+ ImageRegistry imgReg = new ImageRegistry();
+ imgReg.put(BUNDLE_IMG_KEY, ImageDescriptor.createFromURL(b.getEntry(BUNDLE_IMG_KEY)));
+ imgReg.put(SOURCE_TYPE_IMG_KEY, ImageDescriptor.createFromURL(b.getEntry(SOURCE_TYPE_IMG_KEY)));
+ imgReg.put(DESTINATION_TYPE_IMG_KEY, ImageDescriptor.createFromURL(b.getEntry(DESTINATION_TYPE_IMG_KEY)));
+ imgReg.put(INTERFACE_IMG_KEY, ImageDescriptor.createFromURL(b.getEntry(INTERFACE_IMG_KEY)));
+ return imgReg;
+ }
+
+ public static boolean isInterfaceTypeClass(Bundle bundle,String className){
+
+ try {
+ Class> clazz = bundle.loadClass(className);
+ return clazz.isInterface();
+ } catch (ClassNotFoundException e) {
+ }
+ return false;
+ }
+
+ public static synchronized Bundle getBundleForClassName(String className) {
+ if (bundlesList.isEmpty())
+ {
+ bundlesList = Arrays.asList(bc.getBundles());
+ }
+ if (!classNameToBundleMap.containsKey(className))
+ {
+ final String classpath = "/"+className.replace(".", "/") +".class";
+ Bundle bundlefound = bundlesList.parallelStream().filter( b -> b.getEntry( classpath)!= null).findFirst().orElse(null);
+ classNameToBundleMap.put(className, bundlefound);
+ }
+ return classNameToBundleMap.get(className);
+ }
+
+ public static Color getColor(Display display,String colorName) {
+ if( colorName != null && "TOOLTIP_BACKGROUND".equals(colorName)) {
+ return TOOLTIP_BACKGROUND == null ? (TOOLTIP_BACKGROUND = new Color(display, new RGB(245, 245, 220))): TOOLTIP_BACKGROUND;
+ }
+ return null;
+
+ }
+
+
+}
diff --git a/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/viewer/AdapterContentProvider.java b/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/viewer/AdapterContentProvider.java
new file mode 100644
index 00000000000..cfc1fa36c26
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/viewer/AdapterContentProvider.java
@@ -0,0 +1,144 @@
+/*******************************************************************************
+ * Copyright (c) Lacherp.
+ *
+ * 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:
+ * Lacherp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.pde.spy.adapter.viewer;
+
+import java.util.Collection;
+
+import org.eclipse.e4.core.di.annotations.Optional;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.pde.spy.adapter.model.AdapterData;
+import org.eclipse.pde.spy.adapter.tools.AdapterHelper;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyleRange;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+
+import jakarta.inject.Inject;
+import jakarta.inject.Named;
+
+/**
+ * This provider is used to display available plugins which contribute to
+ * adapters.exsd extension point
+ *
+ * @author pascal
+ *
+ */
+public class AdapterContentProvider extends ColumnLabelProviderCustom implements ITreeContentProvider {
+
+ @Inject
+ private ImageRegistry imgReg;
+
+ private int columnIndex;
+
+ private Boolean sourceToDestination = true;
+
+ @Override
+ public Object[] getElements(Object inputElement) {
+
+ if (inputElement instanceof Collection>) {
+ return ((Collection>) inputElement).toArray();
+ }
+ return (Object[]) inputElement;
+ }
+
+ @Override
+ public Object[] getChildren(Object parentElement) {
+ if (parentElement instanceof AdapterData) {
+ return (Object[]) ((AdapterData) parentElement).getChildren(sourceToDestination);
+ }
+
+ return new Object[0];
+ }
+
+ @Override
+ public Object getParent(Object element) {
+ if (element instanceof AdapterData) {
+ return ((AdapterData) element).getParent();
+ }
+ return null;
+ }
+
+ @Override
+ public boolean hasChildren(Object element) {
+
+ if (element instanceof AdapterData) {
+ return ((AdapterData) element).hasChildren();
+ }
+ return false;
+ }
+
+ @Override
+ public String getText(Object element) {
+
+ if (element instanceof AdapterData) {
+ return ((AdapterData) element).getText(columnIndex);
+ }
+ return "";
+ }
+
+ @Override
+ public Image getImage(Object element) {
+ if (columnIndex == 0) {
+ if (element instanceof AdapterData) {
+ String imgname = ((AdapterData) element).getImageName();
+ return imgname == null ? super.getImage(element) : imgReg.get(imgname);
+ }
+
+ }
+ return super.getImage(element);
+ }
+
+ @Override
+ public int getToolTipStyle(Object object) {
+ return SWT.SHADOW_OUT;
+ }
+
+ @Override
+ public Color getToolTipBackgroundColor(Object object) {
+ return AdapterHelper.getColor(Display.getDefault(),"TOOLTIP_BACKGROUND");
+
+ }
+
+ @Override
+ protected StyleRange[] getToolTipStyleRanges(Object element) {
+ if (element instanceof AdapterData) {
+ return ((AdapterData) element).getToolTipStyleRanges(sourceToDestination, columnIndex);
+ }
+ return null;
+ }
+
+ @Override
+ public String getToolTipText(Object element) {
+ if (element instanceof AdapterData && ((AdapterData) element).getToolTipText(sourceToDestination, columnIndex) != null) {
+ return ((AdapterData) element).getToolTipText(sourceToDestination, columnIndex).replaceAll("\"","");
+ }
+ return "";
+ }
+
+ @Inject
+ @Optional
+ public void updateTextSearchFilter(@Named(AdapterFilter.UPDATE_CTX_FILTER) FilterData filterData) {
+ if (filterData == null) {
+ return;
+ }
+ this.sourceToDestination = filterData.getSourceToDestination();
+ }
+
+ public void setColumnIndex(int columnIndex) {
+ this.columnIndex = columnIndex;
+
+ }
+}
diff --git a/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/viewer/AdapterDataComparator.java b/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/viewer/AdapterDataComparator.java
new file mode 100644
index 00000000000..7188851907a
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/viewer/AdapterDataComparator.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) Lacherp.
+ *
+ * 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:
+ * Lacherp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.pde.spy.adapter.viewer;
+
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.pde.spy.adapter.model.AdapterData;
+import org.eclipse.swt.SWT;
+
+public class AdapterDataComparator extends ViewerComparator {
+
+ private int columnIndex;
+ private int direction;
+
+ public AdapterDataComparator(int columnIndex) {
+ this.columnIndex = columnIndex;
+ direction = SWT.UP;
+ }
+
+ /** Called when click on table header, reverse order */
+ public void setColumn(int column) {
+ if (column == columnIndex) {
+ // Same column as last sort; toggle the direction
+ direction = (direction == SWT.UP) ? SWT.DOWN : SWT.UP;
+ } else {
+ // New column; do a descending sort
+ columnIndex = column;
+ direction = SWT.DOWN;
+ }
+ }
+
+ @Override
+ public int compare(Viewer viewer, Object e1, Object e2) {
+ // Now can compare the text from label provider.
+ if (e1 instanceof AdapterData && e2 instanceof AdapterData) {
+ int rc = ((AdapterData) e1).compareTo((AdapterData) e2);
+ // If descending order, flip the direction
+ return (direction == SWT.DOWN) ? -rc : rc;
+ }
+ return -1;
+ }
+
+ public int getDirection() {
+ return direction;
+ }
+}
diff --git a/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/viewer/AdapterFilter.java b/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/viewer/AdapterFilter.java
new file mode 100644
index 00000000000..a12c684e8a5
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/viewer/AdapterFilter.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) Lacherp.
+ *
+ * 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:
+ * Lacherp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.pde.spy.adapter.viewer;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.eclipse.e4.core.di.annotations.Optional;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.pde.spy.adapter.model.AdapterData;
+import org.eclipse.pde.spy.adapter.model.AdapterElementType;
+
+import jakarta.inject.Inject;
+import jakarta.inject.Named;
+
+/**
+ * Adapter Tree viewer filter
+ * @author pascal
+ *
+ */
+public class AdapterFilter extends ViewerFilter {
+
+ public static final String UPDATE_CTX_FILTER ="updateCtxfilter";
+
+ private String txtSeachFilter;
+ private Boolean showPackageFilter = Boolean.TRUE;
+ private Boolean sourceToDestination = Boolean.TRUE;
+
+ @Override
+ public boolean select(Viewer viewer, Object parentElement, Object element) {
+
+ if(element instanceof AdapterData) {
+
+ ((AdapterData)element).setShowPackage(showPackageFilter);
+ }
+
+ if (txtSeachFilter != null && !txtSeachFilter.isEmpty()) {
+ doFilter((AdapterData) element);
+ }
+ if(txtSeachFilter != null && txtSeachFilter.isEmpty())
+ {
+ ((AdapterData)element).setVisibilityFilter(true);
+ ((AdapterData)element).propagateVisibility();
+ }
+ return ((AdapterData)element).isVisibilityFilter();
+ }
+
+ @Inject
+ @Optional
+ public void updateTextSearchFilter(@Named(UPDATE_CTX_FILTER) FilterData filterData) {
+ if( filterData == null )
+ {
+ return;
+ }
+ this.txtSeachFilter = filterData.getTxtSearchFilter();
+ this.showPackageFilter= filterData.getShowPackage();
+ this.sourceToDestination = filterData.getSourceToDestination();
+ }
+
+
+ private void doFilter(AdapterData adapterData)
+ {
+ if( Boolean.TRUE.equals(sourceToDestination) && adapterData.getAdapterElementType().equals(AdapterElementType.SOURCE_TYPE))
+ {
+ doVisibility(adapterData);
+ }
+ if( Boolean.FALSE.equals(sourceToDestination) && adapterData.getAdapterElementType().equals(AdapterElementType.DESTINATION_TYPE))
+ {
+ doVisibility(adapterData);
+ }
+ }
+
+ private void doVisibility(AdapterData adapterData) {
+ AtomicBoolean bfound = new AtomicBoolean(false);
+ adapterData.textSearch(txtSeachFilter, bfound);
+ adapterData.setVisibilityFilter(bfound.get());
+ adapterData.propagateVisibility();
+ }
+}
diff --git a/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/viewer/ColumnLabelProviderCustom.java b/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/viewer/ColumnLabelProviderCustom.java
new file mode 100644
index 00000000000..708e39244a9
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/viewer/ColumnLabelProviderCustom.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) Lacherp.
+ *
+ * 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:
+ * Lacherp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.pde.spy.adapter.viewer;
+
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.swt.custom.StyleRange;
+
+public class ColumnLabelProviderCustom extends ColumnLabelProvider {
+
+ protected StyleRange[] getToolTipStyleRanges(Object element) {
+ return null;
+ }
+
+}
diff --git a/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/viewer/ColumnViewerToolTipSupportCustom.java b/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/viewer/ColumnViewerToolTipSupportCustom.java
new file mode 100644
index 00000000000..330268ac2f2
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/viewer/ColumnViewerToolTipSupportCustom.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) Lacherp.
+ *
+ * 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:
+ * Lacherp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.pde.spy.adapter.viewer;
+
+import org.eclipse.jface.util.Policy;
+import org.eclipse.jface.viewers.CellLabelProvider;
+import org.eclipse.jface.viewers.ColumnViewer;
+import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
+import org.eclipse.jface.viewers.ViewerRow;
+import org.eclipse.jface.window.ToolTip;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyleRange;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+
+public class ColumnViewerToolTipSupportCustom extends ColumnViewerToolTipSupport {
+
+ private ColumnViewer viewer;
+ private static final String VIEWER_CELL_KEY = Policy.JFACE
+ + "_VIEWER_CELL_KEY"; //$NON-NLS-1$
+
+ private StyleRange [] ranges;
+ protected ColumnViewerToolTipSupportCustom(ColumnViewer viewer, int style, boolean manualActivation) {
+ super(viewer, style, manualActivation);
+ this.viewer = viewer;
+ }
+
+ /**
+ * Enable ToolTip support for the viewer by creating an instance from this
+ * class. To get all necessary informations this support class consults the
+ * {@link CellLabelProvider}.
+ *
+ * @param viewer
+ * the viewer the support is attached to
+ */
+ public static void enableFor(ColumnViewer viewer) {
+ new ColumnViewerToolTipSupportCustom(viewer, ToolTip.NO_RECREATE, false);
+ }
+
+ @Override
+ protected boolean shouldCreateToolTip(Event event) {
+ boolean rv = super.shouldCreateToolTip(event);
+ if (!rv) {
+ return false;
+ }
+ Point pt = new Point(event.x,event.y);
+ ViewerRow row = viewer.getCell(pt).getViewerRow();
+ Object element = row.getItem().getData();
+ ColumnLabelProviderCustom customlabelProvider = (ColumnLabelProviderCustom) viewer.getLabelProvider(viewer.getCell(pt).getColumnIndex());
+ ranges = customlabelProvider.getToolTipStyleRanges(element);
+ String txt = customlabelProvider.getToolTipText(element);
+ return !txt.isEmpty();
+ }
+
+
+ @Override
+ protected Composite createToolTipContentArea(Event event, Composite parent) {
+ setData(VIEWER_CELL_KEY, null);
+ String text = getText(event);
+ Color bgColor = getBackgroundColor(event);
+ StyledText styledText = new StyledText(parent, SWT.NONE);
+ if (text != null) {
+ styledText.setText(text);
+ }
+ if ( ranges != null) {
+
+ styledText.setStyleRanges(ranges);
+ }
+ if(bgColor != null) {
+ styledText.setBackground(bgColor);
+ }
+ return styledText;
+ }
+
+}
diff --git a/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/viewer/FilterData.java b/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/viewer/FilterData.java
new file mode 100644
index 00000000000..a53d80cf6a2
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.adapter/src/org/eclipse/pde/spy/adapter/viewer/FilterData.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) Lacherp.
+ *
+ * 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:
+ * Lacherp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.pde.spy.adapter.viewer;
+
+/**
+ * This class is used to store data filter in the context
+ * @author pascal
+ *
+ */
+public class FilterData {
+
+ String txtSearchFilter;
+ boolean showPackage;
+ boolean sourceToDestination;
+ /**
+ * Ctor
+ */
+ public FilterData() {
+ showPackage = Boolean.TRUE;
+ sourceToDestination = Boolean.TRUE;
+ }
+
+ /**
+ * Copy ctor
+ * @param fdata
+ */
+ public FilterData(FilterData fdata)
+ {
+ this.txtSearchFilter = fdata.txtSearchFilter;
+ this.showPackage = fdata.showPackage;
+ this.sourceToDestination = fdata.sourceToDestination;
+ }
+ /**
+ * @return the txtSearchFilter
+ */
+ public String getTxtSearchFilter() {
+ return txtSearchFilter;
+ }
+
+ /**
+ * @param txtSearchFilter the txtSearchFilter to set
+ */
+ public void setTxtSearchFilter(String txtSearchFilter) {
+ this.txtSearchFilter = txtSearchFilter;
+
+ }
+
+ /**
+ * @return the showPackage
+ */
+ public Boolean getShowPackage() {
+ return showPackage;
+ }
+
+ /**
+ * @param showPackage the showPackage to set
+ */
+ public void setShowPackage(Boolean showPackage) {
+ this.showPackage = showPackage;
+ }
+
+ /**
+ * @return the sourceToDestination
+ */
+ public Boolean getSourceToDestination() {
+ return sourceToDestination;
+ }
+
+ /**
+ * @param sourceToDestination the sourceToDestination to set
+ */
+ public void setSourceToDestination(Boolean sourceToDestination) {
+ this.sourceToDestination = sourceToDestination;
+ }
+
+
+}