Archive

Posts Tagged ‘kubuntu’

Kubuntu 11.10: Mapping the Windows Key to Activate KMenu

January 7, 2012 12 comments

This post is an explanation of how to map the Windows key on a Dell Studio 17 running Kubuntu 11.10 to open the KMenu. If you, or your programs, rely on the Windows key as a Meta key for certain functionality this will break that. This is your only warning.

This is taken from the Mepis docs that can be found at http://www.mepis.org/docs/en/index.php?title=Extra_keys. I wandered around the world for a long time before I stumbled onto this wiki and it laid everything out step-by-step. I am simply listing the same steps from the Mepis Extra Keys documentation modified for Kubuntu running on my Studio 17 notebook.
Read more…

Writing an Eclipse Plug-in (Part 18 – Take 2): Common Navigator: Adding submenus (Presentation/Behavior)

February 21, 2010 Leave a comment

Well, don’t I feel silly.

During the writing of Part 19, Adding Behavior to the menu items, I discovered something both heartening and disturbing: the addition of behavior to the New Wizards is much easier than I thought. Where I used the org.eclipse.ui.menus extension point to add the menu items to the New menu of the default popup menu I could have used the org.eclipse.ui.navigator.navigatorContent –> commonWizard extension instead. This would take care of both presentation and behavior.

Since using the org.eclipse.ui.menus to accomplish this task is wrong (yes, wrong*) I thought I would correct this obvious affront to civilization and pleasant company before the wrong kind of meme invades too many impressionable minds and causes an aggregation of incorrect behavior leading to that worst of all possible behaviors: rudeness.

Consider this a refactoring of Part 18 as the things discovered in it are still valid and will help in the controlling of the popup menu in other contexts…just not this one.

Okay! Places everyone! This time with feeling!

[Pretend that you just finished reading the brilliant advice that was Part 17 and are looking for the enlightenment that only comes from believing in God, unicorns or the Na’vi.]

And now, the moment you’ve all been waiting for: adding commands to the popup menu.

I know, you are just aquiver in anticipation.

What menus do we need to put in? Just a few. The Custom Navigator popup menu should contain:

  • New – Sub-menu with choices (Custom Project, Schema, and Deployment. Eventually we will change Schema to Tables, Views, Filters)
  • Copy – Ctrl+C (an item in a category or an entire category)
  • Paste – Ctrl+V (an item in a category or an entire category)
  • Remove – Del or Ctrl+X (an item in a category or an entire category)

We will not worry about Import/Export behavior as that will be added to the Import/Export Wizard with the associated additions to the main menu, toolbar, etc. done as appropriate (meaning later, when I care).

The thing to remember is: presentation first, behavior second. Actually, by the time we’re done we will have done both for the price of one (well, at least for the New wizards).

Where should the popup menu configuration/code go: into the customplugin or customnavigator project? Because we are directly affecting the navigator popup menu the configuration will go into the customnavigator plug-in. I promise not to regret it later when someone points out why it would really be in the customplugin project.

How (are we doing it?)

First: let’s add one menu item to the New menu.

  1. customnavigator –> plugin.xml –> Extensions –> org.eclipse.ui.navigator.navigatorContent –> New –> commonWizard
    • type: new
    • wizardId: customplugin.wizard.new.custom
  2. As a sanity check start the runtime workbench, go to the Custom Perspective and right click in the empty Custom Navigator.

    Back to the grindstone.

  3. org.eclipse.ui.navigator.navigatorContent –> New –> commonWizard
    • type: new
    • wizardId: customplugin.wizard.file.schema
  4. org.eclipse.ui.navigator.navigatorContent –> New –> commonWizard
    • type: new
    • wizardId: customplugin.wizard.file.deployment
  5. I know: you probably think that the above was too easy. You’re right. It was. In addition to the presentation we got the behavior for free. And no code so we’re ahead.

Next: let’s add three standard menus: Copy/Paste/Delete. Again, for now we will assign default commands that we will change later.

Let’s use the following icons for the copy/paste/delete menu items (yes, I copied them from Eclipse):

  1. customnavigator –> plugin.xml –> Extensions –> All Extensions –> Add –> org.eclipse.ui.menus
  2. org.eclipse.ui.menus –> New –> menuContribution
    • locationURI: popup:customnavigator.navigator?before=import
  3. popup:customnavigator.navigator?before=import (menuContribution) –> New –> command
    • commandId: org.eclipse.ui.edit.copy
    • label: Copy
    • icon: icons/copy_16x16.png
  4. popup:customnavigator.navigator?before=import (menuContribution) –> New –> command
    • commandId: org.eclipse.ui.edit.paste
    • label: Paste
    • icon: icons/paste_16x16.png
  5. popup:customnavigator.navigator?before=import (menuContribution) –> New –> command
    • commandId: org.eclipse.ui.edit.delete
    • label: Delete
    • icon: icons/delete_16x16.png
  6. popup:customnavigator.navigator?before=import (menuContribution) –> New –> separator
    • name: customnavigator.separator
    • visible: true

The above is a lot to do all at once so feel free to add one section at a time and check the runtime workbench. Once you add the org.eclipse.ui.menus extension along with the menuContribution and one of the commands you should be able to open the Custom Perspective, right click in the Custom Navigator and see a lovely popup menu.

The final result is beautifully displayed in the screen capture (don’t sweat the fact that Copy is not disabled. That is under the control of Eclipse and the clipboard. You will probably have a different item enabled or none).

But first: time to reveal the magic.

Why (did we do it that way?)

If you want to add a menu item to the popup menu the easiest way is to use the org.eclipse.ui.menus extension and add a menuContribution to it (hmm. That would imply there is another way to do this. Yes, using actionSets…which have been deprecated, so don’t). The menuContribution‘s locationURI is the path to the location within the popup where your new menu item should go. If we were adding our menu item at the top level popup we would simply have used a locationURI of popup:customplugin.customnavigator?after=additions; that’s right: simply using the id of the navigator places the menu item into its popup. Using the after=additions piece puts the menu items directly in the popup right after the last item…which is not where we want it.

