Export QList to QML vol. 2

The most complex and ellegant way to export QList of custom objects to QML is to subclass one of the Qt abstract models ( QAbstractItemModel, or easier QAbstractListModel, QAbstractTableModel ) and build up a whole model with user specified roles. Subclassing QAbstractItemModel allows you to define all the properties and behaviour of your model, however in this case it is enough to subclass QAbstractListModel. In that case we have to provide implementations of only a few pure virtual methods plus some methods to manipulate models content.
Following implementation will show how to subclass QAbstractListModel with a class providing custom roles which will be used for text, its color and image source path. The good point is that they are defined as QVariants so it doesn’t matter if you pass a color, number or text. Expected result is similar to the one in a previous example.

Lets start with defining a list model item. Methods necessary to define fine read/write item are Getter, Setter and a method returning QHash binding role with member name description. Following example should explain this more clearly.
Base class definition:
listitemapi.h

#ifndef LISTITEMAPI_H
#define LISTITEMAPI_H

#include <QObject>
class ListItemAPI : public QObject
{
	Q_OBJECT
public:
	ListItemAPI( QObject* a_pParent = 0 )
		: QObject( a_pParent )
	{}
	virtual ~ListItemAPI() {}

	virtual QVariant GetData( int a_iRole ) const = 0;
	virtual void SetData( int a_iRole, QVariant a_variantData ) = 0;
	virtual QHash<int, QByteArray> RoleNames() const = 0;
};
#endif // LISTITEMAPI_H

Real item class implementation:
mylistitem.h

#ifndef MYLISTITEM_H
#define MYLISTITEM_H

#include <QVariant>
#include <QColor>
#include <QHash>
#include "listitemapi.h"
class MyListItem : public ListItemAPI
{
	Q_OBJECT
public:
	enum ERoles
	{ ROLE_1					= Qt::UserRole + 1
	, ROLE_2					= Qt::UserRole + 2
	, ROLE_3					= Qt::UserRole + 3
	, ROLE_4					= Qt::UserRole + 4
	, ROLE_5					= Qt::UserRole + 5
	};
	explicit MyListItem( QObject* a_pParent = 0 );
	MyListItem( const MyListItem& a_rOther );
	virtual ~MyListItem();

	virtual QVariant GetData( int a_iRole ) const;
	virtual void SetData( int a_iRole, QVariant a_variantData );
	virtual QHash<int, QByteArray> RoleNames() const;

private:
	void SetInitialValues();
	QHash<ERoles, QVariant> m_aDataHash;
};
#endif // MYLISTITEM_H

mylistitem.cpp

#include "mylistitem.h"
MyListItem::MyListItem( QObject* a_pParent )
	: ListItemAPI( a_pParent )
{
	SetInitialValues();
}

MyListItem::MyListItem( const MyListItem& a_rOther )
	: ListItemAPI( a_rOther.parent() )
{
	m_aDataHash = a_rOther.m_aDataHash;
}

MyListItem::~MyListItem()
{
}

QVariant MyListItem::GetData( int a_iRole ) const
{
	return m_aDataHash[static_cast<ERoles>( a_iRole )];
}

void MyListItem::SetData( int a_iRole, QVariant a_variantData )
{
	m_aDataHash[static_cast<ERoles>( a_iRole )] = a_variantData;
}

QHash<int, QByteArray> MyListItem::RoleNames() const
{
	QHash<int, QByteArray> aRoleNames;
	aRoleNames[ROLE_1]			= "m_role1";
	aRoleNames[ROLE_2]			= "m_role2";
	aRoleNames[ROLE_3]			= "m_role3";
	aRoleNames[ROLE_4]			= "m_role4";
	aRoleNames[ROLE_5]			= "m_role5";
	return aRoleNames;
}

void MyListItem::SetInitialValues()
{
	m_aDataHash[ROLE_1] = QVariant( "string" );
	m_aDataHash[ROLE_2] = QVariant( QColor( "#FFFFFF" ) );
	m_aDataHash[ROLE_3] = QVariant( 123 );
	m_aDataHash[ROLE_4] = QVariant( "otherString" );
	m_aDataHash[ROLE_5] = QVariant( 11.34 );
}

