Saturday, February 11, 2012

Qml FileDialog for symbian anna and belle

I recently ported my Audiobook Reader app for symbian using symbian components. As there is no common QML based file dialog, I need to create my own.

I uploaded my implementation to Gitorious repository here. Currently this code works for only symbian as its used symbian components, but it can be easily ported to work on meego as well.

In this post I will try to explain how this file dialog can be used. Repository also include full working sample.

Lets start with main.cpp file. We need to create instance of FileModel and share it with QML and rest of code is to launch our mainl Qml file.

int main( int argc, char* argv[] ) {
    QApplication app(argc,argv);

    QDeclarativeView view;

    FileModel fileModel;
    QDeclarativeContext *ctxt = view.rootContext();
    ctxt->setContextProperty("fileModel", &fileModel);

    view.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
    view.setResizeMode( QDeclarativeView::SizeRootObjectToView );
    view.setSource(QUrl("qrc:/main.qml"));
    view.show();

    return app.exec();
}
Now QML file which needs to use FileDialog, following code can be used. Here in openFile function, if you want to select Folder/Directory then dirMode should be set to true, if you want to select File than set it to false.
    Page{
        id:page

        function openFile( dirMode ) {
            var component = Qt.createComponent("FileDialog.qml");
            var dialog = component.createObject(page);
            if( dialog !== null ) {
                if( dirMode) {
                    dialog.dirMode = true;
                }
                dialog.fileSelected.connect(fileSelected);
                dialog.directorySelected.connect(directorySelected);
                dialog.open();
            }
        }

        function fileSelected( filePath ) {
            console.debug("File selected:" + filePath);
        }

        function directorySelected( dirPath ) {
            console.debug("Folder selected:" + dirPath);
        }

        tools: ToolBarLayout {
            ToolButton {
                iconSource: "toolbar-back";
                onClicked: {
                    Qt.quit();
                }
            }
            ToolButton {
                text: "File Selection"
                onClicked: {
                    page.openFile(false);
                }
            }
            ToolButton {
                text: "Folder Selection"
                onClicked: {
                    page.openFile(true);
                }
            }
        }
    }
Following are few snaps of FileDialog component running from my Audiobook reader application.

Here is demo of file dialog.

Audiobook Reader for symbian Belle and Anna



I recently ported my Audiobook Reader application to Symbian (supports Anna and Belle).

I struggled a lot while porting this to symbian. For example phonon has some problem with Qt 4.7 on symbian and I wested almost one day to find out solution. If you are also facing similar problem. Then visit this link and this.

Capturing volume key was another problem. I required to use native symbian remote control api to resolve this issue. Visit this link for more info.

And as I use ubuntu machine as development machine, debugging and compilation was another problem.

But finally I was able to port it successfully and now its available on Nokia Store.
Please download it from below.
- Fixed web browser: http://store.ovi.com/content/120217
- Nokia mobile browser: http://store.ovi.mobi/content/120217
Following is demo. Hope you will like it.


Friday, February 10, 2012

Unboxing Nokia Lumia 800

I recently received Nokia Lumia 800 from Nokia Launchpad program. Following are few unboxing snaps.

So far experiance is good, nice little box with accessory and phone cover.


Phone build quality is good and fealt solid while holding it.
I was not able to get beyound following screen, it stuck here and I was not able to boot phone. I can not understand if this screen meant to connect it to pc or it is asking for charging. I tried both but did not get success. Thus unboxing ends here and starts my struggle with my first windows phone.


Update: Now that I received replacement device, I was able to boot and use it for some time. Here are few snaps after power on. I used it only for some time, I prefer to use my meego device, but I liked this device a quite a lot, its animation is quite smooth and fluid. It's UI is quite refreshing and simple. App are lauhced in vary responsive manner and did not faced any hang. Office integration is good and I can easily access my skydrive account from it.

Thing I dont liked are, not able to upgrade it over the air, lack of mass storage, must use of zune( which is not availble for linux), and most dispressing I can not develop apps for it as tools are only for windows. Still device is good and I would like to try developing for it, someday when I have access to windows machine.



 


 





Friday, February 3, 2012

Qt SDK 1.1.4 installation problem on Ubuntu 11.10

Recently Qt SDK 1.1.4 got released and I was trying to install it on my ubuntu machine with Ubuntu 11.10.

All other previous version of Qt SDK were getting installed fine but when I try to install Qt SDK 1.1.4, I found that soon after starting installer, installer disappear and never shows it self again. Same problem also happens to SDK upgrader of Qt SDK 1.1.3.

But I was not having enough time to identify the problem so I continued using older Qt SDK. But now I found solution to this problem.

It looks like that GTK+ GUI style is not compatible with Qt on Ubuntu 11.10, so you need to change that to something else. I changed it to Motif and then new installer started working. To change GUI style you need to use "qtconfig-qt4"

Install it using following command, if you don't have it already.
sudo apt-get install qt4-qtconfig
More information can be found here.

Sunday, January 22, 2012

Animating element on curve in QML

I got comment on my post "Animating object along with curve in Qt using QPainterPath" that how similar thing can be achieved in QML. 

I tried to answer that comment in this post.

Originally I intend to achieve it using only QML but did not find any easy way. So I created a custom QDeclarativeItem that uses QPainterPath and implement required functionality.