So the $54,000 question is: what locationURI do we use to put our menu items in the correct spot?

That turns out to be the wrong question (I am starting to dislike that word).

The real question is: if there is a shortcut to adding New Wizards to the main menu, why isn’t there a way to do that with the navigator popup menu? If you recall from Part 15 we added our 3 New Wizards to the main menu by using the org.eclipse.ui.perspectiveExtensions –> perspectiveExtension –> newWizardShortcut. By simply supplying the New Wizard id Eclipse took care of adding it to the main menu File –> New and to the toolbar New button.

The real answer is: there is a way to do it and it involves the org.eclipse.ui.navigator.navigatorContent extension point. It has a child extension named commonWizards that does the equivalent behavior of the newWizardShortcut but for popup menus. On one hand, this is the greatest thing since sliced bread since we don’t have to configure as much (and did I mention no code?), but on the other hand we still have no idea how to add to a popup menu submenu such as New when the behavior we want to add has nothing to do with a wizard.

Let’s speak to that later. [Peek at the end of the post after the configuration files; I speak to the madness needed to implement the method of adding to the default popup menu supplied with the Common Navigator Framework.]

The configuration of the remaining menus now make sense. Add a new menuContribution to the org.eclipse.ui.menus extension and, using the high-level custom navigator path location URI (popup:customnavigator.navigator?before=import), we tell Eclipse to put the menus before the import section. Again, just to supply the required information we assign the internal copy, paste, and delete commandIds to the various menus.

Here are the instructions again:

  • org.eclipse.ui.menus –> New –> menuContribution
    • locationURI: popup:customnavigator.navigator?before=import
  • popup:customnavigator.navigator?before=import (menuContribution) –> New –> command
    • commandId: org.eclipse.ui.edit.copy
    • label: Copy
    • icon: icons/copy_16x16.png
  • popup:customnavigator.navigator?before=import (menuContribution) –> New –> command
    • commandId: org.eclipse.ui.edit.paste
    • label: Paste
    • icon: icons/paste_16x16.png
  • popup:customnavigator.navigator?before=import (menuContribution) –> New –> command
    • commandId: org.eclipse.ui.edit.delete
    • label: Delete
    • icon: icons/delete_16x16.png
  • popup:customnavigator.navigator?before=import (menuContribution) –> New –> separator
    • name: customnavigator.separator
    • visible: true

Doesn’t it look great? It just makes you proud to be a plug-in developer.

The next big question: why did we do it that way? Or more accurately: where is the documentation for this magic?

Part of the answer is easy: instructions on adding to a popup menu can be found here. Part of the answer is weak: I stumbled on the help documentation for commonWizard while I was looking up something else.

Time to wash up:

  • Go to the Overview tab, click on Externalize Strings Wizard and externalize the strings
  • In plugin.xml click on the MANIFEST.MF tab, click on the light bulb in the left hand margin and select Add Missing Packages

Who’s better than you?

What Just Happened?

The popup menu items have been added! With and without behavior! Who says you can’t have your cake and eat it too?

The cat is not only alive, but curious, which leads one to worry about the cat’s future.

(I hope this was a better answer to your question, Augusto. It’s always better the second time…)

* I know, I know: it still works. So what? you may say. So what?! So everything. If I had known about the commonWizard extension sooner I would have used it first as it would have eliminated the need for the Plug-in Spy and the search from the Common Navigator popup menu path to the New menu. While it is still just configuration, it is needless configuration. Needless. Need less. Compare what commonWizard needs:


to what org.eclipse.ui.menus –> menuContribution is looking for:

Use the more extensive extension when extensiveness is called for. Otherwise, strive to be simple. Like a new born baby. Or the brain of a politician.

Code

No code…again.

bundle.properties

#Properties file for customnavigator_1.0.0.7
Bundle-Name = Custom Navigator Plug-in
view.name = Custom Plug-in Navigator
category.name = Custom Projects
navigatorContent.name = Custom Navigator Content
copy.command.label = Copy
paste.command.label = Paste
delete.command.label = Delete

plugin.xml (customnavigator)

<?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">
      <viewerActionBinding
            viewerId="customnavigator.navigator">
         <includes>
            <actionExtension
                  pattern="org.eclipse.ui.navigator.resources.*">
            </actionExtension>
         </includes>
      </viewerActionBinding>
      <viewerContentBinding
            viewerId="customnavigator.navigator">
         <includes>
            <contentExtension
                  pattern="customnavigator.navigatorContent">
            </contentExtension>
         </includes>
      </viewerContentBinding>
   </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>
      <commonWizard
            type="new"
            wizardId="customplugin.wizard.new.custom">
         <enablement></enablement>
      </commonWizard>
      <commonWizard
            type="new"
            wizardId="customplugin.wizard.file.schema">
         <enablement></enablement>
      </commonWizard>
      <commonWizard
            type="new"
            wizardId="customplugin.wizard.file.deployment">
         <enablement></enablement>
      </commonWizard>
   </extension>
   <extension
         point="org.eclipse.ui.menus">
      <menuContribution
            locationURI="popup:customnavigator.navigator?before=import">
         <command
               commandId="org.eclipse.ui.edit.copy"
               icon="icons/copy_16x16.png"
               label="%copy.command.label"
               style="push">
         </command>
         <command
               commandId="org.eclipse.ui.edit.paste"
               icon="icons/paste_16x16.png"
               label="%paste.command.label"
               style="push">
         </command>
         <command
               commandId="org.eclipse.ui.edit.delete"
               icon="icons/delete_16x16.png"
               label="%delete.command.label"
               style="push">
         </command>
         <separator
               name="customnavigator.separator"
               visible="true">
         </separator>
      </menuContribution>
   </extension>