In header i define few general purpose roles. Depending on use it is up to single list instance to interpret which role relates to which property. Using QVariant allows to set many various property types to one variable (of QVariant type). (NOTE: remember that if you bind a single item role from c++ string to qml color then it will result in property binding error).
In this class i also define copy constructor so i can set some common default properties for all list objects in one object and then just copy it to other items.

Having an item defined we can move further to QAbstractListModel reimplementation:
mylistmodel.h

#ifndef MYLISTMODEL_H
#define MYLISTMODEL_H

#include <QAbstractListModel>
#include "listitemapi.h"

class MyListModel : public QAbstractListModel
{
	Q_OBJECT
	Q_PROPERTY( int count READ rowCount NOTIFY signalCountChanged )
public:
	explicit MyListModel( QObject* a_pParent = 0 );
	explicit MyListModel( ListItemAPI* a_pPrototype, QObject* a_pParent = 0 );
	virtual ~MyListModel();

	// QAbstractListModel reimplemented methods
	int rowCount( const QModelIndex& a_rParent = QModelIndex() ) const;
	QVariant data( const QModelIndex& a_rIndex, int a_iRole = Qt::DisplayRole ) const;
	QHash<int, QByteArray> roleNames() const;
	bool removeRows( int a_iRow, int a_iCount, const QModelIndex& a_rParent = QModelIndex() );

	// Methods created to match QML Model style of data manipulation
	Q_INVOKABLE void append( ListItemAPI* a_pItem );
	Q_INVOKABLE QVariant get( int a_iIndex );
	Q_INVOKABLE void clear();

	inline ListItemAPI* GetItem( int a_iIndex );
signals:
	void signalCountChanged( int a_iNewCount );
protected:
	ListItemAPI* m_pPrototype;
	QList<ListItemAPI*> m_aItems;
};
/////////////////////////////////////////////////////////
ListItemAPI* MyListModel::GetItem( int a_iIndex )
{
	if ( m_aItems.size() > a_iIndex )
	{
		return m_aItems[a_iIndex];
	}
	return 0;
}
#endif // MYLISTMODEL_H

and its following implementation:
mylistmodel.cpp

#include "mylistmodel.h"

MyListModel::MyListModel( QObject* a_pParent )
	: QAbstractListModel( a_pParent )
	, m_pPrototype( 0 )
	, m_aItems ( QList<ListItemAPI*>() )
{
}

MyListModel::MyListModel( ListItemAPI* a_pPrototype, QObject* a_pParent )
	: QAbstractListModel( a_pParent )
	, m_pPrototype( a_pPrototype )
	, m_aItems ( QList<ListItemAPI*>() )
{
}

MyListModel::~MyListModel()
{
	clear();
}

int MyListModel::rowCount( const QModelIndex& a_rParent ) const
{
	Q_UNUSED( a_rParent );
	return m_aItems.size();
}

QVariant MyListModel::data( const QModelIndex& a_rIndex, int a_iRole ) const
{
	if ( a_rIndex.row() < 0 )
	{
		return QVariant();
	}
	if ( a_rIndex.row() > m_aItems.size() )
	{
		return QVariant();
	}
	ListItemAPI* pValidate = m_aItems.at( a_rIndex.row() );
	if ( pValidate )
	{
		return pValidate->GetData( a_iRole );
	}
	return QVariant();
}

QHash<int, QByteArray> MyListModel::roleNames() const
{
	if ( m_pPrototype )
	{
		return m_pPrototype->RoleNames();
	}
	return ( QHash<int, QByteArray>() );
}

bool MyListModel::removeRows( int a_iRow, int a_iCount, const QModelIndex& a_rParent )
{
	if ( a_iRow < 0 )
	{
		return false;
	}
	if ( a_iCount <= 0 )
	{
		return false;
	}
	if ( ( a_iRow + a_iCount ) > m_aItems.size() )
	{
		return false;
	}
	beginRemoveRows( a_rParent, a_iRow, a_iRow + a_iCount - 1 );
	for ( int i = 0; i < a_iCount; i++ )
	{
		ListItemAPI* pItem = m_aItems.takeAt( a_iRow );
		pItem->deleteLater();
		pItem = 0;
	}
	endRemoveRows();
	emit signalCountChanged( rowCount() );
	return true;
}

void MyListModel::append( ListItemAPI* a_pItem )
{
	if ( a_pItem != 0 )
	{
		beginInsertRows( QModelIndex(), rowCount(), rowCount() );
		m_aItems.append( a_pItem );
		endInsertRows();
		emit signalCountChanged( rowCount() );
	}
}

