Friday, April 19, 2013

Printing multiple Printables in Java

Java is a great language that let's you concentrate on features to implement instead of figuring out how to manage the memory addresses for example. But sometimes, you can be challenged by the runtime and have to get dirty to create some advance functions.

Printing in Java is quite easy. But it can be a bit to simplified for your needs and you'll end up coding at a low level to get the desired result. Basically, when you want to print, you have to calculate the space required for each word, handle any carriage return and draw the result on a a Graphics. For images, you'll have to resize the image to fit the paper size, draw lines for underlined text, etc... You know the drill.

Of course, there are tons of libraries that will handle complex document printing like JasperReport. With these tools, you design your templates, invoke a database and print the result on your printer or a PDF file.

For simpler documents, you can populate a JTable and print it directly quite easily. The same goes for a JTextArea or a JTextPane. But you can only print one component in a PrinterJob at a time. There is no way to print a JTable and a JTextArea on the same page or in the same PrinterJob. Even combining both in a Book (Pageable class) will result as each component being printed on a new page instead of being printed one after the other.

Here's an example:




This is a case where you'll have to rely on an external library or do some low level coding... At least, until now...

The issue is that PrinterJob.print() will call the Printable object with a page index. The index will be 0 on the JTable, and 1 on the JTextArea in a Pageable object (Book). Only the JTable will be printed. If you manage manually the page index, calling 0 on both, you will have no other choice then printing on two different pages as there is no way to invoke the second printing on the same page, following the first one.

Basically, PageFormat is your friend as you can use it to specify here to print the component on your page. All you need to do is manage your page index and modify the PageFormat (Imageable Area) to indicate where you can start printing the next component. The problem is that you don't know where the printing operation ended on the Y axis. If you table heigh is know, there is a work around that can be used, but if your JTable height is greater than one page, you're stuck. You'll have to implement complex calculation to find how much was printed based on the paper size, paper orientation, cell size and so on. It can become quickly a nightmare if you plan printing several Printable components in a single PrinterJob.

I've search the Internet and that issue has been confusing Java coders for the last decade. Either you implement a low level printing algorithm or you use an external library and implements a totally different design just to be able to print tables and texts. JTable, JTextArea and JTextPane can handle printing by themselves and provide excellent results without much effort. But not together...

I finally found a clean solution to make them work together. The main issue is to find how much space is left when a component has finished printing. Using a BufferedImage to do a pre-printing is how I was able to do it. You'll have to pre-print anyway to find out the total page count required if you want to build a table of content, so it's not a big deal.

Here's the code, a simple Printable class, wrapping the Printable object of the component. This wrapper will handle the amount of space left after the printing. All you need to do is check how much space is left and create a new page when needed and restart the page index at 0 for each new page.

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package printer;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.awt.print.PageFormat;
import java.awt.print.Paper;
import java.awt.print.Printable;
import java.awt.print.PrinterException;

/**
*
* @author pballeux
*/
public class MyPrintable implements Printable {

Printable delegate;
double spaceLeft = 0;
double minimumRequired = 72;
static int debugindex = 0;

public MyPrintable(Printable p) {
this.delegate = p;
}

public MyPrintable(Printable p, double minimumHeight) {
this.delegate = p;
this.minimumRequired = minimumHeight;
}

public void setMinimumRequired(double height) {
minimumRequired = height;
}

public double getMinimumRequired() {
return minimumRequired;
}


public double getSpaceLeft() {
return spaceLeft;
}

private int detectLastLine(BufferedImage img) {
int lastIndex = 0;
int[] data = ((DataBufferInt) img.getRaster().getDataBuffer()).getData();
for (int i = data.length - 1; i > 0; i--) {
if (data[i] != 0) {
lastIndex = i;
break;
}
}
return (lastIndex / img.getWidth());
}

@Override
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
BufferedImage img = new BufferedImage((int) pageFormat.getWidth(), (int) pageFormat.getHeight(), BufferedImage.TRANSLUCENT);
Graphics2D g = img.createGraphics();
int retValue = delegate.print(g, pageFormat, pageIndex);
if (retValue == PAGE_EXISTS) {
//Find out bound of printing...
//System.out.println("Last Line drawn is : " + detectLastLine(img));
// try {
// ImageIO.write(img, "jpg", new File("img" + debugindex++ + ".jpg"));
// } catch (IOException ex) {
// }
spaceLeft = (pageFormat.getImageableY() + pageFormat.getImageableHeight()) - detectLastLine(img);
retValue = delegate.print(graphics, pageFormat, pageIndex);
//Updating paper after the hardprint
Paper paper = pageFormat.getPaper();
paper.setImageableArea(paper.getImageableX(), paper.getImageableY() + paper.getImageableHeight() - spaceLeft, paper.getImageableWidth(), spaceLeft);
pageFormat.setPaper(paper);
}
return retValue;
}
}


