Saturday, December 31, 2011

i-muz Tx72 7" inch android tablet

Recently I purchased iMuz Tx72 7" inch android tablet. I wanted a tablet on which I can read book and browse internet and this tablet full fill both that requirement quite well.

I went for this tablet as other similar config tablet like Kindle Fire or Nook are not easily available here or available but need to pay extra price. This was easily available for me, placed order online on gmakret and got it next day.

Currently it comes with android 2.3.3 and their site suggest that android 4 will be supported in around month time.

It has 512 mb ram, Cortext A8 1GHz cpu and 8 gb internal storage with up to 32 gb SD card support.  Its wifi only model and support TV out using HDMI , mini usb and front camera for video call. If you want a full specifiction its here.

Its multitouch device and display quality is good. Thought its supported resolution is 480x800 only. Its sound quality its good, sound is clear and loud enough and video from youtube and dailymotion played fine.

I tried HDMI out, but was not successful trying to see device screen on my TV, might be cable problem but i suspect its device problem.

Home key, back , search and other standard android key are not backlight supported , so using them at night is guess work.

Battery takes time to get fully charged but once charged enough, it keeps going for atlest two days for normal reading and browsing use and works around 4 hour if watching you tube video.

Now on software part, by default it comes with app called app installer which let you install android apk file, browser, Email client, ES file explorer , Gallary and music application.

It was kind of disappointment by not seeing android market place application, but I was expecting it as it kind of entry level device. I tried to install market place by apk but its says not supported and web version keep complaining that you dont have any device attched to your google account. So I cant install any application from official android market place.

But I was able to install amazon store and getjar store and was able to install app from those store.

I installed PDF reader and worked great. I tried to install skype app but it never worked and was not able to login, so can not try it. But Fring worked great and also supported video calling feature.  And other normal application like Angry bird, guitar hero, piano worked great. 

I also liked ES file explorer as it allows to browse device easily and also it allows network shared storage. Like I shared my computer's folder over network and I was able to connect that computer and download contect from that shared folder using ES file explorer.  It also allows to connect to Dropbox and FTP server easily. But I tried only network shared folder.

Overall, its good device for reading and browsing and serve well as development device. It has fairly supported standard feature of tablet at fair price.



Saturday, December 24, 2011

Creating custom list view and adaptor in Android

I recently got new toy for myself a imuz TX72 7" android tablet to satisfy my book reading hobby.

I will write a seperate post for tablet, but as I got this tablet, I thought to port my Audiobook reader app to Android so I can here my audiobook on this tablet as well.

As I started to port, First thing I need to learn is how to create view and specially list view. I required to create custom Listview so I can show thumnail and other audiobook details.

So to start, First you need to create is activity. I also wanted to put button on main activity so I did not derived my activity from ListActivity but derived it from Activity. For new people to android like me, Activity is something that we see on screen , a view.

My main activity goes like below.

    
public class AudiobookReaderActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       
       setContentView(R.layout.main);
       
       ListView list = (ListView) findViewById(R.id.BookList);
       list.setAdapter( new BookListAdaptor(this));  
    }  
}

Now we have list view, but how invidiual list item looks is decided by item's xml file, which provide layout and views details to be drawn as item.

Following is my list item, with one image and two text view.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android=
       "http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal" >
    
    <ImageView
        android:id="@+id/AlbumArt"        
      android:layout_width="55dip"
  android:layout_height="55dip"/>
    
 <LinearLayout xmlns:android=
              "http://schemas.android.com/apk/res/android"
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
     android:orientation="vertical" >    
 
  <TextView xmlns:android=
                "http://schemas.android.com/apk/res/android"
      android:id="@+id/BookName"     
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:textStyle="bold" 
      android:padding="3dp"
      android:textColor="#FFFF00" 
      android:textSize="16sp" >
  </TextView>
  
  <TextView xmlns:android=
                      "http://schemas.android.com/apk/res/android"
      android:id="@+id/TrackName"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:padding="3dp" >
  </TextView>
  
 </LinearLayout>
</LinearLayout>

Now look is set for list view, now we need to provide data to list, by creating adaptor class. Adaptor class act as model and provide data to list view.

Following is my custom list adaptor class to support Book data structure. Here getView method is importat as it uses our xml file to create liste item and decide our list view's look.

import java.util.ArrayList;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import android.content.Context;

public class BookListAdaptor extends BaseAdapter {
 
 public BookListAdaptor( Context context) {
  mContext = context;
  
  //load book list from file or database
  mBookList = new ArrayList();

  mBookList.add(new AudioBook("Harry Potter"));
  mBookList.add(new AudioBook("The Hobbit"));
 }

 @Override
 public int getCount() { 
  return mBookList.size();
 }

 @Override
 public Object getItem(int position) {
  return mBookList.get(position);
 }

 @Override
 public long getItemId(int position) {
  return position;
 }

 @Override
 public View getView(int position, View convertView, ViewGroup parent) {  
  
        if (convertView == null) {
   LayoutInflater layoutInflator = 
                             LayoutInflater.from(mContext);
   convertView = layoutInflator.
                             inflate(R.layout.list_item, null);
        }
     
        TextView bookName = (TextView) convertView.
                                      findViewById(R.id.BookName);
        TextView trackName = (TextView)convertView.
                                      findViewById(R.id.TrackName);
        ImageView imageView = (ImageView)convertView.
                                      findViewById(R.id.AlbumArt);
  
  
  AudioBook book = mBookList.get(position);
  bookName.setText(book.bookName());
  trackName.setText(book.bookName());
  imageView.setBackgroundResource(android.R.drawable.btn_plus);
  
  return convertView;
  
 }

    private Context mContext;
    private ArrayList mBookList;
}

Book class looks something like following.

package com.niku;

import java.util.ArrayList;


public class AudioBook {
 
    public AudioBook( String aBookName) {
 mBookName = aBookName;
    }
 
    public String bookName() 
    {
        return mBookName;
    }

    private String mBookName;
}  
That's all. Final list view will looks like followign snap. Thanks fo reading my blog.






Friday, December 23, 2011

Crazy Flight a classic helicopter game now available on N9 Harmattan

I created this game - Crazy Flight, when I was on vacation in india, to please my nephew, so he can play on my phone and I can work on my computer.

Game is created using QML and C++ and backend and works on N9/N950 Harmattan plaform. Well programing did not take much time but creating graphics and polishing it took a while and around a week time I was able to publish this game on Ovi store for N9.

Game is vary simple to play,  you have to touch on screen to make plane go up and release touch to go down and avoid obstacle which may come.

You can download this game from Ovi store here. It free game with Ads.
Mobile link is here.