</plugin>

Extra Credit

So you want to add non-Wizard behavior to the default popup menu and aren’t sure how? You’ve come to the right place. Let’s look at what it means to add a new menu item to the New menu item of the default popup menu of our Custom Navigator.

But before I can answer that we have to fix something. Well, some of us have to fix something.

For those of you doing this on Windows: shield your eyes and move on to the section titled CONTINUE HERE (while goto may be considered harmful, continue here isn’t).

Now that we have all of those miscreants out of the way: those of you who need to see the answer with your own eyes, but are using Kubuntu, need to change the Eclipse key binding for the runtime workbench from Shift+Alt+F2 to Shift+Alt+F3. Why? Because in order to discover the correct path to the New menu in the popup we need the Plug-in Spy to work. The Plug-in Spy, at least on Kubuntu, does not work properly because Shift+Alt+F2 doesn’t work properly; changing the key binding from Shift+Alt+F2 to Shift+Alt+F3 works.

How do we change the key binding? Start and do the following from the runtime workbench:

  1. Window –> Preferences –> General –> Keys
  2. In the text field below the Scheme drop down type: shift+alt+f
  3. Press Delete in the Binding field to remove the current key binding
  4. With the cursor in the Binding field press the shift key, the alt key and the F3 key all at the same time.
  5. Click OK to close the Preferences window

Now the bad news: you will have to do this every time you start the runtime workbench if you want to use the Plug-in Spy unless you unset the Launch configuration to clear the workspace; by not clearing the workspace you may find weird behavior that isn’t weird but appears to be weird because the runtime workbench is not cleaning up after itself. I recommend leaving the Launch configuration alone…meaning with the Clear selection checked.

The good news: you don’t need to use the Plug-in spy that often so this manual step is something you will not do too often. Grow up or start taking stronger meds.

CONTINUE HERE

Those of you on Windows: every time I say press Shift+Alt+F3 you must press Shift+Alt+F2. Got it? Shift+Alt+F3 really mean Shift+Alt+F2 (just in Windows). Think you can handle that?

  1. Start the runtime workbench and open the Custom Perspective
  2. Press Shift+Alt+F3. Notice the cursor changes appearance
  3. Right click in the Custom Navigator and select New –> Project
  4. Oh look! A window with wonderful information!

And there it is: the path used by the active contribution location URI: common.new.menu. If you change the current path for the Copy/Paste/Delete command from popup:customplugin.customnavigator?after=additions to popup:common.new.menu?after=additions and start the runtime workbench again you will find that the menus are part of the submenus associated with New.

So where can you find all this great information on inserting a menu item in the popup menu’s New menu?

My answer is going to be very unsatisfying: I don’t know. I went through a number of plug-ins, web sites and help files and found nothing. When I remembered the Plug-in Spy, and fixed the Shift+Alt+F2 problem (Kubuntu, remember?), I was able to discover the path I was looking for.

The cat remained quiet and was of no value whatsoever.

Writing an Eclipse Plug-in (Part 18): Common Navigator: Adding Submenus (Presentation)

February 7, 2010 2 comments

[Before you get too engaged in this post: you might want to skip it. Yes, I realize that the writing is engaging, witty, poetic, philosophical, daring, edgy, and technically astute, but what is all that to being wrong? Just jump forward to Part 18 – Take 2 for a refactoring of this post with many of the wrong parts taken out. However, the writing is still what it is and for that I offer my apologies.]

And now, the moment you’ve all been waiting for: adding commands to the popup menu.

I know, you are just aquiver in anticipation.

What menus do we need to put in? Just a few. The Custom Navigator popup menu should contain:

  • New – Sub-menu with choices (Custom Project, Schema, and Deployment. Eventually we will change Schema to Tables, Views, Filters)
  • Copy – Ctrl+C (an item in a category or an entire category)
  • Paste – Ctrl+V (an item in a category or an entire category)
  • Remove – Del or Ctrl+X (an item in a category or an entire category)

We will not worry about Import/Export behavior as that will be added to the Import/Export Wizard with the associated additions to the main menu, toolbar, etc. done as appropriate (meaning later, when I care).

The thing to remember is: presentation first, behavior second.

For now, we are going to set up the menus with bogus behavior. Since I don’t usually test the presentation this works out well for me. We’ll get around to behavior in the next post. Let’s get the menus in place and then we will snap the commands (next time).

Where should the popup menu configuration/code go: into the customplugin or customnavigator project? Because we are directly affecting the navigator popup menu the configuration will go into the customnavigator plug-in. I promise not to regret it later when someone points out why it would really be in the customplugin project.

How (are we doing it?)

First: let’s add one menu item to the New menu.

  1. customnavigator –> plugin.xml –> Extensions –> All Extensions –> Add –> org.eclipse.ui.menus
  2. org.eclipse.ui.menus –> New –> menuContribution
    • locationURI: popup:common.new.menu?after=additions
  3. popup:common.new.menu?after=additions (menuContribution) –> New –> command
    • commandId: org.eclipse.ui.newWizard
    • label: Custom Project
    • icon: icons/project-folder.png
  4. As a sanity check start the runtime workbench.

    Back to the grindstone.

  5. popup:common.new.menu?after=additions (menuContribution) –> New –> command
    • commandId: org.eclipse.ui.newWizard
    • label: Schema File
    • icon: icons/schema-file_16x16.png (copy this from the customplugin icon folder)
  6. popup:common.new.menu?after=additions (menuContribution) –> New –> command
    • commandId: org.eclipse.ui.newWizard
    • label: Deployment File
    • icon: icons/deployment-file_16x16.png (copy this from the customplugin icon folder)

Next: let’s add three standard menus: Copy/Paste/Delete. Again, for now we will assign default commands that we will change later.