QVariant MyListModel::get( int a_iIndex )
{
	if ( a_iIndex < 0 )
	{
		return QVariant();
	}
	if ( a_iIndex >= m_aItems.size() )
	{
		return QVariant();
	}
	QMap<QString, QVariant> aItemData;
	ListItemAPI* pItem = m_aItems.at( a_iIndex );
	if ( pItem )
	{
		QHashIterator<int, QByteArray> aRolesItr( pItem->RoleNames() );
		while ( aRolesItr.hasNext() )
		{
			aRolesItr.next();
			aItemData.insert( aRolesItr.value(), QVariant( pItem->GetData( aRolesItr.key() ) ) );
		}
		return QVariant( aItemData );
	}
	return QVariant();
}

void MyListModel::clear()
{
	if ( m_aItems.size() > 0 )
	{
		removeRows( 0, m_aItems.size() );
	}
}

In general reimplementation is done according to Qt docs with one exception. This is a ‘prototype item’. When creating an instance of listmodel class we have to pass prototype item to tell the class what types of items will be filled with. Here roleNames() class implementation is redirected to prototypes RoleNames() definition. Doing it this way i can have one common MyListModel class for all lists exported to QML and only to create new MyListModelItems (well, in fact i don’t even subclass MyListModelItem, i just add more item Roles with numbering and manage their meanings separately for every use).

The last class presented in this tutorial is actual QML listView reflection in C++. It provides a few methods to manipulate data in both ways (QmlC++).
customlistview.h

#ifndef CUSTOMLISTVIEW_H
#define CUSTOMLISTVIEW_H

#include <QQuickItem>
#include "mylistmodel.h"
#include "mylistitem.h"
class CustomListView : public QQuickItem
{
	Q_OBJECT
	Q_PROPERTY( int m_iCurrentIndex READ GetCurrentIndex WRITE SetCurrentIndex NOTIFY signalCurrentIndexChanged )
	Q_PROPERTY( MyListModel* m_pListModel READ GetListModel NOTIFY signalListModelChanged )
public:
	explicit CustomListView( QQuickItem* a_pParent = 0 );
	explicit CustomListView( MyListModel* a_pListModel, QQuickItem* a_pParent = 0 );
	virtual ~CustomListView();

	inline int GetCurrentIndex() const { return m_iCurrentIndex; }
	Q_INVOKABLE void SetCurrentIndex( int a_iNewCurrentIndex );

	void ClearElements();
	void AppendElement( MyListItem* a_pNewElement );

	inline MyListModel* GetListModel() const { return m_pListModel; }
signals:
	void signalCurrentIndexChanged( int a_iNewCurrentIndex );
	void signalListModelChanged();

protected:
	MyListModel* m_pListModel;
	int m_iCurrentIndex;
};
#endif // CUSTOMLISTVIEW_H

customlistview.cpp

#include "customlistview.h"

CustomListView::CustomListView( MyListModel* a_pListModel, QQuickItem* a_pParent )
	: QQuickItem( a_pParent )
	, m_pListModel( a_pListModel )
	, m_iCurrentIndex( -1 )
{
}

CustomListView::CustomListView( QQuickItem* a_pParent )
	: QQuickItem( a_pParent )
	, m_pListModel( new MyListModel( new MyListItem() ) )
	, m_iCurrentIndex( -1 )
{
}

CustomListView::~CustomListView()
{
	if ( m_pListModel )
	{
		delete m_pListModel;
		m_pListModel = 0;
	}
}

void CustomListView::SetCurrentIndex( int a_iNewCurrentIndex )
{
	if ( a_iNewCurrentIndex != m_iCurrentIndex )
	{
		m_iCurrentIndex = a_iNewCurrentIndex;
		emit signalCurrentIndexChanged( m_iCurrentIndex );
	}
}

void CustomListView::ClearElements()
{
	if ( m_pListModel )
	{
		m_pListModel->clear();
		m_iCurrentIndex = -1;
		emit signalListModelChanged();
	}
}

void CustomListView::AppendElement( MyListItem* a_pNewElement )
{
	if ( a_pNewElement && m_pListModel )
	{
		m_pListModel->append( a_pNewElement );
		emit signalListModelChanged();
	}
}