Here are few snapshot from game. If you have any comments I am glad to have those.





Saturday, December 17, 2011

Handling bluetooth headphone event with QmKeys in Harmattan

Currently I am working on upgrade of Audiobook reader application. As part of upgrade I am planing to support bluthooth headset support. In this upgrade I am planning to support only play/pause event.

Harmattan has QmSystem Qt library that provide events for various system activity. I used QmKeys API from QmSystem to capture and handle bluetooth headset event.

This is first time I am using QmSystem Library so I thought to put whatever I learned in blogpost in hope that it might help someone.

Following is my code to capture bluetooth headset event. It can be used to capture other system key event as well like Powekey, Volume key, Camera , keyboard slider and others.

First add qmsystem2 to CONFIG Qt project file.
CONFIG += qmsystem2
And also you need to include qmkeys.h.
#include <qmkeys.h> 
. Then need to create instace of QmKeys and connect its keyEvent SIGNAL to our SLOT.
mQmkeys = new MeeGo::QmKeys(this);

connect(mQmkeys, SIGNAL(keyEvent(MeeGo::QmKeys::Key, MeeGo::QmKeys::State)),
       this, SLOT(keyEvent(MeeGo::QmKeys::Key, MeeGo::QmKeys::State)));
Now our slot keyEvent will get called when ever there is key event. I am instrested only in play/pause event so following code list only those event.
void HeadsetKeyListener::keyEvent(MeeGo::QmKeys::Key key, 
    MeeGo::QmKeys::State state) {

    if( state != MeeGo::QmKeys::KeyDown ) {
        return;
    }

    switch( key) {
    case MeeGo::QmKeys::Play:
        emit playPauseClicked();
        break;
    case MeeGo::QmKeys::Pause:
        emit playPauseClicked();
        break;
    }
}
Well this is it, its vary simple to use.

Friday, December 9, 2011

Using QDeclarativeImageProvider to load QPixmap to QML Image element

Recently for my mobile application, I required cache image from network and use that in QML application. Prior to caching, I was using WebView element to show image from network, but I needed to show that image multiple places, to avoid multiple network request I decided to prefetch network image and show that using Image element.

To make it work, I downloaded network image to QPixmap using QNetworkAccessManager and then used QDeclarativeImageProvider to provide cached QPixmap to Image element.

As per documentation "The QDeclarativeImageProvider class provides an interface for supporting pixmaps and threaded image requests in QML."  I also used it as proxy image provider. When actual Image data is not available my image provider class will provide some dummy image and when actual data is available it will provide actual image data.

Following is my code for my custom image provider derived from QDeclarativeImageProvider.

In following code, by providing QDeclarativeImageProvider::Pixmap as ImageType, I am saying I will povide QPixmap as Image type and in this case requestPixmap API will be called by declarative engine to fetch image. You can also use QDeclarativeImageProvider::Image, to provide QImage to Image and in that case requestImage API will be called.

#include <QDeclarativeImageProvider>

class ImageProvider: public QDeclarativeImageProvider
{
public:
    ImageProvider(ImageManager* manager)
        : QDeclarativeImageProvider(QDeclarativeImageProvider::Pixmap),
          mManager(manager)
    {}

    QPixmap requestPixmap(const QString &id, QSize *size, 
        const QSize &requestedSize)
    {
        int width = 320;
        int height = 53;

        QPixmap result;

        if( mManager->imageData() == 0 ) {
     QPixmap pixmap(requestedSize.width() > 0?requestedSize.width():width,
             requestedSize.height() > 0 ?requestedSize.height():height);

            pixmap.fill(QColor(id).rgba());

            if ( size ) *size = QSize(width, height);
            result = pixmap;
        } else {

            result = *mManager->imageData();
            if ( size ) *size =result.size();

            if (requestedSize.isValid()) {              
                result = result.scaled(requestedSize,Qt::IgnoreAspectRatio);
            } 
        }
        return result;
    }

private:
    ImageManager* mManager;
};
Now custom image provider is ready, but we need to register our image provide to declarative engine, so that it will now forward image loading request to our image provider. To do that, we need to use QDeclarativeEngine::addImageProvider API, as described in following code. Here in addImageProvider API, "MyImage" is provider name, that will be used in QML to indicate that our custom image provider should be used.
QScopedPointer view(new QDeclarativeView());
view->engine()->addImageProvider(QLatin1String("MyImage"), 
    new ImageProvider(ImageManager::instance()));
Now we are ready to use our custom image provider with Image element, like shown below. Here in Image.source we providing path as image://MyImage, which will tell system to use MyImage image provider and remaining part of url will be used as id in requestPixmap or requestImage parameter. Which can be used to decide what kind of image data to provide.
import QtQuick 1.0

Rectangle {
    id:container
    width: 320;height: 53
    anchors.horizontalCenter: parent.horizontalCenter    

    Connections{
        target: ImageManager
        onImageAvailable:{
            myImage.source = "image://MyImage/test"
        }
    }

    Image {
        id: myImage
        anchors.centerIn: parent
        source: "image://MyImage/"+container.color
    }
}
This is all that is needs to be done to implement custom image provide. Hope it will be usefull.

Saturday, November 26, 2011

Using custom Font with Qt

Recently in one of my application I wanted to use custom font and in little time I figured out that Qt has vary nice support to use custom font with both Qt C++ and QML.

I used following code in my application. Here is output of below code.


Following is code to use custom font with Qt C++.
#include <QPainter>
#include <QFontDatabase>

MyWidget::MyWidget(QWidget *parent) :
    QWidget(parent)
{
    QFontDatabase::addApplicationFont("sandsped.ttf");
}

void MyWidget::paintEvent(QPaintEvent */*event*/) {
    QPainter painter(this);
    painter.drawText(10,20,"Default Font");
    painter.setFont(QFont("Sandoval Speed"));
    painter.drawText(10,50,"Custom Font");
}


Following is code to use custom font with QML.
    FontLoader { id: myFont; source: "sandsped.ttf" }

    Column {
        spacing: 30
        anchors.horizontalCenter: parent.horizontalCenter
        Text {
            text: "Default Font"
        }

        Text {
            font.family: myFont.name
            text: "Custom Font";
        }
    }

Thursday, November 17, 2011

Virtual Joystick with QML

Recently out of curiosity I tried to created virtual joystick, which nowadayx s used quite frequently touch based games.

Well my implementation still required some improvement to provide real feel of joystick but its still quite useful. Here is output.

To test my joystick, I also created a sprite which moves in almost all direction.

Here is my QML code for joystick. I basically used two circle and checking inner circle position with outer circle and deciding direction. I am not describing code, but tried to put necessary comment in code.
import QtQuick 1.0

