While playing around in Cascades I found an interesting method in coding an ArrayModel ListView.  In a cursory look, I didn’t see this on line anywhere else so I thought I might share the things I discovered. Much of this may be common knowledge, but not having coded in QML or Java before I found it interesting.

Specifically I found that the labels in the list view can be self-parsing as shown in the code:

text: qsTr(ListItemData).split(“\t”)[0].trim() 

This allowed me to save data as a simple array using a tab character to separate items. There are other comments in the QML code that may also be of interest, but I have seen similar references elsewhere on the net.  Just for fun I included an array sort function.

To invoke the action items in the listview, press and hold a list view entry.

I hope someone finds this useful.

Create a BlackBerry ListView Cascades project and add the following code to the program:

1) applicationui.cpp:

To the “ApplicationUI::ApplicationUI() :  QObject(){“ section add this reference:
 
/ Create scene document from main.qml asset, the parent is set
// to ensure the document gets destroyed properly at shut down.
QmlDocument *qml = QmlDocument::create(“asset:///main.qml”).parent(this);

 

//
qml->setContextProperty(app,this);
//

Add these routines to the end of the file:

//  Added routines
QString ApplicationUI::read(QString key, QString defaultValue)
 {
    QSettings settings(“MyTestProgram”,“Settings”);
    return settings.value(key,defaultValue).toString();
 }

 

void ApplicationUI::save(QString key,QString value)
 {
    QSettings settings(“MyTestProgram”,“Settings”);
    settings.setValue(key,value);
 }
//

2) applicationui.hpp:

To the namespace add:

namespace bb
{
    namespace cascades
    {
        class Application;
        class LocaleHandler;
    }
}

To the class Application add:

class ApplicationUI : public QObject
{
    Q_OBJECT
public:
    // added routines
    Q_INVOKABLE void save(QString key, QString value);
    Q_INVOKABLE QString read(QString key, QString defaultValue);
    //
    ApplicationUI();
    ApplicationUI(bb::cascades::Application *app);
    virtual ~ApplicationUI() {}
private slots:
    void onSystemLanguageChanged();
private:
    QTranslator* m_pTranslator;
    bb::cascades::LocaleHandler* m_pLocaleHandler;
};

These functions allow you to save persistent data in your application. We will need this for our listview to be able to save the data in the completed program.

Change the main.qml file to this:

import bb.cascades 1.2
import bb.system 1.2

 

NavigationPane {
    id: navMain
    Page {
        id: pgMain
        onCreationCompleted: {
            // This creates a global reference to the dataModel for our action items. You can also access it directly
            // using code like “parent.parent.parent.parent.parent.parent.parent.parent.dataModel” but this
            // gets rather convoluted in my opinion. It reports an “unknown member” error in the IDE but seems to
            // work none the less
            Qt.arrayModel = arrayModel
        }
        Container {
            ListView {
                // Specify an ArrayDataModel as the data model for
                // the ListView
                id: lvwFavorites
                dataModel: ArrayDataModel {
                    id: arrayModel
                    property alias myArrayModel: arrayModel
                    // Much to my surprise and delight you can add functions right in your ArrayDataModel
                    function mfClearSavedItems(){
                        app.save(“savedItems”, “”)
                    }
                    function mfRemoveSavedItem(item){
                        app.save(“savedItems”, app.read(“savedItems”,“”).replace(item, “”))
                    }
                    function mfReplaceSavedItem(oldName, newName){
                        app.save(“savedItems”, app.read(“savedItems”,“”).replace(oldName, newName))
                    }
                    function mfAddNewItem(newName){
                        app.save(“savedItems”, app.read(“savedItems”,“”) + newName + “\n”)
                    }
                    function mfSortArrayDataModel() {
                        mfQuickSort(0, arrayModel.size() – 1);              // mfQuickSort all the elements in the array
                    }             
                    function mfQuickSort(start, end)  // just the a good old quick sort
                    {
                        var i = start;                         
                        var k = end;                           
                        if (end – start >= 1){                  
                            var pivot = arrayModel.value(start);      
                            while (k > i)                  
                            {
                                while (arrayModel.value(i) <= pivot && i <= end && k > i){ 
                                    i++
                                }                                   
                                while (arrayModel.value(k) > pivot && k >= start && k >= i){
                                    k–
                                }                                       
                                if (k > i){                                      
                                    arrayModel.swap(i, k)
                                }
                            }
                            arrayModel.swap( start, k);        
                            mfQuickSort(start, k – 1);
                            mfQuickSort(k + 1, end); 
                        } else {  
                            return;                 
                        }
                    }
                }
                onTriggered: {
                    clearSelection();
                    select(0, true);
                }                 
                listItemComponents: [
                    ListItemComponent {
                        type: ""
                        CustomListItem {
                            dividerVisible: true
                            highlightAppearance: HighlightAppearance.Full
                            Container {
                                layout: StackLayout {
                                    orientation: LayoutOrientation.LeftToRight
                                }
                                Label {
                                    id: lblDescription
                                    // this is pretty interesting.  The list view component can be parsed.
                                    // I seperated my values with a tab charater. No seperate parsing routine is required.
                                    text: qsTr(ListItemData).split("\t")[0].trim() 
                                    multiline: true
                                    layoutProperties: StackLayoutProperties {
                                        spaceQuota: 4
                                    }
                                }
                                Label {
                                    id: lblPoints
                                    text: qsTr(“    “ + qsTr(ListItemData).split(“\t”)[1].trim())
                                    verticalAlignment: VerticalAlignment.Bottom
                                    layoutProperties: StackLayoutProperties {
                                        spaceQuota: 1
                                    }
                                    textStyle {
                                        fontWeight: FontWeight.Bold
                                        fontFamily: ‘Courier New’
                                    }
                                }
                            }
                            contextActions: [
                                // Add a set of four actions to the context menu for
                                // a list item
                                ActionSet {
                                    id: actionSet
                                    ActionItem {
                                        title: "Edit Item"
                                        onTriggered: {
                                            dialogEditValues.open()
                                        }
                                        attachedObjects: [
                                            Dialog {
                                                id: dialogEditValues
                                                Container{
                                                    topPadding: 100
                                                    leftPadding: 20
                                                    rightPadding: 20
                                                    Container {
                                                        topPadding: 20
                                                        leftPadding: 20
                                                        rightPadding: 20
                                                        bottomPadding: 20
                                                        layout: StackLayout {
                                                            orientation: LayoutOrientation.TopToBottom
                                                        }
                                                        background: Color.DarkGray
                                                        Label {
                                                            text: "Edit Item"
                                                            textStyle.fontSize: FontSize.Medium
                                                            textStyle.fontWeight: FontWeight.Bold
                                                        }
                                                        Label {
                                                            text: "Description:"
                                                        }
                                                        TextArea {
                                                            id: txtDescription
                                                            hintText: "Description"
                                                            horizontalAlignment: HorizontalAlignment.Fill
                                                            text: qsTr(ListItemData).split("\t")[0].trim()
                                                        }
                                                        Container {
                                                            layout: StackLayout {
                                                                orientation: LayoutOrientation.LeftToRight
                                                            }
                                                            background: Color.DarkGray
                                                            Label {
                                                                text: “Points:”
                                                                verticalAlignment: VerticalAlignment.Center
                                                                layoutProperties: StackLayoutProperties {
                                                                    spaceQuota: 2
                                                                }
                                                            }
                                                            TextField {
                                                                id: txtPoints
                                                                text: qsTr(ListItemData).split(“\t”)[1].trim()
                                                                hintText: “Points”
                                                                inputMode: TextFieldInputMode.PhoneNumber
                                                                layoutProperties: StackLayoutProperties {
                                                                    spaceQuota: 2
                                                                }
                                                            }
                                                            Label {
                                                                // spacer only
                                                                text: “”
                                                                layoutProperties: StackLayoutProperties {
                                                                    spaceQuota: 0.25
                                                                }
                                                            }
                                                            Button {
                                                                text: “Save”
                                                                property string newPoints
                                                                layoutProperties: StackLayoutProperties {
                                                                    spaceQuota: 2
                                                                }
                                                                onClicked: {
                                                                    newPoints = Math.round(txtPoints.text)
                                                                    newPoints = qsTr(txtDescription.text).replace(“\n”, “\r”).trim() + “\t” + newPoints
                                                                    Qt.arrayModel.mfReplaceSavedItem(ListItemData,newPoints)
                                                                    Qt.arrayModel.replace(Qt.arrayModel.indexOf(ListItemData), newPoints)
                                                                    dialogEditValues.close()
                                                                }
                                                            }
                                                            Button {
                                                                text: “Cancel”
                                                                layoutProperties: StackLayoutProperties {
                                                                    spaceQuota: 2
                                                                }
                                                                onClicked: {
                                                                    dialogEditValues.close()
                                                                }
                                                            }
                                                        } 
                                                    }
                                                }
                                            }
                                        ]
                                    }
                                    ActionItem {
                                        title: “Add New Entry”
                                        id: mfAddNewItem
                                        onTriggered: {
                                            dialogAddItem.open()
                                        }
                                        attachedObjects: [
                                            Dialog {
                                                id: dialogAddItem
                                                Container{
                                                    topPadding: 100
                                                    leftPadding: 20
                                                    rightPadding: 20
                                                    Container {
                                                        topPadding: 20
                                                        leftPadding: 20
                                                        rightPadding: 20
                                                        bottomPadding: 20
                                                        layout: StackLayout {
                                                            orientation: LayoutOrientation.TopToBottom
                                                        }
                                                        background: Color.DarkGray
                                                        Label {
                                                            text: "Add New Entry"
                                                            textStyle.fontSize: FontSize.Medium
                                                            textStyle.fontWeight: FontWeight.Bold
                                                        }
                                                        Label {
                                                            text: "Description:"
                                                        }
                                                        TextArea {
                                                            id: txtAddDescription
                                                            hintText: "Description"
                                                            horizontalAlignment: HorizontalAlignment.Fill
                                                        }
                                                        Container {
                                                            layout: StackLayout {
                                                                orientation: LayoutOrientation.LeftToRight
                                                            }
                                                            background: Color.DarkGray
                                                            Label {
                                                                text: "Points:"
                                                                verticalAlignment: VerticalAlignment.Center
                                                                layoutProperties: StackLayoutProperties {
                                                                    spaceQuota: 2
                                                                }
                                                            }
                                                            TextField {
                                                                id: txtAddPoints
                                                                hintText: "Points"
                                                                inputMode: TextFieldInputMode.PhoneNumber
                                                                layoutProperties: StackLayoutProperties {
                                                                    spaceQuota: 2
                                                                }
                                                            }
                                                            Label {
                                                                // spacer only
                                                                text: ""
                                                                layoutProperties: StackLayoutProperties {
                                                                    spaceQuota: 0.25
                                                                }
                                                            }
                                                            Button {
                                                                text: "Save"
                                                                property string newPoints
                                                                layoutProperties: StackLayoutProperties {
                                                                    spaceQuota: 2
                                                                }
                                                                onClicked: {
                                                                    if(txtAddDescription.text.trim() == ""){
                                                                        dialogAddItem.close()
                                                                    }else{
                                                                        newPoints = Math.round(txtAddPoints.text)
                                                                        newPoints = qsTr(txtAddDescription.text).replace("\n", "\r").trim() + "\t" + newPoints 
                                                                        Qt.arrayModel.append(newPoints);
                                                                        Qt.arrayModel.mfAddNewItem(newPoints);
                                                                        dialogAddItem.close()
                                                                    }
                                                                }
                                                            }
                                                            Button {
                                                                text: "Cancel"
                                                                layoutProperties: StackLayoutProperties {
                                                                    spaceQuota: 2
                                                                }
                                                                onClicked: {
                                                                    dialogAddItem.close()
                                                                }
                                                            }
                                                        } 
                                                    }
                                                }
                                            }
                                        ]
                                    }
                                    ActionItem {
                                        title: “Delete Item”
                                        onTriggered: {
                                            var index =  Qt.arrayModel.indexOf(ListItemData.toString())
                                            //var currentStr = app.read(“savedItems”,”")
                                            if(index != -1){
                                                // remove item from model and settings
                                                Qt.arrayModel.removeAt(index)
                                                Qt.arrayModel.mfRemoveSavedItem(ListItemData.toString())
                                            }
                                        }
                                    }
                                    ActionItem {
                                        title: “Delete All”
                                        onTriggered: {
                                            dialogConfirmDeletetion.show()
                                        }
                                        attachedObjects: [
                                            SystemDialog {
                                                id: dialogConfirmDeletetion
                                                title: "Confirm Complete List Deletion"
                                                body: "This will delete all items in the list./nAre you sure you want to delete all the items?"
                                                onFinished: {
                                                    if (dialogConfirmDeletetion.result == SystemUiResult.ConfirmButtonSelection){
                                                        Qt.arrayModel.clear()
                                                        Qt.arrayModel.mfClearSavedItems()
                                                    }
                                                }
                                            }
                                        ]
                                    }                               
                                    ActionItem {
                                        title: “Sort”
                                        onTriggered: {
                                            if( Qt.arrayModel.size() > 0) {
                                                Qt.arrayModel.mfSortArrayDataModel()
                                            }
                                        }
                                    }
                                } // end of ActionSet
                            ]
                        }
                    }                   
                ]
                onCreationCompleted: {
                    // After the ListView is created, add an initial
                    // set of names
                    var data = app.read(“savedItems”, “”).split(“\n”)
                    var newSavedItems = “”
                    app.save(“savedItems”, “”)  // clear all records
                    for ( var i = 0; i < data.length; i++ ) {
                        if(data[i] != “”) {
                            // skip empty items
                            arrayModel.append(data[i]);
                            newSavedItems = newSavedItems + data[i] + “\n”  
                        }
                    }
                    app.save(“savedItems”, newSavedItems)  // recreate list without empties
                    if (newSavedItems.length == 0 ){
                        // nothing avaialble so add an item to exspose the actionSet
                        arrayModel.append(“My first item\t1\n”)
                        arrayModel.mfAddNewItem(“My first item\t1\n”)
                    }

 

                }
            }
        }
    }
}