Here i have defined MyListModel as Q_PROPERTY (this is possible as QAbstractListModel is a QObject derived class, unlike the QList class) to be able to refer to its items through it. There is also currentIndex property to notify Qml/C++ about listview index changes. You can also define here other properties used to specify PathView behaviour and bind them in qml such as:
pathItemCount: id_listView.m_iPathItemCount
highlightMoveDuration: id_listView.m_iAnimationDuration
..and a few others.

QmlListView.qml

import MyCustoms 1.0
import QtQuick 2.0

CustomListView
{
	id: id_listView

	onSignalCurrentIndexChanged:
	{
		id_listViewPath.currentIndex = m_iCurrentIndex
	}
	Component
	{
		id: id_delegate
		Item
		{
			id: id_delegate_item
			scale: PathView.iconScale
			opacity: PathView.iconOpacity
			Image
			{
				id: id_img
				anchors.horizontalCenter: id_delegate_item.horizontalCenter
				width: 60
				height: 60
				source: m_role1
			}
		}
	}
	PathView
	{
		id: id_listViewPath
		anchors.fill: id_listView

		model: id_listView.m_pListModel
		delegate: id_delegate
		pathItemCount: 3

		snapMode: PathView.NoSnap
		highlightMoveDuration: 300
		interactive: true

		preferredHighlightBegin: 0.5
		preferredHighlightEnd: 0.5
		highlightRangeMode: PathView.StrictlyEnforceRange
		dragMargin: 20
		path: Path
		{
			id: id_path
			startX: id_listViewPath.width / 2
			startY: id_listViewPath.y
			PathAttribute { name: "iconScale"; value: 0.5 }
			PathAttribute { name: "iconOpacity"; value: 0.5 }
			PathLine { x: id_listViewPath.width / 2; relativeY: id_listViewPath.height / 2 }
			PathAttribute { name: "iconScale"; value: 1 }
			PathAttribute { name: "iconOpacity"; value: 1 }
			PathLine { x: id_listViewPath.width / 2; relativeY: id_listViewPath.height / 2 }
		}
		onCurrentIndexChanged:
		{
			id_listView.m_iCurrentIndex = currentIndex
		}
	}
	Text
	{
		id: id_text
		anchors.left: id_listView.left
		anchors.verticalCenter: id_listView.verticalCenter
		text: id_listView.m_pListModel.get(id_listView.m_iCurrentIndex) ? id_listView.m_pListModel.get(id_listView.m_iCurrentIndex).m_role2 : ""
		color: id_listView.m_pListModel.get(id_listView.m_iCurrentIndex) ? id_listView.m_pListModel.get(id_listView.m_iCurrentIndex).m_role3 : "red"
	}
}

main.qml

import QtQuick 2.0
import QtQuick.Window 2.0
import MyCustoms 1.0
import "res/qml"
Window
{
	id: id_root
    visible: true
	width: 400
	height: width
	Rectangle
	{
		id: id_rect
		width: id_root.width
		height: id_root.height
		QmlListView
		{
			id: id_listView
			anchors.fill: id_rect
			objectName: "ListView_Instance"
		}
	}
}

My main.qml file looks like this, and to get a pointer to my id_listView item after creation of main.qml with Window object i use ‘findChild’ method. A good idea is to set listView’s objectName so we never get mislead when more instances of objects of the same type have the same parent().

The whole setup is done in main and is self explaining and consists of a few main parts:
Create application window
Retrieve pointer to my listview class
Set listview model items

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QDebug>

#include "mylistitem.h"
#include "customlistview.h"

void registerCustomQMLTypes();
void fillModel(CustomListView* a_pView);
int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
	registerCustomQMLTypes();
    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
	
	CustomListView* pQmlListView = 0;
	QList<QObject*> aRoots = engine.rootObjects();
	for( int i=0; i<aRoots.size(); i++ )
	{
		pQmlListView = aRoots[i]->findChild<CustomListView*>("ListView_Instance");
		if (pQmlListView != 0)
			break;
	}
	
	fillModel(pQmlListView);

    return app.exec();
}

void registerCustomQMLTypes()
{
	qmlRegisterType<MyListItem>("MyCustoms", 1, 0, "MyListItem");
	qmlRegisterType<MyListModel>("MyCustoms", 1, 0, "MyListModel");
	qmlRegisterType<CustomListView>("MyCustoms", 1, 0, "CustomListView");
}