Item {
    id:joyStick;
    property int offset:30;

    signal dirChanged(string direction);
    signal pressed();
    signal released();

    Rectangle {
        id:totalArea
        color:"gray"
        radius: parent.width/2
        opacity: 0.5
        width:parent.width;height:parent.height
    }

    Rectangle{
        id:stick
        width:totalArea.width/2; height: width
        radius: width/2
        x: totalArea.width/2 - radius;
        y: totalArea.height/2 - radius;        
        color:"black"
    }

    MouseArea{
        id:mouseArea
        anchors.fill: parent

        onPressed: {
            joyStick.pressed();
        }

        onMousePositionChanged: {            
         //(x-center_x)^2 + (y - center_y)^2 < radius^2
         //if stick need to remain inside larger circle
         //var rad = (totalArea.radius - stick.radius);
         //if stick can go outside larger circle
         var rad = totalArea.radius;
         rad =  rad * rad;

         // calculate distance in x direction
         var xDist = mouseX - (totalArea.x + totalArea.radius);
         xDist = xDist * xDist;

         // calculate distance in y direction
         var yDist = mouseY - (totalArea.y + totalArea.radius);
         yDist = yDist * yDist;

         //total distance for inner circle
         var dist = xDist + yDist;            

         //if distance if less then radius then inner circle is inside larger circle
         if( rad < dist) {
             return;
         }

         //center of larger circle
         var oldX = stick.x; var oldY = stick.y;
         stick.x = mouseX - stick.radius;
         stick.y = mouseY - stick.radius;

         //using L R U D LU RU LD RD for describe direction
         var dir="";

         //check if Right or left direction, 
         //by checking if inner circle's y is near center of larger circle
         if( stick.y >= totalArea.radius - stick.radius - joyStick.offset 
 && stick.y+stick.height <= totalArea.radius + stick.radius + joyStick.offset) {
             if( stick.x + stick.radius > totalArea.x + totalArea.radius) {
                 dir = "R";
             } else if( stick.x < totalArea.x + totalArea.radius) {
                 dir = "L";
             }
         }
         //check if Up or Down direction, 
         //by checking if inner circle's x is near center of larger circle
         else if( stick.x >= totalArea.radius - stick.radius - joyStick.offset 
 && stick.x + stick.width <= totalArea.radius + stick.radius + joyStick.offset) {
            if( stick.y + stick.radius > totalArea.y + totalArea.radius) {
                 dir = "D";
            } else if( stick.y < totalArea.y + totalArea.radius) {
                 dir = "U";
            }
         }
         //check if Up Left or Up Right direction,
         //by checking if inner circle is near one of top corner of larger circle
         else if( stick.y < totalArea.radius - stick.radius ) {
            if( stick.x + stick.radius > totalArea.x + totalArea.radius) {
                dir = "R";
            } else if( stick.x < totalArea.x + totalArea.radius) {
                dir = "L";
            }
            dir = dir +"U";
         }
         //check if Down Left or Down Right direction,
         //by checking if inner circle is near one of bottom corner of larger circle
         else if ( stick.y + stick.radius >= totalArea.radius + stick.radius ) {
            if( stick.x + stick.radius > totalArea.x + totalArea.radius) {
               dir = "R";
            } else if( stick.x < totalArea.x + totalArea.radius) {
               dir = "L";
            }
            dir = dir +"D";
         }

         joyStick.dirChanged(dir);
        }

        onReleased: {
            //snap to center
            stick.x = totalArea.width /2 - stick.radius;
            stick.y = totalArea.height/2 - stick.radius;

            joyStick.released();
        }
    }
}

Follwing my code for sprite used in above video.
import QtQuick 1.0

Item {
    id:sprite
    width: 50; height: 50
    clip:true
    property alias running: timer.running;
    property int frameCount: 5
    property int frame:0
    property int row:0

    property int xDir:0;
    property int yDir:0;

    Image{
        id:image
        source:"man.png"
        x:-sprite.width * sprite.frame;
        y:-sprite.height * sprite.row;
    }

    function changeDirection(direction) {
        if( direction === "L") {
            sprite.row=6;
            sprite.xDir = -1;
            sprite.yDir = 0;
        } else if( direction === "R") {
            sprite.row=2;
            sprite.xDir = 1;
            sprite.yDir = 0;
        } else if( direction === "U") {
            sprite.row=4;
            sprite.xDir = 0;
            sprite.yDir = -1;
        } else if( direction === "D") {
            sprite.row=0;
            sprite.xDir = 0;
            sprite.yDir = 1;
        } else if( direction === "RU") {
            sprite.row = 3;
            sprite.xDir = 1;
            sprite.yDir = -1;
        } else if( direction === "LU") {
            sprite.row = 5;
            sprite.xDir = -1;
            sprite.yDir = -1;
        } else if( direction === "RD") {
            sprite.row = 1;
            sprite.xDir = 1;
            sprite.yDir = 1;
        } else if( direction === "LD") {
            sprite.row = 7;
            sprite.xDir = -1;
            sprite.yDir = 1;
        }
    }

    function nextFrame() {
        sprite.frame = ++sprite.frame  % sprite.frameCount
        sprite.x = sprite.x + 5* sprite.xDir;
        sprite.y = sprite.y + 5* sprite.yDir;
    }

    Timer {
       id:timer
       interval: 150; running: false; repeat: true
       onTriggered: {
           nextFrame();
       }
    }
}
Finally, main qml file which include both joystick and sprite.
import QtQuick 1.0

Image {
    width: 854 ;  height:480    
    source:"grass.jpg"
    fillMode: Image.Tile

    Sprite{
        id:man
        x:parent.width/2 ; y: parent.height/2;
    }

    Connections {
        target: joyStick
        onDirChanged:{
            man.changeDirection(direction)
        }

        onPressed:{
            man.running=true;
        }

        onReleased:{
            man.running=false;
        }
    }

    Joystick{
        id:joyStick
        anchors.bottom: parent.bottom
        anchors.left: parent.left
        anchors.bottomMargin: 10
        anchors.leftMargin: 10
        width:150;height:150
    }
}


Friday, November 4, 2011

Taking backup of Audiobook Reader on N9/N950

Recently I upgraded my N950 to PR 1.1 and realized that its camera is not working any longer.

After googling a bit I found that issue can be solved by flashing "Linux_OCF_39-5_RM680-RM680-OEM1.bin" image. But that means loosing all data, you can use backup and restore app but unfortunately my Audiobook Reader currently dose not support backup restore.  I need to  implement this feature in next release.

But if you need this support currently like me, then you can try following work around.