For each Printable, JTable.getPrintable(...), wrap it with MyPrintable object and then print the wrapper.


MyPrintable prt = new MyPrintable(table.getPrintable(...))
...
while (prt.print(graphics,pf,pageIndex) == PAGE_EXISTS){
if (prt.getSpaceLeft() < 100){
// create a new page or a new graphics
// reset page index to 0
}
pageIndex++;
}
// looping to the next Printable...



Have fun!

Wednesday, April 17, 2013

Ubuntu 13.04 on the Nexus 7... It works!

I could not resist the temptation to flash my Nexus 7 with the special Ubuntu 13.04 version built by Canonical.

The flashing process is quite easy to execute but does require some geek experience to avoid bricking your precious Android device. As writing this post, there is a major flaw in Ubuntu where the touch interface dies leaving you with no way to interact with the GUI. But there is hope as dedicated developers are working on this issue and have released today a patch to "fix" the problem (Link to patch in comments)

After installing the patch, it does work almost like a charm. I still triggered the issue but it took a while before it happened. As a plan B, make sure to have an external keyboard connected or a Remote Desktop access enable to be able to logout and login again, resetting the issue.




What works!
- Wifi
- Brightness control
- Sound and microphone
- Bluetooth (used a BT keyboard)
- Ubuntu One file sharing
- Playing video streams, using Chromium
- Sharing folders over Samba
- Remote Desktop Access (VNC)
- Sound level is way louder than using Android
- Video playback fullscreen





Everything seems to work as a regular Ubuntu desktop!

What does not work...
- The webcam
- Could not find a workable Flash player
- Playing music sometime have hiccups.
- USB file access is not implemented (at least, not by default)

What I think

It's just amazing. Of course, it's a preview distribution and not meant for a mainstream. It's a proof of concept, that's all. But it's usable to some point.

The overall experience is pretty smooth. Not much lag, not more than Android as a matter of fact. Icons are too small in some cases making it difficult to click on the right one. The virtual keyboard is okay, but since it can be fully customized, there is a way to make it more practical. The default keyboard layout is too small so you have to be careful when typing.

A few tips

Lower the default brightness level as the battery drains fast. Actually, I found out that the battery last almost the same time as when it is running Android, if you are not transcoding a video file for example.

Have an external keyboard available as it can save your butt when the touch interface stops working. With the available patch, it's far less serious, but still possible. Also enable the desktop icon in the virtual keyboard settings to invoke the keyboard. Even if Unity is not capturing touch events, the keyboard icon still is. Press "Alt" to invoke a "Run" command line and type "log". The dashboard will show you a short cut to "Log out". This will bring you back to the login screen and reset the touch interface to a working state.

Also enable Remote Desktop access as you can, from another computer or device regain access to your tablet using VNC.

Enable Ubuntu One or Shared folders via Samba which will let you copy some files on your device.

Firefox does run well, but Chromium is way smoother on the Nexus.

After booting up, sound is always muted, but it works if you adjust the volume with the hardware buttons, unmuting it.

Chromium does interact better with the virtual keyboard than Firefox.

Enable multi-desktop in your settings, it does work perfectly and let's you have multiple apps opened with an easy access.

Be prepared to re-flash everything if it does not work for you.

Flashing from Windows, it's possible!

Most tutorials are written for using an Ubuntu computer to unlock and flash the Nexus 7. But you can do it using Windows 7 also.

Install Wug's Toolkit to unlock the Nexus (http://www.wugfresh.com/nrt/). Follow the instructions until your tablet is unlocked.

