Friday Jul 06, 2012

Eclipse and NetBeans replacing embedded IDEs (part 2 and part 3)

After part 1, in Embedded Insights, the series Eclipse and NetBeans replacing embedded IDEs by principal analyst Robert Cravotta continues below.

Many embedded tool developers are choosing to migrate their embedded development toolset to an open source IDE platform for a number of reasons. Maintaining an up-to-date IDE with the latest ideas, innovations, and features requires continuous effort from the tool development team. In contrast to maintaining a proprietary IDE, adopting an open source IDE platform enables the tool developers to leverage the ideas and effort of the community and take advantage of advances in IDE features much sooner and without incurring the full risk of experimenting with new features in their own toolsets. Both the Eclipse and NetBeans platforms deliver regular releases that enable tool developers to more easily take advantage of the newest features in the platform architecture. 

Read more of part 2 here, in an article published Thursday, May 17th, 2012.

Both the NetBeans and Eclipse projects began as development environments and both evolved into platforms that support a wider array of software products. Both platforms have been actively supported and evolving open source projects that have competed and coexisted together for the past decade and this has led to a level a parity between the two platforms. From the perspective of a tool developer, applications are built the same way on either platform – the difference is in the specific terminology and tools.

Read more of part 3 here, in an article published Tuesday, June 12th, 2012.

And, as a bonus in this blog entry, here's how to get started creating an IDE on the NetBeans Platform

http://netbeans.dzone.com/how-to-create-commercial-quality-ide

Thursday Jul 05, 2012

Feed Reader Fix

In the FeedReader sample (available in the New Projects window), there's this piece of code:

private static Feed getFeed(Node node) {
    InstanceCookie ck = node.getLookup().lookup(InstanceCookie.class);
    if (ck == null) {
        throw new IllegalStateException("Bogus file in feeds folder: " +
                node.getLookup().lookup(FileObject.class));
    }
    try {
        return (Feed) ck.instanceCreate();
    } catch (ClassNotFoundException ex) {
        Exceptions.printStackTrace(ex);
    } catch (IOException ex) {
        Exceptions.printStackTrace(ex);
    }
    return null;
}

Since 7.1, for some reason, the above doesn't work. What does work, and is simpler, is this, instead of the above:

private static Feed getFeed(Node node) {
    Feed f = FileUtil.getConfigObject("RssFeeds/sample.instance", Feed.class);
    if (f == null) {
        throw new IllegalStateException("Bogus file in feeds folder: " +
                node.getLookup().lookup(FileObject.class));
    }
    return f;
}

So, the code needs to be fixed in the sample.

Wednesday Jul 04, 2012

Viewing the NetBeans Central Registry (Part 2)

Jens Hofschröer, who has one of the very best NetBeans Platform blogs (if you more or less understand German), and who wrote, sometime ago, the initial version of the Import Statement Organizer, as well as being the main developer of a great gear design & manufacturing tool on the NetBeans Platform in Aachen, commented on my recent blog entry "Viewing the NetBeans Central Registry", where the root Node of the Central Registry is shown in a BeanTreeView, with the words:

"I wrapped that Node in a FilterNode to provide the 'position' attribute and the 'file extension'. All Children are wrapped too. Then I used an OutlineView to show these two properties. Great tool to find wrong layer entries."

I asked him for the code he describes above and he sent it to me. He discussed it here in his blog, while all the code involved can be read below.

The result is as follows, where you can see that the OutlineView shows information that my simple implementation (via a BeanTreeView) kept hidden:

And so here is the definition of the Node.

class LayerPropertiesNode extends FilterNode {

    public LayerPropertiesNode(Node node) {
        super(node, isFolder(node) ? 
                Children.create(new LayerPropertiesFactory(node), true) : 
                Children.LEAF);
    }

    private static boolean isFolder(Node node) {
        return null != node.getLookup().lookup(DataFolder.class);
    }

    @Override
    public String getDisplayName() {
        return getLookup().lookup(FileObject.class).getName();
    }