Audiobook reader setting file is store at "/home/user/.config/kunal/audiobookreader.conf". You can copy this file to your pc using ssh and then restore it at same place when you need.

I am not sure but same trick can be used for N900 as well.

Hope this helps.

Saturday, October 22, 2011

SSH Login problem after upgrading Harmattan N950 to PR 1.1

Recently PR 1.1 upgrade notification poped up on my N950 developer device and as normal reflex I started upgrade.

This time update was supported over wifi and upgrade gone well, with some low memory warning which we can safely ignore.

But after upgrade I found that I could no longer ssh to device with root account. 

Root login via ssh (password or public key) is now disabled with PR1.1. But If you still want to login using ssh then you can try following work around.

You need to unlock developer account and set password for developer account.

To do this, on your device's terminal type devel-su (to access device as root) and then type "rootme" password.
devel-su
Now you have root access to device. Now you need to set developer account password, using following command.
passwd developer
Enter new password for developer account.

Now you can ssh using developer account and new password.
ssh developer@192.168.2.15

now if you wish to have root access you can type devel-su command,
devel-su

Now you will have access to root account. Following is output from my terminal.

ssh developer@192.168.2.15
developer@192.168.2.15's password: 


BusyBox v1.19.0.git (MeeGo 3:1.19-8+0m6) built-in shell (ash)
Enter 'help' for a list of built-in commands.

/home/developer $ devel-su
Password: 


BusyBox v1.19.0.git (MeeGo 3:1.19-8+0m6) built-in shell (ash)
Enter 'help' for a list of built-in commands.

~ # 

Saturday, October 15, 2011

Audiobook Reader now available for N9 / N950 ( Harmattan ) on Nokia Store

I recently updated my Audiobook reader application for N9 Harmattan platform. It is also supported on N950. You can download it from Nokia Store from here.





For those who dont know about this application, Audiobook reader is simple Audiobook player which lets you add audiobook with single large audio file or folder with audio files for each chapter. It automatically bookmark the last position of audiobook and resume playback from that position. It also allow to add custom bookmark and playback from certain chapter from Audiobook.

For N9, I completely reimplemented UI layer to give native look and feel. For this version I am also showing book cover image, downloaded from AWS to give more feel of book.




Same as N900 version, this version also support custom bookmark support and chapter selection support. Volume can be changed by using Hardware key.


Thursday, October 6, 2011

Enabling Booster support for QML applicaion in Harmattan

Recently I added support for Booster for My QML application. Its quite easy to add booster support for existing QML or new QML application.

I am wiring down my experience here in hope it will help someone.

The QML booster reduce application startup latency by creating instances of QApplication and QDeclarativeView the classes in MDeclarativeCache.

To use this class you will need to add following header.

#include <MDeclarativeCache>
And then you will need to use QApplication and QDeclarativeView class instance provided by MDeclarativeCache. Following code shows how that can be done.

QApplication* app = MDeclarativeCache::qApplication(argc, argv);
QDeclarativeView* view = MDeclarativeCache::qDeclarativeView();
To enable booster and link with it properly you need to add following line in to your Qt project (.pro) file.

# enable booster
CONFIG += qt-boostable qdeclarative-boostable
LIBS += -lmdeclarativecache

If you are planning to use applauncerd to launch application then you will need to use Q_DECL_EXPORT macro in front of main function from "QtCore/QtGlobal" header file as shown in following code.

#include ≶QtCore/QtGlobal>

Q_DECL_EXPORT int main( int argc, char* argv[] ) {
}
You will also need modify include path in your pro file in order to locate header file properly.

INCLUDEPATH += /usr/include/applauncherd
And finally in your desktop file, you need to use --type=d to launch application using booster.

Exec=/usr/bin/invoker --single-instance --type=d /usr/bin/appname

The Math Game now available for N9/N950 (Harmatta) on Ovi Store

Today The Math Game's Harmattan version passed the Ovi QA process and its now available on Ovi Store.

The Math Game is fun and simple math game for little once. I created  game in hope that it will help to increase kid's interest in Math.

Harmattan version is now available here.

You can find maemo version here.

Please find more information regarding this application here.

Saturday, September 24, 2011

Crazy Chickens game available on N9/N950 Harmattan

Recently I ported my Crazy Chickens game for Harmattan / Maemo6. Its now available on Ovi Store.

Find out more information about this game here. Following are few snaps of game from Harmattan version.






Saturday, September 10, 2011

Accessing Amazon Web service from Qt

Currently I am trying to port my Audiobook reader application to Harmattan. I decided to improve its UI and as a change I decided to show book cover page in background.

Initially I thought to use taglib to fetch album art from audio file, but then I decided to download cover art from internet as some audio file might not contain album art information.

To download cover art from internet, I decided to use Amazon web service. Initially I struggled to successfully communicate with AWS.

AWS required to send signature with every request you send and there is certain procedure to create that signature. Creating signature with Qt is quite easy, but still I was facing problem with retrieving data from AWS because I did not read QUrl documentation carefully.

While generating QUrl, it expect human redable URL string with no percentage encoding. But I was trying to generate QUrl from already encoded parameters.

And as a result I was getting such error message.
"Value 2011-09-11T05%3A18%3A42 for parameter Timestamp is invalid. Reason: Must be in ISO8601 format".

Double encoding was causing above problem.

I am posting my code here, in hope that will be helpful to someone.

First all to communicate with AWS you required to have AWS access key id and Secret Access key. You can get it from here.

Here is AWS doc that explain how to generate signature. And here utility which you can use to verify if you generated correct signature.

Now we are ready for implementation. Following is my code.

Here in below code, I am trying to create AWS request to get all image for mentioned book. In request I am also specifying SignatureMetod to HmacSHA1, by default AWS use HmacSHA256 signature method for comparison.

const char AWS_KEY[] = "YOU ACCESS KEY";
const char AWS_PASS[] = "YOUR SECRET KEY";
const char END_POINT[] = "http://ecs.amazonaws.com/onca/xml";

AwsAlbumArtHelper::AwsAlbumArtHelper(QObject *parent) :
    QObject(parent)
{
    _netManager = new QNetworkAccessManager(this);    
}

QByteArray AwsAlbumArtHelper::getTimeStamp()
{
    QDateTime dateTime = QDateTime::currentDateTimeUtc();
    return dateTime.toString(Qt::ISODate).toUtf8();
}

