20 november 2009

No network on virtualbox guest ubuntu

When trying ubuntu 9.10 on virtualbox, sometimes there was no network. That was very irritating!

Luckily there are forums and in one of them the answer was found:

Scroll way down the the bottom and the second to last post by TerryE (from 17 sep 2008) says


The issue is to do with the persistence model implemented by the udev discover
process because your MAC address has changed. The easiest workaround is to edit the
file /etc/udev/rules.d/70-persistent-net.rules and delete the lines including "'# PCI
Device ..." to end. The net generator will recreate the correct entries on the next
reboot.


It works for me.
The only thing is that it will be a pain in the ... to have to edit that file and restart every time there is no network connection :-(

16 november 2009

My favorite songs

The dutch radio station Radio Veronica broadcasts at the end of the year a top 1000 of all times. This list is compiled from listeners who vote for there personal top 10 on the website. There are some restrictions to voting. The songs have to be more than a year old, not all songs are in the list from which you can choose and there may be only one song of a band of musician. This year my list is:


1. Boston - More Than A Feeling
2. Radiohead - Creep
3. Evanescence - My Immortal
4. Guns 'n Roses - November Rain
5. Metallica - The Unforgiven
6. Air Supply - All Out Of Love
7. Nirvana - Lithium
8. The Babys - Everytime I Think Of You
9. The Cure - A Forest
10. AC/DC - Thunderstruck


Songs that missed this top 10 were:


Roxette: Fading like a flower
Robert Plant Big log
Toto Hold the line
Aerosmith I don't want to miss a thing
Bryan Adams Run to you
Bonny Tyler Total eclipse of the heart
Bon Jovi Always
The cranberries Zombie
K's choice Not an addict
The Cult Ciao Edie (not on the radio veronica list)
John Miles Music
Def Leppard Love bites
Deep purple Child in time
Ellen Foley We belong to the night
Pat Benatar Invincible
The Verve Bitter sweet symphony
Foreigner I want to know what love is
Fisher Z Marliese (not on the radio veronica list)
Gary Moore Empty rooms
Phil Lynott Out in the fields (not on the radio veronica list)
Heart Allies (not on the radio veronica list)
Kings of leon Use somebody
Metallica The unforgiven
Marillion Lavender
Wihtin Temptation All I need (not on the radio veronica list)
Meatloaf Bat out of hell
REO Speedwagon Keep on loving you
Ozzy Osbourne Dreamer
Phil Collins Against all odds
Queen Who wants to live forever
Survivor The search is over (not on the radio veronica list)
Skunk Anansie Weak
Therapy? Diane
Van Halen Running with the devil
ZZ Top Rough boy


And these are only the songs I considered for the top 10. There ara so much more good songs out there.

If you look at the list it probably isn't to hard to guess what music style I like ;-)
And another thing you can see is that, although I am Dutch, there are no dutch songs on the list. Oh, and no christmas songs to, even if it is the end of the year

15 november 2009

Setting up JavaFX and Maven2 on Ubuntu

I wanted to have a good, IDE independent, working environment. So i made a VirtualBox Ubuntu vm and tried to make JavaFX and Maven work together.

Setting up Maven

Setting up maven is not to difficult, just search for maven in Synaptic package manager and select maven2. I do wonder why Groovy, Ivy and Velocity also want to be installed. Then edit the settingsfile (in /etc/maven2/) and set your local repository if you don't want the standard repo location

Setting up JavaFx

Setting up JavaFX is a bit trickier. It is not in the Synaptic package manager list of apps. You can download it from Sun. This will get a script file which will set up the javafx environment. Since I have not to much experience with linux I had no idea where to put it. I decided to put it in /etc/ (open a terminal, chmod a+x javafx_sdk-1_2_1-linux-i586.sh, cd to the directory where you want it installed and execute the script with: sudo /home/andre/Downloads/javafx_sdk-1_2_1-linux-i586.sh ). For working with javafx it doesn't really matter, just remember the path, you need it later on.

Making the two work together

The first thing to do for making maven and javafx work together is to let maven find the javafx compiler. There is a plugin for maven which does exactly that. The only thing you need then is to make the environment variable JFX_HOME. After looking up how to do that, maven tried to compile a demo class.

Off course it didn't compile the first time, because the compiler could not find the javafx classes. After searching the net I used this way, but later i want to not haven all the javafx dependencies in my pom, so I need to search for a better way.

Then it still did not work because I forgot some imports in the javafx class ;-( After fixing that it compiled fine.

Off course,with that working I wanted more. I wanted to also run it from maven. Since I wasn't the first to want to do that there was an answer on internet. I only needed the last bit of the comment from Marcos Muíño on the bottom of the page and presto! My first javafx compile, install and run with maven.



<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
<configuration>
<executable>/opt/javafx-sdk1.2/bin/javafx</executable>
<arguments>
<argument>nl.tikal.common.javafxmavenproject.Controls</argument>
<argument>-classpath</argument>
<classpath />
</arguments>
</configuration>
</plugin>



TODO:

Removing the javafx dependencies from the pom.

Making maven work with combined JavaFx and Java projects.
http://sourceforge.net/apps/mediawiki/jfxpictureview/index.php?title=Using_Maven_2_with_JavaFX

The complete pom


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>nl.tikal.common</groupId>
<artifactId>JavaFxMavenProject</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>JavaFxMavenProject</name>
<url>http://maven.apache.org</url>
<properties>
<javafx.home>/opt/javafx-sdk1.2</javafx.home>
</properties>
<dependencies>
<dependency>
<groupId>javafx</groupId>
<artifactId>compiler</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/shared/javafxc.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>runtime</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/shared/javafxrt.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>desktop-rt15</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/desktop/rt15.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>geom</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/desktop/javafx-geom.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>ui-common</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/desktop/javafx-ui-common.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>ui-desktop</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/desktop/javafx-ui-desktop.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>ui-swing</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/desktop/javafx-ui-swing.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>fxdloader</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/desktop/fxdloader.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>websvc</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/desktop/websvc.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>ui-controls</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/desktop/javafx-ui-controls.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>ui-charts</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/desktop/javafx-ui-charts.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>common</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/desktop/javafx-common.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>io</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/desktop/javafx-io.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>eula</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/desktop/eula.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>anim</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/desktop/javafx-anim.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>decora-runtime</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/desktop/decora-runtime.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>decora-j2d-rsl</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/desktop/decora-j2d-rsl.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>decora-ogl</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/desktop/decora-ogl.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>sg-common</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/desktop/javafx-sg-common.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>sg-swing</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/desktop/javafx-sg-swing.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>jogl</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/desktop/jogl.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>gluegen-rt</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/desktop/gluegen-rt.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>jmc</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/desktop/jmc.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>script-api</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/desktop/script-api.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>mobile-cldc</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/mobile/javafxapi-cldc.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>mobile-cldc_1.1</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/mobile/cldc_1.1.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>mobile-midp_2.0</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/mobile/midp_2.0.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>mobile-jsr120_1.1</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/mobile/jsr120_1.1.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>mobile-jsr135_1.1</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/mobile/jsr135_1.1.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>mobile-jsr172_1.0</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/mobile/jsr172_1.0.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>mobile-jsr177_1.0</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/mobile/jsr177_1.0.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>mobile-jsr179_1.0</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/mobile/jsr179_1.0.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>mobile-jsr184_1.1</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/mobile/jsr184_1.1.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>mobile-jsr234_1.0</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/mobile/jsr234_1.0.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>mobile-jsr256_1.1</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/mobile/jsr256_1.1.jar</systemPath>
</dependency>
<dependency>
<groupId>javafx</groupId>
<artifactId>mobile-jsr75_1.0</artifactId>
<version>1.2</version>
<scope>system</scope>
<systemPath>${javafx.home}/lib/mobile/jsr75_1.0.jar</systemPath>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<sourceDirectory>src/main/java</sourceDirectory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerId>javafxc</compilerId>
<include>**/*.fx</include>
<fork>true</fork> <!-- NOTE: only “fork” mode supported now -->
</configuration>
<dependencies>
<dependency>
<groupId>net.sf.m2-javafxc</groupId> <!-- NOTE: groupdId conforms project domain name, was: net.sf.m2-javafxc -->
<artifactId>plexus-compiler-javafxc</artifactId>
<version>0.3</version> <!-- NOTE: 0.3 is the current version in Maven Central repository -->
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
<configuration>
<executable>/opt/javafx-sdk1.2/bin/javafx</executable>
<arguments>
<argument>nl.tikal.common.javafxmavenproject.Controls</argument>
<argument>-classpath</argument>
<classpath />
</arguments>
</configuration>
</plugin>
</plugins>
</build>
</project>

8 november 2009

Ubuntu 9.10 virtualbox ose 2.2.4 and guestadditions

Installing Ubuntu 9.10 on virtualbox ose 2.2.4is not a problem. Just make a new machine, set Ubuntu 9.10 iso as cd image and install from there.

Problems arise when trying to install the guest additions. Since Ubuntu 9.10 has a more recent kernel than virtualbox expects, an error occurs


error: implicit declaration of function utf8_mbtowc


You can find a solution for this on the net, but for me the easiest solution was to download the guest additions for the newest version (3.0.8) of the VBoxGuestAdditions
and install these.


Set VBoxGuestAdditions_3.0.8.iso as cd image in VirtualBox and

Open a terminal (by pressing ALT-F2) and enter “terminal” on gnome.
cd /media/cdrom
sudo bash ./VBoxLinuxAdditions-x86.run
(the one for your platform, in my case x86)


Now it should compile and install and is finally usable.

18 januari 2009

Golf and JavaFX, part 3

The code from the last two parts has been cleaned and the GUI has been prettyfied.



This new code is available as a netbeans project.

Now that a schedule can be displayed , the next challenge is to be able to go to the individual tournaments. Therefore the tournament names need to be links to another JavaFx class, which will be dispayed next to the schedule.

The most easy way is to make a JavaFX class ScheduleRow which contains not only the text and format, but also the link to the tournamentpage. This then replaces the Group in the for loop in Schedule.fx.


public function getSchedule(year:String):Node[] {
var europeanTour = new EuropeanTour();
if(tournaments == null) {
var schedule = europeanTour.getSchedule();
tournaments = [
for (tournament in schedule) {
counter++;
var yposition = counter * (tournamentFontSize + tournamentFontSize/2);
ScheduleRow {
tournament: tournament
tournamentFontSize: tournamentFontSize
tournamentlink: "link"
width:width
y: yposition

}
}
];
} else {
tournaments = [];
}
}


The new getSchedule() method in Schedule.fx


import javafx.scene.CustomNode;
import javafx.scene.Node;
import javafx.scene.Group;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.scene.paint.Color;
import javafx.scene.paint.Stop;
import javafx.scene.text.Font;
import javafx.scene.paint.LinearGradient;

/**
* @author André Hogenkamp
*/

public class ScheduleRow extends CustomNode {

public var tournamentlink: String;
public var tournament: String;
public var tournamentFontSize: Integer;
public var width: Integer;
public var y: Integer;

function getRow() {
}

override function create() : Node {
Group {
content: [
Rectangle {
x: 0
y: y
width: width
height: tournamentFontSize + tournamentFontSize/2
fill: LinearGradient {
startX: 0.0, startY: 0.0, endX: 0.0, endY: 1.0
proportional: true
stops: [ Stop { offset: 0.0 color: Color.rgb(40, 40, 40) },
Stop { offset: 1.0 color: Color.rgb(30, 30, 30) }
]
}

}
Text {
content: tournament;
fill: Color.LIGHTGREY
font: Font {
size: tournamentFontSize
}
x: 5
y: y + tournamentFontSize + tournamentFontSize/4
}
]

}
}



The new class ScheduleRow.fx

The method getSchedule() in EuropeanTour.java must now return a Java Object rather then a String[] because we need both the name and the link of the tournament. The new java class TournamentLink.java does this for us.

The new getValuesforClass() from Parser.java return a List of these Tournamentlink classes.

The new JavaFX class Tournament can then load this page to read the scores and display the default playerscores, the top10 players.

This class also let the user choose other views, such as players from a specified nation.

4 januari 2009

Golf and JavaFX, part 2

In the first part of this series an chart was made to show a graph on a grid.

In this part the content for the page is extracted from the page www.europeantour.com.

Before the tournament data (which we eventually want) can be fetched, first the schedule of a year is fetched from the homepage. JavaFX does have a class for getting http requests, but doesnt have one for the parsing of html, so the htmlparser was used. In the end it was easier to do all the html work in Java and only the presentation in JavaFX.

A method that uses an xpath expression, a tagvalue and an attributename does the work of getting the url for the schedule page. The xpathexpression was used as a more general way of specifying which element would be needed, but in the end only the element name is used.


/**
* Returns the value of the requested attribute of the requested node.
*
* @param xpath The xPath expression to the requested node, including the nodename.
* @param tagvalue The value of the requested node.
* @param attributeName The attributename of the requested attribute of the requested node.
* @return The value of the requested attribute of the requested node.
* @throws javax.swing.text.BadLocationException
*/
public String getAttributeValue(String xpath, String tagvalue, String attributeName) throws BadLocationException {
String attributeValue = null;
try {
NodeList list = new NodeList ();
String tagName = xpath.substring(xpath.lastIndexOf("/") + 1);
// System.out.println("tagName = " + tagName);
NodeFilter filter = new AndFilter(new NodeFilter[] {
new TagNameFilter(tagName),
new HasChildFilter(new RegexFilter(tagvalue, RegexFilter.MATCH)),
new HasAttributeFilter(attributeName)
});
for (NodeIterator e = parser.elements (); e.hasMoreNodes ();) {
e.nextNode ().collectInto (list, filter);
}
// System.out.println("list size = " + list.size());
if(list.size() > 0) {
TagNode node = (TagNode)list.elementAt(0);
attributeValue = node.getAttribute(attributeName);
}
} catch(ParserException px) {
throw new BadLocationException(xpath, 0);
}
return attributeValue;
}



The AndFilter does all the hard work for us, it is a nice way of finding the right element. From that we get the value of the 'href' attribute.

The fetching of the schedule (list of tournaments) is mostly the same. Except that a list is needed and that it must be from a childelement of the elements we look for (A 'TD' element with css class 'tournNameCell' and child element 'a' which contains the name of the tournament)


/**
* Gets a list of values for all elements that have the css class type given and a child element
* with the specified name. The value is taken from the child element.
*
* @param xpath
* @param classvalue
* @param childElementName
* @return
* @throws javax.swing.text.BadLocationException
*/
public List getElementValuesForClass(String xpath, String classvalue, String childElementName) throws BadLocationException {
List tournamentNames = new ArrayList();
try {
NodeList list = new NodeList ();
String tagName = xpath.substring(xpath.lastIndexOf("/") + 1);
// System.out.println("tagName = " + tagName);
NodeFilter filter = new AndFilter(new NodeFilter[] {
new TagNameFilter(tagName),
new HasAttributeFilter("class", classvalue)
});
for (NodeIterator e = parser.elements (); e.hasMoreNodes ();) {
e.nextNode ().collectInto (list, filter);
}
// System.out.println("list size = " + list.size());
for (int i = 0; i < list.size(); i=i+2) {
TagNode node = (TagNode)list.elementAt(i);
NodeList childList = new NodeList();
NodeFilter childFilter = new TagNameFilter(childElementName);
for (NodeIterator e = node.getChildren().elements(); e.hasMoreNodes();) {
e.nextNode().collectInto(childList, childFilter);
}
TagNode childNode = (TagNode)childList.elementAt(0);
String tournamentLink = childNode.getText();
NodeList textChildList = new NodeList();
NodeFilter textChildFilter = new NodeClassFilter(TextNode.class);
for (NodeIterator e = childNode.getChildren().elements(); e.hasMoreNodes();) {
e.nextNode().collectInto(textChildList, textChildFilter);
}
String tournamentName = textChildList.elementAt(0).getText();
tournamentNames.add(tournamentName);
// System.out.println("list item = " + tournamentName);
}
} catch(ParserException px) {
throw new BadLocationException(xpath, 0);
}
return tournamentNames;
}



The method in the EuropeanTour class puts it all together.


import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.text.BadLocationException;

/**
*
* @author André Hogenkamp
*/
public class EuropeanTour {
private static final String EUROPEANTOUR_URL = "http://www.europeantour.com/";

/**
* returns a schedule from the european tour as a String array.
*
* @return
*/
public String[] getSchedule() {
List schedule = new ArrayList();
try {
HtmlParser parser = new HtmlParser(EUROPEANTOUR_URL);
parser.parse();
String scheduleUrl = parser.getAttributeValue("/html/body/table[1]/tr[2]/td/ul/li[6]/ul/li[4]/a", "Schedule", "href");
// System.out.println("scheduleUrl:" + scheduleUrl);
if(scheduleUrl != null) {
parser = new HtmlParser(scheduleUrl);
parser.parse();
schedule = parser.getElementValuesForClass("/html/body/table/tr[4]/td/table/tr/td[2]/table/tr/td/div/div/table/tr/td", "tournNameCell", "a");
// System.out.println("schedule length:" + schedule.size());
}
} catch (IOException ex) {
Logger.getLogger(HtmlParser.class.getName()).log(Level.SEVERE, null, ex);
} catch (BadLocationException blx) {
Logger.getLogger(HtmlParser.class.getName()).log(Level.SEVERE, null, blx);
}
String[] scheduleArray = new String[schedule.size()];
return (String[]) schedule.toArray(scheduleArray);
}

}


Now the presentation part.

The main page is just a simple one for now. It shows a list of years (the idea is to get the schedule for that year, but i don't know if that wil work, since the europeantour page does not have that functionality :-( ) and the schedule for that year (2009 for now)


import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.text.Text;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.layout.VBox;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;

/**
* @author André Hogenkamp
*/

var schedule = Schedule {
year: "2009";
};

Stage {
title: "Golf scores"
width: 500
height: 800
scene: Scene {
fill: Color.BLACK
content:
[
VBox {
spacing: 5
content:
[
Text {
content: "2009 2008"
fill: Color.WHITE
font: Font.font("Helvetica", FontWeight.BOLD, 16)
y: 16
}
HBox {
spacing: 5
translateY: 50
content: [
schedule
]
}
]
}
]
}
}


The VBox and HBox should space the containing nodes, but this does not seem to work. Maybe the used custom nodes are not complete yet.
The schedule class formats the schedule for printing on the screen. A Text node with 'Schedule' and the year followed by the list of tournaments. Content was a Text[] since the tournamet list contains only Text nodes, but was changed to a Node[] to make a group of the Text nodes and be able to change tre position.


import javafx.scene.CustomNode;
import javafx.scene.Node;
import javafx.scene.text.Text;
import javafx.scene.Group;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import nl.tikal.sport.golf.net.EuropeanTourFx;

/**
* @author André Hogenkamp
*/

public class Schedule extends CustomNode {
public var year: String = "2009";

var content: Node[];

def tour: EuropeanTourFx = EuropeanTourFx {
}

/**
* The grid contains lines to form a grid.
*/
var schedule : Group = Group {
content: bind [
Text {
content: "Schedule {year}"
fill: Color.WHITE
font: Font.font("Helvetica", FontWeight.BOLD, 16)
}
Group {
content: content
translateY: 20
}
]
}

public function getSchedule(year:String):Node[] {
content = tour.getTournaments();
}

override function create() : Node {
getSchedule(year);
schedule;
}

}

The list is filled from the EuropeanTourFx.getTournaments() method, which get its information from the java class EuropeanTour.



import javafx.scene.text.Text;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import java.lang.System;

/**
* @author André Hogenkamp
*/

public class EuropeanTourFx {

var tournaments: Text[];
var fontSize = 12;
var counter = -1;

public function getTournaments() :Text[] {
var europeanTour = new EuropeanTour();
if(tournaments == null) {
var schedule = europeanTour.getSchedule();
tournaments = [
for (tournament in schedule) {
counter++;
Text {
content: tournament;
fill: Color.YELLOW
font: Font {
size: fontSize
}
y: counter * fontSize
};
}
];
} else {
tournaments = [];
}
}


The for loop returns the last element therefore the counter++ is the first expression and the counter is initialised at -1.

When run it looks like


It is still basic, but it does what it should do.

17 december 2008

Golf and JavaFX, part 1

Since i am both a fan of golf and JavaFX, it would be nice to combine both.

One thing that i think is missing from the scoreboards on the european tour (or race to dubai as it's now called) is a trace of the position of the players. Yes you can see their current position and thier starting position, but not how they got there.

So let's make a chart that tracks those positions.

The goal

We will start with a drawing of how the endresult will look like.

Just a simple grid with two lines.

I can think of more to put in, but for now this will do.

Since we need a line chart, we'll start with that.
A line chart is a combination of a grid and a line graph.

First the grid

The variables for a grid are the number of lines (both vertical and horizontal) and their color and the size of the grid. So these were made public vars.

We want the lines to be neatly spaced out over the whole width and height, so we compute them by dividing the width with the nnumber of horizontal lines. The sequence xcoords than stores these horizontal coordinates. The sequence ycoords than does the same for the vertical coordinates. The sequences xcoordindex and ycoordindex are used for navigating through the *coords sequences.

The var grid defines the Group with the lines and the create() function creates the Grid node.

/*
* Grid.fx
*
* Created on Dec 16, 2008, 9:42:15 PM
*/

package nl.tikal.javafx.scene.chart;

import javafx.scene.paint.Color;
import javafx.scene.CustomNode;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.shape.Line;

/**
* @author André Hogenkamp
*/

public class Grid extends CustomNode {
public var stroke: Color;
public var width: Number;
public var height: Number;
public var horizontallines: Integer;
public var verticallines: Integer;

public def xcoords = [0..width step width/horizontallines];
public def ycoords = [0..height step height/verticallines];
def xcoordindex = [0..horizontallines];
def ycoordindex = [0..verticallines];

/**
* The grid contains lines to form a grid.
*/
def grid : Group = Group {
content: [
for (x in xcoordindex) {
Line {
stroke: stroke
startX: 0
startY: ycoords[x]
endX: width
endY: ycoords[x]
}
}
for (y in ycoordindex) {
Line {
stroke: stroke
startX: xcoords[y]
startY: 0
endX: xcoords[y]
endY: height
}
}
]
}

override function create() : Node {
grid
}
}

Next the linegraphs.

The variables for a linegraph are the stroke color and width, the size of the linegraph and the point that make up the linegraph. So these were made public vars again. Most of the code is the same as for the grid, except of course that this draws a line instead of a grid ;-)


/*
* LineGraph.fx
*
* Created on Dec 16, 2008, 10:29:08 PM
*/

package nl.tikal.javafx.scene.chart;

import javafx.scene.CustomNode;
import javafx.scene.Node;
import javafx.scene.paint.Color;
import javafx.scene.Group;
import javafx.scene.shape.Line;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.MoveTo;

/**
* @author André Hogenkamp
*/

public class LineGraph extends CustomNode {
public var strokeColor: Color;
public var strokeWidth: Integer;
public var width: Number;
public var height: Number;
public var horizontallines: Integer;
public var verticallines: Integer;
public var linepoints: GridPoint[];

public def xcoords = [0..width step width/horizontallines];
public def ycoords = [0..height step height/verticallines];
def reversedycoords = reverse ycoords;
def coordindex = [0..verticallines - 1];
var point1 = linepoints[0];

/**
* The lineGraph contains a path to form a graph.
*/
def lineGraph : Group = Group {
content: [
Path {
stroke: strokeColor
strokeWidth: strokeWidth
elements: [
MoveTo {x: xcoords[point1.x] y: reversedycoords[point1.y]}
for (x in coordindex) {
var point = linepoints[x];
LineTo {x: xcoords[point.x] y: reversedycoords[point.y]}
}
]
}
]
}

override function create() : Node {
lineGraph
}
}

For a complete lineChart we combine the grid and the linegraph. A lineChart can contain more than one linegraph, so this variable is a sequence of lineGraphs. There is also a variable to show or hide the grid.


/*
* LineChart.fx
*
* Created on Dec 17, 2008, 8:25:31 PM
*/

package nl.tikal.javafx.scene.chart;

import javafx.scene.CustomNode;
import javafx.scene.Node;
import javafx.scene.Group;

/**
* @author André Hogenkamp
*/

public class LineChart extends CustomNode {

public var grid: Grid;
public var showGrid: Boolean;
public var lineGraphs: LineGraph[];

/**
* The grid contains lines to form a grid.
*/
def lineChart : Group = Group {
content: [
grid, lineGraphs
]
}

override function create() : Node {
lineChart
}

}


So far for this first part. In the next part the pagedata is read from the htmlpage.