    @Override
    public Image getIcon(int type) {
        FileObject fo = getLookup().lookup(FileObject.class);
        try {
            DataObject data = DataObject.find(fo);
            return data.getNodeDelegate().getIcon(type);
        } catch (DataObjectNotFoundException ex) {
            Exceptions.printStackTrace(ex);
        }
        return super.getIcon(type);
    }

    @Override
    public Image getOpenedIcon(int type) {
        return getIcon(type);
    }

    @Override
    public PropertySet[] getPropertySets() {
        Set set = Sheet.createPropertiesSet();
        set.put(new PropertySupport.ReadOnly<Integer>(
                "position", Integer.class, "Position", null) {
            @Override
            public Integer getValue() throws IllegalAccessException,
                    InvocationTargetException {
                FileObject fileEntry = getLookup().lookup(FileObject.class);
                Integer posValue = (Integer) fileEntry.getAttribute("position");
                return posValue != null ? posValue : Integer.valueOf(0);
            }
        });
        set.put(new PropertySupport.ReadOnly<String>(
                "ext", String.class, "Extension", null) {
            @Override
            public String getValue() throws IllegalAccessException,
                    InvocationTargetException {
                FileObject fileEntry = getLookup().lookup(FileObject.class);
                return fileEntry.getExt();
            }
        });
        PropertySet[] original = super.getPropertySets();
        PropertySet[] withLayer = new PropertySet[original.length + 1];
        System.arraycopy(original, 0, withLayer, 0, original.length);
        withLayer[withLayer.length - 1] = set;
        return withLayer;
    }

    private static class LayerPropertiesFactory extends ChildFactory<FileObject> {

        private final Node context;

        public LayerPropertiesFactory(Node context) {
            this.context = context;
        }

        @Override
        protected boolean createKeys(List<FileObject> list) {
            FileObject folder =
                    context.getLookup().lookup(FileObject.class);
            FileObject[] children = folder.getChildren();
            List<FileObject> ordered =
                    FileUtil.getOrder(Arrays.asList(children), false);
            list.addAll(ordered);
            return true;
        }

        @Override
        protected Node createNodeForKey(FileObject key) {
            AbstractNode node = new AbstractNode(org.openide.nodes.Children.LEAF,
                    key.isFolder()
                    ? Lookups.fixed(key, DataFolder.findFolder(key))
                    : Lookups.singleton(key));
            return new LayerPropertiesNode(node);
        }
        
    }
    
}

Then here is the definition of the Action, which pops up a JPanel, displaying an OutlineView:

@ActionID(category = "Tools",
id = "de.nigjo.nb.layerview.LayerViewAction")
@ActionRegistration(displayName = "#CTL_LayerViewAction")
@ActionReferences({
    @ActionReference(path = "Menu/Tools", position = 1450, separatorBefore = 1425)
})
@Messages("CTL_LayerViewAction=Display XML Layer")
public final class LayerViewAction implements ActionListener {

    @Override
    public void actionPerformed(ActionEvent e) {
        try {
            Node node = DataObject.find(FileUtil.getConfigRoot()).getNodeDelegate();
            node = new LayerPropertiesNode(node);
            node = new FilterNode(node) {
                @Override
                public Component getCustomizer() {
                    LayerView view = new LayerView();
                    view.getExplorerManager().setRootContext(this);
                    return view;
                }
                @Override
                public boolean hasCustomizer() {
                    return true;
                }
            };
            NodeOperation.getDefault().customize(node);
        } catch (DataObjectNotFoundException ex) {
            Exceptions.printStackTrace(ex);
        }
    }

    private static class LayerView extends JPanel implements ExplorerManager.Provider {

        private final ExplorerManager em;
        
        public LayerView() {
            super(new BorderLayout());
            em = new ExplorerManager();
            OutlineView view = new OutlineView("entry");
            view.addPropertyColumn("position", "Position");
            view.addPropertyColumn("ext", "Extension");
            add(view);
        }

        @Override
        public ExplorerManager getExplorerManager() {
            return em;
        }

    }

}

Tuesday Jul 03, 2012

