Archive

Archive for the ‘Eclipse development’ Category

Help! I Programmatically Created a Resource in my Project, but My Code Doesn’t Find It!

January 1, 2011 5 comments

Let’s say that you wanted to test the existence of a file you programmatically created in your project. While there are a lot of situations where you might create an IResource on the fly, creating a file for use in a test is not a bad example.

The test code could look like this (TestUtilities is a convenience class that does things for me):

...
import org.junit.Assert;
...
    @Test
    public void testFileExistsTrue() throws IOException, CoreException {
        _project = TestUtilities.createProject("x"); //$NON-NLS-1$
        TestUtilities.createTemplateFileInProjectAt(_project, CustomSchemaSupport.SCHEMA_FOLDER_NAME, CustomSchemaSupport.FILENAME);

        boolean actual = _customSchemaSupport.fileExists(_project);

        try {
            Assert.assertTrue(actual);
        } finally {
            // always do this before returning
            _project.delete(true, null);
        }
    }

Read more…

Advertisements

Writing an Eclipse Plug-in (Part 24): Common Navigator: Configuring the submenus (Presentation…again)

August 29, 2010 9 comments

When we last left our erstwhile travelers (that would be all of you) they were surfing the quantum wave on their way to a future refactoring of their past to allow them to simultaneously feel proud of their work and embarrassed that they were following some guy who is making it all up as he goes along causing them to need refactoring in the first place.

Hey. Refactoring happens. All the time. Just ask evolution (only don’t mention the alligators).

What I will post about is adding behavior to our menu items. After having added 4 (count ’em) new menu items it is time to make them actually do something. What should they do? Well, they are going to add elements into their respective XML files (and respectively) while looking like they are adding items into their respective category nodes in the navigator.
Read more…

Writing an Eclipse Plug-in (Part 23): Common Navigator: Rewriting History

August 14, 2010 3 comments


[I am now using Git for my source control using the EGit plug-in. Of course it is only partially working. One of my projects has fully committed and the others say they are in staging no matter how many times I tell EGit to Commit. Sigh.

Also, starting with this post I am also going to make the code in this convoluted journey available for download in each post as well as the Missing Zip Files page. It will always be available in the format of whatever Eclipse I happen to be using at the time (7/18/10: Eclipse 3.6 Helios Release) so don’t blame me if you are using an older version and something doesn’t work the way I describe it. If you follow me you walk the edge. Of course, in switching to EGit I have no idea where the code for Parts 21 and 22 have gone. I hate when that happens.

Don’t forget to add your favorite plug-ins: in my case that means EGit, EclEmma, Eclipse-CS, and UMLet]

[Woo hoo! Eclipse 3.6 is finally released! I can’t wait to be one of the first to download it! Hey! Where is everybody? Oh, it was released June 23? Really? I hate when I miss an opening party…by almost two months…but it was because I was busy…in Miami…meeting with Michael Westin…]

Well, long time no hear! Yes, I am trying to write these posts a little more often than I have been, but it is amazing how real life gets in the way…what with the cat coming in and out of the box and the squirrels distracting me to no end (don’t get me started on the platypus). I guess I may be stuck with only one post per month (maybe less).

I promise not to beat myself up over it.

Speaking of which: when I started this post the sun was out scorching everything, and I was doing everything I could to stay out of its path. After a failed attempt at getting back into running (you know, diet and exercise will help you live forever, unless you exercise wrong thereby screwing up your leg muscles making it almost impossible to walk), but after a successful attempt to eat better (salad and seafood, anyone?) it is time to pay attention to the things that keep us getting up in the morning and make life worth living (no, not sex, drugs, and rock and roll, though they help): Eclipse plug-ins.

I was going to write a post on genetic programming, but I suspect the cat hid my Koza book because it thought I was going to write a fitness function to force it to choose one state or another. I’ll do that on my next visit to Copenhagen.

What I will post about is, well, fixing the past. Usually, that is quite difficult, but we will make an exception and pretend that we can fix what we did, not because it was wrong, but because our needs have changed (that’s my story and I’m sticking to it).
Read more…

Writing an Eclipse Plug-in: The Missing Zip Files

June 29, 2010 3 comments

After only 22 Eclipse postings I have finally gotten around to creating the zip files for each of the posts where changes were actually made to the project. Bear in mind that the various zip files will not necessarily match up with the blog posts.

Here are the zip files:
Read more…

Writing an Eclipse Plug-in (Part 22): Common Navigator: Adding submenus (Presentation)

May 30, 2010 2 comments

[If anyone cares: I have upgraded to Eclipse 3.6 RC3]

