måndag 21 februari 2011

Pdf viewer as a JPanel

The project I'm working on is run by a book publishing company in Sweden. So for them to want to be able to provide integrated support for pdf viewing in the product seemed fairly obvious. After spending quite some time googling for different derivatives of "open source pdf jpanel swing" and such, I first found PdfRenderer, an original SwingLabs project that seemed to not be worked on at that time (but perhaps will be restarting soon? Keep an eye on that link if you're interested, I know I will).

There are multiple options if you're looking for commercially licensed products and, what seem like, good ones too. But I wanted open source. After a while I found http://www.icepdf.org and it seemed like their mozilla public licensed ICEpdf project offered what I was looking for.

What I wanted was fairly simple. I had a pdf file and wanted a viewer panel extending JPanel.

And voila, this is what my code ended up looking:

import org.icepdf.ri.common.SwingController;
import org.icepdf.ri.common.SwingViewBuilder;

InputStream inputStream = MY_PDF_AS_STREAM;
SwingController controller = new SwingController();
SwingViewBuilder factory = new SwingViewBuilder(controller);
JPanel viewerComponentPanel = factory.buildViewerPanel(); 
MY_MAIN_PANEL.add(viewerComponentPanel, BorderLayout.CENTER);
controller.openDocument(inputStream, "", "");

And this is what I got, in our Netbeans RCP application:

As you can see, all expected icons are there... The pdf functionality includes everything I expected (as search, text selections and links). All in all, I think ICEpdf is a pretty nice acquaintance.

Ohh, and if you read this far, you might like what I used for selecting what pdf to view. I found http://pwnt.be/lab/jflow/ I know that it has been done before, but in this case I actually think a Cover Flow selection component actually adds some value as well as some sexy. The excellent JFlow project required only very light tweaking to fit my needs, so you might want to check that out!

Yes, I only offered two books to choose from...

Until next time!

torsdag 17 februari 2011

Screen Shots

Here are some screen shots of our application and how the art director envisioned it using photoshop. The application is an accounting software. In escence a program for smal to medium sized organisations to keep their books.

Another photoshop image:

And these are actual screen shots of our application where its at today:

Info screen


And using pretty much nimbus defaults (icons are the same which will have to be addressed)

It's this work that made me write this post about tweaking Nimbus

Tweaking Nimbus

I'm just back from JFokus in Stockholm and a very good meeting with people sharing my Nb RCP interest. We might have been the only people at that Steak House that particular evening trading netbeans advice...

******** EDIT: 2011-02-19 ***************
Thanks to Geertjan's article I figured out how to make a complete redraw in real time.
Actually setting the UI to a different laf and then straight back again actually redraws the entire UI like I wanted to below.

public static void updateUI() { 
  try { 
  } catch (Exception ex) {}
  UIManager.put(nimbusBlueGrey, YOUR_NEW_COLOR);
Strange, but it works.

At that dinner I had the opportunity to show and discus my current project's struggles with adopting the Nimbus Look&Feel to what our art director have created in photoshop.

The thing is that we want the user to be able to change his or her settings in real time so we want to change the nimbus drawing properties in real time programatically.

This can typically be done like this:

for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()){
  if ("Nimbus".equals(info.getName())) {
    UIManager.put("nimbusBase", new Color(21, 21, 21));
    UIManager.put("nimbusBlueGrey", new Color(44, 44, 44));
    UIManager.put("control", new Color(40, 40, 40));
    UIManager.put("textText", Color.WHITE);
    jFrame = (JFrame) WindowManager.getDefault().getMainWindow();

In my current project I run code similar like the one above in my module Installer class like this:

public void restored() {
  WindowManager.getDefault().invokeWhenUIReady(new GuiInitialiser());

The code above is what gets done in the GuiInitialiser.
However, and this is my main concern right now, this code behaves quite differently when I, instead of setting tha laf programatically like above, set it by adding

run.args.extra=--laf com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel

in my project's platform.properties file. The problem seem to have something to do with performing a COMPLETE and clean redrawing of the entire project UI when setting it programatically. To illustrate this I have created a small project that illustrates what I'm talking about. If you run it, you will find that the main menu "row" at the top of th screen is quite ugly.

This is because I set

  UIManager.put("nimbusBase", Color.MAGENTA);
  UIManager.put("nimbusBlueGrey", Color.CYAN);

before updating the UI the first time. However, changing the same properties after that does not redraw that part of the UI.

In this program there are some predefined settings that you can try but also a text field where you can try to change the color of any other nimbus property that you might like. However, due to the Nimbus logic of derived colors (which by the way is illustrated quite well in the application above - set nimbusBase to red and watch how red is implemented on for instance the comboBox) it is quite hard to find a color property that just instantly does what you want/expect it to.

So if your interested, you can download the project and play around with it. I hope that both the application and its source can benefit someone. Obviously this application should have been presented as a java web start, but that rendered even differently which someone also should feel very free to get back to me about...

So, if you like this, download it and experiment. Run it as is or with the laf-setting in the platform-file instead. Run it as JNLP.

Over and out!