Showing posts with label Eclipse. Show all posts
Showing posts with label Eclipse. Show all posts

Wednesday, October 8, 2014

Eclipse SWT CheckboxCellEditor hangs on Mac OS X

.. when using the wrong value type.

The CheckboxCellEditor requires an Integer as its value, i.e. the index of one of its labels. When instead providing the label text, the SWT event loop will hang on Mac OS X. The combo editor's setValue method has an assertion to check the value type, but this doesn't result in an Exception with normal settings. Instead, the debugger will typically show that the main loop is stuck in handling the mouse-down event which activated the cell editor.

The fix is simply to provide the correct value, but unfortunately the reason of the hangup is not immediately obvious, there is no exception or log message that indicates the wrong value type as the reason for the hangup.

Wednesday, July 4, 2012

Eclipse E4 Selections, Events, Context Variables

Eclipse 4.2 includes the new "E4" APIs which offer different ways of communication between portions of your Eclipse application.
The Lars Vogel article http://www.vogella.com/articles/Eclipse4Services/article.html nicely lists these, and here are some comments from trying them out.

Selections

In Eclipse 3.x, you used the ISelectionProvider:

ISelectionProvider selections = null;
selections.setSelection(new StructuredSelection(selected_item));

Obtaining the selection provider could be circuitous, and the selection had to be published as an ISelection, typically a StructuredSelection.

On the receiving end, you needed to register a listener to the selection provider and unpack the ISelection.
In Eclipse E4, there is @Inject magic at play that can be difficult to debug, but the resulting code is sure nice:

// In a "GUI creation" routine invoked via @PostConstruct,
// arguments are injected because the @Inject is implied.
// To get an ESelectionService injected into other method,
// a specific @Inject would be required.
@PostConstruct
public void createControls(final Composite parent,
    final ESelectionService selections)
{
    // Create GUI...
    // ... monitor for example selection of list.
    MyModelObject my_selected_object = ...;
    // Publish any selectd model object or array of model objects "as is".
    // No need to wrap into StructuredSelection:
    selections.setSelection(my_selected_object);
});

To receive such a selection in another piece of E4 code:

// E4 will invoke this whenever the active selection changes.
// If the active selection is instanceof MyModelObject, it will be provided.
// Otherwise, null will be sent.
@Inject
public void handleChangedSelection(
    @Optional
    @Named(IServiceConstants.ACTIVE_SELECTION)
    final MyModelObject selected)
{
    // No need to unpack a StructuredSelection.
    // May only have to check for null
    System.out.println("Received changed selection " + selected);
}

If your selection listener happens to only receive null arguments, the reason is likely that the selected object does not match the type that you want to receive. To debug this, change the argument of your selection receiver from MyModelObject to just Object and check the type of the received object.
When porting existing code, you may by accident still publish a StructuredSelection that wraps your MyModelObject class. The E4 framework will not unwrap a StructuredSelection. Just publish and receive the exact class that you want to transfer!

Context Variables

There is only one global selection mechanism. If you want to pass updates on various model items between E4 components, you can use context variables.
Publishing anything into a context variable is as easy as publishing a selection, but note that you can now name the item that you put into the context. This allows you to publish different types of information under different names, effectively having access to multiple selection services.
You can either use a string or a class reference:

@Inject
public void methodThatPublishesContextVariable(final MWindow window)
{
    MyModelObject my_selected_object = ...;

    final IEclipseContext context = window.getContext();
    context.declareModifiable("my_item");
    context.set("my_item", my_selected_object);
}

Receiving the item updates is very similar to receiving the selection:

// E4 will invoke this whenever the named context variable changes.
@Inject
public void handleChangedItem(
    @Optional
    @Named("my_item")
    final MyModelObject item)
{
    // May have to check for null
    System.out.println("Received changed item " + item);
}

It is important to remember that the context is hierarchical!
In the publishing code it is tempting to directly ask E4 to inject the context like this instead of going via the MWindow as shown before:

@Inject
public void methodThatPublishesContextVariable(final IEclipseContext context)
{
    ...
    context.set("my_item", ...);
}

This will not work as expected! The context that your part gets injected will be the context of your part. You will then publish the context variable for "my_item" within that local context, and updates are not received by other parts. By instead asking for the window to be injected and publishing to the window's context, all parts within that window will receive updates:

@Inject
public void methodThatPublishesContextVariable(final MWindow window)
{
    final IEclipseContext context = window.getContext();
    ...
    context.set("my_item", my_selected_object);
}

If you want all windows of your application to receive updates, you can even use the application's context:

@Inject
public void methodThatPublishesContextVariable(final MApplication app)
{
    final IEclipseContext context = app.getContext();
    ...
    context.set("my_item", my_selected_object);
}

The scoped, hierarchical nature of the context variable mechanism therefore allows you to control who receives the updates: The same part, all parts in the window, or everything in the application.

Event Broker

Finally, the IEventBroker provides a lower level mechanism to post and receive events. When posting events, you can decide to simply post them in a fire-and-forget mode, or send them and wait for the receivers to handle them:

class MyClass
{
    // Receive event broker.
    // Could also fetch in code via
    // IEclipseContext.get(IEventBroker.class)
    @Inject
    private IEventBroker event_broker;
    
    void codeThatSendsEvents()
    {
        MyModelObject my_object = ...;
        event_broker.post("my_object", my_object);
    }

The 'post()' shown here is the fire-and-forget way. Use 'send()' to wait for receivers to handle the event.
To receive events for the topic "my_object" that carry data of type MyModelObject, use the following:

@Inject
public void receiveEvent(
    @Optional
    @UIEventTopic("my_object") final MyModelObject item)
{
    System.out.println("Received " + item);
}

When replacing @UIEventTopic with @EventTopic, events will be received on some event handling thread. The annotation @UIEventTopic asserts that events are received on the user interface thread, which is useful if your event receiver intends to make UI modifications, for example display the event in SWT widgets.




Friday, June 15, 2012

Eclipse Plugins with Native Code for Multiple Platforms

Eclipse plugins can contain native code. Since the native code is specific to a certain architecture, this should probably be put into a fragment that is then added to the 'main' plugin depending on the architecture.

Such fragments can support multiple platforms, for example Linux on both 32 and 64 bit CPUs, by adding something like this to the MANIFEST.MF:

Eclipse-PlatformFilter: (& (osgi.os=linux) (| (osgi.arch=x86)(osgi.arch=x86_64)))
Bundle-NativeCode
 lib/linux/x86/mylib.so;    osname=linux; processor=x86,
 lib/linux/x86_64/mylib.so; osname=linux; processor=x86_64

On Linux, the correct library for either CPU type will be now available.Excellent!

However, when combining such plugins into a feature-based product, a problem arises. Assume you have a fragment for windows, one for Linux, one for OS X. When you add the fragments to the product's feature, you must again specify their architecture:

   plugin
         id="org.mylib.linux"
         os="linux"
         arch="x86"
         ...
If you don't specify the os and arch in the feature, the build will fail: Eclipse will try to include your plugin on both Windows and Linux, but then complain that the "linux" plugin doesn't work on Windows and vice versa.

If you do specify the os and arch, however, you can only list one arch, even though our linux fragment would work on both x86 and x86_64.

The solution is to list the same fragment again in the fragment.xml with the other os and arch settings:

