Eclipse PDE, Navigator View, TreeSelection - Obtaining the file type and name
Asked Answered
S

4

7

I'm trying to obtain details of an Eclipse user's structured selection in the Navigator Tree view. At present I have the following which is based on the org.eclipse.ui.popMenus extension point:

public void run(IAction action) {

Shell shell = new Shell();

ISelection selection = workbenchPart.getSite().getSelectionProvider().getSelection();

if (structuredSelection instanceof org.eclipse.jface.viewers.TreeSelection) {

   org.eclipse.jface.viewers.TreeSelection treeSelection = (org.eclipse.jface.viewers.TreeSelection) structuredSelection;
   IAdaptable firstElement = (IAdaptable) treeSelection.getFirstElement();

   // Relies on an internal API, bad juju
   if (firstElement instanceof org.eclipse.jdt.internal.core.CompilationUnit) {
    org.eclipse.jdt.internal.core.CompilationUnit compilationUnit = (org.eclipse.jdt.internal.core.CompilationUnit) firstElement;                                   
    String editorSelection = new String(compilationUnit.getContents());
   }            
}

The problem with this is that it's currently coupled to the JDT compilation unit API, which is internal and too specific for what I want.

Ideally I want to be able to get the underlying file name, type and contents without having to rely on:

  1. An internal API
  2. The JDT Compilation Unit Code.

This would then allow me to obtain the properties of a generic file when the user right clicks on a file in the navigator view.

Can somebody provide me with any pointers on how I go about doing this please?

Strategy answered 22/4, 2009 at 4:40 Comment(1)
Is it possible to do that without dependency to JDT? Are there any updates as of January 2014?Mirthless
E
9

[EDIT: I added the following alternative - the original answer is father down]

First: if you select something in the Package Explorer, the selected items are all Java Model objects - you have to deal with them at some level. There are two ways you can handle this:

  1. Use the ICompilationUnit directly (see farther down)
  2. Create an Eclipe adapter factory to automate the conversion

Adapter Factory Approach

You can create an adapter factory (which can live in your main plugin or a different one) that eclipse can use to automatically convert from an ICompilationUnit to an IFile.

Note: if you create the adapter factory in a different plugin, you'll probably need to set up an early-startup for it to get the adapter factory loaded. Otherwise, you'll need to have your plugin that will work with the selection depend on the plugin that provides the adapter.

There's some great details on adapters at http://www.eclipse.org/resources/resource.php?id=407, but I'll go over an implementation for this problem here.

Dependencies

The plugin that will host the adapter needs the following dependencies

  • org.eclispe.core.resources
  • org.eclipse.jdt.core

The adapter factory class

Define the following class in your new plugin

package com.javadude.foo;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IAdapterFactory;
import org.eclipse.jdt.core.ICompilationUnit;

public class CompilationUnitToFileAdapter implements IAdapterFactory {
    @Override
    public Object getAdapter(Object adaptableObject, Class adapterType) {
        if (adaptableObject instanceof ICompilationUnit)
            // note: "adapting" it here just means returning the ref'd IFile
            return (IFile) ((ICompilationUnit)adaptableObject).getResource();
        return null;
    }
    @Override
    public Class[] getAdapterList() {
        return new Class[] {IFile.class};
    }
}

The extension

In the plugin that will host the adapter factory, add the following to your plugin.xml:

<extension point="org.eclipse.core.runtime.adapters">
    <factory
        adaptableType="org.eclipse.jdt.core.ICompilationUnit"
        class="com.javadude.foo.AdapterFactory1">
        <adapter type="org.eclipse.core.resources.IFile" />
    </factory>
</extension>

Using the Adapter

With the above in place, you can now write:

Object firstElement = ((ITreeSelection) selection).getFirstElement();
IFile file = (IFile) Platform.getAdapterManager().
                         getAdapter(firstElement, IFile.class);
if (file == null)
    // adapter not present; cannot use as IFile
else
    // adapter present - you can use it as an IFile

Using this approach, you can add additional adapters to convert other types to IFile and your selection code doesn't care.


Direct ICompilationUnit Approach

[EDIT: I've changing the answer, but leaving the following as reference information b/c it's the standard way to explore the content of a compilation unit that was selected in the package explorer]

This is actually the preferred way to get the contents of a file in the package explorer...

Rather than use CompilationUnit, you should use ICompilationUnit. Most of the eclipse APIs use interfaces for public consumption, and classes for internal details.

If you change your code to

if (firstElement instanceof ICompilationUnit) {
    ICompilationUnit unit = (ICompilationUnit firstElement;
    String contents = new String(unit.getContents());
}

You'll be in good shape.

To see details of examining/modifying the Java Model and source code:

(In Eclipse)
Help->
  Help Contents->
    JDT Plug-in Developer's Guide->
      Programmer's Guide->
        JDT Core

That shows how to work with the Java Model appropriately

To isolate where you reference the java model, you can create an (eclipse) adapter that will convert Java Model objects into files. Assuming such an adapter exists, you can then ask the AdapterManager to convert it to a java file for you. I'll take a peek and see if one exists.

Enumerate answered 22/4, 2009 at 14:9 Comment(11)
Sure, but: This interface is not intended to be implemented by clients.Strategy
You're not implementing it; you're using it as a handle to the implementations. This is the intended usage. Check out the doc page (and please remove the down vote!)Enumerate
And that doesn't help me anyway as it's still tied to the JDT, I was looking to "obtain the properties of a generic file" as per the question, please read it carefully - thank you anyway.Strategy
If you're selecting something in the Package Explorer, it is an ICompilationUnit. You can't get around that. If you want to get the IFile from it, you can call unit.getResource(), but why convert it when not necessary. I am giving you the correct answer for the context you are in. If you do the selection in another type of viewer (non-package-explorer), you can get something else as the selection. See the JDT core guide above for the navigation structure.Enumerate
And, ICompilationUnit is the correct way to access it. The API docs say clients should not implement it, as in "public class Foo implements ICompilationUnit".Enumerate
Read the question! "Ideally I want to be able to get the underlying file name, type and contents without having to rely on: 1. An internal API 2. The JDT Compilation Unit Code."Strategy
The code in your question refers to CompilationUnit. This tells me that you're doing the selection from the Package Explorer. The package explorer represents java files as ICompilationUnits. ICompilationUnit is not internal -- it's the proper handle to use to refer to java files that are selected from the package explorer. You cannot refer to the selection as something else.Enumerate
Let me ask this -- what are you trying to accomplish? Why do you want to avoid ICompilationUnit? (You're correct in wanting to avoid CompilationUnit - it is internal)Enumerate
I'm trying to avoid ICompilationUnit and CompilationUnit because I want a GENERIC way of obtaining the contents of a file, the filename and the type of file. It might not be a Java file, or any other type of language for that matter, it could be a text file, it could be a monkey file, it could be a badger file. Regardless, I want the metadata regarding that file and its' contents.Strategy
It depends on which context you're selecting things. If you select items in the Package Explorer, you have to deal with the Java model - there's no way around it. If you select things in a different view, it depends on what that view exposes.Enumerate
I've updated my answer to talk about how to register adapters for the selection. Note that you'll need to register adapters for each type of selection object.Enumerate
S
4

That (decoupling Resource from JDT) was one of the goals of E4 (Eclipse 4).
The plugin list for REsources doesn't mention JDT anymore (again, Eclipse 4.x only):

  • org.eclipse.core.filesystem - An abstract, generic file system API, including an implementation of this API for the local file system. This is the API through which the resources plugin accesses an underlying file system.
  • org.eclipse.core.resources - Contains the API and implementation of the resource model
  • org.eclipse.core.resources.compatibility - A plug-in providing migration support for users opening old workspaces in Eclipse 3.1 or greater

A Demo project like e4photo don't require any JDT for accessing IResource from the selection of an IContainer.

void setSelection(@Named(IServiceConstants.ACTIVE_SELECTION)
        IResource selection) {
...
IResource[] members = input.members();
...
IResource resource = members[i];
if (resource.getType() == IResource.FILE) {
  InputStream contents = ((IFile) resource).getContents();
Sirup answered 26/1, 2014 at 17:25 Comment(0)
H
3

What are you trying to achieve? Do you want to get file contents? Then you can try:

IAdaptable firstElement = (IAdaptable) treeSelection.getFirstElement();

IFile file = (IFile) firstElement.getAdapter(IFile.class);
if (file != null && file.isAccessible()) {
    // Use getContents API
    ....
}
Highbrow answered 22/4, 2009 at 7:30 Comment(2)
"Ideally I want to be able to get the underlying file name, type and contents."Strategy
this won't work unless an adapter has been registered to convert the selection to an IFile -- see my answer below for how to do thisEnumerate
S
3

It looks like the JDT is already defining an IAdapterFactory for all Java elements including compilation unit (org.eclipse.jdt.internal.ui.JavaElementAdapterFactory). The adapter is defined for IResource rather than IFile so you should be able to do:

Object firstElement = treeSelection.getFirstElement();

IResource resource = (IResource)Platform.getAdapterManager().getAdapter(firstElement, IResource.class);
Sheol answered 28/1, 2014 at 21:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.