void fillModel(CustomListView* a_pView)
{
	if (a_pView)
	{
		MyListModel* pModel = a_pView->GetListModel();
		if (pModel)
		{
			MyListItem* pItem = new MyListItem();
			if (pItem)
			{
				pItem->SetData(MyListItem::ROLE_1, QVariant("qrc:/res/img/cat0.png"));
				pItem->SetData(MyListItem::ROLE_2, QVariant("Text_0"));
				pItem->SetData(MyListItem::ROLE_3, QVariant( QColor(0x00, 0xFF, 0xFF)));
				pModel->append(pItem);
			}
			pItem = new MyListItem();
			if (pItem)
			{
				pItem->SetData(MyListItem::ROLE_1, QVariant("qrc:/res/img/cat1.png"));
				pItem->SetData(MyListItem::ROLE_2, QVariant("Second cat"));
				pItem->SetData(MyListItem::ROLE_3, QVariant( QColor(0x00, 0x00, 0x00)));
				pModel->append(pItem);
			}
			.
			.
			.
		}
		a_pView->SetCurrentIndex(0);
	}
}

When creating new items for a model i use 3 roles. I decided that ROLE_1 will describe list delegate Image.source property (and it is a string), ROLE_2 describes an item text (also string) and item text color (QColor). This properties are binded to QML names from MyListItem file:

QHash<int, QByteArray> MyListItem::RoleNames() const
{
	QHash<int, QByteArray> aRoleNames;
	aRoleNames[ROLE_1]			= "m_role1";
	aRoleNames[ROLE_2]			= "m_role2";
	aRoleNames[ROLE_3]			= "m_role3";
	aRoleNames[ROLE_4]			= "m_role4";
	aRoleNames[ROLE_5]			= "m_role5";
	return aRoleNames;
}

so in QML names are recognised as m_roleX:

			Image
			{
				id: id_img
				anchors.horizontalCenter: id_delegate_item.horizontalCenter
				width: 60
				height: 60
				source: m_role1
			}

If you have any questions feel free to write to me and i will try to explain things in more clear way.
Whole project compiled under Ubuntu 14.04 using Qt 5.2 is available here. (Should work with previous Qt versions as well)
In the next post I will write about creating truly flexible ListViews with proper-user defined scalling and with automated ListView delegates creation.

Spotify on Raspberry Pi ( MPD )

Hello! So I got famous Raspberry Pi B+ on Christmas. First thing I wanted to do with it was setting up so-called “Home Media Center”. The thing is the device I like to use for listening to music is on the other side of my room, so I had to plug-in my phone to mini-jack. After all, phone is not the best device to use it as a playlist provider because every time you get a call you have to get up and pick it up turning off the music. The other thing is that i don’t like to see cables all around my bedroom. So, long story short I started my investigation on how to set up raspberry pi to be able to play music from my Spotify account.

My Raspi runs Wheezy Raspbian distro and it is connected to my local network via WLAN. After a quick research I already knew that there is no ready-to-use Spotify client for Raspbian available, so i had to find some workaround. Finally I went for Mopidy as it turned out to be really user-friendly and installation steps on Raspbian are clear and easy.

What are the common steps to install and successfully run Mopidy daemon? Following the steps in Mopidy docs is essential. Here I provide console commands from Mopidy docs with a few comments from my own experience.

    1. Installing Mopidy
      • It is recommended to set IPv6 support on Raspi as well as add it to boot setup.
        sudo modprobe ipv6
        echo ipv6 | sudo tee -a /etc/modules
      • Add Mopidy archive GPG key
        wget -q -O - https://apt.mopidy.com/mopidy.gpg | sudo apt-key add -
      • Add repositories to your apt-get lookup list
        sudo nano /etc/apt/sources.list
        # Mopidy APT archive
        deb http://apt.mopidy.com/ stable main contrib non-free
        deb-src http://apt.mopidy.com/ stable main contrib non-free
      • Update your system and download mopidy
        sudo apt-get update && sudo apt-get install mopidy
      • Download Spotify extension for Mopidy
        sudo apt-get install mopidy-spotify

