This website uses cookies for visitor traffic analysis. By using the website, you agree with storing the cookies on your computer.More information

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:

JVx, JavaFX UI and CalendarFX

JVx, JavaFX UI and CalendarFX

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:

private void initializeUI() throws ModelException
    {
        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:

AppointmentsStorage apps = new AppointmentsStorage();
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:

add(new UICustomComponent(calendarView));

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:

((FXInternalWindow)getResource()).setContent(calendarView);

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 :)