void AwsAlbumArtHelper::downloadAlbumArt(const QString& bookname)
{
    _bookName = bookname;
    QMap< QString,QString > queryItems;
    queryItems["AWSAccessKeyId"] = AWS_KEY;
    queryItems["ResponseGroup"] = "Images";
    queryItems["Keywords"] = QUrl::toPercentEncoding(bookname);
    queryItems["Operation"] = "ItemSearch";
    queryItems["SearchIndex"] = "Books";
    queryItems["Service"] = "AWSECommerceService";
    queryItems["SignatureMethod"] = "HmacSHA1";
    queryItems["Timestamp"] = QUrl::toPercentEncoding(getTimeStamp());
    queryItems["Signature"] = createSignature(queryItems);

    QUrl downloadUrl = createUrl(queryItems);
    QNetworkRequest request(downloadUrl);

    disconnect(_netManager,SIGNAL(finished(QNetworkReply*)),this,SLOT(imageDownloaded(QNetworkReply*)));
    connect(_netManager,SIGNAL(finished(QNetworkReply*)),this,SLOT(xmlDownloaded(QNetworkReply*)));
    _netManager->get(request);
}
Following code create signature from query parameters. I used code pasted here for signing string with hmacSha1.
QByteArray AwsAlbumArtHelper::createSignature(const QMap< QString,QString >& queryItems)
{
    QUrl url(END_POINT);
    QString stringToSign = "GET\n";
    stringToSign.append(url.host() + "\n");
    stringToSign.append(url.path() + "\n");

    QList<qstring> keys = queryItems.keys();
    for( int i=0; i < keys.count() ; ++i ) {
        stringToSign.append(keys[i]+"="+queryItems[keys[i]]);
        if( i != keys.count() -1  ) {
            stringToSign.append("&");
        }
    }
    QString signature = hmacSha1(AWS_PASS,stringToSign.toUtf8());
    return QUrl::toPercentEncoding(signature);
}

QUrl AwsAlbumArtHelper::createUrl( const QMap< QString,QString >& queryItems )
{
    QUrl url(END_POINT);
    QMapIterator<QString, QString> it(queryItems);
    while (it.hasNext()) {            
        it.next();
        //everything is already URL encoded
        url.addEncodedQueryItem(it.key().toUtf8(), it.value().toUtf8());
    }
    return url;
}
Now we are ready to submit request using downloadAlbumArt method with required book name and AWS should return xml data with various image link. We need to parse xml and use mentioned link to download image.

Sunday, September 4, 2011

Porting Qt app to Harmattan

As I received Nokia N9 Dev kit from Qt Ambassador program, I started working on porting my existing Maemo 5 application to Maemo 6 (Harmattan/Meego) platform.

It seems from documentation that preferred way to create Meego application is by using QML and com.meego components. In order to make my Qt and QML application to work correctly on meego I needed to make quite a few changes.

First thing I noticed is that, Qt Widget are available on harmattan but that just for backword compatiblity and dose not provide native look and feel for Harmattan platform. That mean Qt Widget library are kind of useless on harmattan. We need to use meego touch library or meego QML component.

Some of my application were QWidget based or some were Graphics View based. I ported most of application to use QML and If i can not port to use QML then I  used QDeclarativeItem to load that component to QML.

For some of my application I was locking orientation, using "WA_Maemo5PortraitOrientation" flag in view.setAttribute(Qt::WA_Maemo5PortraitOrientation, true); API call, But on Harmattan I need to use following code in QML page.
 Page{
        orientationLock: PageOrientation.LockPortrait
    }
To make application full screen, I need to disable statusbar and toolbar from PageStackWindow. I used following code

PageStackWindow {
    showStatusBar: false
    showToolBar: false
}
In one of my application I was using GraphicsView framework, I loaded graphics view to QML using QDeclarativeItem and QGraphicsProxyWidget. Visit following link for more info. 

But after GraphicsView loaded to QML, view was displaying some white area that initially I was not able to remove. After a white I realized it was frame for graphics view. I removed it by using setFrameStyle API.
setFrameStyle(QFrame::NoFrame);
Desktop file also needs to be changed to locate icon correctly and to launch only single instance of application.
[Desktop Entry]
Encoding=UTF-8
Version=0.1
Name=appname
GenericName=app name
Comment=some comment
Exec=/usr/bin/single-instance /usr/bin/appname
Terminal=false
Type=Application
Icon=/usr/share/icons/hicolor/64x64/apps/icon.png
Also in control file, to make your application user application and not system component, we need to add following flag.
Maemo-Flags: visible
I used following in my project file to transfer icon file to proper location.
unix  {
    #VARIABLES
    isEmpty(PREFIX) {
        PREFIX = /usr
    }
    BINDIR = $$PREFIX/bin
    DATADIR =$$PREFIX/share

    DEFINES += DATADIR=\\\"$$DATADIR\\\" PKGDATADIR=\\\"$$PKGDATADIR\\\"

    INSTALLS += target desktop icon64

    target.path =$$BINDIR

    desktop.path = $$DATADIR/applications
    desktop.files += ./image/$${TARGET}.desktop

    icon64.path = /usr/share/icons/hicolor/64x64/apps/
    icon64.files += ./image/$${TARGET}.png
}
I also faced segmentation fault while testing Webview with emulator, but on device it works fine.

That's all, most of my experience was smooth while porting and did not struggled much.

Saturday, August 27, 2011

Snake game for N9/N950 Meego Harmattan now available on ovi store

I am happy to announce that Snake game is now available on N9/N950 Meego harmattan device also.


You can download game from Ovi Store from here. This game is port of N900 version, please find more information about game here.

 Now I am planning to port my Crazy Chickens game for meego. I hope I will be able to finish working on it soon.

Using Phonon Video player from QML

Recently one of my friend asked me to give some sample code for integrating Phonon Video Player to QML. Long back I had created a application which download video from dailymotion and play the video using Phonon.

QtMultimediaKit provides QML Video element which we cause use for playing video. But form reason if you need to use your exiting code then you can follow what I did.

I tried to my video widget from that application with sample QML application. I was able to integrate that widget quite easily without any problem.

Following is sample code for video player that uses the Phonon VideoPlayer to play video.

#include <phonon/videoplayer.h>
#include <QUrl>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{    
    player = new Phonon::VideoPlayer(Phonon::VideoCategory, this);

    QVBoxLayout* mainLayout = new QVBoxLayout(this);
    mainLayout->setMargin(0);
    mainLayout->addWidget( player);
}

void Widget::play()
{
    if( player->isPlaying() == false )
        player->play(QUrl("URL FOR VIDEO"));
}
Then I created an custom QDeclarativeItem, which uses my video widget class through QGraphicsProxyWidget. Visit my post for more information how we can use this class into QML.
#include "qmlvideo.h"
#include <QGraphicsProxyWidget>

#include "widget.h"