Happy Memorial Day weekend, everyone (at least those in the United States)!

For those who have accepted that life is meaningless, short and painful: chow down at the grill! Eat, drink and be merry for tomorrow you die!

For those who believe that life is meaningful, long and joyous: don’t overdo your carbs, remember that hot dogs have artificial colors and mystery meat, and grilling your food causes the formation of cancer causing agents due to carbonization. In other words, don’t eat, drink or be too merry because the odds are you won’t be dying tomorrow (or maybe you will).

But, hey! Enjoy the weekend!

Well, with that sense of merriment out of the way it is time to go back to the real reason we are here: finishing up the popup menu.
Read more…

Writing an Eclipse Plug-in (Part 21): Return of the Popup Menu (Displaying Resources)

[In case anyone cares: I have upgraded to Eclipse 3.6 RC1]

Welcome to the second of what will probably be 4 posts on creating popup menus using the Common Navigator Framework.

In the last post we created a two item popup that appears when there are no resources displayed or selected. In this post we will have the popup menu appear even when we right click on a resource.

How (are we doing it?)

Perform the following on the customnavigator plug-in project.

  1. Delete the navigatorContent enablement adapt entries for both CustomNewActionProvider and CustomRefreshActionProvider.
    • plugin.xml –> Extensions
    • org.eclipse.ui.navigator.navigatorContent –> customnavigator.popup.actionprovider.CustomNewActionProvider –> (enablement) –> (or) –> org.eclipse.core.resources.IResource (adapt) –> Delete
    • org.eclipse.ui.navigator.navigatorContent –> customnavigator.popup.actionprovider.CustomRefreshActionProvider –> (enablement) –> (or) –> org.eclipse.core.resources.IResource (adapt) –> Delete
  2. Add two enablement instanceof entries for both CustomNewActionProvider and CustomRefreshActionProvider.
    • org.eclipse.ui.navigator.navigatorContent –> customnavigator.popup.actionprovider.CustomNewActionProvider –> (enablement) –> (or) –> New –> instanceof
      • value: customnavigator.navigator.ICustomProjectElement
    • org.eclipse.ui.navigator.navigatorContent –> customnavigator.popup.actionprovider.CustomRefreshActionProvider –> (enablement) –> (or) –> New –> instanceof
      • value: customnavigator.navigator.ICustomProjectElement
  3. Start the runtime workbench, create a Custom Project, go to the Custom Perspective and right click on the project. You should see the popup menu.

Why (did we do it that way?)

First, let’s do that simplest thing I can think of: have a popup menu appear with one menu item. Once that is in place the rest are mechanical steps.

In order to have a new popup menu appear Eclipse needs to recognize the resource so that it will show just the menus you want and no others. How do we do that? By setting up an enablement with our custom project type.

Perform the following on the customnavigator plug-in project.

Go to plugin.xml –> Extensions.

Remove the entry for IResource (adapt):

  • org.eclipse.ui.navigator.navigatorContent –> customnavigator.popup.actionprovider.CustomNewActionProvider –> (enablement) –> (or) –> org.eclipse.core.resources.IResource (adapt) –> Delete

That entry told Eclipse to open the popup when the selected resource was of type IResource. Well the custom project does not include the IResource. We don’t need it for now. What we do need is for the popup to open when any of our custom types is selected. Since all of the custom nodes implement ICustomProjectElement we use that instead.

  • org.eclipse.ui.navigator.navigatorContent –> customnavigator.popup.actionprovider.CustomNewActionProvider –> (enablement) –> (or) –> New –> instanceof
    • value: customnavigator.navigator.ICustomProjectElement

Why use instanceof instead of adapt? An adapt entry means that the selected object, in this case CustomProjectParent, can be adapted (converted) into the listed type, originally IResource, Since a CustomProjectParent does not implement IResource anywhere in its inheritance hierarchy the adapt will never work. Adapt means that we would have to change the custom node types while instanceof puts the onus on Eclipse. You know where my vote goes.

Perform the same steps for CustomRefreshActionProvider:

  1. org.eclipse.ui.navigator.navigatorContent –> customnavigator.popup.actionprovider.CustomRefreshActionProvider –> (enablement) –> (or) –> org.eclipse.core.resources.IResource (adapt) –> Delete
  2. org.eclipse.ui.navigator.navigatorContent –> customnavigator.popup.actionprovider.CustomRefreshActionProvider –> (enablement) –> (or) –> New –> instanceof
    • value: customnavigator.navigator.ICustomProjectElement
  3. Start the runtime workbench, create a Custom Project, go to the Custom Perspective and right click on the project. You should see the popup menu.

