Quiet often, we come across the same old problem. Few days ago, a collegue of mine also came across this problem. Yes, I am talking about a print preview and print control that is customized to your application’s need. Unless, you are ready to spend some money, it can be hard to write a complete print preview and print control yourself. But there is a simple way around and the one preferred by many developers. In fact, if you use it properly, you can display and print just about any type of documents.

This simple way around is generating your document as HTML and using web browser control to display it and also to print it. In fact, you can use some CSS to make it look even better. But of course there are some hick-ups with this approach. Like for example, a page that looks very nice in IE or Firefox, may not appear the same way in this default web browser control. This happens because these default webbrowser controls that come with Java and .NET are not substitute for IE or Firefox. They do not support all the CSS formattings and HTML/DHTML tags. But for most basic purposes, these controls are more than sufficient.

In .NET there is a WebBrowser component, that you can drag from Toolbox and put it on your form. Then just put one or two lines of code and the magic is done.

For example,

//name of webbroser component is webBrowser1
public void setContent()
{
//Set the content
String tempstr="<table border=1>" +
				"<tr><td><h1>I am Heading 1</h1></td></tr>" +
				"<tr><td><img src=http://developerspoint.files.wordpress.com/" +
				"2008/06/establish-encrypted-communication.jpg></td></tr></table>";

webBrowser1.DocumentText = tempstr;
}

public void printReport()
{
//now print it
webBrowser1.print()
}

In case of Java, it is a little bit tricky when HTML consists of images. So, in terms of simplicity, I should admit that .NET beats Java, at least in this particular case. But, its not even that hard in Java. You just need to make sure that images load synchronously. Following is a sample code.

 

import java.awt.BorderLayout;
import java.io.IOException;

import javax.swing.JButton;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.text.View;
import javax.swing.text.ViewFactory;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.ImageView;

public class HTMLPrintSample extends JFrame
{
	private JEditorPane pane;
	private JButton btnPrint;

	public HTMLPrintSample()
	{
		pane = new JEditorPane();
		pane.setEditable(false);
		btnPrint = new JButton("Print");

	    HTMLEditorKit kit = new HTMLEditorKit()
	    {
	       public ViewFactory getViewFactory()
	       {
	          return new HTMLFactory()
	          {
	             public View create(javax.swing.text.Element elem)
	             {
	                View view = super.create(elem);

	                if (view instanceof ImageView)
	                {
	                   ((ImageView) view).setLoadsSynchronously(true);
	                }
	                return view;
	             }
	          };
	       }
	    };
	    pane.setEditorKit(kit);

		setHTML("<table border=1>" +
				"<tr><td><h1>I am Heading 1</h1></td></tr>" +
				"<tr><td><img src=http://developerspoint.files.wordpress.com/" +
				"2008/06/establish-encrypted-communication.jpg></td></tr></table>");

		add(new JScrollPane(pane), BorderLayout.CENTER);
		add(btnPrint, BorderLayout.SOUTH);
	}

	public void setHTML(String htmlString)
	{
		pane.setText(htmlString);
	}

	public void setURL(String urlString)
	{
		try
		{
			pane.setPage(urlString);
		}
		catch(IOException e)
		{
			e.printStackTrace();
		}
	}

	public static void main(String[] args)
	{
		try {
	        UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
	    } catch (Exception evt) {}

		HTMLPrintSample app = new HTMLPrintSample();
		app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		app.setSize(640, 480);
		app.setVisible(true);
	}
}

However, there is a little glitch with this approach. Though above code can print images from inside HTML, these images are linked. This can cause problems, especially when the images are rendered from within your application.


It is straight forward to add buttons into the toolbars. But, it can be a bit tricky to add other components, such as combo boxes. Again just adding the controls is not enough, because you will have to handle the events to make them useful. To add combo boxes or any other controls, one easy way is to create a custom control.

In this article, I will show a way to add combo boxes to toolbars by creating a custom control. With this approach, you can put just anything in the toolbars.

Lets take a look at following code.

import org.eclipse.jface.action.ControlContribution;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;

public class MyCombo extends ControlContribution {

	Combo combo;
	public MyCombo(String str)
	{
		super(str);
	}

	@Override
	protected Control createControl(Composite parent)
	{
		combo = new Combo(parent, SWT.NONE | SWT.DROP_DOWN | SWT.READ_ONLY);

		combo.add("String 1");
		combo.add("String 2");
		combo.add("String 3");
		combo.add("String 4");
		combo.setTextLimit(10);
		combo.select(0);

		combo.addModifyListener(
		new ModifyListener()
		{
			public void modifyText(final ModifyEvent e)
			{
		MessageDialog.openInformation(
				null, "My App",
				"Item at " + combo.getSelectionIndex() + " clicked.");

			}
		});

		return combo;
	}

	public void setValue(int index)
	{
		combo.select(index);
	}

}

This code creates a custom control called MyCombo. This custom control is extended from ControlContribution.

The components to be contained within this custom control and their layouts are defined in the createControl method. In our case, we just need to show a combo box. In addition to instantiating the combo box, I have put some additional codes to handle the events also.

It might be a good idea to put a method that can be called externally to manipulate the items in combo box. So, just for a demo purpose, I also put a method called setValue.

Now, to add this custom control go to your application’s ActionBarAdvisor derived class. Usually in a normal RCP application, the name of this derived class is ApplicationActionBarAdvisor. Here you will have to override a method. A sample is shown below.


    MyCombo myCombo = null;

    protected void fillCoolBar(ICoolBarManager coolBar)
    {
    	IToolBarManager toolbar = new ToolBarManager(coolBar.getStyle());
    	coolBar.add(toolbar);

    	myCombo = new MyCombo("Demo Combo box");
	toolbar.add(myCombo);
    }

Now, if everything goes right then the combo box should appear on the toolbar.