QmlVideo::QmlVideo(QDeclarativeItem *parent) :
    QDeclarativeItem(parent)
{
    myVideoWidget = new Widget;
    QGraphicsProxyWidget* proxy = new QGraphicsProxyWidget(this);
    proxy->setWidget(myVideoWidget);
}


void QmlVideo::play()
{
    myVideoWidget->play();
}
Now finally I created QML file which uses above created declarative item. I also tried how we can put player control with video player. Following is final code with some unnecessary code removed.
import QtQuick 1.0
import qmlVideo 1.0

Rectangle {
    width: 624 ; height: 480
    QmlVideo{
        id:videoPlayer
    }

    Item{
        anchors.bottom: parent.bottom
        anchors.horizontalCenter: parent.horizontalCenter
        width: playerControl.width
        height: playerControl.height
        MouseArea{
            id:mouseArea
            anchors.fill: parent
            hoverEnabled:true

            onEntered: {
                playerControl.opacity = 1
            }

            onExited: {
                playerControl.opacity = 0
            }
        }
    }

    Rectangle{
        width: 200
        height: 50
        anchors.bottom: parent.bottom
        anchors.horizontalCenter: parent.horizontalCenter
        id:playerControl
        color: "gray"
        opacity: 0
        radius:10

        Row{
            anchors.horizontalCenter: parent.horizontalCenter
            anchors.verticalCenter: parent.verticalCenter
            spacing: 20

            Button{
                icon: "backward.png"
                iconOn:"backward_on.png"
                onClicked: {
                    videoPlayer.backward();
                }
            }
        }

        Behavior on opacity {
            NumberAnimation { duration: 500 }
        }
    }
}
Following is output and here is link to source code.Hope it will be useful to someone.

Friday, August 12, 2011

The Math Game for maemo now available on Ovi Store


I had created  and submitted The Math Game for Meego Coding competition. Find more information about this game here.

Meantime I had also uploaded the game on Ovi store. There were quite a lot problem to got it through Ovi Store QA, But finally maemo version of game got published today.

I am still now able to pass my Symbian version though. There is some problem for creating sis file using remote compiler.

This game is fun game for little ones, you can download it for free from here and from mobile visit this link.

Crazy Chickens for maemo updated, available on Ovi store

Today my update for crazy chickens game got published on Ovi store.

This update solve one bug which was preventing to catch egg for some speed and thus preventing to achieve higher score.

This Update also have some improved graphics, hope you will like this changes.

Game is now available on Ovi store here. To download from mobile visit this link.

Here are few snaps from updated game.





Friday, August 5, 2011

Snake game for Maemo upgraded and now available on Ovi Store

I upgraded Snake game for Maemo. Major change are related to new graphics and usage of touch interface to direct snake.

Now Maemo version no longer support Accelerometer, but instead it uses touch interaction to direct snake. Though keyborad support is still there.

Game is available on Ovi Store here.




New version is similar to Symbian version. Please visit this blog post for more information regarding game.

Visit this link for more information regarding snake game for maemo.

Un-boxing Nokia N9 Dev Kit (Nokia N950)


As being Qt Ambassador, Yesterday I received Nokia N9 Dev Kit in a cute little box. Box itself was quite interesting indicating new user interaction concept - swipe interaction and purpose of dev kit - Go Create application.



Opening the box revealed the mighty N950.





Though, its development device it has great polished Hardware with equally polished OS. As using N900 for so long,  It took little time to get comfortable to new swipe interaction. But After getting used to it, I realized it quite easy to navigate around using swipe.

After swiping through some of application and getting feel of device. I launched the terminal. Terminal software also come with new angle. Allow you to change color schema with swipe and zoom fonts with pinch gesture.





And as its development device, it also comes with SDK software for all major development platform. Now I am thinking which of my Application I should port first for new Nokia N9.


Thursday, July 28, 2011

Audiobook reader New Features, Chapter selection and custom Bookmark support added

Today my next version of Audiobook reader application got published on Ovi Store. This version include some new feature with some other impoverishment.

New feature are as below,

  • Chapter Selection, If Audiobook has multiple audio file for individual chapter then now you can select and play individual chapter.
  • Custom Bookmark support, In case Audiobook is one large audio file and you found some interesting chapter then you can add bookmark, Bookmark will save play position. Latter if you wish to hear that chapter, you can go to bookmark screen and play that bookmark.
Both bookmark and chapter selection feature are available from main Booklist screen. In following snap, by pressing icon next to play icon will lead you to bookmark/ chapter screen.


Following is Chapter/Bookmark Screen. By pressing Icon next to back icon, will show chapter or bookmark screen.

In following snaps is showing chapter screen. On this screen if you press book icon, it will switch screen to bookmark screen.


Following snap is showing Bookmark screen, by pressing list icon you can switch back to Chapter Screen.


You can add custom bookmark from player screen, by pressing + icon and then entering bookmark name on Add Bookmark dialog.



Hope you will like this new feature, If you have any comment please feel free to add comment.

Saturday, July 23, 2011

Simple download manager with pause support implementation

In one of my previous post, I described how a simple download manage with pause/ resume feature can be implemented. Here is post.

After that post I got few request for further explanation or working code sample. So in this post I will describe implementation in more details and provide full working code sample.

I lost older working code because of my laptop crash, so created another sample application for this post, so code might differ a little bit from my older post, but idea is same.

So here code the code.

Following is download function where download request is placed by client.
void DownloadManager::download( QUrl url )
{
    mDownloadSizeAtPause =0;
    mCurrentRequest = QNetworkRequest(url);
    mFile = new QFile("download.part");
    mFile->open(QIODevice::ReadWrite);

    download(mCurrentRequest);
}

Following function put download request to QNetworkAccessManager and setup signal slot connection.
void DownloadManager::download( QNetworkRequest& request )
{
    mCurrentReply = mManager->get(request);

    connect(mCurrentReply,SIGNAL(finished()),this,SLOT(finished()));
    connect(mCurrentReply,SIGNAL(downloadProgress(qint64,qint64)),this,SLOT(downloadProgress(qint64,qint64)));
    connect(mCurrentReply,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(error(QNetworkReply::NetworkError)));
}

Now the interesting functions comes that enable pause/resume functionality to download manager. Following is pause function. If simply abort current request, disconnect the signal/slot so we don't get any error signal and mess with our error handling code and most importantly it write data to our IODevice here its file which is storing downloaded data.
void DownloadManager::pause()
{
    if( mCurrentReply == 0 ) {
        return;
    }
    disconnect(mCurrentReply,SIGNAL(finished()),this,SLOT(finished()));
    disconnect(mCurrentReply,SIGNAL(downloadProgress(qint64,qint64)),this,SLOT(downloadProgress(qint64,qint64)));
    disconnect(mCurrentReply,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(error(QNetworkReply::NetworkError)));

    mCurrentReply->abort();
    mFile->write( mCurrentReply->readAll());
    mCurrentReply = 0;
}

