Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Native Development

Reply
Highlighted
Developer
Posts: 163
Registered: ‎12-06-2012
My Device: Z10, Q10
My Carrier: BlackBerry
Accepted Solution

How do I set one item type of list view as a header?

I use a QVariantListDataModel. 

QVariantMap map = QVariantMap();
	dataModel.clear();
	map["title"] = resultList.value(id).toMap().value("QUESTION").value<QString>();
	dataModel << map;
	map["title"] = resultList.value(id).toMap().value("CHOICE1").value<QString>();
	dataModel << map;
	map["title"] = resultList.value(id).toMap().value("CHOICE2").value<QString>();
	dataModel << map;
	map["title"] = resultList.value(id).toMap().value("CHOICE3").value<QString>();
	dataModel << map;
	map["title"] = resultList.value(id).toMap().value("CHOICE4").value<QString>();
	dataModel << map;
	map["title"] = resultList.value(id).toMap().value("CHOICE5").value<QString>();
	dataModel << map;


	RecipeItemFactory *recipeItemManager = new RecipeItemFactory();
	list->setListItemProvider(recipeItemManager);

 I show the data from the database. The resultList containts data fetched from database. How do I make some of them as header? I learned that you have to set the type of the listItem as "header". But where do I set it? I am following the cascadescookbookcpp sample. They didn't show how to do it and I don't understand how. I can see how to do it with qml. But I am using c++.

Developer
Posts: 1,524
Registered: ‎12-18-2012
My Device: Z30, Z10 LE, DevAlpha C, PlayBook

Re: How do I set one item type of list view as a header?

Hi,

 

If dataModel is implemented in C++, you can override itemType function in your DataModel subclas:

http://developer.blackberry.com/native/reference/cascades/bb__cascades__datamodel.html#function-item...

High-level models such as GroupDataModel also inherit from DataModel, so you can subclass them as well and override this function.

 

In this function based on indexPath and/or data determine if this entry should be of header or some other type.

 

If ListView is declared in QML, you can also declare itemType JavaScript function in ListView {}. There is sample code in ListView docs:

http://developer.blackberry.com/native/reference/cascades/bb__cascades__listview.html

 


Andrey Fidrya, @zmeyc on twitter
Developer
Posts: 163
Registered: ‎12-06-2012
My Device: Z10, Q10
My Carrier: BlackBerry

Re: How do I set one item type of list view as a header?

Hi. I am not subclassing the DataModel. I just create an object and use it. I use a ListView to show my data. I follow this documentation
http://developer.blackberry.com/native/reference/cascades/bb__cascades__listitemprovider.html

This is also used in the "cascadescookbookcpp" sample app.
Developer
Posts: 1,524
Registered: ‎12-18-2012
My Device: Z30, Z10 LE, DevAlpha C, PlayBook

Re: How do I set one item type of list view as a header?

QVariantListDataModel returns empty itemType by default. To return a specific itemType, subclass the model which you're currently using:

 

 

class MyDataModel: public QVariantListDataModel
{
public:
    virtual Q_INVOKABLE QString itemType (const QVariantList &indexPath);
}
QString MyDataModel::itemType(const QVariantList &indexPath)
{
  if (...)
     return "header";
  return "item";
}

 

 

If you don't want to subclass the data model, another option is implementing ListItemTypeMapper as described here:

http://developer.blackberry.com/native/reference/cascades/bb__cascades__qlistdatamodel.html#function...

To configure ListView with typeMapper, use ListView's setListItemTypeMapper function providing an instance of ListItemTypeMapper subclass.

 

 


Andrey Fidrya, @zmeyc on twitter
Developer
Posts: 163
Registered: ‎12-06-2012
My Device: Z10, Q10
My Carrier: BlackBerry

Re: How do I set one item type of list view as a header?

[ Edited ]

Hi.

I have sbuclassed the QvariantListDataModel like you. I inserted data like this,

map = QVariantMap();
map["title"] = QString("At 09:55 PM,");
map["type"] = "header";
dataModel << map;

map = QVariantMap();
map["title"] = QString("Sound a beep for 2 seconds");
map["type"] = "item";
dataModel << map;

map = QVariantMap();
map["title"] = QString("Sound a vibrate for 4 seconds");
map["type"] = "item";
dataModel << map;

 the itemType function looks like this,

QString MyDataModel::itemType(const QVariantList &indexPath)
{
	QVariantMap map = this->data(indexPath).toMap();
	qDebug()<<"TYPE: "<<map.value("type").toString();
	return map.value("type").toString();

}

 I have seen the debug output and it prints "header" for the first data and "item" for the last two. But the UI looks like this,

ListView with QvariantListDataModel

 

The header and items doesn't look any different. I thought the UI would look similar to the first image from here,

http://developer.blackberry.com/native/reference/cascades/bb__cascades__listview.html

 

Thanks.

 

Developer
Posts: 1,524
Registered: ‎12-18-2012
My Device: Z30, Z10 LE, DevAlpha C, PlayBook

Re: How do I set one item type of list view as a header?

You are using ListItemProvider, right?

 