Now you should have installed working mopidy daemon. It needs a little configuration ( ie. Spotify user/pass details ). The thing to notice is a little mess in configuration files. Mainly there are two important configuration files: in your ~/.config/mopidy/ dir and in /etc/mopidy/ dir. First one is used when you start mopidy as a standard process of your user, while second is used when started as a daemon. I recommend to just have the same configuration in both files.

  1. Configure Mopidy.
    • Check your device IP address
      ifconfig
    • open configuration file
      sudo nano ~/.config/mopidy/mopidy.conf
    • If you want to use MPD applications for your smartphone to manage your playlists set MPD configuration – host ( wlan0 in my case ), port and password
      [mpd]
      enabled = true
      hostname = 192.168.1.5 #wlan0 ip
      port = 6600
      password = *setPass*
    • If you want to use http client to manage your playlists set HTTP configuration.
      [http]
      enabled = true
      hostname = 192.168.1.5
      port = 6680
    • set spotify user configuration (see comment below)
      [ spotify ]
      enabled = true
      username = *yourSpotifyUsername*
      password = *yourSpotifyPass*
      bitrate = 320
      If you login to Spotify using Facebook account you have to create username/pass for your devices on your Spotify account settings. To do so, go to https://www.spotify.com/pl/account/set-device-password/ and follow the instructions (send email to your email account with a link to set password)
  2. Now save your configuration file and check if everything works fine. To do so run in console:
    mopidy
    You should see a few warnings probably about your configuration of local libraries (used when you want to play music from your Raspi local disk). After a while there should be also a notification that ‘xy playlists imported from Spotify’. If you see such information then you know you have done everything properly. You can kill your process now. To run your daemon service with the same configuration you have to copy config file from ~/.config/mopidy/mopidy.conf to /etc/mopidy/ directory (backup existing file first).
    sudo cp /etc/mopidy/mopidy.conf /etc/mopidy/mopidy.conf_backup && sudo cp ~/.config/mopidy/mopidy.conf /etc/mopidy/mopidy.conf
  3. You probably want to run your service on Raspi startup so you don’t have to think about this anymore. When installing the most recent Mopidy there should be a script for this already installed. see:
    cat /etc/init.d/mopidy
    In case you see nothing there, here is the script I had predefined and it works fine:

    #!/bin/sh
    ### BEGIN INIT INFO
    # Provides: mopidy
    # Required-Start: $network $remote_fs
    # Required-Stop: $network $remote_fs
    # Should-Start: $named alsa-utils avahi dbus pulseaudio
    # Should-Stop: $named alsa-utils avahi dbus pulseaudio
    # Default-Start: 2 3 4 5
    # Default-Stop: 0 1 6
    # Short-Description: Mopidy music server
    ### END INIT INFO

    PATH=/sbin:/usr/sbin:/bin:/usr/bin
    DESC="Mopidy music server"
    NAME=mopidy
    DAEMON=/usr/bin/mopidy
    DAEMON_USER=mopidy
    DAEMON_GROUP=audio
    CONFIG_FILES="/usr/share/mopidy/conf.d:/etc/mopidy/mopidy.conf"
    PIDFILE=/var/run/$NAME.pid
    SCRIPTNAME=/etc/init.d/$NAME

    # Exit if the package is not installed
    [ -x $DAEMON ] || exit 0

    # Read configuration variable file if present
    [ -r /etc/default/$NAME ] && . /etc/default/$NAME

    # Load the VERBOSE setting and other rcS variables
    . /lib/init/vars.sh

    # Define LSB log_* functions.
    . /lib/lsb/init-functions

    do_start()
    {
    start-stop-daemon --start --quiet --name $NAME --pidfile $PIDFILE \
    --startas $DAEMON --test > /dev/null \
    || return 1
    start-stop-daemon --start --quiet --name $NAME --pidfile $PIDFILE \
    --chuid $DAEMON_USER:$DAEMON_GROUP --background --make-pidfile \
    --startas $DAEMON -- --quiet --config $CONFIG_FILES \
    || return 2
    }

    do_stop()
    {
    start-stop-daemon --stop --quiet --name $NAME --pidfile $PIDFILE \
    --retry=TERM/30/KILL/5
    RETVAL="$?"
    [ "$RETVAL" = 2 ] && return 2
    # Wait for children to finish too if this is a daemon that forks
    # and if the daemon is only ever run from this initscript.
    # This typically happens with pulseaudio.
    start-stop-daemon --stop --quiet --oknodo --user $DAEMON_USER \
    --retry=TERM/30/KILL/5
    [ "$?" = 2 ] && return 2
    rm -f $PIDFILE
    return "$RETVAL"
    }

    # Remove the action from $@ before it is used by the run action
    action=$1
    [ "$action" != "" ] && shift

    case "$action" in
    start)
    [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC " "$NAME"
    do_start
    case "$?" in
    0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
    2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
    esac
    ;;
    stop)
    [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
    do_stop
    case "$?" in
    0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
    2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
    esac
    ;;
    status)
    status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
    ;;
    restart|force-reload)
    log_daemon_msg "Restarting $DESC" "$NAME"
    do_stop
    case "$?" in
    0|1)
    do_start
    case "$?" in
    0) log_end_msg 0 ;;
    1) log_end_msg 1 ;; # Old process is still running
    *) log_end_msg 1 ;; # Failed to start
    esac
    ;;
    *)
    # Failed to stop
    log_end_msg 1
    ;;
    esac
    ;;
    run)
    echo -n "\"service mopidy run\" is deprecated. " 1>&2
    echo "Use \"mopidyctl\" instead." 1>&2
    /usr/sbin/mopidyctl $@
    ;;
    *)
    echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload|run}" >&2
    exit 3
    ;;
    esac

    :

    Now the last thing to do is to notify system to execute this script on boot:
    sudo update-rc.d mopidy defaults

  4. Installing Spotify for Mopidy Http client (for more clients see Mopidy docs)
    • You need python-pip package to be able to easily install Mopidy-Spotify extension for your daemon.
      sudo apt-get install python-pip build-essential
    • Now you are only one step away from browsing your playlists from Spotify using Raspi:
      pip install Mopidy-Mopify