Now the resume function. So most important thing here is "Range" header. It tell the server that I want to start download from this much bytes and not from beginning, because we already received this much data when we paused the request.

void DownloadManager::resume()
{
    mDownloadSizeAtPause = mFile->size();
    QByteArray rangeHeaderValue = "bytes=" + QByteArray::number(mDownloadSizeAtPause) + "-";
    mCurrentRequest.setRawHeader("Range",rangeHeaderValue);

    download(mCurrentRequest);
}

Another important function, if you want to show correct progress. Remember to add mDownloadSizeAtPause (number of bytes already downloded when we pause the request ) to bytesReceived and bytesTotal, function to show correct progress.
void DownloadManager::downloadProgress ( qint64 bytesReceived, qint64 bytesTotal )
{
    mFile->write( mCurrentReply->readAll() );
    int percentage = ((mDownloadSizeAtPause+bytesReceived) * 100 )/ (mDownloadSizeAtPause+bytesTotal);
    emit progress(percentage);
}

here is link to full working sample project. Thank you for visiting my blog. Let me know if you need more details.

Sunday, July 17, 2011

Swipe to unlock animation effect using QML

Now its raining heavily here and that provided me some free time to play with my iPod. As I was using my iPod I got curious about how that "swipe to unlock" animation could have been implemented.

I decided to implement such animation my self with QML and following is output of my effort.



If you also curious about how it can be implemented, than solution is quite simple.
The code is similar to code for Marquee text animation. To give marquee text effect, I used to change position of text element only. Here I change position of both text and parent Item element.

Here is full code. In code I created one static text in gray color which is fully visible and another text with white color which is partially visible only ans used for scrolling animation. I put this animating text inside Item element.

Now on timer event, I am increasing x position of Item element with some delta , at same time I am also reducing same delta from text x position. This will give effect as color or gray static text is changing.

import QtQuick 1.0

Item {
    id:marqueeText
    height: staticText.height
    clip: true    
    property int tempX: 0
    property alias text: staticText.text
    Text {
        x:0;y:0        
        id:staticText
        width: marqueeText.width
        color: "darkgray"
    }

    Item {
        width: 40
        height: marqueeText.height
        x: tempX
        clip: true
        Text {
            id:scrollingText
            text: marqueeText.text
            color: "white"
        }
    }

    Timer {
        id:timer
        interval: 200; running: true; repeat: true
        onTriggered:{            
            tempX = tempX + 10
            scrollingText.x = -tempX;

            if( tempX > staticText.width ) {
                tempX=-40
            }
        }
    }
}
Here is how above code can be used.
Rectangle {
        border.width: 2
        border.color: "black"
        color:"gray"
        anchors.horizontalCenter: parent.horizontalCenter
        width: 200
        height: text.height + 10
        y:100
        ScrollText {
            id:text
            width: 150
            anchors.verticalCenter: parent.verticalCenter
            anchors.horizontalCenter: parent.horizontalCenter
            text: "Swipe to unlock the phone"
        }
    }

That's all. Hope you enjoyed it.

Saturday, July 16, 2011

My new 3D Plasma HD TV (Samsung PN43D490A1D-S)

Recently I purchased Samsung 43 inch 3d Plasma tv (PN43D490A1D-S). Its entry level model thus I got only one 3d shutter glass model(SSG-3500CR).

I have tried 2-3 shutter glasses from Samsung and I feel that glasses which I got with TV put less strain on eyes and don't feel flicker of LCD of shutter glasses with this model.


As soon as I got it, I tried to play some HD content on it and result looks great from 4-5 feet distance.

It got one USB port and 3 HDMI port. We can plug USB drive and play video from it. You need to select USB drive as input source and then it will show file manager and there you can browse for content. It has inbuilt movie player. Which play movie from USB drive. I tried to use this inbuilt media player and found it quite nice and useful. It recognize many video format include mp4  and divx. I also tried some mkv file which has dual audio support. It can play that source as well and allow to change language.

Now that I tried 2D content,  I wanted to try some 3d content.

To watch 3d content,I connected my laptop via HDMI cable and made my tv primary monitor then played some 3d content from youtube.

It took me quite some time to figure out that, that to watch 3d content from 3d tv. I need to play video that is in half side by side (half sbs) format other kind of video want give 3d effect with 3d tv with shutter technology.

After starting half sbs movie, you need change to 3D mode from 2D and select side by side format. Now put on glasses and can enjoy 3D content.





After playing 3D content from my laptop, I downloaded some sample half SBS 3D content and tied to play it with its inbuilt media player. I feel that content looks great on inbuilt player than from PC.

Thats all now I am going to watch some moive on my new Tv. Thanks for reading.

Tuesday, July 5, 2011

How to display QWidget into QML

Recently in one of my project I required to embed QWidget derived class to QML scene. While its straight forward to embed QML scene to QWidget or QGraphicsScene.

It required small effort to embed QWidget derived class to QML scene. Still its not great effort and its also vary straigt forward.

All you need to do is, create new class derived from QDeclarativeItem. Create instance of required widget and add that widget to QGraphicsProxyWidget. Now we need to register this newly created class to QML using qmlRegisterType. Now we can use this class from QML which display our QWidget derived class.

Following is code that demonstrate the same. For demo I have created class which embed QLabel to QML scene.

Following code is my custom QDeclarativeItem derive class which will expose QLabel to QML scene.
#include <QDeclarativeItem>

class QLabel;

class QmlLabel : public QDeclarativeItem
{
    Q_OBJECT    
    Q_PROPERTY(QString text READ text WRITE setText)
public:
    explicit QmlLabel(QDeclarativeItem *parent = 0);
    ~QmlLabel();    

public slots:

    void setText(const QString& text);

    QString text() const;

private:

    QLabel* mLabel;
    QGraphicsProxyWidget* mProxy;

};

#include <QLabel>
#include <QGraphicsProxyWidget>

QmlLabel::QmlLabel(QDeclarativeItem *parent) :
    QDeclarativeItem(parent)
{
    mLabel = new QLabel(QString(""));
    mProxy = new QGraphicsProxyWidget(this);
    mProxy->setWidget(mLabel);
}

QmlLabel::~QmlLabel()
{
    delete mLabel;
}

void QmlLabel::setText(const QString& text)
{
    mLabel->setText(text);
}

QString QmlLabel::text() const
{
    return mLabel->text();
}