While I was doing this I found that the above did not work. It turned out that my Launch configuration thought I only needed 73 of the existing plug-ins while I needed a few more. It is possible that your Launch Configuration might not have enough dependencies selected. In Eclipse 3.6 RC1 this needed 80 out of 375 plug-ins. The only other plug-in I have installed is EGit.

What Just Happened?

Not a lot just happened. Changing the adapt entry to instanceof specific to our custom project type was enough to get the popup to behave the way we needed. Not a lot of work.

What we need to do next is create New behavior for:

  • New Schema Table
  • New Schema View
  • New Schema Filter
  • New Stored Procedure

That will take commands, handlers and command images.

Our current setup creates new projects, schema files and deployment files. Oops. We’ll have to change that. Next time. Maybe.

After that we’ll add properties pages to each node type fix the New menus in the toolbar and main menu.

The cat is tired. It may be time to do some genetic programming posts.

Code

<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
   <extension
         point="org.eclipse.ui.views">
      <category
            id="customnavigator.category"
            name="%category.name">
      </category>
      <view
            allowMultiple="false"
            category="customnavigator.category"
            class="org.eclipse.ui.navigator.CommonNavigator"
            icon="icons/navigator.png"
            id="customnavigator.navigator"
            name="%view.name">
      </view>
   </extension>
   <extension
         point="org.eclipse.ui.navigator.viewer">
      <viewer
            viewerId="customnavigator.navigator">
         <popupMenu
               id="customnavigator.navigator#PopupMenu">
            <insertionPoint
                  name="group.new">
            </insertionPoint>
            <insertionPoint
                  name="group.build"
                  separator="true">
            </insertionPoint>
         </popupMenu>
      </viewer>
      <viewerContentBinding
            viewerId="customnavigator.navigator">
         <includes>
            <contentExtension
                  pattern="customnavigator.navigatorContent">
            </contentExtension>
         </includes>
      </viewerContentBinding>
      <viewerActionBinding
            viewerId="customnavigator.navigator">
         <includes>
            <actionExtension
                  pattern="customnavigator.popup.actionprovider.CustomNewAction">
            </actionExtension>
            <actionExtension
                  pattern="customnavigator.popup.actionprovider.CustomRefreshAction">
            </actionExtension>
         </includes>
      </viewerActionBinding>
   </extension>
   <extension
         point="org.eclipse.ui.navigator.navigatorContent">
      <navigatorContent
            activeByDefault="true"
            contentProvider="customnavigator.navigator.ContentProvider"
            id="customnavigator.navigatorContent"
            labelProvider="customnavigator.navigator.LabelProvider"
            name="%navigatorContent.name">
         <triggerPoints>
            <instanceof
                  value="org.eclipse.core.resources.IWorkspaceRoot">
            </instanceof>
         </triggerPoints>
         <commonSorter
               class="customnavigator.sorter.SchemaCategorySorter"
               id="customnavigator.sorter.schemacategorysorter">
            <parentExpression>
               <or>
                  <instanceof
                        value="customnavigator.navigator.CustomProjectSchema">
                  </instanceof>
               </or>
            </parentExpression>
         </commonSorter>
      </navigatorContent>
      <actionProvider
            class="customnavigator.popup.actionprovider.CustomNewActionProvider"
            id="customnavigator.popup.actionprovider.CustomNewAction">
         <enablement>
            <or>
               <instanceof
                     value="customnavigator.navigator.ICustomProjectElement">
               </instanceof>
               <adapt
                     type="java.util.Collection">
                  <count
                        value="0">
                  </count>
               </adapt>
            </or>
         </enablement>
      </actionProvider>
      <actionProvider
            class="customnavigator.popup.actionprovider.CustomRefreshActionProvider"
            id="customnavigator.popup.actionprovider.CustomRefreshAction">
         <enablement>
            <or>
               <instanceof
                     value="customnavigator.navigator.ICustomProjectElement">
               </instanceof>
               <adapt
                     type="java.util.Collection">
                  <count
                        value="0">
                  </count>
               </adapt>
            </or>
         </enablement>
      </actionProvider>
      <commonWizard
            type="new"
            wizardId="customplugin.wizard.new.custom">
         <enablement></enablement>
      </commonWizard>
   </extension>

</plugin>

Writing an Eclipse Plug-in (Part 19): A Quick Display Fix

February 28, 2010 2 comments

[I am deep into solving a CNF issue, but since I haven’t solved it yet you will have to settle for a bug fix.]

Random bug: when the cursor hovers over the custom navigator title bar a tooltip opens letting us know that the navigator can’t find a label for the root node. The full error message is Error: no label provider for R/. Tells you everything you need to know. Except what the problem is. Or how to fix it. Or, for Eclipse novices, what R/ means.