…and this is it. Now in your browser you can go to http://’device_ip’:’configured_port’/mopify/ (in my case http://192.168.1.5:6680/mopify/), plug mini jack from your home device to Raspi and enjoy your music!

Feel free to post any comments and questions if I have missed something in this tutorial and you if you have any problems with setting it up.
Cheers!

Export QList to QML

Problem:

How to expose QList<QObject*> into QML so I can dynamically change its content?

Comment:

Sometimes when developing Qt application we want to show some content in a fancy QML UI controls but we still want to stick to C++ in terms of object manipulating. By QML controls i mean stuff like ListView, PathView and similar model-based controls. So why is exposing QList to QML such a big deal? The thing is, QList is not a QObject-derived, so it cannot be easily exposed to QML. There are a few ways to accomplish this which are going to be covered in this post:

  • Create a list property in QML file and access it using functions declared in QML ( modifying already existing content requires redeclaring all items at list )
  • Use a class provided by Qt ( QQmlListProperty ) to make a QList<QObject*> created in C++ visible at QML side
  • Subclass QAbstractListModel to create a complete model which can be used in QML

Each of this ways obviously have its pros and cons. They are listed from least time-consuming ( and though least elegant ) to the most time-consuming order. So, lets make our hands dirty…

The easiest way is to create a property list in QML, functions to modify its content and QMetaObject::InvokeMethod them from C++.

… will be added later…

The other way is to use provided by Qt special class QQmlListProperty<MyQObject>. All we have to do is to declare a Q_PROPERTY of this class type with a proper accessors. The most simple example would be a ReadOnly list. This means it can be modified from C++ and notify signal will be sent to QML so it updates, but no changes from QML can be made. Here it is:
cqmllist.h

#include &lt;QQuickItem&gt;
class CQmlList : public QQuickItem
{
    Q_OBJECT
    Q_PROPERTY(QQmlListProperty&lt;QObject&gt; m_aItems READ getQmlItemList NOTIFY signalQmlItemListChanged)
    // there is no need to call Q_PROPERTIES the same as in c++. i just use it to know who is who.
public:
    inline QQmlListProperty&lt;QObject&gt; getQmlItemList()
    {
        return QQmlListProperty&lt;QObject&gt;( this, m_aItems );
    }
signals:
    void signalQmlItemListChanged(QQmlListProperty&lt;QObject&gt; a_aItems );
private:
    QList&lt;QObject*&gt; m_aItems;
};

Now, to make its content dynamical we need to declare a few more methods. ( Note the need of copying pointers to objects before deleting it to notify QML about this )