   plugin
         id="org.mylib.linux"
         os="linux"
         arch="x86_64"
         ...

Note that you may have to do this directly in the feature.xml. The feature editor's Plug-Ins tab doesn't support adding an already included plugin multiple times, but once you did add it in the feature.xml, you can view and edit it in there.

Wednesday, February 29, 2012

Eclipse JFace 'VIRTUAL' TreeViewer basically requires TreeColumnLayout?

When switching a TreeViewer from an ITreeContentProvider to a 'VIRTUAL' TreeViewer with ILazyTreeContentProvider, the tree display initially appeared blank. The items in the tree would only become visible after waiting a little, or by doing some window operations that result in a refresh of the tree. This happened especially on Mac OS X.

After looking closer, it became obvious that the one and only column of the tree had a nearly zero width. Note the arrow in the image that shows the column separator:




The issue seems to be that a non-VIRTUAL TreeViewer knows all its items right away and can size the tree columns appropriately. When swtiching to a VIRTUAL TreeViewer, the items are updated as needed, and the column refresh can lag.

Early "fixes" involved forcing a refresh after setting the TreeViewer input:

tree.setRedraw(false);
tree_viewer.setInput(config);
tree_viewer.refresh();
tree.setRedraw(true);

or

tree_viewer.expandAll();

But the best workaround seems to be to use a TreeColumnLayout that always auto-sizes the one and only column:


// Note that the TreeViewer needs to be the only widget
// under the parent widget. If necessary, add Composite
// to wrap the TreeViewer
final TreeColumnLayout layout = new TreeColumnLayout();
parent.setLayout(layout);
final TreeViewer v = new TreeViewer(shell, SWT.VIRTUAL | SWT.BORDER);
v.setLabelProvider(new LabelProvider());

Friday, February 3, 2012

Avoid Soft Links in Eclipse Headless build - or ant in general?

Ran into a really strange problem.
As a result of a headless Eclipse product build, I usually get an abc.app for Mac OS X.
But this time around I got an abc.app for Mac OS X that "worked", but the program icon was wrong. In addition, there was an Eclipse.app directory that's mostly empty.
Products for other architectures (Linux, Windows) looked OK.

Apparently, the build process had first put the Eclipse.app in place, tried to assign the icon etc., and then renamed it to the actual product name abc.app, but something failed in the process. The Eclipse.app partially remained in place, and there was no icon.

Solution: I had recently changed the build directory to /tmp. On Mac OS X, /tmp is a soft link (symbolic link) to /private/var. Either the Eclipse headless build or maybe ant in general has problems with soft links. After using a "real" directory path without any soft links as the build directory, things were fine again.

Saturday, August 13, 2011

Mercurial seems to hang in SourceForge connection because of host key change

Had a problem where mercurial seemed to hang forever in a SourceForge transaction.
It was run from within Eclipse via MercurialEclipse, and there was no indication as to
what's happening nor any way to stop it other than to kill Eclipse.

This was under Windows with hg calling putty, which in turn was configured to use an ssh key pair registered with SourceForge that had worked OK some time ago.

When executing hg from the command line, it would also hang, but I could stop it with Control-C, and then it would show the following message:

hg clone ssh://name@....hg.sourceforge.net/hgroot/....
interrupted!
remote: The server's host key is not cached in the registry. You
remote: have no guarantee that the server is the computer you
remote: think it is.
remote: The server's rsa2 key fingerprint is:
remote: ssh-rsa 2048 86:7b:1b:12:85:35:8a:b7:98:b6:d2:97:5e:96:58:1d
remote: If you trust this host, enter "y" to add the key to
remote: PuTTY's cache and carry on connecting.
remote: If you want to carry on connecting just once, without
remote: adding the key to the cache, enter "n".
remote: If you do not trust this host, press Return to abandon the
remote: connection.
remote: Store key in cache? (y/n) ^C

Again this was under Windows. On a real operating system the host key change prompt might have appeared before the Ctrl-C and thus be more obvious.

Anyway, the fix:

Run
putty -i path\to\the\key.ppk
once which will show the same host key change prompt and this time you can accept it.

From then on, hg works OK again.

Friday, July 15, 2011

Change Eclipse plugin_customization.ini via feature

Eclipse has an elaborate hierarchical preference mechanism:
  • Plugins have a preferences.ini.
  • The product can override the settings of any plugin via a plugin_customization.ini file
  • Finally you can provide your own defaults via a command-line option -pluginCustomization /path/to/my/settings.ini.
When you create products, you typically include a plugin_customization.ini file in your product.

What if you need to create products with different settings?

Can you put the plugin_customization.ini file into fragments for your product plugin? That doesn't work. Plugin customization.ini files in fragments seem to be ignored.

But here's what you can do: Fake localization.

In your product plugin, have a plugin_customization.ini file that looks like this:

some.plugin/some_setting=%some_value

Then, in a fragment of the product plugin, place a plugin_customization.properties file that contains

some_value=Value A

In another fragment, you can have

some_value=Value B

By loading the appropriate fragments, for example from an update site, you can now install the settings that you want!

Thursday, March 10, 2011

"Portable" Eclipse Projects

When you create a new Eclipse 'Plug-in' project, its initial configuration will lock to your current JRE and compiler settings.
When you then share that project with other people, they will see compiler errors because you may have used Java 1.6_19 on Linux while they use Java 1.6_20 on Windows.

To make your project more portable, do this:

  1. In the Package Explorer, right-click on your Plug-in Project and select "Properties"
  2. Under "Java Build Path", select tab "Libraries", item "JRE System Library", button "Edit". It should default to a specific "Execution environment" like "JavaSE1-6 (MacOS X 1.6.0 System). Change that to "Workspace default JRE", meaning: Use whatever the developer has configured in her workspace.
  3. Under "Java Compiler", by default "Enable project specific settings" will be checked. Uncheck that, meaning: Use the compiler settings that the developer has selected in her workspace.
  4. When you now switch to the Navigator view, you should find that the ".settings" directory that previously contained project-specific compiler settings is now empty. You can delete it.
After these steps, developers on other operating systems with slightly different java versions will have fever problems when they try to use your Plug-in source. Your MANIFEST.MF can still require a certain execution environment, so you are not loosing much control.

Tuesday, January 18, 2011

Eclipse Build Path Problem After Mac OS X Java Update

In early January 2011, I received a Mac OS X Software Update that included Java changes.
This was on a Mac that had been upgraded to Snow Leopard, so older Java setups were still present, but this update must have removed older JVMs and JDKs.

As a result, Eclipse builds would fail with this error:
The container 'JRE System Library [J2SE-1.5]' references non existing library '/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Classes/laf.jar'
In general, the OS X Java setup changed from using
/System/Library/Frameworks/Java.VM.framework/Versions/...
to using a path like
/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home

After going to Eclipse/Preferences/Java/Installed JREs and "Add..."ing a new JVM that uses the above path with ".../JavaVirtualMachines/..." all is fine again. You might have to look for the full path to that .../Home in a terminal window and copy/paste it into the Eclipse preference dialog, because the "Browse" button in the dialog might only show the 1.6.0.jdk as a package, not as a subdirectory into which you can drill down.

Next issue: You might not have a src.jar in that JDK to be able to view the Java sources, so you cannot view the source code for String, Map, ... and the other standard Java classes. That's because the default JDK is really more like a JRE.

After downloading the Java Development package from the Apple Developer Connection, something like javadeveloper_10.6_10m3261.dmg, you get a new JDK in

/Library/Java/JavaVirtualMachines/1.6.0_22-b04-307.jdk

and that one has a Content/Home/src.jar.
Note that the JDK that you install yourself, the one that includes the sources, is under /Library/Java/... while the Java stuff that comes with the OS is under /System/Library/Java/...

Eclipse should automatically detect the src.jar in the JDK that you install.

Note on finding the Java Development package as of August 2011:
  • http://developer.apple.com/
  • Member Center
  • Dev Centers: Mac
  • Resources
  • Mac OS X Developer Downloads
  • Java
  • Java for Mac OS X ... Developer ...

Friday, January 14, 2011

Eclipse Draw2D and GEF Sources, Online Help

When installing the Eclipse IDE for RCP development, it includes the Draw2D and GEF binaries, but not the sources. At least not in the Mac OS X version for Eclipse 3.5 and 3.6(.1).

How to get them: Also download the "Modeling" version of the IDE, and copy the following plugins from that into your RCP IDE's plugins directory:
  • org.eclipse.draw2d.doc.*.jar
  • org.eclipse.draw2d.source_*.jar
  • org.eclipse.gef.doc.*.jar
Yes, this contradicts everything you ever learned about P2, but it seemed the simplest way to get the sources & help.

Thursday, May 13, 2010

Features for Multi-OS Plugins

Assume you have a plugin for more than one, but not all platforms. One that may run on Windows and Linux, but not OS X. Assume it's called the "non_osx_tool" plugin, and the plugin's MANIFEST.MF contains a filter:

Eclipse-PlatformFilter: (| (osgi.os=linux) (osgi.os=win32))

Fine.

Now you switch to P2, and base your Product on Features. So there's a feature that lists this plugin. If you just list the plugin, then try to compile for all OS, all will look OK, but installation will fail on OS X because the feature requires the installation of the "non_osx_tool" plugin, which in turn declares itself unavailable for OS X.

You can specify in feature.xml that a plugin is OS-specific:

<plugin id="non_osx_tool" os="linux" ...

That way, the installation will work better because the feature will only trigger installation of the non_osx_tool on Linux. But you can only list one OS, Linux or Windows, not both.
I tried to use os="linux,win32" but that resulted in compiler errors The type ... cannot be resolved. It is indirectly referenced from required .class files referring to code in dependent plugins which were suddenly not found. Listing multiple architectures is either unsupported, or uses a format that I couldn't find.

Solution:
Create additional features "my_feature.win32" and "my_feature.linux". They each list the plugin for only win32 or linux, and the top-level feature then includes both these sub-features with a filter:

<includes
id="my_feature.linux"
version="0.0.0"
os="linux"/>
<includes
id="my_feature.win32"
version="0.0.0"
os="win32"/>

Sunday, May 9, 2010

Copyright Header Utility

Found this Copyright wizard for Eclipse http://www.wdev91.com/?p=cpw_ug that works very well! Download zip, add single jar to dropins or use update manager, then invoke menu Project/Apply Copyright... and it helps to
  • Determine the text based on EPL or other examples
  • Add that to all *.java files or even other file types (see Preferences/General/Copyright)
  • Update previously entered copyright headers to make them all consistent

Friday, May 7, 2010

Product Editor Bug

When switching to P2 and changing from plugin-based to a feature-based product, the application suddenly refused to start because of problems in the config.ini.

Traced down to misleading product editor, https://bugs.eclipse.org/bugs/show_bug.cgi?id=312086

Default Eclipse Workspace via config.ini

By default, the workspace of an RCP app is somewhere inside the install location, and might actually differ for Linux, Windows, OS X or different Eclipse releases.
I needed a location in the user home directory, independent from the OS, and not affected by updates (including complete replacement) of my RCP application.
The solution is adding something like this to the RCP's config.ini:

# Set default workspace location
osgi.instance.area.default=@user.home/MyRCPAppWorkspace

In the *.product file editor, the Configuration section allows you to specify a custom config.ini to accomplish this, but that brought up another problem: The original content of the config.ini beyond my workspace location settings, entries like osgi.framework=file\:plugins/org.eclipse.osgi_3.5.2.R35x_v20100126.jar, changes with Eclipse releases, so you have to continually update your custom config.ini?

Solution with P2: Use the auto-generated config.ini, and instruct P2 to add your custom content by adding a file p2.inf to your product with the following content:

# Add the following to the generated config.ini
instructions.install = \
setProgramProperty(propName:osgi.instance.area.default,propValue:@user.home/MyRCPAppWorkspace);

Tuesday, May 4, 2010

Learning Eclipse P2

Good intros: http://www.vogella.de/articles/EclipseP2Update/article.html ,
http://www.slideshare.net/irbull/p2-introduction.

Exporting a feature with P2 info from the IDE is quite straight forward.

When adding the P2 UI to the final product by adding the feature org.eclipse.equinox.p2.user.ui, I had strange problems under Eclipse 3.5.2:
Product wouldn't start, or not include the P2 UI, or not have much P2 information.
It only works halfway from within the IDE, and only after the run-configuration is deleted and re-created.

To export a working product:
Include org.eclipse.equinox.p2.user.ui with either the full version number, or use 0.0.0, but beware that this must be entered manually because of https://bugs.eclipse.org/bugs/show_bug.cgi?id=279480

This will provide a product with the P2 GUI, but About/Installation Details would be nearly empty, Configuration completely blank unless also exporting with metadata.
Checking the "metadata" option on export combined with source export, however, results in error "gather.sources" does not exist because of bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=286940.
Export with meta data but without sources works OK.

Info about plugins/features in general, based on the old update mechanism: http://www.eclipse.org/articles/article.php?file=Article-Update/index.html Includes tip to always end the update site link with "/"!

Merging repositories, for example a repository resulting from a new stable version into the 'main' repository on a web site:

Remaining issue:
  • OK to export product, based on features, into repository
  • OK to export additional feature into repository, then install into product via UI
  • OK to export update for that additional feature, and update product via UI
What doesn't seem to be possible:
  • Export update for feature in product to repository. Update fails with message regarding conflict between the new plugin from the updated feature and the original plugin that the product requires
Workaround: Always update the whole product, including version of the whole product, then the old product can update itself.