Saturday Sep 08, 2012

How to Draw Lines on the Screen (Part 1)

I've seen occasional questions on mailing lists about how to use the NetBeans Visual Library to draw lines, e.g., to make graphs or diagrams of various kinds by drawing on the screen. So, rather than drag/drop causing widgets to be added, you'd want widgets to be added on mouse clicks, and you'd want to be able to connect those widgets together somehow.

Via the code below, you'll be able to click on the screen, which causes a dot to appear. When you have multiple dots, you can hold down the Ctrl key and connect them together. A guiding line appears to help you position the dots exactly in line with each other. When you go to File | Print, you'll be able to preview and print the diagram you've created.

A picture that speaks 1000 words:

Here's the code (first create a NetBeans module, then use the New Window wizard to create a new TopComponent, then integrate the code below into the TopComponent):

public final class PlotterTopComponent extends TopComponent {

    private final Scene scene;
    private final LayerWidget baseLayer;
    private final LayerWidget connectionLayer;
    private final LayerWidget interactionLayer;

    public PlotterTopComponent() {

        initComponents();
        
        setName(Bundle.CTL_PlotterTopComponent());
        setToolTipText(Bundle.HINT_PlotterTopComponent());
        
        setLayout(new BorderLayout());

        this.scene = new Scene();
        this.baseLayer = new LayerWidget(scene);
        this.interactionLayer = new LayerWidget(scene);
        this.connectionLayer = new LayerWidget(scene);

        scene.getActions().addAction(new SceneCreateAction());
        
        scene.addChild(baseLayer);
        scene.addChild(interactionLayer);
        scene.addChild(connectionLayer);
    
        add(scene.createView(), BorderLayout.CENTER);
        
        putClientProperty("print.printable", true);
    
    }

    private class SceneCreateAction extends WidgetAction.Adapter {
        @Override
        public WidgetAction.State mousePressed(Widget widget, 
        WidgetAction.WidgetMouseEvent event) {
            if (event.getClickCount() == 1) {
                if (event.getButton() == MouseEvent.BUTTON1 || 
                        event.getButton() == MouseEvent.BUTTON2) {
                    baseLayer.addChild(new BlackDotWidget(scene, widget, event));
                    repaint();
                    return WidgetAction.State.CONSUMED;
                }
            }
            return WidgetAction.State.REJECTED;
        }
    }

    private class BlackDotWidget extends ImageWidget {
        public BlackDotWidget(Scene scene, Widget widget, 
                WidgetAction.WidgetMouseEvent event) {
            super(scene);
            setImage(ImageUtilities.loadImage("org/netbeans/plotter/blackdot.gif"));
            setPreferredLocation(widget.convertLocalToScene(event.getPoint()));
            getActions().addAction(
                    ActionFactory.createExtendedConnectAction(
                       connectionLayer, new BlackDotConnectProvider()));
            getActions().addAction(
                    ActionFactory.createAlignWithMoveAction(
                       baseLayer, interactionLayer,
                       ActionFactory.createDefaultAlignWithMoveDecorator()));
        }
        
    }

    private class BlackDotConnectProvider implements ConnectProvider {

        @Override
        public boolean isSourceWidget(Widget source) {
            return source instanceof BlackDotWidget && source != null ? true : false;
        }

        @Override
        public ConnectorState isTargetWidget(Widget src, Widget trg) {
            return src != trg && trg instanceof BlackDotWidget ? 
                    ConnectorState.ACCEPT : ConnectorState.REJECT;
        }

        @Override
        public boolean hasCustomTargetWidgetResolver(Scene arg0) {
            return false;
        }

        @Override
        public Widget resolveTargetWidget(Scene arg0, Point arg1) {
            return null;
        }

        @Override
        public void createConnection(Widget source, Widget target) {
            ConnectionWidget conn = new ConnectionWidget(scene);
            conn.setTargetAnchor(AnchorFactory.createCircularAnchor(target, 10));
            conn.setSourceAnchor(AnchorFactory.createCircularAnchor(source, 10));
            connectionLayer.addChild(conn);
        }

    }