Q_INVOKABLE void clearItems()
{
	QList&lt;QObject*&gt; tmpList = m_aItems;
	// we have to notify QML that content changed before actually deleting objects
	m_aItems.clear();
	emit signalQmlItemListChanged(getQmlItemList());
	qDeleteAll(tmpList);
	tmpList.clear();
	emit signalQmlItemListChanged(getQmlItemList());
}
void appendItem(QObject *a_pItem)
{
	m_aItems.append(a_pItem);
	emit signalQmlItemListChanged(getQmlItemList());
}

This is it! Now when you pass to the list an item of your MyQObject* type you will be able to access its content just like in C++ as it will be autocasted to your type. Lets see how it works. Declare a class with your own Q_PROPERTIES and proper accessors.
clistitem.h

#include &lt;QObject&gt;
class CListItem : public QObject
{
	Q_OBJECT
	Q_PROPERTY(QString m_strName READ getName WRITE setName NOTIFY nameChanged)
	Q_PROPERTY(QString m_strImgSource READ getImgSource WRITE setImgSource NOTIFY imgSourceChanged)
public:
	explicit CListItem(QObject *pParent = 0)
		: QObject(pParent)
		, m_strImgSource(&quot;dummy&quot;)
		, m_strName(&quot;dummy&quot;)
	{}
	virtual ~CListItem(){}

	inline QString getName() const { return m_strName; }
	inline void setName(QString a_strNewName) { m_strName = a_strNewName; }

	inline QString getImgSource() const { return m_strImgSource; }
	inline void setImgSource(QString a_strNewImgSource) { m_strImgSource = a_strNewImgSource; }
signals:
	void nameChanged(QString a_strNewName);
	void imgSourceChanged(QString a_strNewImgSource);
private:
	QString m_strName;
	QString m_strImgSource;
};

…And now use it in QML! This example may look a bit complicated but i highlighted the most important lanes. I use PathView which delegate is previously declared Component id_component is an image with source stored in class Q_PROPERTY ‘m_strImgSource’. There is also a textbox at the bottom. I could not add this textbox to a Component as i want it to be visible only for currently selected item. I accomplish this by checking PathView currentIndex property. I just display a name ( stored under ‘m_strName’ property ) of an item on a list with a currentIndex, otherwise i set an empty string.
QmlList.qml

import QtQuick 2.0
import MyCustoms 1.0

CQmlList
{
	id: id_myList
	Component
	{
		id: id_component
		Item
		{
			id: id_rect
			scale: PathView.iconScale
			opacity:  PathView.iconOpacity
			Image
			{
				anchors.horizontalCenter: id_rect.horizontalCenter
				width: 60
				height: 60
				// m_strImgSource property registered in C++
				source: m_strImgSource
			}
		}
	}
	//real view starts here
	PathView
	{
		id: id_view
		anchors.fill: id_myList
		model: m_aItems
		delegate: id_component
		preferredHighlightBegin: 0.5
		preferredHighlightEnd: 0.5
		pathItemCount: 3
		dragMargin: 100
		interactive: true
		snapMode: PathView.SnapOneItem
		path: Path
		{
			startX: id_myList.x
			startY: id_myList.height/2
			PathAttribute { name: &quot;iconScale&quot;; value: 0.5 }
			PathAttribute { name: &quot;iconOpacity&quot;; value: 0.5 }
			PathLine { relativeX: id_myList.width/2; y: id_myList.height/2 }
			PathAttribute { name: &quot;iconScale&quot;; value: 1 }
			PathAttribute { name: &quot;iconOpacity&quot;; value: 1 }
			PathLine { relativeX: id_myList.width/2; y: id_myList.height/2 }
		}
	}
	Text
	{
		anchors.bottom: id_myList.bottom
		anchors.horizontalCenter: id_myList.horizontalCenter
		// make sure to set text only if ItemList index is valid
		// m_strName property registered in C++
		text: id_myList.m_aItems[id_view.currentIndex] ? id_myList.m_aItems[id_view.currentIndex].m_strName : &quot;&quot;

		MouseArea
		{
			anchors.fill: parent
			onClicked:
			{
				// just provoke some action in qml from c++ function
				// it was declared as Q_INVOKABLE so i can do this
				id_myList.clearItems()
			}
		}
	}
}

the final effect looks like this:
qml_list qml_list1
For a full qt project with this issue you can go to my gitorious and download it here

In the next post I describe more complex approach to flexible QObject list exporting to QML.