Following code demonstrate how to register above class to QML. In qmlRegisterType first argument is component uri, which is used for importing component to QML. second and third argument is version information and fourth argument is element name in QML, By using this name we can created QML element.

#include <QtDeclarative>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    qmlRegisterType<QmlLabel>("qmlLabel", 1, 0, "QmlLabel");
    QDeclarativeView viewer;
    viewer.setSource(QUrl("qml/hybrid/main.qml"));
    viewer.show();
    return app.exec();
}

Finally following is QML code. To be able to use our custom QML element we need to import component to QML using import statement.
import QtQuick 1.0
import qmlLabel 1.0

Rectangle {
    width: 360
    height: 360
    QmlLabel {         
        x:100; y:100
        text: "QML Label"
    }
}

Following is out put from above code.

Friday, June 24, 2011

Marquee text element with Qt Quick (QML)

Currently I am adding new feature to one of my QML application. While doing so I created marquee text element for QML.

I had created such component for Symbian long time ago when I was working on Avkon. Using similar logic I created similar component for QML as well.

I needed this component because while displaying one line text item in QML, sometime text is much larger than display area.

Following is code which I created my purpose, I tried to make it as much reusable as I can without putting much effort. Hope this will be to helpful to someone.

In following code whenever someone touch text element, it start scrolling its content. To scroll I am using text's actual width and display width. On timer event I am increasing x position of text so new text can be displayed. But I am subtracting same x delta from text's x location so text element remain on same position. And as I have enabled clipping on item element text which is outside of visible area will not be displayed.

import QtQuick 1.0

Item {
    id:marqueeText
    height: scrollingText.height
    clip: true    
    property int tempX: 0
    property alias text: scrollingText.text
    Text {        
        x: tempX
        id:scrollingText        
    }

    MouseArea {
        id:mouseArea
        anchors.fill: parent
        onClicked: {                            
            tempX = 0;
            timer.running = true;            
        }
    }

    Timer {
        id:timer
        interval: 200; running: false; repeat: true
        onTriggered:{            
            tempX = tempX + 5
            scrollingText.x = -tempX;

            if( tempX + marqueeText.width > scrollingText.width ) {
                timer.running = false
                pauseTimer.running = true
            }
        }
    }

    Timer {
        id:pauseTimer
        interval: 500; running: false; repeat: false
        onTriggered: {
            scrollingText.x = 0
        }
    }
}

Following is code, how above code can be used.
Rectangle {
        border.width: 2
        border.color: "black"
        color: "lightsteelblue"
        anchors.horizontalCenter: parent.horizontalCenter
        width: 250
        height: text.height + 10
        y:100
        MarqueeText {
            id:text
            width: 200
            anchors.verticalCenter: parent.verticalCenter
            anchors.horizontalCenter: parent.horizontalCenter
            text: "start ------ abcdefghijklmnopqrtaksdjfkdfjklsdjflksdjfklsjadfkljsad;flasjdlfjasdfjldsdfljf---- end"
        }
    }

Following output from above code.

Saturday, June 18, 2011

Trying out iPhone SDK Mapkit framework

Currenly I am working on my small pet project for my iPod. I want my iPod to communicate with my Nokia device to get current location and display it.

I have not make much progress yet,  now days I don't have much free time. But I was easily able to display hard coded location on my application.

To display map and location you can use iPhone SDK's Mapkit framework. But before using it you must add framework to your project.  To add framework right click on framework-> add -> existing frameworks and then choose Mapkit framework.




Now I added instance of MKMapView to my view controller like below.

#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>

@interface MapkitDemoViewController : UIViewController {
 IBOutlet MKMapView* mapView;
}

@property(retain,nonatomic) MKMapView* mapView;

@end

And initialized it in viewDidLoad function like below. I am using CLLocationCoordinate2D structure to set required cordinate and MKCoordinateSpan to specify required zoom level.  Then creating MKCoordinateRegion from above info and setting that to mapView.

We can also add our custom place marker using MKPointAnnotation, its concrete implementation for MKAnnotation protocol. Creating instance of MKPointAnnotation and setting it to mapView is quite strait forward.

- (void)viewDidLoad {
[super viewDidLoad];
 
 mapView = [[MKMapView alloc] initWithFrame:self.view.bounds];
 mapView.mapType = MKMapTypeHybrid;
 
 CLLocationCoordinate2D coord = {latitude: 37.247414,longitude: 127.058278};
 MKCoordinateSpan span = {latitudeDelta: 0.001, longitudeDelta:0.001};
 MKCoordinateRegion region = {coord, span};
 
 [mapView setRegion:region];
 
 MKPointAnnotation *anno = [[MKPointAnnotation alloc] init];
 [anno setCoordinate:coord];
 [anno setTitle:@"Test"];
 [anno setSubtitle:@"Test annotation"];
 [mapView addAnnotation:anno];
  
 [self.view addSubview:mapView];
}

In case you need convert latitude and longitude between decimal degrees and degrees, minutes, and seconds. Here is link which I used.

And also If you face "Couldn't register com.yourcompany.Mapkit Demo with the bootstrap server" kind of error. I used to kill my simulator and relaunch application and it worked fine then after.

That's all for now, following is output from above code.


Wednesday, June 15, 2011

Using TextInput in Qt Quick (QML)

Recently I wanted to created a text input dialog box in QML. QML has nice support for editing large text and one line text. For editing large text we can use TextEdit QML element and for one line text we can use TextInput QML element.

But default appearance of TextInput might not suite look and feel of your application. It was not suited for my application as well. Following is my initial code.

TextInput {
        y:50
        anchors.horizontalCenter: parent.horizontalCenter
        id: text1
        font.pixelSize: 20; font.bold: true
        text: "Enter text here ..."
        focus: true
        width: container.width - 30 ; height: 40
    }

And following is output from above code.


To change appearance, I put it inside Rectangle element and modified its border and other properties.

Here how it looks after my change.


Here is modified code. In following code container is parent Rectangle element.
    Rectangle{
        y: 100
        width: container.width - 30 ; height: 40
        anchors.horizontalCenter: parent.horizontalCenter
        border.width: 3
        border.color: "#4b4b4b"
        color: "lightsteelblue"
        radius: 5
        TextInput {
            anchors.verticalCenter: parent.verticalCenter
            anchors.horizontalCenter: parent.horizontalCenter
            id: text2
            font.pixelSize: 20; font.bold: true
            text: "Enter text here..."
            width: container.width - 40 ;
            color: "#4b4b4b"
            focus: true
        }

        MouseArea {
            anchors.fill: parent
            onClicked: {
                text2.selectAll();
            }
        }
    }

Hope it will help someone.