    ...
    ...
    ...

Note: The code above was written based on the Visual Library tutorials on the NetBeans Platform Learning Trail, in particular via the "ConnectScene" sample in the "test.connect" package, which is part of the very long list of Visual Library samples referred to in the Visual Library tutorials on the NetBeans Platform Learning Trail.

The next steps are to add a reconnect action and an action to delete a dot by double-clicking on it. Would be interesting to change the connecting line so that the length of the line were to be shown, i.e., as you draw a line from one dot to another, you'd see a constantly changing number representing the current distance of the connecting line. Also, once lines are connected to form a rectangle, would be cool to be able to write something within that rectangle. Then one could really create diagrams, which would be pretty cool.

Friday Sep 07, 2012

Get Started With Java Music Development

Thursday Sep 06, 2012

Using irc in NetBeans IDE 7.2

Turns out to be easy to use irc in NetBeans IDE 7.2. Install Irssi (I was able to do apt-get to install it), which has a handy guide here, and then use the Terminal window in NetBeans IDE (Window | Output | Terminal):

In the above, do this:

irssi
/connect irc.freenode.net
/join #netbeans

Then, next time you have a problem in NetBeans IDE or there's some question you have about how to do something, just type your question in the Terminal window and someone will help you, if someone is there who knows the answer.

Wednesday Sep 05, 2012

Custom Lookup Provider For NetBeans Platform CRUD Tutorial

For a long time I've been planning to rewrite the second part of the NetBeans Platform CRUD Application Tutorial to integrate the loosely coupled capabilities introduced in a seperate series of articles based on articles by Antonio Vieiro (a great series, by the way). Nothing like getting into the Lookup stuff right from the get go (rather than as an afterthought)!

The question, of course, is how to integrate the loosely coupled capabilities in a logical way within that tutorial. Today I worked through the tutorial from scratch, up until the point where the prototype is completed, i.e., there's a JTextArea displaying data pulled from a database. That brought me to the place where I needed to be. In fact, as soon as the prototype is completed, i.e., the database connection has been shown to work, the whole story about Lookup.Provider and InstanceContent should be introduced, so that all the subsequent sections, i.e., everything within "Integrating CRUD Functionality" will be done by adding new capabilities to the Lookup.Provider.

However, before I perform open heart surgery on that tutorial, I'd like to run the scenario by all those reading this blog who understand what I'm trying to do! (I.e., probably anyone who has read this far into this blog entry.)

So, this is what I propose should happen and in this order:

  1. Point out the fact that right now the database access code is found directly within our TopComponent. Not good. Because you're mixing view code with data code and, ideally, the developers creating the user interface wouldn't need to know anything about the data access layer. Better to separate out the data access code into a separate class, within the CustomerLibrary module, i.e., far away from the module providing the user interface, with this content:
    public class CustomerDataAccess {
    
        public List<Customer> getAllCustomers() {
            return Persistence.createEntityManagerFactory("CustomerLibraryPU").
                    createEntityManager().createNamedQuery("Customer.findAll").getResultList();
        }
    
    }
  2. Point out the fact that there is a concept of "Lookup" (which readers of the tutorial should know about since they should have followed the NetBeans Platform Quick Start), which is a registry into which objects can be published and to which other objects can be listening. In the same way as a TopComponent provides a Lookup, as demonstrated in the NetBeans Platform Quick Start, your own object can also provide a Lookup. So, therefore, let's provide a Lookup for Customer objects. 
    import org.openide.util.Lookup;
    import org.openide.util.lookup.AbstractLookup;
    import org.openide.util.lookup.InstanceContent;
    
    public class CustomerLookupProvider implements Lookup.Provider {
    
        private Lookup lookup;
        private InstanceContent instanceContent;
    
        public CustomerLookupProvider() {
            // Create an InstanceContent to hold capabilities...
            instanceContent = new InstanceContent();
            // Create an AbstractLookup to expose the InstanceContent...
            lookup = new AbstractLookup(instanceContent);
            // Add a "Read" capability to the Lookup of the provider:
            //...to come...
            // Add a "Update" capability to the Lookup of the provider:
            //...to come...
            // Add a "Create" capability to the Lookup of the provider:
            //...to come...
            // Add a "Delete" capability to the Lookup of the provider:
            //...to come...
        }
    
