#!/bin/bash FILES=/path/to/eclipse/plugins/*jar for f in $FILES do echo "Processing $f file\n:" jar xf $f icons doneAfter running this script an icon folder will be created with all the icons extracted from the plugins directory. I suppose next logical step would be to enhance this script to query Eclipse repository directly.
Programming Barn
Collection of notes on common problems and issues I faced while doing day to day programming
Monday, August 10, 2015
Extracting icons from Eclipse directory
I am always in need for icons that I want to use in my own plugins. Unfortunately hunting them down is quite a task that involves finding plugins that contain the icons, opening jar files and extracting the icons. To ease this task I wrote a little script that does this for you
Thursday, January 8, 2015
What to do when getting error "Profile id _SELF_ is not registered." when working with p2 API
This came up while I was writing some code using p2 API to uninstall certain features at launch of my product. No matter what I did I was getting this dreaded message that made little sense to me. Well, it made some sense, but how do I register this _SELF_ profile? Turns out all I needed to do was to check checkbox "Support software installation in the launched application" in Configuration tab of Launch configuration. After this whenever the following code was executed, a Profile(SelfHostingProfile) would get returned.
IProfileRegistry registry = (IProfileRegistry) agent.getService(IProfileRegistry.SERVICE_NAME);This forum post was a big help in resolving this issue. I wish the exception I was getting was more verbose as it seems the only fix for it is to check that checkbox.
IProfile selfProfile = registry.getProfile(IProfileRegistry.SELF);
Wednesday, November 20, 2013
Customizing item provider adapter in EMF
Tuesday, November 12, 2013
Making Annotation part of the model when generating EMF model
When generating EMF model from XSD or otherwise it is beneficial to make annotations such as documentation part of the model. This information can be used to communicate to the user what particular model object does. Unfortunately while this seems like a easy task it did not work for me right away.
There is a nifty class EcoreUtil that has vast amount of information that you can get from your model. One of the methods that was useful to me was EcoreUtil.getDocumentation(EModelElement element) and to use it all I need to do is:
However, I was just not getting my annotation which in fact had URI of http://www.eclipse.org/emf/2002/GenModel. Looking in GenModel class that is responsible for generating my model, there was a method GenModel.setSuppressGenModelAnnotations(boolean bool). Naming of the method suggests what it does and in fact in my genmodel's Model properties there is an entry 'Suppress GenModel Annotations' which is set to 'true' by default. Setting this property to false generated my annotations. I am still not sure why it's set to 'true' by default as setting to 'false' would make more sense in my opinion.
There is a nifty class EcoreUtil that has vast amount of information that you can get from your model. One of the methods that was useful to me was EcoreUtil.getDocumentation(EModelElement element) and to use it all I need to do is:
EObject myObj = ... String documentation = EcoreUtil.getDocumentation(myObj.eClass());Simple enough, but it did not work. I was always getting null for documentation. Looking further and doing some debugging in getDocumentation() method I saw that first line was:
protected static final String GEN_MODEL_PACKAGE_NS_URI = "http://www.eclipse.org/emf/2002/GenModel"; ... EAnnotation eAnnotation = eModelElement.getEAnnotation(GEN_MODEL_PACKAGE_NS_URI);Which suggests that obviously code should look for annotations with GEN_MODEL_PACKAGE_NS_URI.
However, I was just not getting my annotation which in fact had URI of http://www.eclipse.org/emf/2002/GenModel. Looking in GenModel class that is responsible for generating my model, there was a method GenModel.setSuppressGenModelAnnotations(boolean bool). Naming of the method suggests what it does and in fact in my genmodel's Model properties there is an entry 'Suppress GenModel Annotations' which is set to 'true' by default. Setting this property to false generated my annotations. I am still not sure why it's set to 'true' by default as setting to 'false' would make more sense in my opinion.
Thursday, August 8, 2013
Performing conditional checkout when building with Maven/Tycho
One of the things I really loved about building with Buckminster was its support for conditional component materialization, more about it here. This is one of the features I missed when I moved build system to Maven/Tycho, how am I suppose to checkout pluginA and pluginB from trunk, but pluginC from branchA? I also wanted to brush up on my Groovy skills because I haven't used it in quite some time.
The idea I head on which components to checkout was to query parent (super) POM of my parent plugin. Each parent POM contains modules section that describes what are the modules that make up the build. One I query the parent POM, I would create a collection of modules and use that information to either checkout or update working directory, in my case Jenkins workspace. Below is the groovy script that I wrote.
Here is the .query file that is used by the script to decide whether to checkout components from branch or trunk.
The idea I head on which components to checkout was to query parent (super) POM of my parent plugin. Each parent POM contains modules section that describes what are the modules that make up the build. One I query the parent POM, I would create a collection of modules and use that information to either checkout or update working directory, in my case Jenkins workspace. Below is the groovy script that I wrote.
package com.iwaysoftware.integration.tools.parent /* * Tycho/Maven builds rely on the fact that components already exist in build workspace (Jenkins in our case). * There is no easy way to checkout what's needed especially with some logic involved. * * This groovy script checks out components from SVN repository and relies on information in parent POM, located in this plugin. * This script will parse POM file and construct a collection of <module> elements, currently module element looks as following: * * <module>../{componentName}</module> * * Name of component will be normalized to just its name. * * The convention in our build is that parent plugin is checked out using Jenkin's SCM and build.xml is called, build.xml in turn executes * this groovy script. Parent plugin MUST end with ".parent". * * Following construction of collection, workspace directory will be checked for existance of component that ends with "parent". * If such directory exists and size of directories is 1, checkout will be performed. Otherwsie update will be done. */ import java.util.logging.ConsoleHandler; import java.util.logging.Logger import groovy.io.FileType import groovy.util.logging.Log; import groovy.util.slurpersupport.NodeChild; public class Checkout{ static def pomFile static def svnRoot static def svnProjectDir static def workspacePath static def svnDir static def queryFile static def ant static Logger logger = Logger.getLogger(Checkout.class.toString()) // namespace of the components. This is used to decide whether checkout or update will be performed static def namespace = "com.iwaysoftware" public static void main(String[] args) { pomFile = args[0] svnRoot = args[1] svnProjectDir = args[2] workspacePath = args[3] svnDir = args[4] queryFile = args[5] /*CustomFormatter formatter = new CustomFormatter() ConsoleHandler handler = new ConsoleHandler() handler.setFormatter(formatter) logger.addHandler(handler)*/ logger.info("Script arguements:") logger.info("pomFile = " + args[0]) logger.info("svnRoot = " + args[1]) logger.info("svnProjectDir = " + args[2]) logger.info("workspacePath = " + args[3]) logger.info("libDir = " + args[4]) logger.info("queryFile = " + args[5]) ant = new AntBuilder() ant.typedef(resource: 'org/tigris/subversion/svnant/svnantlib.xml'){ classpath { fileset(dir: svnDir, includes: '*.jar') } } new Checkout().startCheckout() } Checkout(){ } private void startCheckout(){ // parse POM file and construct collection modules consisting of module names def records = new XmlSlurper().parse(new File(pomFile)) def modules = records.depthFirst().findAll{ it.name() == 'module' } logger.info("modules.size = " + modules.size()) def advisors = getAdvisors(queryFile) // normalize collection items by stipping leading '../' modules = modules.collect { it.toString().substring(3, it.toString().size()) } // Query workspace directory for presence of a directory (plugin), here convention is that // parent plugin with parent POM is checked out first following by call to build.xml in the plugin. // Depending on component size and its values either checkout or update will be performed. def components = [] logger.info("workspace = " + workspacePath) def workspaceLocation = new File(workspacePath) workspaceLocation.eachFileRecurse (FileType.DIRECTORIES) { file -> if(file.name.startsWith(namespace)){ components << file } } logger.info("components.size = " + components.size()) // check if components collection is of size one and name of directory (plugin) ends with "parent" if(components.size() == 1 && components[0].toString().endsWith("parent")){ logger.info("modules = " + modules) modules.each { def checkoutUrl = svnProjectDir + "/" + it logger.info("checkoutUrl = " + checkoutUrl) logger.info("workspace = " + workspacePath) def workingDirectoryPath = workspacePath + "/" + it logger.info("workingDirectoryPath = " + workingDirectoryPath) if(advisors.containsKey(it)){ checkoutUrl = constructCheckoutUrl(it, advisors) } logger.info("checkout url:" + checkoutUrl) // start checkout of components in modules collection ant.svn(javahl: 'false', svnkit: 'true'){ checkout(url: checkoutUrl, destPath: workingDirectoryPath) } } } // workspace directory already contains checkout components, perform update else if(components.size() > 1){ logger.info("modules.size = " + modules.size()) modules.each { logger.info("updating " + it) def updateDir = workspacePath + "/" + it ant.svn(javahl: 'false', svnkit: 'true'){ update(dir: updateDir) } } } } /* * Iterates branches List and checks whether SVN location at ${svnRoot}/branches/${branch}/${module} exists. * If it does matched SVN location will be checked out, if not another branch from the List is considered, * if none of the SVN branch locations exist, module will be checked out from trunk. */ private String constructCheckoutUrl(String module, Map advisors){ def branches = advisors.get(module) for(branch in branches){ try{ ant.svn(javahl: 'false', svnkit: 'true'){ info(target: svnRoot + "/branches/" + branch + "/" + module) } def url = svnRoot + "/branches/" + branch + "/" + module logger.info("constructed url: " + url) return url } catch(e){ logger.warning("No SVN INFO for " + svnRoot + "/branches/" + branch + "/" + module) continue } } return svnProjectDir + "/" + module } /* * Reads advisor elements from .query file and constucts map of component:modules[:] * <advisor component="com.iwaysoftware.eclipse.workspace" branch="adapter,test"/> */ private Map getAdvisors(String queryFile) { def root = new XmlSlurper().parse(new File(queryFile)) def advisorsList = root.depthFirst().findAll{ it.name() == 'advisor' } def advisorsMap = [:] advisorsList.each { def key def branches = [] if(it instanceof NodeChild){ def attributes = ((NodeChild)it).attributes() key = attributes.get("component") branches = attributes.get("branch").split(",") advisorsMap.put(key, branches) } } logger.info("advisors: " + advisorsMap) return advisorsMap } }And here the ant script that calls this groovy script
<?xml version="1.0" encoding="UTF-8"?> <project name="svnCheckout" default="checkout"> <property environment="env"/> <property name="svn.root" value="/path/to/svn/root"/> <property name="svn.project.dir" value="/path/to/svn/project/root"/> <property name="svn.lib" location="/path/to/svn/libs" /> <property name="groovy.lib" location="/path/to/groovy/libs" /> <property name="workspace" location="${env.WORKSPACE}" /> <property name="basedir" value="." /> <property name="groovy.script" location="/path/to/groovy/script/Checkout.groovy" /> <property name="advisors" location="${basedir}/adapterBranch.query"/> <taskdef name="groovy" classpath="${groovy.lib}/groovy-all-2.1.3.jar" classname="org.codehaus.groovy.ant.Groovy" /> <target name="checkout"> <echo>${groovy.script}</echo> <groovy src="${groovy.script}"> <!-- pom file --> <arg line="${basedir}/pom.xml"/> <!-- SVN root --> <arg line="${svn.root}"/> <!-- SVN location of project that contains components to be build --> <arg line="${svn.project.dir}"/> <!-- workspace, if using Jenkins use ${env.WORKSPACE} --> <arg line="${workspace}"/> <!-- location of SVNAnt jars --> <arg line="${svn.lib}"/> <!-- location of advisors query file --> <arg line="${advisors}"/> </groovy> </target> </project>As you can see this script just calls groovy script with needed parameters.
Here is the .query file that is used by the script to decide whether to checkout components from branch or trunk.
<advisors> <advisor component="pluginA" branch="adapter"/> <advisor component="pluginB" branch="adapter"/> <advisor component="featureA" branch="adapter"/> <advisor component="featureX" branch="adapter"/> </advisors>There are still things to be done to improve this script. Adding regular expressions to .query files to make file smaller in cases that there are a lot of repetition of components. Addition of consideration of tags SVN directory is something that will be useful as well. Right now during update I go through collection of checked out components and update them all. Updating can be costly task (time wise), so using svn info command to compare revisions will cut update time.
Thursday, July 25, 2013
Editing TreeViewer's cell with two clicks
With introduction of ColumnViewerEditorActivationStrategy in Eclipse 3.3 there is an ability to control when cell of a viewer gets activated for editing. Unfortunately the events for cell selection is limited to ColumnViewerEditorActivationEvent.MOUSE_CLICK_SELECTION and ColumnViewerEditorActivationEvent.MOUSE_DOUBLE_CLICK_SELECTION as far mouse events go. MOUSE_CLICK_SELECTION was not something I wanted to do because I didn't want cell editing to be activated each time selection changes in TreeViewer. I did not want to resort to MOUSE_DOUBLE_CLICK_SELECTION either because something else was suppose to happen on double-click in my case. I needed a way to enable cell editing when user click on a cell once and then again to edit.
The solution I found was suggested by David Green (http://greensopinion.blogspot.com/2009/11/treeviewer-two-clicks-to-edit.html). However it did not work in my case. I am not sure exactly why, may be because I was using Nebula's Grid Widget (although it uses the same interfaces as TreeViewer) or custom EditingSupport. I've spend some time figuring out what was the problem, but then decided to take a different approach. Below is the code for my ColumnViewerEditorActivationStrategy implementation.
import org.eclipse.jface.viewers.ColumnViewer; import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent; import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.swt.events.MouseEvent; class SecondClickColumnViewerEditorActivationStrategy extends ColumnViewerEditorActivationStrategy implements ISelectionChangedListener { private int counter = 0; public SecondClickColumnViewerEditorActivationStrategy(ColumnViewer viewer) { super(viewer); viewer.addSelectionChangedListener(this); } @Override protected boolean isEditorActivationEvent(ColumnViewerEditorActivationEvent event) { counter++; if(counter == 1){ return false; } // this is in case when user clicked on tree node once, but second time activated context menu by clicking on right button, // we don't want to activate cell editing in this case else if(counter > 1 && isRightMouseClick(event)){ return false; } else{ return true; } } public void selectionChanged(SelectionChangedEvent event) { counter = 0; } /** * Determine if right mouse button was clicked * @param event * @returnAs you can see the editing enablement is controlled by counters. The important thing here is chain of calls between selectionChanged() and isEditorActivationEvent() methods. When user clicks on cell selectionChanged() gets called, and all subsequential clicks are handled by isEditorActivationEvent() method where counter is being incremented and appropriate return value is set. Note use of isRightMouseClick() call in isEditorActivationEvent(), I did not want to activate both context menu on the cell and editing when user clicked on a tree node and then activated context menu by clicking on right mouse button.true
if right mouse button was clicked,false
otherwise. */ private boolean isRightMouseClick(ColumnViewerEditorActivationEvent event){ return event.eventType == ColumnViewerEditorActivationEvent.MOUSE_CLICK_SELECTION && ((MouseEvent)event.sourceEvent).button == 3; } }
Friday, July 12, 2013
Scrolling draw2d ScrollPane using mouse wheel
Today I was working on a project where there was a need to scroll draw2d ScrollPane using only mouse wheel. Why? Because in this particular project there is a tree drawn using draw2d Figures and to the left of it a Nebula Grid. I won't go in details of why that is, but both trees needed to be scrolled using Grid's scroll bar. However, since draw2d tree had no scroll bar visible (by design), I still wanted to give user ability to scroll the tree using mouse wheel since the wheel is pretty much standard on all modern mice.
There is no mouse wheel listener for ScrollPane or Viewport, but I found a nice little helper interface MouseWheelHelper. This interface has just one method:
void handleMouseWheelScrolled(Event event);From there it was just a matter of finding the right variable that stores scroll value:
public class MyEditPart extends TreeEditPart implements MouseWheelHelper{ private static final int SCROLL_OFFSET = 10; ... ... @Override // subtracting or adding values below controls direction of the scrolling public void handleMouseWheelScrolled(Event event) { pane.scrollVerticalTo(pane.getViewport().getVerticalRangeModel().getValue() - (event.count * SCROLL_OFFSET)); } }That's it. Now when user clicks into the tree and uses scroll wheel the tree with scroll. What's neat is that by changing value of SCROLL_OFFSET you can speed up or slow down the scrolling. Of course this would not work for draw2d only case, because my ScrollPane was inside an EditPart that was already part of gef stack and that's why I could take advantage of MouseWheelHelper interface.
Subscribe to:
Posts (Atom)