Then, open a console as "Administrator" (type "cmd" in the Start menu, CMD.exe will show up, right-click on it to "Run as an administrator".

Download the 2 files to install Ubuntu (https://wiki.ubuntu.com/Nexus7/Installation). Follow the instructions from the wiki page...

Copy your Ubuntu files in C:\Program Files(x86)\WugFresh Development\Data. The command "fastboot" is located there. The in your console, move to that folder and follow the wiki instructions the same way.

After a few minutes, you'll have a brand new Ubuntu tablet!

Have fun!

Patrick Balleux

Sunday, April 14, 2013

Just code it as I want!

One of the hardest thing in the professional life of a programmer is to explain to a customer why the requested feature won't be implemented.

It can be a technical limitation of the language, a lack of resource available or simply a feature that is so specific that it will require to apply major modifications to the existing code.

From the user perspective, just adding a new button may seem an easy task, but the impact can be disastrous on the delivery date of the next version.

The worst approach to justify the major delay or simply why that new "must-have" feature won't be implemented is to describe in great details all the technical issues that may occur. Too much detail is just too confusing for the non-programmer. And they actually and honestly don't care, that's YOUR problem...

The second worst approach is considering that the client is using the wrong method to solve his problem and should use "our" method based on some "best practices" written by some "specialist". In theory, you may be right but the reality is that real life will prove you wrong. Often, some odd requirements are based on other requirements related to internal policies, accepted methodology from a professional association or simply because it's been like this for the last 50 years.

A third worst approach to deny that "amazing" requested new feature is simply stating that's it is impossible to do. To the non-programmer, if mankind was able to go to the moon, mankind is able to create a piece of software that will guess the user's mind. However impossible to achieve, a bit of explanation is required anyway.

How do the programmer can successfully explain and describe the issue without looking stubborn, stupid or lazy?

1 - Make sure that you perfectly understood the customer requirements. Often, the user is asking for a workaround to solve another issue. Maybe you can easily fix the triggering issue instead of creating a fully automated workaround.
2 - Some users may not realized that they are using the wrong tool to do their work. Is the software meant to do what the user is anticipating.
3 - Can the requested featured be implemented gradually? Resources are not unlimited and you have to deal with what you have: a small team of programmers, limited hardware availability, lack of funding or simply not enough time to execute the required technical research.
4 - Is your software scalable? Maybe it's time to rebuild from scratch so new features can be added easily.

Make sure that the issue preventing the implementation is not triggered by your own implementation of the solution. If that's the case, it's time to do your homework and plan a new major version. It will then be easy to explain that you (as a team) are in a process of rebuilding the software and that the requested feature will be evaluated and implemented in the next major release.

It is also possible that this new feature is not in your roadmap. Better lose a single customer than all of them by trying to please everyone. When a piece of code is meant to do everything, it will eventually do nothing...

A lack of resource or budget is not what companies want to talk about. It's even worse when some layoffs occurred or a some administration changes happened. Better put the focus on the roadmap of the project or the internal procedures that your team has to comply with. Make it look like your team is well structured and dedicated to keep a high quality product so that adding a new feature must be evaluated first and it can take some time before it can be implemented.

Facing an "impossible" feature is better explained by listing required technologies to achieve that goal and most importantly, the cost of such a mandatory modification. Money talks, everywhere, anywhere and anytime. Just provide the honest cost of what is being asked and the client will change his mind on a dime. In the event that money is not problem, it's time for you and your team to take the opportunity to move that next better and improved version...

Convert any technical modification into time, resource and cost. This will gave you the most understood argument in mankind: Money!

With enough funding, mankind could land on the moon again and broadcast in full HD this time...


Patrick Balleux

Wednesday, April 10, 2013

The news is about...

If you follow the actuality on the net about mobile devices, you may have already seen some trends in the news.

Overall, when comparing Apple, Google and Blackberry products, you can easily see that they do not report the same kind of news.

Apple
Currently, everything is about the next iPad and the next iPhone. Of course, the look of the next iOS 7 is another major source of news, rumours and expectations. On the side, there are a bunch of news and reports about app updates, new apps and some new way to use the iPhone or the iPad (Mini).

Google
As for the Android devices, you have news about new devices in the coming months and some info about the next Android OS. There are more reports about technical specifications than Apple, but it's understandable since there are many brands involved using the OS. You have the usual review of apps but most importantly the analysis of the next evolution of each Google Services that you can access from your mobile device.

Blackberry
Everything is about the Z10 and lately the Q10. Some app reviews are available but mainly, it's all about comparisons between the Z10 and (iPhone, Galaxy, Nexus...). I've even seen an "analysis" saying that Apple is doomed and Blackberry is winning against Apple. Seems that since Apple's shares have drop 40% and Blackberry's shares have doubled in value, it's a fact that Blackberry is a clear winner... They just did not pointed out that Apple is worth around 440$/share and Blackberry is work around 15$/share. Oh yeah, Google is a nobody with around 770$/share.

Microsoft
I don't really read about MS products but once in a while some news are popping out. A bit about the hardware, a bit about tiles, a bit about this and that... That's probably why nothing seems to attract my attention.

In the end, Apple and Google are leading in exciting news around the net. New devices, new OS, new apps and a fierce competition on features, looks and experiences.

Since we were able to read the news about technology online, never there was a time so full of surprises and breakthroughs. Every week, headlines are changing sides, new data is leaking and rumours are created.

Thank you Apple and Google for creating a "new" world where every boundaries must be pushed to the limit. As for the others players that were once major, keep on, wind can change side sometimes. We've seen it happen in the last 5 years.


Patrick Balleux

Saturday, April 6, 2013

Mobile evolution... What's next?

It's incredible what happened in the last 15 years of so. From big ugly noisy boxes we had on a desk at home, we arrived to a point where we can hold the world in our hand, everywhere and anywhere.

The "computer" transformed itself from a display, a keyboard and a mouse to a small beautiful device that it way more powerful, versatile and intuitive. Don't tell me what it can do, but show me how it looks!

We now have tablets and smartphones as any usual appliances like the TV, the telephone or the refrigerator. It's so common that owning such a device is not cool anymore. Apple and Google have solved a lot of issues and realized a lot of dreams in the last 5 years:

- Watch a movie, on the go
- Stay connected with our friends, all the time, anywhere
- Help us create masterpieces such as movies, pictures and new trends
- Play games somewhere else than on the TV
- Use our hands to interact with the softwares instead of relying on a keyboard and a mouse.

On those issues, mission accomplished!

What's left now? Have we reached a technological barrier? Internet access is available from any location. Device quality has improved to a point that the human eye cannot see the difference. The amount of information is much higher than what the human brain can process.

Currently, two new devices are being talked about: the "smart watch" and the "smart glasses". Those ideas are cool, but what are they trying to solve as issues.

- The smart watch provides a way to access information without having to reach for the smartphone in the back pocket. That's about it. It cannot be used to watch a movie or communicate by text. It can show you a small amount of information in a single display and maybe let you interact by voice with some online services. It's a smart phone that is really too small to be useful.

- The smart glasses (or any concept involving some wearable device in our visual field) are trying to solve the concept of having informations available directly into our brain. No keyboard, no mouse, no fingers! Just your voice and the visual feedback integrated into your own visual field: your eyes.

Computer evolution can be described as integrating data accessibility and processing into:
1 - Our home (2000, internet access and computers)
2 - Our lives (2007, mobile internet access an smartphones)
3 - Our personality (2012, social media)

The next step is to integrate data accessibility and processing into our thought process. To achieve this, the next device must make the information available before we even started thinking about what we will do next.

By combining what's around us, our preferences and the current action currently happening, a software could "guess" and "suggest" the next course of action that should be taken... That's a bit scary, but possible.

Let's say that you are in a grocery store and buying some stuff for dinner. The smart "unit" can notify you that you are near the chicken wings aisle and since they are currently on sale, why not invited some friends to watch the football game that is schedule in the evening on TV.

Instead of having an evening with your loved one, you will probably get the chicken wings and some tacos, and some beer, and some salsa. You will then post on Facebook, G+ and Twitter to all your friends that you will be hosting a Football night at home and who ever is available, to join you and your loved one.

There is nothing wrong with changing your plans. But for that change to happen, you have to be influenced before thinking about it. That's the next thing to achieve, integrate data accessibility and processing into our mind, into our thought process.

I doubt that the smart watch will be able to do this. On the other hand, the smart glasses may have a chance but it's a bit inconvenient if you don't need glasses in the first place.

So what would be best? A smart ear bud gently whispering into our ear? What about a "Star Trek" comm badge, able to display data on what ever surfaces in front of us?

The best would be a display that could be visible when needed. I'm not talking about some 3D images rotating in thin air, but more about the possibility of having a display that does not need a physical support to be visible.

If technology is able to produce some kind of display that does not need a physical surface, that will be the "next thing". Be it a hologram or an induced processed image directly into our brain...

Until then, let's try to keep our mind in control. (Yes darling, I'm coming...)

Patrick Balleux