        @Override
        public Lookup getLookup() {
            return lookup;
        }
        
    }
  3. Point out the fact that, in the same way as we can publish an object into the Lookup of a TopComponent, we can now also publish an object into the Lookup of our CustomerLookupProvider. Instead of publishing a String, as in the NetBeans Platform Quick Start, we'll publish an instance of our own type. And here is the type:
    public interface ReadCapability {
        public void read() throws Exception;
    }

    And here is an implementation of our type added to our Lookup:

    public class CustomerLookupProvider implements Lookup.Provider {
    
        private Set<Customer> customerSet;
        private Lookup lookup;
        private InstanceContent instanceContent;
    
        public CustomerLookupProvider() {
            customerSet = new HashSet<Customer>();
            // Create an InstanceContent to hold capabilities...
            instanceContent = new InstanceContent();
            // Create an AbstractLookup to expose the InstanceContent...
            lookup = new AbstractLookup(instanceContent);
            // Add a "Read" capability to the Lookup of the provider:
            instanceContent.add(new ReadCapability() {
                @Override
                public void read() throws Exception {
                    ProgressHandle handle = ProgressHandleFactory.createHandle("Loading...");
                    handle.start();
                    customerSet.addAll(new CustomerDataAccess().getAllCustomers());
                    handle.finish();
                }
            });
            // Add a "Update" capability to the Lookup of the provider:
            //...to come...
            // Add a "Create" capability to the Lookup of the provider:
            //...to come...
            // Add a "Delete" capability to the Lookup of the provider:
            //...to come...
        }
    
        @Override
        public Lookup getLookup() {
            return lookup;
        }
    
