Friday, July 26, 2013

BB10 QTranslator and QLocale

In our apps, language change is very common functionality. Before jumping into that topic, let us see the basics QLocale and QTransaltor.

      QLocale contains the language and country details. QLocale() will construct a locale object with the system language and locale. If you want to construct a locale of you interest, then initialize like this

QLocale englishLocale = QLocale(QLocale::English, QLocale::UnitedStates);
std::cout << "Locale is : " << englishLocale.name().toStdString();

The output for the above code is en_US.

     To add a new locale support to your application go to bardescreptor.xml --> Localization tab. You can find the default language already defined. To add your support, click on Add and select the language from the list. This will  be like

Select language

  I'm selecting Hindi from the list. Then we can specify the title, app icon, splash screen in the right pane when the locale is changed to Hindi. The specified values will be automatically reflected once the system language is changed to Hindi. Reference picture below.


     Once you build the application, under the translations folder of the project, projectname_hi.ts will be automatically generated. See the red circle in the above picture. We can define, the hindi translation for a specific string in the generated files.

The question is how will we load these .ts files into our application. This leads us to QTranslator.

     QTranslator is capable of loading the language string file(.ts format) for the specified locale with simple steps.
  • Create a locale object
  • Load the translator with that locale
  • Install the translator into the application. 
QLocale hindiLocale = QLocale(QLocale::Hindi, QLocale::India);
QTranslator translator;
QString locale_string = hindiLocale.name();
QString filename = QString("FileHandling_%1").arg(locale_string);
if (translator.load(filename, "app/native/qm")) {
    Application::instance()->installTranslator(&translator);
}

     In the above code, we are instantiating hindiLocale, initializing translator object, getting the name of hindi locale, load it into  translator, install the translator to the application.

If the specified locale is not found, application will install the default locale.

Tuesday, July 23, 2013

Listview with CustomListItem in Blackberry 10

Listview in BB 10 follows MVC architecture. Here we will learn how to add custom rows to listview. To start, we have to look into 4 topics.

  1. Listview component (View)
  2. DataModel (Model)
  3. ListItemProvider (Controller)
  4. ListItem
The below picture illustrates the overview of listview.



The data of the listview is present in DataModel. ListitemProvider is a factory class which creates the listitem with the data present in the DataModel. At run time, listview will pass the datamodel to the ListItemProvider which then uses DataModel and creates a ListItem. The ListItem is a single row of the ListView.

Let us jump into the example for more practical view.


QuotesListItemProvider *myItemProvider = new QuotesListItemProvider(0);
ArrayDataModel *listDataModel = new ArrayDataModel();
// Here Add data to the listmodel .
// In my case I added strings to the dataModel.
ListView *listView = pane->findChild("quotesList");
listView->setDataModel(listDataModel);
listView->setListItemProvider(myItemProvider);

In the above code, I extracted the listview from the QML, initialised ArrayDataModel, appended data to the model, initialized costom ListItemProvider (QuotesListItemProvider), attached datamodel and listitemprovider to the listview.

To define a CustomListItemProvider class it is mandatory to inherit ListItemProvider class. Our custom class should override createItem() and updateItem() functions of ListItemProvider

QuotesListItemProvider.h is 


#include <bb/cascades/ListItemProvider>
#include <bb/cascades/ListView>
#include <bb/cascades/Container>
#include <bb/cascades/VisualNode>
#include <QVariant>

using namespace bb::cascades;


class QuotesListItemProvider: public bb::cascades::ListItemProvider {
public:
    QuotesListItemProvider(Container *container);
    virtual ~QuotesListItemProvider();

    VisualNode * createItem(ListView* list, const QString &type);
    void updateItem(ListView* list, VisualNode *listItem, 
        const QString &type, const QVariantList &indexPath,
        const QVariant &data);

private:
    Container *container;
};

QuotesListItemProvider.cpp is:

#include "QuotesListItemProvider.h"
#include "QuotesListItem.h"
#include <bb/cascades/StandardListItem>
#include <bb/cascades/LayoutProperties>

QuotesListItemProvider::QuotesListItemProvider(Container *container) {
    this->container = container;
}

QuotesListItemProvider::~QuotesListItemProvider()
{

}

VisualNode * QuotesListItemProvider::createItem(ListView* list,
        const QString &type) {
    
    QuotesListItem *myItem = new QuotesListItem(container);
    return myItem;
}

void QuotesListItemProvider::updateItem(ListView* list,
        bb::cascades::VisualNode *listItem, const QString &type,
        const QVariantList &indexPath, const QVariant &data) {
   
    QuotesListItem *myItem = static_cast(listItem);
    myItem->setTitle(data.toString());
}

In createItem() function, ListItem's are created. The created listitems are then passed to updatedItem() function. Observe the first line of UpdateItem method, VisualNode is casted to  CustomListItem(QuotesListItem). And also the parameter 'data' of QVariant type in updateItem() function is the data of our ArraydataModel in ListView. As our DataModel contains strings, I'm converting this into the string format and updated label in QuotesListItem class.

For creating a list row ( Custom ListItem), we have to inherit CustomControl. 

QuotesListItem.h is 

#include <QObject>
#include <QUrl>
#include <iostream>
#include <bb/cascades/CustomControl>
#include <bb/cascades/QmlDocument>
#include <bb/cascades/Container>
#include <bb/cascades/Image>
#include <bb/cascades/ImageView>
#include <bb/cascades/Label>
#include <bb/cascades/controls/activityindicator.h>

using namespace bb::cascades;

class QuotesListItem: public CustomControl {
    Q_OBJECT
public:
    virtual ~QuotesListItem();
    void setTitle(QString text);
    QuotesListItem(Container *container);

private:

    QString pictureURL;
    Label *label;
    void init();
};

QuotesListItem.cpp is


#include "QuotesListItem.h"
#include "bb/cascades/StackLayout"

QuotesListItem::QuotesListItem(Container* container) :
        CustomControl(container) {

    QmlDocument *document = 
             QmlDocument::create("asset:///QuotesListItem.qml");
    Container *rootContainer = document->createRootObject();

    label = rootContainer->findChild

In this class, I'm inflating a QML and used setRoot function of CustomControl class to attach the QML's root object. setTitle() function is used to set the text. This function is called from updateItem()  of QuoteListItemProvider class.