Let’s use the following icons for the copy/paste/delete menu items (yes, I copied them from Eclipse):

  1. org.eclipse.ui.menus –> New –> menuContribution
    • locationURI: popup:customnavigator.navigator?before=import
  2. popup:customnavigator.navigator?before=import (menuContribution) –> New –> command
    • commandId: org.eclipse.ui.edit.copy
    • label: Copy
    • icon: icons/copy_16x16.png
  3. popup:customnavigator.navigator?before=import (menuContribution) –> New –> command
    • commandId: org.eclipse.ui.edit.paste
    • label: Paste
    • icon: icons/paste_16x16.png
  4. popup:customnavigator.navigator?before=import (menuContribution) –> New –> command
    • commandId: org.eclipse.ui.edit.delete
    • label: Delete
    • icon: icons/delete_16x16.png
  5. popup:customnavigator.navigator?before=import (menuContribution) –> New –> separator
    • name: customnavigator.separator
    • visible: true

The above is a lot to do all at once so feel free to add one section at a time and check the runtime workbench. Once you add the org.eclipse.ui.menus extension along with the menuContribution and one of the commands you should be able to open the Custom Perspective, right click in the Custom Navigator and see a lovely popup menu.

The final result is beautifully displayed in the screen capture (don’t sweat the fact that Delete is not disabled. That is under the control of Eclipse and the clipboard. You will probably have a different item enabled or none).

Don’t let the gratuitous use of Ctrl+N upset you. We will take care of messing those up later.

But first: time to reveal the magic.

Why (did we do it that way?)

If you want to add a menu item to the popup menu the easiest way is to use the org.eclipse.ui.menus extension and add a menuContribution to it (hmm. That would imply there is another way to do this. Yes, using actionSets…which have been deprecated, so don’t). The menuContribution‘s locationURI is the path to the location within the popup where your new menu item should go. If we were adding our menu item at the top level popup we would simply have used a locationURI of popup:customplugin.customnavigator?after=additions; that’s right: simply using the id of the navigator places the menu item into its popup. Using the after=additions piece puts the menu items directly in the popup right after the last item…which is not where we want it.

So the $54,000 question is: what locationURI do we use to put our menu items in the correct spot?

Before I can answer that we have to fix something. Well, some of us have to fix something.

For those of you doing this on Windows: shield your eyes and move on to the section titled CONTINUE HERE (while goto may be considered harmful, continue here isn’t).

Now that we have all of those miscreants out of the way: those of you who need to see the answer with your own eyes, but are using Kubuntu, need to change the Eclipse key binding for the runtime workbench from Shift+Alt+F2 to Shift+Alt+F3. Why? Because in order to discover the correct path to the New menu in the popup we need the Plug-in Spy to work. The Plug-in Spy, at least on Kubuntu, does not work properly because Shift+Alt+F2 doesn’t work properly; changing the key binding from Shift+Alt+F2 to Shift+Alt+F3 works.

How do we change the key binding? Start and do the following from the runtime workbench:

  1. Window –> Preferences –> General –> Keys
  2. In the text field below the Scheme drop down type: shift+alt+f
  3. Press Delete in the Binding field to remove the current key binding
  4. With the cursor in the Binding field press the shift key, the alt key and the F3 key all at the same time.
  5. Click OK to close the Preferences window

Now the bad news: you will have to do this every time you start the runtime workbench if you want to use the Plug-in Spy unless you unset the Launch configuration to clear the workspace; by not clearing the workspace you may find weird behavior that isn’t weird but appears to be weird because the runtime workbench is not cleaning up after itself. I recommend leaving the Launch configuration alone…meaning with the Clear selection checked.

The good news: you don’t need to use the Plug-in spy that often so this manual step is something you will not do too often. Grow up or start taking stronger meds.

CONTINUE HERE

Those of you on Windows: every time I say press Shift+Alt+F3 you must press Shift+Alt+F2. Got it? Shift+Alt+F3 really mean Shift+Alt+F2 (just in Windows). Think you can handle that?

  1. Start the runtime workbench and open the Custom Perspective
  2. Press Shift+Alt+F3. Notice the cursor changes appearance
  3. Right click in the Custom Navigator and select New –> Project
  4. Oh look! A window with wonderful information!

And there it is: the path used by the active contribution location URI: common.new.menu. Change the current path from popup:customplugin.customnavigator?after=additions to popup:common.new.menu?after=additions and start the runtime workbench again. The menus are exactly where we want them.

The configuration of the remaining menus now make sense. Add a new menuContribution to the org.eclipse.ui.menus extension and, using the high-level custom navigator path location URI (popup:customnavigator.navigator?before=import), we tell Eclipse to put the menus before the import section. Again, just to supply the required information we assign the internal copy, paste, and delete commandIds to the various menus.

Here are the instructions again:

  • org.eclipse.ui.menus –> New –> menuContribution
    • locationURI: popup:customnavigator.navigator?before=import
  • popup:customnavigator.navigator?before=import (menuContribution) –> New –> command
    • commandId: org.eclipse.ui.edit.copy
    • label: Copy
    • icon: icons/copy_16x16.png
  • popup:customnavigator.navigator?before=import (menuContribution) –> New –> command
    • commandId: org.eclipse.ui.edit.paste
    • label: Paste
    • icon: icons/paste_16x16.png
  • popup:customnavigator.navigator?before=import (menuContribution) –> New –> command
    • commandId: org.eclipse.ui.edit.delete
    • label: Delete
    • icon: icons/delete_16x16.png
  • popup:customnavigator.navigator?before=import (menuContribution) –> New –> separator
    • name: customnavigator.separator
    • visible: true

Doesn’t it look great? It just makes you proud to be a plug-in developer.

The next big question: why did we do that? Or more accurately: where is the documentation for this magic?

My answer is going to be very unsatisfying: I don’t know. I went through a number of plug-ins, web sites and help files and found nothing. When I remembered the Plug-in Spy, and fixed the Shift+Alt+F2 problem (Kubuntu, remember?), I was able to discover the path I was looking for.