        public Set<Customer> getCustomers() {
            return customerSet;
        }
        
    }
  4. Point out that we can now create a new instance of our Lookup (in some other module, so long as it has a dependency on the module providing the CustomerLookupProvider and the ReadCapability), retrieve the ReadCapability, and then do something with the customers that are returned, here in the rewritten constructor of the TopComponent, without needing to know anything about how the database access is actually achieved since that is hidden in the implementation of our type, above:
    public CustomerViewerTopComponent() {
    
        initComponents();
        setName(Bundle.CTL_CustomerViewerTopComponent());
        setToolTipText(Bundle.HINT_CustomerViewerTopComponent());
    
    //        EntityManager entityManager = Persistence.createEntityManagerFactory("CustomerLibraryPU").createEntityManager();
    //        Query query = entityManager.createNamedQuery("Customer.findAll");
    //        List<Customer> resultList = query.getResultList();
    //        for (Customer c : resultList) {
    //            jTextArea1.append(c.getName() + " (" + c.getCity() + ")" + "\n");
    //        }
    
        CustomerLookupProvider lookup = new CustomerLookupProvider();
        ReadCapability rc = lookup.getLookup().lookup(ReadCapability.class);
        try {
            rc.read();
            for (Customer c : lookup.getCustomers()) {
                jTextArea1.append(c.getName() + " (" + c.getCity() + ")" + "\n");
            }
        } catch (Exception ex) {
            Exceptions.printStackTrace(ex);
        }
    
    }

Does the above make as much sense to others as it does to me, including the naming of the classes? Feedback would be appreciated! Then I'll integrate into the tutorial and do the same for the other sections, i.e., "Create", "Update", and "Delete". (By the way, of course, the tutorial ends up showing that, rather than using a JTextArea to display data, you can use Nodes and explorer views to do so.)

Tuesday Sep 04, 2012

Presentation Plugin for NetBeans IDE 7.2

I got some excellent help from Mark Stephens, who is from IDR Solutions, which produces JPedal. Using the LGPL version of JPedal, and code provided by Mark, it's now possible to right-click the node that appears in the Presentation Window:

...after which, using a file browser (to locate a file on disk) or a URL (a very simple check is done, the URL must start with "http" and end with "pdf"), you can now open PDF files as images (thanks to conversion from PDF to images done by JPedal) into NetBeans IDE, typically (I imagine) for presentation purposes:

Note that you should consider the plugin in "alpha" state. But, despite that, I've had good results. Try it and use the URL below, as a control test (since it works fine for me), which produces the result shown above:

http://edu.netbeans.org/contrib/slides/netbeans-platform/presentation-4-actions.pdf 

However, for some PDFs, the plugin doesn't work, and I don't know why yet (trying to figure it out with Mark), resulting in this stack trace:

java.lang.ArrayIndexOutOfBoundsException: 8
   at org.jpedal.objects.acroforms.formData.SwingData.completeField(Unknown Source)
   at org.jpedal.objects.acroforms.rendering.DefaultAcroRenderer.createField(Unknown Source)
   at org.jpedal.objects.acroforms.rendering.DefaultAcroRenderer.createDisplayComponentsForPage(Unknown Source)
   at org.jpedal.PDFtoImageConvertor.convert(Unknown Source)
   at org.jpedal.PdfDecoder.getPageAsImage(Unknown Source)
   at org.jpedal.PdfDecoder.getPageAsImage(Unknown Source)

Here's the location of the plugin, install it into NetBeans IDE 7.2; feedback is very welcome:

http://plugins.netbeans.org/plugin/44525

Update. The problem above is solved now (see the comments below) and when you go to the link above, you'll get the 1.1 version of the plugin, which includes the fix.

Monday Sep 03, 2012

Be There: Tinkerforge/NetBeans Platform Integration Course

Tinkerforge is an electronic construction kit. It exposes a number of API bindings, including, of course, Java. The nice thing also is that Tinkerforge products are open source, both on the hardware and software levels, so that you can take their bases as a starting point for your own modifications.

"The TinkerForge system is a set of pre-built electronics boards that are built in such a way that you can stack the boards (known as bricks), attach accessories (known as bricklets), and have your prototype and and running quickly. Unlike systems, such as the Arduino or Launchpad, the TinkerForge has to be attached to a computer and the computer does all of the work. With an easy set of application programming interfaces (APIs) available in C/C++, C#, Java, PHP, and Ruby, the system is easy to interface and program over USB in a snap." (from this useful article)

Henning Krüp, who has arranged several NetBeans Platform Certified Training Courses in the past, in the Nordhorn/Lingen area in Germany, had the inspired idea to focus the next course on integration with Tinkerforge. In other words, the whole course will be focused on creating a standalone Java desktop application that leverages the NetBeans Platform to interact with Tinkerforge!

Interested in joining the course or setting up something similar yourself? The course organized by Henning will be held from 19 to 21 September, as explained here, together with contact details.  If you'd like to organize a similar course at a location of your choosing, leave a comment at the end of this blog entry and we'll set something up together!

Saturday Sep 01, 2012

PDF to Image Conversion in Java

In the past, I created a NetBeans plugin for loading images as slides into NetBeans IDE. That means you had to manually create an image from each slide first. So, this time, I took it a step further. You can choose a PDF file, which is then automatically converted to an image for each page, each of which is presented as a node that can be clicked to open the slide in the main window.

As you can see, the remaining problem is font rendering. Currently I'm using PDFBox. Any alternatives that render font better?

This is the createKeys method of the child factory, ideally it would be replaced by code from some other library that handles font rendering better:

@Override
protected boolean createKeys(List<ImageObject> list) {
    mylist = new ArrayList<ImageObject>();
    try {
        if (file != null) {
            ProgressHandle handle = ProgressHandleFactory.createHandle(
                    "Creating images from " + file.getPath());
            handle.start();
            PDDocument document = PDDocument.load(file);
            List<PDPage> pages = document.getDocumentCatalog().getAllPages();
            for (int i = 0; i < pages.size(); i++) {
                PDPage pDPage = pages.get(i);
                mylist.add(new ImageObject(pDPage.convertToImage(), i));
            }
            handle.finish();
        }
        list.addAll(mylist);
    } catch (IOException ex) {
        Exceptions.printStackTrace(ex);
    }
    return true;
}

The import statements from PDFBox are as follows:

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
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
« September 2012 »
SunMonTueWedThuFriSat
      
2
16
19
      
Today