Luckily this is something that we are not afflicted with here at Hidden Clause. The message did tell us everything we needed to know. The Custom Navigator label provider is ignoring the root node used by the navigator (the R/ referred to in the error) and returning an empty string. The code for LabelProvider.getText() is:

   public String getText(Object element) {
        String text = ""; //$NON-NLS-1$
        if (ICustomProjectElement.class.isInstance(element)) {
            text = ((ICustomProjectElement)element).getText();
        }
        // else ignore the element

        return text;
    }

(Notice how it so brilliantly ignores everything except elements of type ICustomProjectElement.)

What the message also tells us, by not telling us, is that our zero-length string appears to be causing consternation in the navigator. It is causing so much consternation that the navigator thinks no label provider is available to supply it with a default label for the root node.

That something is easily fixed in the LabelProvider. I’m not sure why Eclipse does not default to no string for the root (damn, those double negatives!), but it does not so we have to assign something to it. Since the standard behavior for other navigator views is to use the name of the view, in this case Custom Plug-in Navigator, that is what we will do.

  1. Open LabelProvider.java
  2. Change getText() to include an else if:
       public String getText(Object element) {
            String text = ""; //$NON-NLS-1$
            if (ICustomProjectElement.class.isInstance(element)) {
                text = ((ICustomProjectElement)element).getText();
            } else if (IWorkspaceRoot.class.isInstance(element)) {
                text = "Custom Plug-in Navigator";
            }
            // else ignore the element
    
            return text;
        }
    
  3. Start the runtime workbench and behold the beauty of our new string.

For Those of You Who Care

I discovered the solution to the above by putting a breakpoint in LabelProvider.getText() and walking the call tree. NavigatorContentServiceLabelProvider.findStyledText() quite explicitly changed the original empty string returned by LabelProvider.getText() into a null which caused NavigatorContentServiceLabelProvider.getStyledText() to assign the error message to the navigator view. It makes sense, it just wasn’t what I wanted.

Extra credit: Run the Externalize String Wizard on LabelProvider.java and add the new string to the message.properties file.

What Just Happened?

Fixed a bug. Contain your excitement.

The cat was not impressed and refused to come out.

Code

messages.properties

CustomProjectParent_Project_Folder=icons/project-folder.png
CustomProjectSchema_Project_Schema=icons/project-schema.png
CustomProjectSchemaFilters_Project_Schema_Filters=icons/project-schema-filters.png
CustomProjectSchemaTables_Project_Schema_Tables=icons/project-schema-tables.png
CustomProjectSchemaViews_Project_Schema_Views=icons/project-schema-views.png
CustomProjectStoredProcedures_Project_Stored_Procedures=icons/project-stored-procedures.png
LabelProvider_Custom_Plugin_Navigator=Custom Plug-in Navigator

LabelProvider.java

/**
 * Coder beware: this code is not warranted to do anything.
 *
 * Copyright Oct 17, 2009 Carlos Valcarcel
 */
package customnavigator.navigator;

import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.swt.graphics.Image;

/**
 * @author carlos
 *
 */
public class LabelProvider implements ILabelProvider {

    /* (non-Javadoc)
     * @see org.eclipse.jface.viewers.ILabelProvider#getImage(java.lang.Object)
     */
    @Override
    public Image getImage(Object element) {
        Image image = null;
        
        if (ICustomProjectElement.class.isInstance(element)) {
            image = ((ICustomProjectElement)element).getImage();
        }
        // else ignore the element
        
        return image;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jface.viewers.ILabelProvider#getText(java.lang.Object)
     */
    @Override
    public String getText(Object element) {
        String text = ""; //$NON-NLS-1$
        if (ICustomProjectElement.class.isInstance(element)) {
            text = ((ICustomProjectElement)element).getText();
        } else if (IWorkspaceRoot.class.isInstance(element)) {
            text = Messages.LabelProvider_Custom_Plugin_Navigator;
        }
        // else ignore the element
        
        return text;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener)
     */
    @Override
    public void addListener(ILabelProviderListener listener) {
        // TODO Auto-generated method stub

    }

    /* (non-Javadoc)
     * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose()
     */
    @Override
    public void dispose() {
        // TODO Auto-generated method stub

    }

    /* (non-Javadoc)
     * @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object, java.lang.String)
     */
    @Override
    public boolean isLabelProperty(Object element, String property) {
        // TODO Auto-generated method stub
        return false;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener)
     */
    @Override
    public void removeListener(ILabelProviderListener listener) {
        // TODO Auto-generated method stub

    }

}