However, that is not the reason why this post has taken so long to appear; I have had a lot on my mind and this wasn’t it. In the next post we will add command objects to the New menu items and ignore the Copy/Paste/Delete stuff (those commands need to be configured to recognize our custom types so they copy things properly. They might work our of the box, but since I haven’t thought through all of the implication I will assume that they will have to be changed).

Time to wash up:

  • Go to the Overview tab, click on Externalize Strings Wizard and externalize the strings
  • In plugin.xml click on the MANIFEST.MF tab, click on the light bulb in the left hand margin and select Add Missing Packages

Who’s better than you?

What Just Happened?

The popup menu items have been added! Without behavior!

In addition it was the Plug-in Spy that made it possible for me to create the proper locationURI I needed to insert the new menus in the correct spot.

Don’t underestimate the power of Plug-in Spy.

The cat is not only alive, but curious, which leads one to worry about the cat’s future.

(I hope this answered your question, Augusto.)

Code

No code…again.

bundle.properties

#Properties file for customnavigator
Bundle-Name = Custom Navigator Plug-in
view.name = Custom Plug-in Navigator
category.name = Custom Projects
navigatorContent.name = Custom Navigator Content
customProject.command.label = Custom Project
schemaFile.command.label = Schema File
deploymentFile.command.label = Deployment File
copy.command.label = Copy
paste.command.label = Paste
delete.command.label = Delete

plugin.xml

<?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">
      <viewerActionBinding
            viewerId="customnavigator.navigator">
         <includes>
            <actionExtension
                  pattern="org.eclipse.ui.navigator.resources.*">
            </actionExtension>
         </includes>
      </viewerActionBinding>
      <viewerContentBinding
            viewerId="customnavigator.navigator">
         <includes>
            <contentExtension
                  pattern="customnavigator.navigatorContent">
            </contentExtension>
         </includes>
      </viewerContentBinding>
   </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>
   </extension>
   <extension
         point="org.eclipse.ui.menus">
      <menuContribution
            locationURI="popup:common.new.menu?after=additions">
         <command
               commandId="org.eclipse.ui.newWizard"
               icon="icons/project-folder.png"
               label="%customProject.command.label"
               style="push">
         </command>
         <command
               commandId="org.eclipse.ui.newWizard"
               icon="icons/schema-file_16x16.png"
               label="%schemaFile.command.label"
               style="push">
         </command>
         <command
               commandId="org.eclipse.ui.newWizard"
               icon="icons/deployment-file_16x16.png"
               label="%deploymentFile.command.label"
               style="push">
         </command>
      </menuContribution>
      <menuContribution
            locationURI="popup:customnavigator.navigator?before=import">
         <command
               commandId="org.eclipse.ui.edit.copy"
               icon="icons/copy_16x16.png"
               label="%copy.command.label"
               style="push">
         </command>
         <command
               commandId="org.eclipse.ui.edit.paste"
               icon="icons/paste_16x16.png"
               label="%paste.command.label"
               style="push">
         </command>
         <command
               commandId="org.eclipse.ui.edit.delete"
               icon="icons/delete_16x16.png"
               label="%delete.command.label"
               style="push">
         </command>
         <separator
               name="customnavigator.separator"
               visible="true">
         </separator>
      </menuContribution>
   </extension>

</plugin>

Help! My Eclipse 3.5 Plug-in Editor has Stopped Working!

September 26, 2009 Leave a comment

The other day I went back to work on a plug-in and found that the plug-in editor was misbehaving. I have multiple installs of Eclipse (3.4 and 3.5) installed on (K)ubuntu and I suspected that might be the problem even though I never had a problem with multiple installations of Eclipse before. Heavens! What’s a blogger to do?

In fact I did what most people would do: I went to Google. What I found was Saminda Wijeratne’s blog where the problem was the same, but the solution described was quite different than I eventually discovered. However, I discovered the solution because the blog encouraged me to go to the Eclipse Preferences window and look at the Plug-in Development –> Target Definitions.

At that point I realized that the ${eclipse_home} variable was pointing to my 3.4 installation instead of 3.5! A little bit more digging also led me to discover that I could not change ${eclipse_home} explicitly within Eclipse. The solution is probably specific to Kubuntu: when I added Eclipse 3.4 and 3.5 to KDE using the Menu Editor I did not set the Advanced –> Work Path. I thought Eclipse would be smart enough to get it right, but I turned out to be wrong (not a good habit to get into).

In the image below notice how the Work Path for the highlighted Eclipse 3.5 entry specifically references my 3.5 path.

kdw-menu-editor-eclipse-3.5.
Once that was done, saved and tested there was much joy in Wonderland.

The cat was alive (though it took a while to find it).

Help! I Can’t Find An Executable Version of XML Copy Editor for 64-bit Kubuntu!

September 18, 2009 5 comments