It should look similar to this:

#ifndef MENULISTITEMPROVIDER_H
#define MENULISTITEMPROVIDER_H

#include <QObject>
#include <bb/cascades/ListItemProvider>

class MenuListItemProvider : public bb::cascades::ListItemProvider
{
        Q_OBJECT
public:
        explicit MenuListItemProvider(QObject *parent = 0);

        bb::cascades::VisualNode *createItem(bb::cascades::ListView *list, const QString &type);

        void updateItem(bb::cascades::ListView* list, bb::cascades::VisualNode *listItem, const QString &type,
                                        const QVariantList &indexPath, const QVariant &data);
signals:

public slots:

};

#endif // MENULISTITEMPROVIDER_H

 

 In createItem create an appropriate ListItem based on itemType (passed as 'type' parameter):

 

VisualNode *MenuListItemProvider::createItem(ListView *list, const QString &type)
{
if (type == "header")
return new HeaderListItem;

// else return new MenuListItem; }

 

updateItem is called when items are initialized or reused (refill them with data at this point):

 

void MenuListItemProvider::updateItem(ListView* list, VisualNode *listItem, const QString &type,
                                const QVariantList &indexPath, const QVariant &data)
{
if (item == "header")
{
HeaderListItem *header = qobject_cast<HeaderListItem *>(listItem);
Q_ASSERT(header);
header->setField( ...set some value extracted from 'data' ...)
}
else if (item == "item")
{
MenuListItem *item = qobject_cast<MenuListItem *>(listItem);
...etc...
}
}

'data' is QVariant returned by data() method of the model and holds the data for current indexPath.

 

ListItems should implement methods defined in ListItemListener class. I usually base them on CustomControls. For example:

 

class MenuListItem : public bb::cascades::CustomControl, public bb::cascades::ListItemListener
{
        Q_OBJECT
public:
        explicit MenuListItem(bb::cascades::Container *parent = 0);

        // getters/setters skipped

        // ListItemListener methods
        void select(bool select);
        void activate(bool activate);
        void reset(bool selected, bool activated);

signals:

public slots:

protected:
        bb::cascades::Label *titleLabel_;
        bb::cascades::Label *descriptionLabel_;
        //skipped
};

 In .cpp file:

MenuListItem::MenuListItem(Container *parent)
        : CustomControl(parent)
        , userData_(NULL)
{
        AppStyle *style = AppStyle::sharedInstance();

        Container *contentContainer = Container::create()
                        .vertical(VerticalAlignment::Center)
                        .add(titleLabel_ = Label::create()
                                 .multiline(true)
                                 .topMargin(0)
                                 .bottomMargin(0)
                                 .textStyle(style->primaryTextStyle()))
                        .add(descriptionLabel_ = Label::create()
                                 .topMargin(0)
                                 .bottomMargin(0)
                                 .textStyle(style->bodyTextStyle()));

        Container *imageContainer = Container::create()
                        .vertical(VerticalAlignment::Center)
                        .layout(DockLayout::create())
                        .preferredSize(121, 109)
                        .add(imageView_ = ImageView::create()
                                 .vertical(VerticalAlignment::Center)
                                 .horizontal(HorizontalAlignment::Center));
        imageContainer->setMinWidth(121);
        imageContainer->setMinHeight(109);

        Container *imageAndContentContainer = Container::create()
                        .layout(StackLayout::create()
                                        .orientation(LayoutOrientation::LeftToRight))
                        .add(imageContainer)
                        .add(contentContainer);

        Container *separatorContainer = Container::create()
                        .layout(StackLayout::create())
                        .add(imageAndContentContainer)
                        .add(Divider::create().topMargin(0).bottomMargin(0));

        Container *selectionContainer = Container::create()
                        .layout(DockLayout::create())
                        .add(separatorContainer)
                        .add(borderImageView_ = ImageView::create("asset:///images/other/selectedControlBorder.amd")
                                 .visible(false)
                                 .vertical(VerticalAlignment::Fill)
                                 .horizontal(HorizontalAlignment::Fill));

        setRoot(selectionContainer);
}

void MenuListItem::select(bool select)
{
        borderImageView_->setVisible(select);
}

void MenuListItem::activate(bool activate)
{
        select(activate);
}

void MenuListItem::reset(bool selected, bool activated)
{
        Q_UNUSED(activated);
        select(selected);
}

 I hope this will help.

 

 

 

 

 

 

 


Andrey Fidrya, @zmeyc on twitter
Retired
Posts: 749
Registered: ‎12-16-2008
My Device: BlackBerry Z30
My Carrier: Bell

Re: How do I set one item type of list view as a header?

Zmey is right, itemType is key. And

 

You should take a look at this page: https://developer.blackberry.com/native/reference/cascades/bb__cascades__listview.html

 

Scroll down to the "The default list visuals" section for how itemType works. The section above explains how to add your own ListItemComponent, as well.

Paul Bernhardt
Application Development Consultant
BlackBerry
@PBernhardt

Did this answer your question? Please accept this post as the solution.
Found a bug? Report it to the Developer Issue Tracker