Sunday, April 10, 2011

 when Reading a text file in Java

If you have code that processes text files using InputStreamReader, you may be puzzled why there are certain garbage characters  at the start of your resulting String data if you output that the contents of the file.

This is due to a Reader processing your input file in ASCII encoding when the data is stored in UTF-8.

While I came across this in Java, the ASCII/UTF-8 solution was actually in this aptly named blog post "Three little characters  designed to make your life hell" by Martyn at the Ventrino Blog.

The solution proposed in the post is basically "if your text file is saved as UTF-8, that is the problem, save as ASCII encoding instead". I think this isn't really a best practice, probably as UTF-8 is better for internationalization, the developer should probably change his/her code to support that format rather than restrict a program to the limited set of US/Western ASCII characters.

Here is an example of code that when reading a UTF-8 encoded file, say a .HTML file will display the 

//stores the html text, in my case I needed to pass it in to an SWT Browser.setText() method.
StringBuffer buffer = new StringBuffer();
//read the HTML to display from a resource
InputStream htmlInStream = Resources.getResourceAsStream(Resources.HTML_ABOUT_HTML);

BufferedReader bufInpStream = new BufferedReader(new InputStreamReader(htmlInStream));
String line = "";

while(line != null){
line = bufInpStream.readLine();
//System.out.println(line);
if(line!= null){
buffer.append(line);
}
}


The key seems to be the InputStreamReader conversion of the underlying InputStream to the HTML file. Readers are by design for processing text, while Streams are more concerned with binary data. So when converting from the Stream, we have to tell it what encoding to use. This correction will solve the problem.

//if we didn't specify char-encoding as UTF-8, it would show these strange chars: 
BufferedReader bufInpStream = new BufferedReader(new InputStreamReader(htmlInStream,"UTF-8"));


Punch Clock has gone live

I have wrapped up development of a beta version of my side-project "Punch Clock". I've created a launch page on Google Sites, and linked from the side bar.

https://sites.google.com/site/punchclockswt/

The released version is basically a public beta, free for anyone to download. Right now I support Windows and Linux.

The feature set is rudimentary but I am adding features as I have time. It has been a good project to learn the ins and outs of SWT for a basic app. I would like to explore refactoring more the UI to use more of the JFace patterns on top of SWT, I was just beginning to use this with the About dialog and the persistent settings modules. From the beginning this was a learning project, where I picked up Apache Derby, SWT, and created a build process in ANT, launched an entire release site with actual documentation, specified a license for the work etc...

More to follow I am sure.

Saturday, April 9, 2011

Seedling update

"J2"


Our Redwood seedlings have survived the long dark New England winter and are starting to grow new shoots and widen their branches. Of the two J2 seems to have done a little better, on B2 there are some needles turning brown on an upper branch. The crown area of J2 has filled out better. Supposedly redwood seedlings can grow several feet per year, but we haven't seen growth like that yet. It could be the indoors, the pots, or even the lower levels of sunlight during our winters here. To make measuring easier I printed off some some color square rules, one inch squares and taped it to a wall as a background. As you can see the heights are about 15" for J2 and around 12" for B2, which has more of a curve. The length of the lower branches is really amazing now, the longest I've measured is around 9" and each of those has several 3-4" offshoots


"B2"
I was partly inspired to write this after watching a great National Geographic documentary Climbing Redwood Giants (2009) on Netflix. The quality was great in HD, seeing the fully grown giants was impressive. The two main focuses of the documentary were researcher Steve Sillett who using a crossbow(!), ropes and pulleys pulls himself up the giants in order to climb into the canopy and measure them. The other story a pair of researches, Micheal Fay and Lindsey Holm, transecting the known extent of the Coastal Redwood range. While a big focus was on trumpeting successes in stopping old-growth logging of Redwoods and conservation, the sheer size of the trees was the big show. I have had the opportunity to see redwoods in Muir Woods, but nothing like the 350 foot giants in the movie.

The trees ecosystem supposedly supports more biomass than any other ecosystem on Earth, including the tropical rain forests. It was interesting to see the mulberry bushes and other plants growing from the branches of some of the trees, hundreds of feet up. Another star was the Wandering Salamander that may spend its life in the tree canopy. They didn't really mention much about birds or insects nesting in the tree, which I would have assumed to be a big part of the ecosystem, although the tannins in the Redwood bark are supposed to deter insects.


Finally here are a few more pictures of the seedlings, and some of their new growths.
 
"B2" new growth shoot
Another shot of both trees.
Two's company



Sunday, April 3, 2011

Collapsible SWT Text Area Snippet

A little sample code showing how you can have a Java SWT button that can collapse other Controls like a toggle switch. This also will show how to resize the container after "collapsing" your control.

I went this route after not finding the SWT ExpandBar widget suiting this purpose.

Screenshots from Windows 7

Source Code

/*
*
*/
package swt.snippet;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

import com.brianl.timetrack.controller.TimeSession;
import com.brianl.timetrack.view.CollapseButtonListener;