[I hate when things change; like when Dr. Who died and became someone else. Very disturbing. Anyway, the links to XML Copy Editor listed below don’t work as the maintainer of the getdeb site is no longer updating software for anything prior to Ubuntu 9.04. The getdeb XML Copy Editor drop was part of the Jaunty Jackolope distro which I guess was before 9.04. Any software for prior versions is still available on the getdeb archive site at http://old.getdeb.net/ and the 64-bit version of XML Copy Editor can be found at http://old.getdeb.net/release/4263. Sorry for any confusion this might have caused even though I didn’t cause it and the maintainer of getdeb didn’t mean to. So get over it. Download XML Copy Editor and be done with it.]

[Another update: 3/12/10: Going to http://old.getdeb.net/ does not appear to work. Apparently they are working on the legacy side of their site. Be patient.]

And now for something completely different. By different I mean short.

If you have been looking for a great XML editor I would recommend XML Copy Editor. The original goal of this post was to show you how to download the code and all of the dependencies needed to run XML Copy Editor. The last time I downloaded XML Copy Editor it did not come in a ready-to-run form for Kubuntu. I had to download all sorts of dependencies and cut the heads off of a few chickens to get it to work, but work it did and I was happy.

After installing Kubuntu again I found that I needed to revisit the installation of XML Copy Editor. Wouldn’t you know? I forgot to take notes on how I did it. And it was not trivial the last time I did it.

As it turns out there is a web site that contains ready-to-run, pre-baked versions of all sorts of program including XML Copy Editor. The site is getdeb and I also recommend it as a place to find software you might have thought was unavailable on Ubuntu.

I happen to run Kubuntu 64-bit so a search for XML Copy Editor returned XML Copy Editor for Ubuntu Jaunty 32 bit. Scrolling down the page revealed a version available for Ubuntu Jaunty 64 bit which exactly matched my need.

The cat was alive.

These are a few of my favorite things

XML Copy Editor does a number of things rather well:

  • Checks well-formedness
  • Validates the XML using DTDs, XSDs, RELAX NG and others
  • Applies XSL transforms so you can test what it is you are transforming
  • Executes arbitrary XPath on the current file
  • Supports the creation of 26 XML-related file types

Do I have to mention that it also uses colored syntax, element folding and a built in web browser?

XML Copy Editor: download it from getdeb. Install it. Use it.

DBUnit in Eclipse

September 5, 2009 4 comments

Just the other day I was wondering how DBUnit was doing. As a former consultant I used to use DBUnit along with various JUnit extensions on a regular basis.

Given that Eclipse has moved on, JUnit has moved on and DBUnit has moved on I thought I would present a straightforward example of how to use DBUnit with JUnit 4.0 and Eclipse.

Not that much has changed therefore there is not going to be a lot of hand holding here.

Assumptions

Eclipse 3.5
JUnit 4.0 – included with Eclipse
DBUnit 2.4.5
SLF4J 1.5.8 – DBUnit needs this
HSQL DB 1.8.0

I implemented this example on Kubuntu 9.10, if that makes any difference.

If you are new to Eclipse then just download any version that seems reasonable as long as it includes a Java development environment.

The Easy Part

Make sure all of the above software is available somewhere on your machine. If not, install all the software in your favorite places.

Start Eclipse.

The Short Version

  1. Start your database
  2. Create a Java Project
  3. Add DBUnit to your classpath
  4. Write and run a database test
    • Create initial and expected dataset files
    • Extend DBTestCase (inheritance) or use a JUnit class (composition)
    • Implement your test methods

The Longer Version

Start your database

I don’t have a database to run so I downloaded and installed HSQL. To run the HSQL server, which I prefer in examples, open a command window, go to the HSQL folder and run:

java -cp lib/hsqldb.jar org.hsqldb.Server -database.0 file:hiddenclause -dbname.0 xdb

In this case the database name is xdb with the database files named hiddenclause.*. Call your files whatever. I will add test data later.

My Eclipse default configuration includes:
Source folder name: src
Output folder name: classes

Default execution environment: JavaSE-1.6

Create a Java Project

Create a Java Project named DBUnitExample. ‘Nuff said.

Add DBUnit to your classpath

Once the project appears in the Package Explorer, right click on the project name and select Properties –> Java Build Path –> Libraries. Click Add External JARs and add the DBUnit JAR file, in this case dbunit-2.4.5.jar, to the list of libraries in the classpath. Yes, you could also have done this when you first created the project.

Add:
slf4j-api-1.5.8.jar
slf4j-simple-1.5.8.jar
hsqldb.jar
to the classpath as well.

Click OK to close the Properties window.

Write and run a database test

Add Test Data

As running a test on a fresh database is a little difficult start the HSQL Database Manager from another shell (in the HSQL directory):

java -cp lib/hsqldb.jar org.hsqldb.util.DatabaseManager

In the Connect window enter:
Setting Name: hiddenclause example
Type: HSQL Database Engine Server
Driver: org.hsqldb.jdbcDriver
URL: jdbc:hsqldb:hsql://localhost/xdb
User: sa
Password: [leave blank]

Click OK.

Almost done. Select Options –> Insert Test Data. Now we have 4 tables worth of data to test with. Run a delete on the CUSTOMER table so that is is empty.

Close the Database Manager.

Write a Database Test

The steps for writing a DBUnit test are:
1. Create initial and expected dataset files
2. Extend DBTestCase (inheritance) or use a JUnit class (composition)
3. Implement your test methods

Once you get comfortable with that the additional steps are:
1. Create initial and expected dataset files
2. Extend DBTestCase (inheritance) or use a JUnit class (composition)
3. Implement getSetUpOperation() and getTearDownOperation() (optional)
4. Override setUpDatabaseConfig() (optional)
5. Implement your test methods

We’ll just do the first one using the test data created by HSQL.

Create initial and expected dataset files

The DBUnit dataset can come from anywhere (files, databases, spreadsheets, etc.). Where the data comes from is hidden behind the class that implements IDataSet. For this example, we will use XML datasets.

Here is the initial dataset file:
customer-init.xml

<?xml version="1.0" encoding="UTF-8"?>
<dataset.
    <CUSTOMER />
</dataset>

Here is the expected dataset (what we expect to find in the database after executing some code):

<?xml version="1.0" encoding="UTF-8"?>
<dataset>
     <CUSTOMER ID="1"
               FIRSTNAME="John"
               LASTNAME="Smith"
               STREET="1 Main Street"
               CITY="Anycity" />
</dataset>
Extend DBTestCase (inheritance) or use a JUnit class (composition)

The first version of CustomerTest will inherit from the DBUnit class DBTestCase. That is the recommended way of creating a DBUnit test. It uses the JUnit 3.8.2 classes which still works even with the JUnit 4.0 JAR file.

public class CustomerTest extends DBTestCase {
...
    @Override
    protected IDataSet getDataSet() throws Exception {
        ...
    }
}

The getDataSet() method is called to initialize the database before the test. Consider it part of your setup logic. Let’s load the initialization dataset.

    @Override
    protected IDataSet getDataSet() throws Exception {
        return new FlatXmlDataSet(
                 new FileInputStream("customer-init.xml"));
    }

There are a number of properties that need to be set prior to DBUnit doing its magic. You can set those properties in the constructor:

    public CustomerTest(String name) {
        super(name);
        System.setProperty(
          PropertiesBasedJdbcDatabaseTester.DBUNIT_DRIVER_CLASS,
          "org.hsqldb.jdbcDriver");
        System.setProperty(
          PropertiesBasedJdbcDatabaseTester.DBUNIT_CONNECTION_URL,
          "jdbc:hsqldb:hsql://localhost/xdb");
        System.setProperty(
          PropertiesBasedJdbcDatabaseTester.DBUNIT_USERNAME,
          "sa");
        System.setProperty(
          PropertiesBasedJdbcDatabaseTester.DBUNIT_PASSWORD,
          "");

        _customerFactory = CustomerFactory.getInstance();
    }

In real life you would set the driver name, connection URL and username and password to their appropriate values.

Implement your test methods

For this example, we are going to test an insert into the db.

    public void testInsert() throws Exception {
        // insert a customer into the database
        Customer customer = _customerFactory.create("John", "Smith");
        customer.setStreet("1 Main Street");
        customer.setCity("Anycity");
        _customerFactory.update(customer);
...

The code for the CustomerFactory and Customer are at the end of this post.

The data that has just been entered into the database becomes your actual assertable values. Go get them.

        // get the actual table values
        IDatabaseConnection connection = getConnection();
        IDataSet databaseDataSet = connection.createDataSet();
        ITable actualTable = databaseDataSet.getTable("CUSTOMER");

The values defined in customer-expected.xml are what you expect the values to be. Go get them.

        // get the expected table values
        IDataSet expectedDataSet = new FlatXmlDataSet(
                                          new FileInputStream("customer-expected.xml"));
        ITable expectedTable = expectedDataSet.getTable("CUSTOMER");

Check the actual against the expected and complain or not as the case may be.
Assertion.assertEquals(expectedTable, actualTable);
}[/sourcecode]
A version that uses a JUnit class as a wrapper around the DBUnit code looks like this:

/**
 * This is an example only! Use it for anything else at your own risk!
 * You have been warned! Coder/user beware!
 *
 * copyright 2009 Carlos Valcarcel
 */
package hiddenclause.example.dbunit;

import java.io.FileInputStream;

import org.dbunit.Assertion;
import org.dbunit.IDatabaseTester;
import org.dbunit.JdbcDatabaseTester;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.ITable;
import org.dbunit.dataset.xml.FlatXmlDataSet;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

/**
 * @author carlos
 */
public class CustomerJunitTest {

    private CustomerFactory _customerFactory;

    private IDatabaseTester databaseTester;

    @Before
    public void setUp() throws Exception {
        databaseTester = new JdbcDatabaseTester("org.hsqldb.jdbcDriver",
                                                "jdbc:hsqldb:hsql://localhost/xdb",
                                                "sa", "");
        // initialize your dataset here
        IDataSet dataSet = new FlatXmlDataSet(new FileInputStream("customer-init.xml"));

        databaseTester.setDataSet(dataSet);

        // will call default setUpOperation
        databaseTester.onSetup();

        _customerFactory = CustomerFactory.getInstance();
    }

    @Test
    public void testInsert() throws Exception {
        // insert a customer into the database
        Customer customer = _customerFactory.create("John", "Smith");
        customer.setStreet("1 Main Street");
        customer.setCity("Anycity");
        _customerFactory.update(customer);

        // get the actual table values
        IDatabaseConnection connection = databaseTester.getConnection();
        IDataSet databaseDataSet = connection.createDataSet();
        ITable actualTable = databaseDataSet.getTable("CUSTOMER");

        // get the expected table values
        IDataSet expectedDataSet = new FlatXmlDataSet(
                                          new FileInputStream("customer-expected.xml"));
        ITable expectedTable = expectedDataSet.getTable("CUSTOMER");

        Assertion.assertEquals(expectedTable, actualTable);

    }

    @After
    public void tearDown() throws Exception {
        databaseTester.onTearDown();
    }
}

Things to notice:
– less configuration (the System.setProperty() calls are gone)
– explicit creation of a IDatabaseTester object
– explicit call to databaseTester.onSetup()
– explicit call to databaseTester.onTearDown()

Run the Database Test

With all the pieces in place it is now safe to run the CustomerTest DBUnit class. You will probably see some warning messages in the Console view about the data type factory being incorrect. You can safely ignore that error for this example. In real life you probably want to instantiate a new DataTypeFactory based on the database you are using.

If any of the above does not quite work as described let me know and I will update the above explanation.

The Code

customer-init.xml

<?xml version="1.0" encoding="UTF-8"?>
<dataset>
    <CUSTOMER />
</dataset>

customer-expected.xml

<?xml version="1.0" encoding="UTF-8"?>
<dataset>
    <CUSTOMER ID="1"
              FIRSTNAME="John"
              LASTNAME="Smith"
              STREET="1 Main Street"
              CITY="Anycity" />
</dataset>

CustomerTest.java

/**
 * This is an example only! Use it for anything else at your own risk!
 * You have been warned! Coder/user beware!
 *
 * copyright 2009 Carlos Valcarcel
 */
package hiddenclause.example.dbunit;

import java.io.FileInputStream;

import org.dbunit.Assertion;
import org.dbunit.DBTestCase;
import org.dbunit.PropertiesBasedJdbcDatabaseTester;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.ITable;
import org.dbunit.dataset.xml.FlatXmlDataSet;

/**
 * @author carlos
 */
public class CustomerTest extends DBTestCase {

    private CustomerFactory _customerFactory;

    public CustomerTest(String name) {
        super(name);
        System.setProperty(
          PropertiesBasedJdbcDatabaseTester.DBUNIT_DRIVER_CLASS,
          "org.hsqldb.jdbcDriver");
        System.setProperty(
          PropertiesBasedJdbcDatabaseTester.DBUNIT_CONNECTION_URL,
          "jdbc:hsqldb:hsql://localhost/xdb");
        System.setProperty(
          PropertiesBasedJdbcDatabaseTester.DBUNIT_USERNAME,
          "sa");
        System.setProperty(
          PropertiesBasedJdbcDatabaseTester.DBUNIT_PASSWORD,
          "");

        _customerFactory = CustomerFactory.getInstance();
    }

    public void testInsert() throws Exception {
        // insert a customer into the database
        Customer customer = _customerFactory.create("John", "Smith");
        customer.setStreet("1 Main Street");
        customer.setCity("Anycity");
        _customerFactory.update(customer);

        // get the actual table values
        IDatabaseConnection connection = getConnection();
        IDataSet databaseDataSet = connection.createDataSet();
        ITable actualTable = databaseDataSet.getTable("CUSTOMER");

        // get the expected table values
        IDataSet expectedDataSet = new FlatXmlDataSet(
                                          new FileInputStream("customer-expected.xml"));
        ITable expectedTable = expectedDataSet.getTable("CUSTOMER");

        Assertion.assertEquals(expectedTable, actualTable);

    }
    /*
     * (non-Javadoc)
     * @see org.dbunit.DatabaseTestCase#getDataSet()
     */
    @Override
    protected IDataSet getDataSet() throws Exception {
        return new FlatXmlDataSet(
                 new FileInputStream("customer-init.xml"));
    }

}

CustomerFactory.java

/**
 * This is an example only! Use it for anything else at your own risk!
 * You have been warned! Coder/user beware!
 *
 * copyright 2009 Carlos Valcarcel
 */
package hiddenclause.example.dbunit;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * @author carlos
 *
 */
public class CustomerFactory {

    static {
        try {
            Class.forName("org.hsqldb.jdbcDriver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static CustomerFactory getInstance()
    {
        return new CustomerFactory();
    }

    public Customer create(String firstName, String lastName) {
        return new Customer(1, firstName, lastName);
    }

    public void update(Customer customer) throws SQLException {
        Connection connection = DriverManager.getConnection("jdbc:hsqldb:hsql://localhost/xdb");
        String sql = "insert into customer (id, firstname, lastname, street, city) values ("
                   + customer.getId() + ", "
                   + "'" + customer.getFirstName() + "', "
                   + "'" + customer.getLastName() + "', "
                   + "'" + customer.getStreet() + "', "
                   + "'" + customer.getCity() + "'"
                   + ")";

        Statement stmt = connection.createStatement();
        stmt.execute(sql);
        if (stmt.getUpdateCount() != 1) {
            throw new SQLException("Insert failed!");
        }
    }

}

Customer.java

/**
 * This is an example only! Use it for anything else at your own risk!
 * You have been warned! Coder/user beware!
 *
 * copyright 2009 Carlos Valcarcel
 */
package hiddenclause.example.dbunit;

/**
 * @author carlos
 *
 */
public class Customer {

    private int _id;
    private String _firstName;
    private String _lastName;
    private String _street;
    private String _city;

    public Customer(int id, String firstName, String lastName) {
        _id = id;
        _firstName = firstName;
        _lastName = lastName;
    }

    public int getId() {
        return _id;
    }

    public String getFirstName() {
        return _firstName;
    }

    public String getLastName() {
        return _lastName;
    }

    public String getStreet() {
        return _street;
    }

    public String getCity() {
        return _city;
    }

    public void setStreet(String street) {
        _street = street;
    }

    public void setCity(String city) {
        _city = city;
    }

}

Personal Wiki: A Brief Opinionated Review of MoinMoin

July 3, 2009 1 comment

I have just started using MoinMoin as a personal wiki on my Kubuntu/Dell notebook. Why would I do such a preposterous thing?

I have been reading the book Pragmatic Thinking and Learning by Andy Hunt. I will have to review it one day, but suffice it to say that I am on my third reading*.

In Pragmatic Thinking and Learning, Andy Hunt mentions using a wiki to rapidly collect information in a connected, but non-linear, way. The second time I read the book I decided to learn deliberately and when I got to page 221 and read about wikis I started to research what wikis were available, what technology they used and how easy they were to use (wikis by defintion are easy to use, but you never know).**

After much hand-wringing and comparison shopping I decided to download MoinMoin. It is Python-based and does not rely on an external web server or database to work. Installing it was as easy as extracting the archive into my local bin directory and running the Python file wikiserver.py. It starts its own little web server sitting on port 8080 and running Firefox on http://localhost:8080 brought up the home page.

Just to be paranoid I created an account (why would I need to do that on my own local box? Did I mention I was paranoid?) and started creating pages. It was so easy a caveman user could do it.

If you know what a wiki is you don’t need much more information than this to convince you that I enjoyed using MoinMoin. Its use of Python, its ease of installation and ease of use made it almost a no-brainer. I am a Java guy from way back, and as much as I disagree with Python’s use of indentation as a measure of scope, I am quite happy with Python in general. MoinMoin made me even happier.

Give it a shot. Your ideas will thank you.

* Yes, third. The last book I read that many times was Domain-Driven Design by Eric Evans. That is another book that did such a great job of joining ideas that had been floating in my head for years that I recommend it to everyone every chance I get (my mother is still trying to understand what he is talking about, but I am sure she will get it one day. After all, she is 85.).

** Andy Hunt ended the section on wikis by recommending the use of an iPhone with a Ruby-based web server with wiki software to make the collecting of ideas as frictionless as possible. Four out of four dinosaurs disagree.