Well code it quite simple, but it required little hack so that I can use some QML element like PathQuad or PathLine into my c++ code. 

So let's now move to code, I will try to explain as much as I can.

So let's begin with QML, what I want my QML code to look like. My QML has one rect item which act as circle and my custom QML element which act as curve.

I want my curve element to be drawn on screen and I also want circle to follow the curve. In code path is list which contain different kind of path element.

I was not able to intrepreat QML Path element into C++ class , so I end up creating my own path property. My curve also has pointAtPercentage function which provide point at certain progress on curve, which I use with timer to make dot follow that curve.
import QtQuick 1.0
import MyCurve 1.0

Rectangle {
    width: 500; height: 500

    Rectangle {
        id:dot
        width:10;height:10; radius: 5
        color:"steelblue"
    }

    MyCurve {
        id:curve
        path:[
                PathQuad { x: 400; y: 400; controlX: 100; controlY: 600 },
                PathLine{x: 120; y: 120},
                PathQuad { x: 120; y: 25; controlX: 260; controlY: 75 },
                PathQuad { x: 120; y: 100; controlX: -20; controlY: 75 }
            ]
    }

    Timer{
        property variant progress:0;
        interval: 100; running: true; repeat: true
        onTriggered: {
            progress += 0.005;
            if( progress > 1 ) {
                progress  = 0;
            }
            var point = curve.pointAtPercent(progress);
            dot.x = point.x
            dot.y = point.y
        }
    }
}
Now lets look at MyCurve, custom QDeclaraiveItem class, which holds the QPainterPath. MyCurve is quite simple class if we don't include code to interpret PathQuad or PathLine QML element. We could have populated QPainterPath directly in c++ class. But I choose not to do so, to make it more reusable and also that I can try my hands on QDeclarativeListProperty and can show how we can read property of QML element.

#ifndef MYCURVE_H
#define MYCURVE_H

#include <QDeclarativeItem>
#include <QPainterPath>
#include <QGraphicspathItem>
#include <QDeclarativeListProperty>

class MyCurve : public QDeclarativeItem
{
    Q_OBJECT
    Q_PROPERTY(QDeclarativeListProperty<QObject> path READ path)
public:
    explicit MyCurve(QDeclarativeItem *parent = 0);

public slots:
    QPointF pointAtPercent(double Percent);

public:
    QDeclarativeListProperty<QObject> path();

private:
    static void appendItem(QDeclarativeListProperty<QObject> *list,
         QObject *pathItem);

    void appendPathQuad( QObject* pathQual);
    void appendPathLine( QObject* pathLine);

private:    
    QGraphicsPathItem* _path;
    QPainterPath _painterPath;
};
#endif // MYCURVE_H
Only Interesting about header is appendItem static method, which I will explain after showing its implementation. So here is implementation of header.
#include "mycurve.h"
#include <QDebug>
#include <QDeclarativeItem>
#include <QPen>

MyCurve::MyCurve(QDeclarativeItem *parent) :
    QDeclarativeItem(parent),_path(0),_startX(0),_startY(0)
{
    _path = new QGraphicsPathItem(this);
    _path->setPen(QPen(Qt::blue));
}

QPointF MyCurve::pointAtPercent(double Percent) {
    return _painterPath.pointAtPercent(Percent);
}

QDeclarativeListProperty<QObject> MyCurve::path()
{
    return QDeclarativeListProperty<QObject>(this,0,&MyCurve::appendItem);
}

void MyCurve::appendItem(QDeclarativeListProperty<QObject> *list, 
    QObject *pathItem)
{
    MyCurve *myCurve = qobject_cast<MyCurve *>(list->object);
    if (myCurve) {
         if( QString(pathItem->metaObject()->className())
                == QString("QDeclarativePathQuad") ) {
             myCurve->appendPathQuad(pathItem);
         } else if (QString(pathItem->metaObject()->className()) 
               == QString("QDeclarativePathLine")){
             myCurve->appendPathLine(pathItem);
         }
       }
}

void MyCurve::appendPathQuad( QObject* pathQuad) {
    double x = pathQuad->property("x").toDouble();
    double y = pathQuad->property("y").toDouble();
    double controlX = pathQuad->property("controlX").toDouble();
    double controlY = pathQuad->property("controlY").toDouble();

    _painterPath.quadTo(controlX,controlY,x,y);
    _path->setPath(_painterPath);
}

void MyCurve::appendPathLine( QObject* pathLine) {
    double x = pathLine->property("x").toDouble();
    double y = pathLine->property("y").toDouble();
    _painterPath.lineTo(x,y);
    _path->setPath(_painterPath);
}
There are quite a few interesting things here.

Usage of QDeclarativeListProperty(I am using it for first time), QDeclarativeListProperty is used to create list of property in QML. To operate on QDeclarativeListProperty, we need to provide static method which take pointer of list object and list item. appendItem is similar static method which add path element to our QPainterPath. To know more how other operation can be implemented on QDeclarativeListProperty, please visit this or this link.

In above code I am using metaObject to identify which QML Path element is being added by appendItem ( which is kind of dirty hack ) and after identifying element I am using property method to get its value and finally using those value to call appropriate QPainterPath method.

And finally here is how it looks,