JavaFX, JVx, CalendarFX and Exchange Server
It's friday, and it's (still) sunny
Some days ago, CalendarFX was released. It's a commercial product and looks promising. Now and then, we play around with new commercial products/libraries because our dev teams should know which product will work in commercial projects. A calendar control is always useful and especially if you organize "something". Many ERP products do this.
In good old swing applications, we did use migcalendar for better UX and visualization. But it's not available for JavaFX, so we tried CalendarFX.
The control is still in an early development stage and has some bugs or missing APIs, but it's very polished and works great with JVx and our JavaFX UI:
We tried to implement a simple JavaFX calendar screen, for Outlook appointments. We already had a connector for Exchange servers, based on EWS Java API and our JVx' storage implementation.
The screen code was simple, and more or less a simply copy/paste of a CalendarFX tutorial application. Here it is:
{
CalendarView calendarView = new CalendarView();
Calendar work = new Calendar("Work");
Calendar home = new Calendar("Home");
work.setStyle(Style.STYLE1);
home.setStyle(Style.STYLE2);
CalendarSource calSources = new CalendarSource("Private");
calSources.getCalendars().addAll(work, home);
calendarView.getCalendarSources().addAll(calSources);
calendarView.setRequestedTime(LocalTime.now());
Thread updateTimeThread = new Thread("Calendar: Update Time Thread")
{
@Override
public void run()
{
while (true)
{
Platform.runLater(() ->
{
calendarView.setToday(LocalDate.now());
calendarView.setTime(LocalTime.now());
});
try
{
// update every 10 seconds
sleep(10000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
};
};
Thread thLoadData = new Thread(new Runnable()
{
public void run()
{
try
{
RemoteDataBook rdb = new RemoteDataBook(apps);
rdb.setDataSource(getDataSource());
rdb.setName("calendar");
rdb.open();
rdb.fetchAll();
ZonedDateTime zdt;
for (int i = 0; i < rdb.getRowCount(); i++)
{
IDataRow row = rdb.getDataRow(i);
Entry entry = new Entry(row.getValueAsString("SUBJECT"));
zdt = ((Date)row.getValue("BEGIN")).toInstant().
atZone(ZoneId.systemDefault());
entry.setStartDate(zdt.toLocalDate());
entry.setStartTime(zdt.toLocalTime());
if (((Boolean)row.getValue("ALLDAY")))
{
entry.setFullDay(true);
entry.setEndDate(entry.getStartDate());
}
else
{
zdt = ((Date)row.getValue("END")).toInstant().
atZone(ZoneId.systemDefault());
entry.setEndDate(zdt.toLocalDate());
entry.setEndTime(zdt.toLocalTime());
}
if (((Boolean)row.getValue("PRIVATE")))
{
Platform.runLater(() -> home.addEntry(entry));
}
else
{
Platform.runLater(() -> work.addEntry(entry));
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
});
thLoadData.start();
updateTimeThread.start();
((FXInternalWindow)getResource()).setContent(calendarView);
setTitle("Calendar FX Demo");
}
The storage definition for fetching appointments was trivial:
apps.setURL(new URI("<url>"));
apps.setUserName("<username>");
apps.setPassword("<password>");
apps.open();
Not more code!
The special thing in our screen was the integration of a custom control. Usually, we would integrate it like this:
but our custom component integration for JavaFX UI wasn't ready. No problem, because it's always possible to access the real UI resource in JVx. So we did:
and everything was as expected. Sure, the screen won't work with Swing because we made a direct access to a JavaFX resource, but this was not relevant for our test