New Calendar Year!

BlackBerry 10 Cascades Calendar Invoke comic

Happy New Year! It only seems fitting to have a posting about the calendar on New Year’s Day, so here we go…  Sticking with RIM’s guidelines to create a seamless experience (much like my previous SHARE invoke) I will show how to invoke the Calendar card to create a new event.  However, unlike the SHARE example, this does require C++ but fear not it is easier than you think, plus I tie it into the QML too.

First things first, this is a derived example from Paul Bernhardt’s (RIM dev, @PBernhardt) example that he presented at BlackBerry Jam Americas and Asia. So its best to download his full source https://github.com/blackberry/Presentations/tree/master/2012-BlackBerryJam-Asia/JAM818/CalendarInvoker from github. He goes over many aspects of the calendar but my goal was to rip out just the parts to create a new event and tie it closer to the QML than he did.  With that being said I may have left some unnecessary code in but nothing that seems to affect performance.

Now I will take you through the steps I did to take his “CalendarInvoker” app and add it to my “CalendarInvokerBS” app.  Obviously, first create a new app called “CalendarInvokerBS” then copy over assets (main.qml) and src files (CalendarInvoker.cpp, CalendarInvoker.hpp) Then I renamed the files to CalendarInvokerBS and made sure to change the name through out the code too.

In the CalendarInvokerBS.cpp you can remove all of the void functions except first one, which creates the main.qml file, and the onComposerButtonClicked() function.  Also since I’ll be handling the signal/slots in QML you can remove that code as well.  Finally I added the contextproperty “callCalendarapp”, which makes your CalendarInokerBS.cpp look like:

// Default empty project template
#include "CalendarInvokerBS.hpp"

#include <bb/cascades/Application>
#include <bb/cascades/QmlDocument>
#include <bb/cascades/AbstractPane>
#include <bb/system/InvokeManager.hpp>
#include <bb/system/InvokeReply.hpp>
#include <bb/PpsObject>
#include <qdebug.h>;

using namespace bb::cascades;
using namespace bb::system;
using namespace bb::pim::calendar;

CalendarInvokerBS::CalendarInvokerBS(bb::cascades::Application *app) :
        QObject(app), _invokeManager(new InvokeManager(this)), _calendarService(
                new CalendarService()) {
    // create scene document from main.qml asset
    // set parent to created document to ensure it exists for the whole application lifetime
    QmlDocument *qml = QmlDocument::create("asset:///main.qml").parent(this);
    qml->setContextProperty("callCalendarapp", this);

    // create root object for the UI
    AbstractPane *root = qml->createRootObject<AbstractPane>();
    // set created root object as a scene
    app->setScene(root);


    QObject::connect(_invokeManager,
            SIGNAL(childCardDone(const bb::system::CardDoneMessage &)), this,
            SLOT(onChildCardDone(const bb::system::CardDoneMessage &)));
}


/***
 * Invokes the event creator card
 *
 * You can prepopulate the event details if you like
 */
void CalendarInvokerBS::onComposerButtonClicked() {
    InvokeRequest cardRequest;

    QVariantList participants = QVariantList();
    participants.append("bob@g.com");
    participants.append("vigandhi@rim.com");
    QVariantMap data = QVariantMap();
    data.insert(QString("participants"), QVariant(participants));
    data["subject"] = "test test";
    qDebug() << " your other data is " << data;
    cardRequest.setTarget("sys.pim.calendar.viewer.eventcreate");
    cardRequest.setAction("bb.action.CREATE");
    cardRequest.setMimeType("text/calendar");
    bool ok;
    QByteArray encData = PpsObject::encode(data, &ok);
    qDebug() << encData;
    cardRequest.setData(encData);
    InvokeTargetReply* reply = _invokeManager->invoke(cardRequest);
}

Next for the .hpp file you can either delete out or comment out the functions you deleted from the .cpp file so you have something like this for your declared slots:

public slots:

//    void onChildCardDone(const bb::system::CardDoneMessage &message);
//    void onPickerButtonClicked();
    void onComposerButtonClicked();
//    void onViewerButtonClicked();

Now to the main.qml file, I reworked the UI to look like this:

BlackBerry 10 Cascades Calendar Invoke

So I have a few Labels, a TextField, a TextArea, a DropDown and the same Button that was in Paul’s example:

import bb.cascades 1.0

// creates one page with a label

Page {
    Container {
        layout: StackLayout {
        }
        Label {
            text: qsTr("Invoke the Calendar")
            textStyle.base: SystemDefaults.TextStyles.BigText
            verticalAlignment: VerticalAlignment.Center
            horizontalAlignment: HorizontalAlignment.Center
        }
        Button {
            objectName: "composerButton"
            id: composerButton
            text: "Compose Event"
           
        }
        Label{
            text: "Title:"
            }
        TextField {
            id: titledetails
        }
        Label{
            text: "Other Stuff?"
            }
        TextArea {
            id: bodydetails
        }
        DropDown {
            id: in1
            objectName: "in1"
            title: "How many New Year's Resolutions"
            horizontalAlignment: HorizontalAlignment.Fill
            Option {
                text: "1"
                value: 1
            }
            Option {
                text: "2"
                value: 2
            }
            Option {
                text: "3"
                value: 3
            }
            Option {
                text: "4"
                value: 4
            }
            Option {
                text: "5"
                value: 5
            }
        }
    }
}

But since we removed the signal/slot code from the cpp we need to add it back into the QML and that is as simple as adding an onClicked with the contextproperty.functionName:

onClicked: {
                callCalendarapp.onComposerButtonClicked();
            }

I want to take you a step further now and make it so information from the QML will be passed into the CPP function so change the onClicked to:

onClicked: {
                var option1 = in1.at(in1.selectedIndex).value;
                callCalendarapp.onComposerButtonClicked(titledetails.text, bodydetails.text, option1);
            }

This makes it so the titledetails text, bodydetails text, and the in1 selected value will be passed to the CPP function. Also we need to have the function prepared for these inputs so adjust the function in the .cpp and .hpp files to:

onComposerButtonClicked(QString titletext, QString bodytext, QString dropd1)

Now you can add these three QString variables to inside of your function, for example something like:

void CalendarInvokerBS::onComposerButtonClicked(QString titletext, QString bodytext, QString dropd1) {
    InvokeRequest cardRequest;

    QVariantList participants = QVariantList();
    QVariantMap data = QVariantMap();
    data.insert(QString("participants"), QVariant(participants));
    data["subject"] = titletext;
    data["body"] = "I would like to talk about my " + dropd1 + " New Year resolutions.\n We will also discuss: " + bodytext;
    qDebug() << " your other data is " << data;
    cardRequest.setTarget("sys.pim.calendar.viewer.eventcreate");
    cardRequest.setAction("bb.action.CREATE");
    cardRequest.setMimeType("text/calendar");
    bool ok;
    QByteArray encData = PpsObject::encode(data, &ok);
    qDebug() << encData;
    cardRequest.setData(encData);
    InvokeTargetReply* reply = _invokeManager->invoke(cardRequest);
}

See the additions to the data[“subject”] and data[“body”] (Note I also removed the appended participants).

The last thing you need to do is add the following libraries to your .pro file:

LIBS += -lbbpim -lbbsystem -lscreen -lbbdata

Running the app you’ll see the info you type in to the fields pre-populated into the calendar event:

BlackBerry 10 Cascades Calendar Invoke2

After you click Save you should be able to see the event you just created in your Calendar App:

BlackBerry 10 Cascades Calendar Invoke Viewed

Starting to feel like a real BlackBerry app now, huh? As always sound off in the comments below with any questions.

-Brian