/**
* Simple SWT Shell that contains a Group with some controls. An arrow button is
* used to toggle the Text area widget as collapsed or not.
*
* @author ammianus http://librixxxi.blogspot.com/
*
*/
public class CollapsibleTextBox {

private static final int NUMBER_GRID_COLUMNS = 1;

private Display _display;

private Shell _shell;

CollapsibleTextBox() {
_display = new Display();
_shell = new Shell(_display);
_shell.setSize(300, 250);
// Collapsible Group
_shell.setText("Collapsible Group Example");
// format shell as single column grid layout
_shell.setLayout(new GridLayout(NUMBER_GRID_COLUMNS, true));

// create the group
Group collapseGroup = new Group(_shell, SWT.NONE);
GridData groupGrid = new GridData(SWT.TOP, SWT.LEFT, false, false);
groupGrid.horizontalSpan = 1;
collapseGroup.setLayoutData(groupGrid);
collapseGroup.setText("Control Group");

// create a Label and Button inside the Group
GridData labelGridData = new GridData(GridData.VERTICAL_ALIGN_END);
labelGridData.horizontalSpan = 1;
String labelText = "Pressing button toggles Text. ";
final Label instructionLabel = new Label(collapseGroup, SWT.NONE);
instructionLabel.setText(labelText);
instructionLabel.setLayoutData(labelGridData);
instructionLabel.pack();

final Button collapseButton = new Button(collapseGroup, SWT.ARROW
| SWT.UP);

// multi-row Text area with word-wrap
final Text textArea = new Text(collapseGroup, SWT.MULTI | SWT.LEAD
| SWT.BORDER | SWT.WRAP);

// set height and width of Text area
GC gc = new GC(textArea);
FontMetrics fm = gc.getFontMetrics();
final int textBoxWidth = 50 * fm.getAverageCharWidth();
final int textBoxHeight = 4 * fm.getHeight();
gc.dispose();
textArea.setSize(textArea.computeSize(textBoxWidth, textBoxHeight));
GridData textBoxGrid = new GridData(SWT.TOP, SWT.LEFT, false, false);
textBoxGrid.horizontalSpan = NUMBER_GRID_COLUMNS;
textBoxGrid.heightHint = textBoxHeight;
textBoxGrid.widthHint = textBoxWidth;
textArea.setLayoutData(textBoxGrid);

// set the layout for the items contained by the Group as a two column
// grid
collapseGroup.setLayout(new GridLayout(2, false));
collapseGroup.layout(true);

// create a listener that waits for button press
collapseButton.addListener(SWT.Selection, new CollapseButtonListener(
textArea, textBoxWidth, textBoxHeight, collapseGroup,
textBoxGrid));

// open the shell and run UI loop
_shell.pack();
_shell.open();
while (!_shell.isDisposed()) {
if (!_display.readAndDispatch())
_display.sleep();
}
_display.dispose();
}

/**
* Runs the demo
*
* @param args
*/
public static void main(String[] args) {
new CollapsibleTextBox();
}

/**
* inner class handles button click events for arrow button
*
*/
public class CollapseButtonListener implements Listener {

private Text _timeNotesBox;
private int _textBoxHeight;
private int _textBoxWidth;
private Group _container;
private GridData _textBoxGrid;

/**
* @param timeNotesBox
* @param textBoxHeight
* @param textBoxWidth
* @param container
* @param textBoxGrid
*/
public CollapseButtonListener(Text timeNotesBox, int textBoxWidth,
int textBoxHeight, Group container, GridData textBoxGrid) {
super();
// save references to the various controls to update
this._timeNotesBox = timeNotesBox;
this._textBoxHeight = textBoxHeight;
this._textBoxWidth = textBoxWidth;
this._container = container;
this._textBoxGrid = textBoxGrid;
}

/*
* (non-Javadoc)
*
* @see
* org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets
* .Event)
*/
@Override
public void handleEvent(Event event) {
// toggles the Text Area as visible or not.
// When Text Area is collapsed, resize the parent group
if (_timeNotesBox.getVisible()) {
// collapse the text area
_timeNotesBox.setSize(_timeNotesBox.computeSize(1, 1));
_textBoxGrid.heightHint = 1;
_textBoxGrid.widthHint = 1;
_timeNotesBox.setLayoutData(_textBoxGrid);
_timeNotesBox.setVisible(false);
_timeNotesBox.pack(true);
System.out.println("Hiding textbox");
} else {
// expand text area back to original sizing
_timeNotesBox.setSize(_timeNotesBox.computeSize(_textBoxWidth,
_textBoxHeight));
_textBoxGrid.heightHint = _textBoxHeight;
_textBoxGrid.widthHint = _textBoxWidth;
_timeNotesBox.setLayoutData(_textBoxGrid);
_timeNotesBox.setVisible(true);
_timeNotesBox.pack(true);
System.out.println("Showing textbox");
}

// in this case the container is the Group
_container.pack(true);

// resize the parent shell too
_container.getParent().pack(true);
}

}
}


Built with:
swt-3.6.1-win32-win32-x86
Java 1.6.0_17
Eclipse 3.4.1

Built on the model of the snippets from java2s and the SWT snippets site.

I came up with this approach as I am trying to have an optional text box in my "Time Track" program. I really didn't see any other way to have this kind of dynamic visual behavior that is pretty common on websites these days. The only prebuilt widget that seemed similar was the ExpandBar, but what that did was create a large pane with expandable widgets within it. These all had a very non-native look and feel and was bit complex to set up when I had a single text box to expand/collapse.