JavaFX in a JSF 2.0 Custom Tag?

I followed these instructions and now have a simple JSF 2.0 tag handler:

The reason I created this is because I'm curious about whether it would be possible to change the tag created above:

<my:hello name="Jack" />

...to something like this:

<my:chart type="pie" xAxis="${some-expression}" yAxis="${some-expression}" width="300" height="500" />

Has anyone tried this? That could be a way to incorporate a JavaFX chart into a Java EE application. That's different to how Adam Bien is doing it in LightFish, but might be a simpler and more reusable way of doing the same thing.

Monday Jul 02, 2012

Advanced Experiments with JavaScript, CSS, HTML, JavaFX, and Java

Once you're embedding JavaScript, CSS, and HTML into your Java desktop application, via the JavaFX browser, a whole range of new possibilities open up to you.

For example, here's an impressive page on-line, notice that you can drag items and drop them in new places:

http://nettuts.s3.amazonaws.com/127_iNETTUTS/demo/index.html

The source code of the above is provided too, so you can drop the various files directly into your NetBeans module and use the JavaFX WebEngine to load the HTML page into the JavaFX browser. Once the JavaFX browser is in a NetBeans TopComponent, you'll have the start of an off-line news composer, something like this:

WebView view = new WebView();
view.setMinSize(widthDouble, heightDouble);
view.setPrefSize(widthDouble, heightDouble);
webengine = view.getEngine();
URL url = getClass().getResource("index.html");
webengine.load(url.toExternalForm());
webengine.getLoadWorker().stateProperty().addListener(
        new ChangeListener() {
            @Override
            public void changed(ObservableValue ov, State oldState, State newState) {
                if (newState == State.SUCCEEDED) {
                    Document document = (Document) webengine.executeScript("document");
                    NodeList list = document.getElementById("columns").getChildNodes();
                    for (int i = 0; i < list.getLength(); i++) {
                        EventTarget et = (EventTarget) list.item(i);
                        et.addEventListener("click", new EventListener() {
                            @Override
                            public void handleEvent(Event evt) {
                                instanceContent.add(new Date());
                            }
                        }, true);
                    }
                }
            }
        });

The above is the code showing how, whenever a news item is clicked, the current date can be published into the Lookup. As you can see, I have a viewer component listening to the Lookup for dates.

Sunday Jul 01, 2012

Invoking JavaScript from Java

Here's an Action class defined in Java. The Action class executes a script via the JavaFX WebEngine:

@NbBundle.Messages("CTL_AddBananasAction=Add Banana")
private class AddBananasAction extends AbstractAction {
    public AddBananasAction() {
        super(Bundle.CTL_AddBananasAction());
    }
    @Override
    public void actionPerformed(ActionEvent e) {
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                webengine.executeScript("addBanana(' " + newBanana + " ') ");
            }
        });
    }
}
How does the 'executescript' call know where to find the JavaScript file? Well, earlier in the code, the WebEngine loaded an HTML file, where the JavaScript file was registered:
WebView view = new WebView();
view.setMinSize(widthDouble, heightDouble);
view.setPrefSize(widthDouble, heightDouble);
webengine = view.getEngine();
URL url = getClass().getResource("home.html");
webengine.load(url.toExternalForm());

Finally, here's a skeleton 'addBanana' method, which is invoked via the Action class shown above:

function addBanana(user){
    statustext.text(user);
}

By the way, if you have your JavaScript and CSS embedded within your HTML file, the code navigator combines all three into the same window, which is kind of cool:

About

Geertjan Wielenga (@geertjanw) is a Principal Product Manager in the Oracle Developer Tools group living & working in Amsterdam. He is a Java technology enthusiast, evangelist, trainer, speaker, and writer. He blogs here daily.

The focus of this blog is mostly on NetBeans (a development tool primarily for Java programmers), with an occasional reference to NetBeans, and sometimes diverging to topics relating to NetBeans. And then there are days when NetBeans is mentioned, just for a change.

Search

Archives
« July 2012 »
SunMonTueWedThuFriSat
14
28
29
30
31
    
       
Today