Merge branch 'master' into situare_interact
authorJussi Laitinen <jupe@l3l7588.ixonos.local>
Tue, 7 Sep 2010 07:21:50 +0000 (10:21 +0300)
committerJussi Laitinen <jupe@l3l7588.ixonos.local>
Tue, 7 Sep 2010 07:21:50 +0000 (10:21 +0300)
Conflicts:
images.qrc
res/images/contact_btn_d.png

18 files changed:
1  2 
images.qrc
src/engine/engine.cpp
src/situareservice/database.cpp
src/situareservice/database.h
src/situareservice/notification.cpp
src/situareservice/notification.h
src/situareservice/situareservice.cpp
src/situareservice/situareservice.h
src/ui/friendlistpanel.cpp
src/ui/friendlistpanel.h
src/ui/mainwindow.cpp
src/ui/mainwindow.h
src/ui/meetpeoplepanel.cpp
src/ui/meetpeoplepanel.h
src/ui/notificationlistitem.cpp
src/ui/notificationlistitem.h
src/ui/notificationpanel.cpp
src/ui/notificationpanel.h

diff --cc images.qrc
          <file>res/images/walk_icon_gray.png</file>
          <file>res/images/zoom_in.png</file>
          <file>res/images/zoom_out.png</file>
 +        <file>res/images/meet_people.png</file>
-         <file>res/images/contact_btn_d.png</file>
-         <file>res/images/contact_btn.png</file>
-         <file>res/images/contact_btn_s.png</file>
 +        <file>res/images/chat.png</file>
-         <file>res/images/location_search.png</file>
-         <file>res/images/list_item_context_button_bar_left.png</file>
-         <file>res/images/list_item_context_button_bar_right.png</file>
-         <file>res/images/list_item_context_button_bar_tile.png</file>
 +        <file>res/images/search_history.png</file>
-         <file>res/images/clear_btn_d.png</file>
-         <file>res/images/clear_btn_s.png</file>
-         <file>res/images/clear_btn.png</file>
 +        <file>res/images/tag_btn.png</file>
 +        <file>res/images/tag_btn_d.png</file>
 +        <file>res/images/tag_btn_s.png</file>
 +        <file>res/images/tag.png</file>
 +        <file>res/images/notification.png</file>
 +        <file>res/images/chat_btn.png</file>
 +        <file>res/images/chat_btn_d.png</file>
 +        <file>res/images/chat_btn_s.png</file>
 +        <file>res/images/empty_avatar.png</file>
 +        <file>res/images/empty_avatar_big.png</file>
      </qresource>
  </RCC>
@@@ -741,13 -723,9 +741,13 @@@ void SituareEngine::signalsFromMainWind
      connect(m_ui, SIGNAL(searchForLocation(QString)),
              this, SLOT(locationSearch(QString)));
  
 -    // signal from friend list panel
 -    connect(m_ui, SIGNAL(requestContactDialog(const QString &)),
 -            this, SLOT(showContactDialog(const QString &)));
 +    // signals from meet people panel
 +    connect(m_ui, SIGNAL(requestInterestingPeople()),
 +            this, SLOT(requestInterestingPeople()));
 +
-     // signal from friend list panel
-     connect(m_ui, SIGNAL(requestContactDialog(const QString &)),
-             this, SLOT(showContactDialog(const QString &)));
++    // signals from notifications panel
++    connect(m_ui, SIGNAL(requestNotifications()),
++            m_situareService, SLOT(fetchNotifications()));
  }
  
  void SituareEngine::signalsFromMapEngine()
@@@ -820,12 -798,6 +820,12 @@@ void SituareEngine::signalsFromSituareS
  
      connect(m_situareService, SIGNAL(updateWasSuccessful()),
              m_ui, SIGNAL(clearUpdateLocationDialogData()));
 +
 +    connect(m_situareService, SIGNAL(interestingPeopleReceived(QList<User>&)),
 +            m_ui, SIGNAL(interestingPeopleReceived(QList<User>&)));
 +
-     connect(m_situareService, SIGNAL(notificationsReceived(QList<Notification*>&)),
-             m_ui, SIGNAL(notificationsReceived(QList<Notification*>&)));
++    connect(m_situareService, SIGNAL(notificationsReceived(QList<Notification>&)),
++            m_ui, SIGNAL(notificationsReceived(QList<Notification>&)));
  }
  
  void SituareEngine::startAutomaticUpdate()
index 89c9f39,0000000..5fdd83f
mode 100644,000000..100644
--- /dev/null
@@@ -1,225 -1,0 +1,235 @@@
 +#include <QDebug>
 +#include <QDir>
 +#include <QSqlQuery>
 +#include <QVariant>
 +
 +#include "database.h"
 +
 +Database::Database(QObject *parent) :
 +    QObject(parent)
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +}
 +
 +Database::~Database()
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +}
 +
 +bool Database::addTag(qulonglong userId, const QString &tag)
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +
 +    bool ret = false;
 +    qulonglong tagId = 0;
 +
 +    if (m_database.isOpen()) {
 +        QSqlQuery tagQuery;
 +        ret = tagQuery.exec(QString("SELECT id FROM tag WHERE name = '%1'")
 +                         .arg(tag));
 +
 +        //Tag already exists
 +        if (ret && tagQuery.next()) {
 +            tagId = tagQuery.value(0).toULongLong();
 +        }
 +        else {
 +            QSqlQuery tagInsertQuery;
 +            ret = tagInsertQuery.exec(QString("INSERT INTO tag VALUES(NULL, '%1')")
 +                             .arg(tag));
 +
 +            if (ret) {
 +                tagId = tagInsertQuery.lastInsertId().toULongLong();
 +            }
 +        }
 +
 +        if (ret && (tagId != 0)) {
 +            QSqlQuery userTagQuery;
 +
 +            ret = userTagQuery.exec(QString("INSERT INTO usertag VALUES('%1', '%2')")
 +                                    .arg(userId).arg(tagId));
 +        }
 +    }
 +
 +    return ret;
 +}
 +
 +bool Database::createNotificationTable()
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +
 +    bool created = false;
 +
 +    if (m_database.isOpen()) {
 +
 +        QSqlQuery query;
 +        created = query.exec("CREATE TABLE IF NOT EXISTS notification ("
 +                             "id INTEGER PRIMARY KEY,"
 +                             "senderid INTEGER,"
 +                             "receiverid INTEGER,"
 +                             "type VARCHAR(10),"
 +                             "timestamp VARCHAR(20),"
 +                             "text TEXT,"
 +                             "FOREIGN KEY(senderid) REFERENCES user(id),"
 +                             "FOREIGN KEY(receiverid) REFERENCES user(id)"
 +                             ")");
 +    }
 +
 +    return created;
 +}
 +
 +bool Database::createTagTable()
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +
 +    bool created = false;
 +
 +    if (m_database.isOpen()) {
 +
 +        QSqlQuery query;
 +        created = query.exec("CREATE TABLE IF NOT EXISTS tag ("
 +                             "id INTEGER PRIMARY KEY,"
 +                             "name VARCHAR(30) UNIQUE"
 +                             ")");
 +    }
 +
 +    return created;
 +}
 +
 +bool Database::createUserTable()
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +
 +    bool created = false;
 +
 +    if (m_database.isOpen()) {
 +
 +        QSqlQuery query;
 +        created = query.exec("CREATE TABLE IF NOT EXISTS user ("
 +                             "id INTEGER PRIMARY KEY,"
 +                             "name VARCHAR(50),"
 +                             "latitude REAL,"
 +                             "longitude REAL,"
 +                             "image_url TEXT"
 +                             ")");
 +    }
 +
 +    return created;
 +}
 +
 +bool Database::createUserTagTable()
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +
 +    bool created = false;
 +
 +    if (m_database.isOpen()) {
 +
 +        QSqlQuery query;
 +        created = query.exec("CREATE TABLE IF NOT EXISTS usertag ("
 +                             "userid INTEGER,"
 +                             "tagid INTEGER,"
 +                             "PRIMARY KEY(userid, tagid),"
 +                             "FOREIGN KEY(userid) REFERENCES user(id),"
 +                             "FOREIGN KEY(tagid) REFERENCES tag(id)"
 +                             ")");
 +    }
 +
 +    return created;
 +}
 +
 +QByteArray Database::getInterestingPeople(qulonglong userId,
 +                                           const GeoCoordinate &southWestCoordinates,
 +                                           const GeoCoordinate &northEastCoordinates)
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +
 +    QSqlQuery query(QString("SELECT user.id, user.name, user.image_url FROM user WHERE "
 +                            "user.latitude >= '%1' AND user.latitude <= '%2' AND "
 +                            "user.longitude >= '%3' AND user.longitude <= '%4' AND user.id IN "
 +                            "(SELECT DISTINCT usertag.userid FROM usertag WHERE usertag.tagid IN "
 +                            "(SELECT usertag.tagid FROM usertag WHERE usertag.userid = '%5') AND "
 +                            "usertag.userid != '%6')")
 +                    .arg(southWestCoordinates.latitude()).arg(northEastCoordinates.latitude())
 +                    .arg(southWestCoordinates.longitude()).arg(northEastCoordinates.longitude())
 +                    .arg(userId).arg(userId));
 +
 +    QString result;
 +    result.append("{\"people\": [");
 +
 +    while (query.next()) {
 +        result.append("{");
 +        result.append("\"uid\": \"" + query.value(0).toString() + "\",");
 +        result.append("\"name\": \"" + query.value(1).toString() + "\",");
 +        result.append("\"image_url\": \"" + query.value(2).toString() + "\"");
 +        result.append("},");
 +    }
 +
 +    int lastComma = result.lastIndexOf(",");
 +    if (lastComma != -1)
 +        result.remove(result.lastIndexOf(","), 1);
 +
 +    result.append("]}");
 +
 +    return result.toUtf8();
 +}
 +
- QList<Notification*> &Database::getNotifications(qulonglong userId)
++QByteArray Database::getNotifications(qulonglong userId)
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +
-     m_notifications.clear();
++    QSqlQuery query(QString("SELECT notification.id, notification.senderid, user.name, "
++                            "user.image_url, notification.timestamp, notification.text "
++                            "FROM notification, user WHERE notification.receiverid = '%1' "
++                            "AND notification.senderid = user.id").arg(userId));
 +
-     QSqlQuery query(QString("SELECT message.id, message.senderid, user.name, message.text FROM "
-                             "message, user WHERE message.receiverid = '%1' AND "
-                             "message.senderid = user.id").arg(userId));
++    QString result;
++    result.append("{\"notifications\": [");
 +
 +    while (query.next()) {
-         Notification *notification = new Notification();
-         notification->setId(query.value(0).toString());
-         notification->setSenderId(query.value(1).toString());
-         notification->setTitle(query.value(2).toString());
-         notification->setText(query.value(3).toString());
-         m_notifications.append(notification);
++        result.append("{");
++        result.append("\"id\": \"" + query.value(0).toString() + "\",");
++        result.append("\"sender_id\": \"" + query.value(1).toString() + "\",");
++        result.append("\"sender_name\": \"" + query.value(2).toString() + "\",");
++        result.append("\"image_url\": \"" + query.value(3).toString() + "\",");
++        result.append("\"timestamp\": \"" + query.value(4).toString() + "\",");
++        result.append("\"text\": \"" + query.value(5).toString() + "\"");
++        result.append("},");
 +    }
 +
-     return m_notifications;
++    int lastComma = result.lastIndexOf(",");
++    if (lastComma != -1)
++        result.remove(result.lastIndexOf(","), 1);
++
++    result.append("]}");
++    qWarning() << result;
++    return result.toUtf8();
 +}
 +
 +QStringList Database::getTags(qulonglong userId)
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +
 +    QStringList tags;
 +
 +    QSqlQuery query(QString("SELECT tag.name FROM usertag, tag WHERE usertag.userid = '%1' "
 +                            "AND usertag.tagid = tag.id").arg(userId));
 +
 +    while (query.next())
 +        tags.append(query.value(0).toString());
 +
 +    return tags;
 +}
 +
 +bool Database::openDatabase()
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +
 +    m_database = QSqlDatabase::addDatabase("QSQLITE");
 +
 +    QString path(QDir::home().path());
 +    path.append(QDir::separator()).append("my.db.sqlite");
 +    path = QDir::toNativeSeparators(path);
 +    m_database.setDatabaseName(path);
 +
 +    return m_database.open();
 +}
index c13d868,0000000..8fce722
mode 100644,000000..100644
--- /dev/null
@@@ -1,40 -1,0 +1,40 @@@
 +#ifndef DATABASE_H
 +#define DATABASE_H
 +
 +#include <QObject>
 +
 +#include <QSqlDatabase>
 +#include <QSqlError>
 +#include <QFile>
 +#include <QStringList>
 +
 +#include "coordinates/geocoordinate.h"
 +#include "notification.h"
 +
 +class Database : public QObject
 +{
 +    Q_OBJECT
 +public:
 +    Database(QObject *parent = 0);
 +    ~Database();
 +
 +    bool addTag(qulonglong userId, const QString &tag);
-     QList<Notification*> &getNotifications(qulonglong userId);
++    QByteArray getNotifications(qulonglong userId);
 +    QStringList getTags(qulonglong userId);
 +    QByteArray getInterestingPeople(qulonglong userId,
 +                                     const GeoCoordinate &southWestCoordinates,
 +                                     const GeoCoordinate &northEastCoordinates);
 +
 +    bool createNotificationTable();
 +    bool createTagTable();
 +    bool createUserTagTable();
 +    bool createUserTable();
 +    bool openDatabase();
 +    bool sendMessage(qulonglong senderId, qulonglong receiverId, const QString &message);
 +
 +private:
 +    QSqlDatabase m_database;
 +    QList<Notification*> m_notifications;
 +};
 +
 +#endif // DATABASE_H
index 696faed,0000000..0169342
mode 100644,000000..100644
--- /dev/null
@@@ -1,94 -1,0 +1,122 @@@
 +#include <QDebug>
 +
 +#include "notification.h"
 +
 +Notification::Notification()
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +}
 +
 +const QString &Notification::id() const
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +
 +    return m_id;
 +}
 +
 +const QPixmap &Notification::image() const
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +
 +    return m_image;
 +}
 +
 +const QString &Notification::senderId() const
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +
 +    return m_senderId;
 +}
 +
++const QString &Notification::senderName() const
++{
++    qDebug() << __PRETTY_FUNCTION__;
++
++    return m_senderName;
++}
++
++
 +void Notification::setImage(const QPixmap &image)
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +
 +    m_image = image;
 +}
 +
 +void Notification::setId(const QString &id)
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +
 +    m_id = id;
 +}
 +
 +void Notification::setSenderId(const QString &senderId)
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +
 +    m_senderId = senderId;
 +}
 +
++void Notification::setSenderName(const QString &senderName)
++{
++    qDebug() << __PRETTY_FUNCTION__;
++
++    m_senderName = senderName;
++}
++
 +void Notification::setText(const QString &text)
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +
 +    m_text = text;
 +}
 +
++void Notification::setTimestamp(const QDateTime &timestamp)
++{
++    qDebug() << __PRETTY_FUNCTION__;
++
++    m_timestamp = timestamp;
++}
 +
 +void Notification::setTitle(const QString &title)
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +
 +    m_title = title;
 +}
 +
 +//void Notification::setType(const NotificationType type)
 +//{
 +//    qDebug() << __PRETTY_FUNCTION__;
 +
 +//    m_type = type;
 +//}
 +
 +
 +const QString &Notification::text() const
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +
 +    return m_text;
 +}
 +
++const QDateTime &Notification::timestamp() const
++{
++    qDebug() << __PRETTY_FUNCTION__;
++
++    return m_timestamp;
++}
++
 +const QString &Notification::title() const
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +
 +    return m_title;
 +}
 +
 +//const NotificationType Notification::type() const
 +//{
 +//    qDebug() << __PRETTY_FUNCTION__;
 +
 +//    return m_type;
 +//}
index 8efd29e,0000000..d58b299
mode 100644,000000..100644
--- /dev/null
@@@ -1,130 -1,0 +1,159 @@@
 +#ifndef MESSAGE_H
 +#define MESSAGE_H
 +
 +#include <QDateTime>
 +#include <QPixmap>
 +#include <QString>
 +
 +/**
 + * @brief Container for a single notification.
 + *
 + * @author Jussi Laitinen - jussi.laitinen@ixonos.com
 + */
 +class Notification
 +{
 +
 +public:
 +
 +    enum NotificationType {Message};
 +
 +    /**
 +    * @brief Constructor
 +    *
 +    * Constructs empty Notication object.
 +    */
 +    Notification();
 +
 +/*******************************************************************************
 + * MEMBER FUNCTIONS AND SLOTS
 + ******************************************************************************/
 + public:
 +    /**
 +    * @brief Returns notification's ID
 +    *
 +    * @return notification's ID
 +    */
 +    const QString &id() const;
 +
 +    /**
 +    * @brief Returns notification's image
 +    *
 +    * @return notification's image
 +    */
 +    const QPixmap &image() const;
 +
 +    /**
 +    * @brief Returns notification sender's ID
 +    *
 +    * @return notification sender's ID
 +    */
 +    const QString &senderId() const;
 +
 +    /**
++    * @brief Returns notification sender's name
++    *
++    * @return notification sender's name
++    */
++    const QString &senderName() const;
++
++    /**
 +    * @brief Sets notification's image
 +    *
 +    * @param image notification's image
 +    */
 +    void setImage(const QPixmap &image);
 +
 +    /**
 +    * @brief Sets notification's ID
 +    *
 +    * @param id notification's ID
 +    */
 +    void setId(const QString &id);
 +
 +    /**
 +    * @brief Sets notification's text
 +    *
 +    * @param text notification's text
 +    */
 +    void setText(const QString &text);
 +
 +    /**
++    * @brief Sets notification's timestamp
++    *
++    * @param image notification's timestamp
++    */
++    void setTimestamp(const QDateTime &timestamp);
++
++    /**
 +    * @brief Sets notification's title
 +    *
 +    * @param title notification's title
 +    */
 +    void setTitle(const QString &title);
 +
 +    /**
 +    * @brief Sets notification sender's ID
 +    *
 +    * @param id notification sender's ID
 +    */
 +    void setSenderId(const QString &senderId);
 +
++    /**
++    * @brief Sets notification sender's name
++    *
++    * @param id notification sender's name
++    */
++    void setSenderName(const QString &senderName);
++
 +//    /**
 +//    * @brief Sets notification's type
 +//    *
 +//    * @param type notification's type
 +//    */
 +//    void setType(const NotificationType type);
 +
 +    /**
 +    * @brief Returns notification's text
 +    *
 +    * @return notification's text
 +    */
 +    const QString &text() const;
 +
 +    /**
++    * @brief Returns notification's timestamp
++    *
++    * @return notification's timestamp
++    */
++    const QDateTime &timestamp() const;
++
++    /**
 +    * @brief Returns notification's title
 +    *
 +    * @return notification's title
 +    */
 +    const QString &title() const;
 +
 +//    /**
 +//    * @brief Returns notification's type
 +//    *
 +//    * @return notification's type
 +//    */
 +//    NotificationType type() const;
 +
 +
 +/*******************************************************************************
 + * DATA MEMBERS
 + ******************************************************************************/
 +private:
-     QDateTime m_creationDateTime;   ///< Notification's date time
++    QDateTime m_timestamp;          ///< Notification's timestamp
 +    QPixmap m_image;                ///< Notification's image
 +    QString m_id;                   ///< Notification's ID
 +    QString m_senderId;             ///< Notification sender's ID
++    QString m_senderName;           ///< Notification sender's name
 +    QString m_text;                 ///< Notification's text
 +    QString m_title;                ///< Notification's title
 +
 +    NotificationType m_type;        ///< Notification's type
 +};
 +
 +#endif // MESSAGE_H
@@@ -75,38 -67,6 +75,42 @@@ SituareService::~SituareService(
      m_friendsList.clear();
  }
  
 +void SituareService::fetchNotifications()
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +
-     QList<Notification*> notifications = m_database->getNotifications(m_user->userId().toULongLong());
++//    QList<Notification*> notifications = m_database->getNotifications(m_user->userId().toULongLong());
 +
-     foreach (Notification *notification, notifications) {
-         notification->setImage(AvatarImage::create(QPixmap(":/res/images/empty_avatar.png"),
-                                                   AvatarImage::Small));
-     }
++//    foreach (Notification *notification, notifications) {
++//        notification->setImage(AvatarImage::create(QPixmap(":/res/images/empty_avatar.png"),
++//                                                  AvatarImage::Small));
++//    }
 +
-     foreach (User *user, m_friendsList) {
-         foreach (Notification *notification, notifications)
-             if (notification->senderId() == user->userId())
-                 notification->setImage(user->profileImage());
-     }
++//    foreach (User *user, m_friendsList) {
++//        foreach (Notification *notification, notifications)
++//            if (notification->senderId() == user->userId())
++//                notification->setImage(user->profileImage());
++//    }
++
++//    emit notificationsReceived(notifications);
++
++    QByteArray arr = m_database->getNotifications(m_user->userId().toULongLong());
 +
-     emit notificationsReceived(notifications);
++    parseNotificationsData(arr);
 +}
 +
 +void SituareService::fetchPeopleWithSimilarInterest(const GeoCoordinate &southWestCoordinates,
 +                                                    const GeoCoordinate &northEastCoordinates)
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +
 +    QByteArray arr = m_database->getInterestingPeople(m_user->userId().toULongLong(),
 +                                                      southWestCoordinates,
 +                                                      northEastCoordinates);
 +
 +    parseInterestingPeopleData(arr);
 +}
 +
  void SituareService::fetchLocations()
  {
      qDebug() << __PRETTY_FUNCTION__;
@@@ -328,55 -288,6 +332,69 @@@ void SituareService::credentialsReady(c
      m_credentials = credentials;
  }
  
 +void SituareService::parseInterestingPeopleData(const QByteArray &jsonReply)
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +
 +    QJson::Parser parser;
 +    bool ok;
 +
 +    QVariantMap result = parser.parse(jsonReply, &ok).toMap();
 +
 +    if (!ok) {
 +        emit error(ErrorContext::SITUARE, SituareError::INVALID_JSON);
 +        return;
 +    } else {
 +        QList<User> interestingPeople;
 +
 +        foreach (QVariant personVariant, result["people"].toList()) {
 +            User user;
 +            QMap<QString, QVariant> person = personVariant.toMap();
 +            user.setUserId(person["uid"].toString());
 +            user.setName(person["name"].toString());
 +            user.setProfileImageUrl(person["image_url"].toUrl());
 +
 +            interestingPeople.append(user);
 +
 +            emit fetchImage(user.userId(), user.profileImageUrl());
 +        }
 +
 +        emit interestingPeopleReceived(interestingPeople);
 +    }
 +}
 +
 +void SituareService::parseNotificationsData(const QByteArray &jsonReply)
 +{
-     qDebug() << __PRETTY_FUNCTION__;
 +    QJson::Parser parser;
 +    bool ok;
 +
-     QVariantMap result = parser.parse (jsonReply, &ok).toMap();
++    QVariantMap result = parser.parse(jsonReply, &ok).toMap();
 +
 +    if (!ok) {
 +        emit error(ErrorContext::SITUARE, SituareError::INVALID_JSON);
 +        return;
-     }
-     else {
++    } else {
++        QList<Notification> notifications;
++
++        foreach (QVariant notificationVariant, result["notifications"].toList()) {
++            Notification notification;
++            QMap<QString, QVariant> notificationMap = notificationVariant.toMap();
++            notification.setId(notificationMap["id"].toString());
++            notification.setSenderId(notificationMap["sender_id"].toString());
++            notification.setSenderName(notificationMap["sender_name"].toString());
++            uint timestampSeconds = notificationMap["timestamp"].toUInt();
++            notification.setTimestamp(QDateTime::fromTime_t(timestampSeconds));
++            notification.setText(notificationMap["text"].toString());
++
++            notifications.append(notification);
++
++            emit fetchImage(notification.senderId(), notificationMap["image_url"].toString());
++        }
 +
++        emit notificationsReceived(notifications);
 +    }
 +}
 +
  void SituareService::parseUserData(const QByteArray &jsonReply)
  {
      qDebug() << __PRETTY_FUNCTION__;
@@@ -102,16 -85,7 +97,20 @@@ public
      */
      void updateLocation(const GeoCoordinate &coordinates, const QString &status, const bool &publish);
  
 +    /**
 +    * @brief Updates tags to the Situare server
 +    *
 +    * CURRENTLY TAGS ARE UPDATED TO THE LOCAL DATABASE, NOT SITUARE SERVER
 +    * @param userId user ID
 +    * @param tags list of user's tags
 +    */
 +    void updateTags(const QString &userId, const QStringList &tags);
 +
  public slots:
++    /**
++    * @brief Retrieves notifications sent to user.
++    */
++    void fetchNotifications();
  
      /**
      * @brief Public slot, to clear user data
@@@ -257,28 -210,6 +256,28 @@@ signals
      void imageReady(User *user);
  
      /**
 +    * @brief Signals when image is downloaded
 +    *
 +    * @param id image ID
 +    * @param image image pixmap
 +    */
 +    void imageReady(const QString &id, const QPixmap &image);
 +
 +    /**
 +    * @brief Signal when fetchPeopleWithSimilarInterest request is finished
 +    *
 +    * @param interestingPeople list of interesting people
 +    */
 +    void interestingPeopleReceived(QList<User> &interestingPeople);
 +
 +    /**
 +    * @brief Signal when fetchNotifications request is finished
 +    *
 +    * @param notifications list of notifications sent to user
 +    */
-     void notificationsReceived(QList<Notification*> &notifications);
++    void notificationsReceived(QList<Notification> &notifications);
 +
 +    /**
      * @brief Signals when address data is retrieved
      *
      * @param address Street address
Simple merge
Simple merge
@@@ -335,38 -333,6 +335,44 @@@ void MainWindow::buildMapScale(
              m_mapScale, SLOT(updateMapResolution(qreal)));
  }
  
 +void MainWindow::buildMeetPeoplePanel()
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +
 +    m_meetPeoplePanel = new MeetPeoplePanel(this);
 +
 +    connect(this, SIGNAL(friendImageReady(QString,QPixmap)),
 +            m_meetPeoplePanel, SLOT(setImage(QString,QPixmap)));
 +
 +    connect(this, SIGNAL(interestingPeopleReceived(QList<User>&)),
 +            m_meetPeoplePanel, SLOT(populateInterestingPeopleListView(QList<User>&)));
 +
 +    connect(m_meetPeoplePanel, SIGNAL(requestInterestingPeople()),
 +            this, SIGNAL(requestInterestingPeople()));
 +
 +    connect(m_meetPeoplePanel, SIGNAL(requestInterestingPeopleSearch()),
 +            this, SLOT(startPeopleSearch()));
 +
 +    connect(m_meetPeoplePanel, SIGNAL(findPerson(GeoCoordinate)),
 +            this, SIGNAL(centerToCoordinates(GeoCoordinate)));
 +}
 +
 +void MainWindow::buildNotificationPanel()
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +
 +    m_notificationPanel = new NotificationPanel(this);
 +
-     connect(this, SIGNAL(notificationsReceived(QList<Notification*>&)),
-             m_notificationPanel, SLOT(populateNotificationListView(QList<Notification*>&)));
++    connect(this, SIGNAL(notificationsReceived(QList<Notification>&)),
++            m_notificationPanel, SLOT(populateNotificationListView(QList<Notification>&)));
++
++    connect(m_notificationPanel, SIGNAL(requestNotifications()),
++            this, SIGNAL(requestNotifications()));
++
++    connect(this, SIGNAL(friendImageReady(QString,QPixmap)),
++            m_notificationPanel, SLOT(setImage(QString,QPixmap)));
 +}
 +
  void MainWindow::buildOsmLicense()
  {
      qDebug() << __PRETTY_FUNCTION__;
@@@ -439,10 -399,7 +445,16 @@@ void MainWindow::buildPanels(
      connect(m_tabbedPanel, SIGNAL(currentChanged(int)),
              m_userInfoPanel, SIGNAL(collapse()));
  
++    connect(m_tabbedPanel, SIGNAL(panelClosed()),
++            m_meetPeoplePanel, SLOT(anyPanelClosed()));
++
++    connect(m_tabbedPanel, SIGNAL(panelClosed()),
++            m_notificationPanel, SLOT(anyPanelClosed()));
++
      // signals for showing and hiding list item context buttons
 +    connect(m_userInfoPanel, SIGNAL(listItemSelectionChanged(bool)),
 +            m_tabbedPanel, SIGNAL(listItemSelectionChanged(bool)));
 +
      connect(m_friendsListPanel, SIGNAL(listItemSelectionChanged(bool)),
              m_tabbedPanel, SIGNAL(listItemSelectionChanged(bool)));
  
@@@ -598,13 -566,6 +598,13 @@@ signals
      void newMapResolution(qreal scale);
  
      /**
 +    * @brief Signal when fetchNotifications request is finished
 +    *
 +    * @param notifications list of notifications sent to user
 +    */
-     void notificationsReceived(QList<Notification*> &notifications);
++    void notificationsReceived(QList<Notification> &notifications);
 +
 +    /**
       * @brief Signal for refreshing user data.
       *
       */
      void viewZoomFinished();
  
      /**
 +    * @brief Signal when fetchMessages request is finished
 +    *
 +    * @param messages list of messages sent to user
 +    */
 +    void messagesReceived(QList<Notification> &messages);
 +
 +    /**
 +    * @brief Requests interesting people from current map viewport.
 +    *
 +    * Interesting people is defined by people with same tags as user has.
 +    */
 +    void requestInterestingPeople();
 +
 +    /**
++    * @brief Requests notifications sent to the user.
++    */
++    void requestNotifications();
++
++    /**
       * @brief Signal for use location ready.
       *
       * @param user User object
index bccb45d,0000000..f53ed7a
mode 100644,000000..100644
--- /dev/null
@@@ -1,81 -1,0 +1,97 @@@
 +#include <QDebug>
 +#include <QVBoxLayout>
 +
 +#include "headerlistitemdelegate.h"
 +#include "personlistitem.h"
 +#include "extendedlistitemdelegate.h"
 +#include "personlistview.h"
 +#include "imagebutton.h"
 +#include "panelcommon.h"
 +#include "user/user.h"
 +
 +#include "meetpeoplepanel.h"
 +
 +MeetPeoplePanel::MeetPeoplePanel(QWidget *parent)
 +    : PanelBase(parent)
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +
 +    QVBoxLayout *meetPeopleLayout = new QVBoxLayout;
 +    meetPeopleLayout->setMargin(0);
 +    meetPeopleLayout->setSpacing(0);
 +    setLayout(meetPeopleLayout);
 +
 +    m_personListView = new PersonListView(this);
 +    m_personListView->setItemDelegate(new ExtendedListItemDelegate(this));
 +    connect(m_personListView, SIGNAL(listItemSelectionChanged()),
 +            this, SLOT(onListItemSelectionChanged()));
 +    connect(m_personListView, SIGNAL(personItemClicked(GeoCoordinate)),
 +            this, SIGNAL(findPerson(GeoCoordinate)));
 +
 +    QVBoxLayout *listViewLayout = new QVBoxLayout;
 +    listViewLayout->setContentsMargins(PANEL_MARGIN_LEFT, PANEL_MARGIN_TOP,
 +                                       PANEL_MARGIN_RIGHT, PANEL_MARGIN_BOTTOM);
 +    listViewLayout->addWidget(m_personListView);
 +    meetPeopleLayout->addLayout(listViewLayout);
 +
 +    ImageButton *refreshInterestingPeopleButton = new ImageButton(":/res/images/refresh.png",
 +                                                                  ":/res/images/refresh_s.png",
 +                                                                  "", this);
 +    connect(refreshInterestingPeopleButton, SIGNAL(clicked()),
 +            this, SIGNAL(requestInterestingPeople()));
 +
 +    ImageButton *searchPeopleButton = new ImageButton(":/res/images/search.png",
 +                                                      ":/res/images/search_s.png", "", this);
 +    connect(searchPeopleButton, SIGNAL(clicked()),
 +            this, SIGNAL(requestInterestingPeopleSearch()));
 +
 +    ImageButton *messageButton = new ImageButton(":/res/images/chat_btn.png",
 +                                                 ":/res/images/chat_btn_s.png",
 +                                                 ":/res/images/chat_btn_d.png", this);
 +    connect(messageButton, SIGNAL(clicked()),
 +            this, SLOT(openMessageDialog()));
 +
 +    m_genericButtonsLayout->addWidget(refreshInterestingPeopleButton);
 +    m_genericButtonsLayout->addWidget(searchPeopleButton);
 +    m_itemButtonsLayout->addWidget(messageButton);
 +}
 +
++void MeetPeoplePanel::anyPanelClosed()
++{
++    qDebug() << __PRETTY_FUNCTION__;
++
++    m_personListView->clearItemSelection();
++}
++
++void MeetPeoplePanel::hideEvent(QHideEvent *event)
++{
++    qDebug() << __PRETTY_FUNCTION__;
++
++    QWidget::hideEvent(event);
++
++    m_personListView->clearItemSelection();
++}
++
 +void MeetPeoplePanel::setImage(const QString &id, const QPixmap &image)
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +
 +    PersonListItem *personItem = dynamic_cast<PersonListItem*>(m_personListView->listItem(id));
 +    if (personItem)
 +        personItem->setAvatarImage(image);
 +}
 +
 +void MeetPeoplePanel::populateInterestingPeopleListView(QList<User> &interestingPeople)
 +{
 +    qDebug() << __PRETTY_FUNCTION__ ;
 +
 +    m_personListView->clearList();
 +
 +    foreach (User interestingPerson, interestingPeople) {
 +        PersonListItem *item = new PersonListItem();
 +        item->setPersonData(interestingPerson);
 +        m_personListView->addListItem(interestingPerson.userId(), item);
 +    }
 +
 +    m_personListView->scrollToTop();
 +}
index 1d08ff1,0000000..42d16c7
mode 100644,000000..100644
--- /dev/null
@@@ -1,68 -1,0 +1,88 @@@
 +#ifndef MEETPEOPLEPANEL_H
 +#define MEETPEOPLEPANEL_H
 +
 +#include <QList>
 +
 +#include "panelbase.h"
 +
 +class QUrl;
 +
 +class GeoCoordinate;
 +class ImageButton;
 +class PersonListView;
 +class User;
 +
 +class MeetPeoplePanel : public PanelBase
 +{
 +    Q_OBJECT
 +
 +public:
 +    /**
 +     * @brief Default constructor
 +     *
 +     * @param parent
 +     */
 +    MeetPeoplePanel(QWidget *parent = 0);
 +
++/*******************************************************************************
++ * BASE CLASS INHERITED AND REIMPLEMENTED MEMBER FUNCTIONS
++ ******************************************************************************/
++protected:
++    /**
++    * @brief Re-implemented from QWidget::hideEvent()
++    *
++    * Calls clear item selection to list.
++    *
++    * @param event
++    */
++    void hideEvent(QHideEvent *event);
++
 +private slots:
 +    /**
++    * @brief Called when any of the panel tabs is closed
++    *
++    * Calls clear item selection to list.
++    */
++    void anyPanelClosed();
++
++    /**
 +    * @brief Sets person's image.
 +    *
 +    * @param id image ID
 +    * @param image image pixmap
 +    */
 +    void setImage(const QString &id, const QPixmap &image);
 +
 +    /**
 +    * @brief Populates interesting people list view.
 +    *
 +    * @param interestingPeople list of interesting people
 +    */
 +    void populateInterestingPeopleListView(QList<User> &interestingPeople);
 +
 +signals:
 +    /**
 +     * @brief Signal for person finding
 +     *
 +     * @param coordinates Target coordinate
 +     */
 +    void findPerson(const GeoCoordinate &coordinates);
 +
 +    /**
 +    * @brief Requests interesting people from current map viewport.
 +    *
 +    * Interesting people is defined by people with same tags as user has.
 +    */
 +    void requestInterestingPeople();
 +
 +    /**
 +    * @brief Requests interesting people search.
 +    */
 +    void requestInterestingPeopleSearch();
 +
 +private:
 +    PersonListView *m_personListView;   ///< Interesting people list view
 +    ImageButton *m_chatButton;          ///< Chat button
 +};
 +
 +#endif // MEETPEOPLEPANEL_H
index d7963a3,0000000..68538aa
mode 100644,000000..100644
--- /dev/null
@@@ -1,53 -1,0 +1,54 @@@
 +#include <QDebug>
 +
 +#include "listcommon.h"
 +#include "situareservice/notification.h"
 +
 +#include "notificationlistitem.h"
 +
 +NotificationListItem::NotificationListItem()
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +
 +    setSubitemTextWidth(SUBITEM_TEXT_MAX_WIDTH);
 +}
 +
 +NotificationListItem::~NotificationListItem()
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +}
 +
 +const QString &NotificationListItem::id() const
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +
 +    return m_id;
 +}
 +
 +void NotificationListItem::setImage(const QPixmap &image)
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +
 +    if(!image.isNull())
 +        setImage(image);
 +}
 +
- void NotificationListItem::setNotificationData(const Notification *notification)
++void NotificationListItem::setNotificationData(const Notification &notification)
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +
-     m_id = notification->id();
++    m_id = notification.id();
 +
-     setTitle(notification->title());
++    setTitle(notification.senderName());
 +
-     if (!notification->image().isNull())
-         setImage(notification->image());
++    if (!notification.image().isNull())
++        setImage(notification.image());
 +
 +    clearSubItems();
 +    QPixmap icon;
 +    //if (notification.type() == Notification::Message)
 +        icon.load(":/res/images/chat.png");
 +    //else
 +    //    icon.load(":/res/images/envelope.png");
-     addSubItem(notification->text(), icon);
++    addSubItem(notification.text(), icon);
++    addSubItem(notification.timestamp().toString(), QPixmap(":/res/images/clock.png"));
 +}
index 54d2f3f,0000000..51d5de8
mode 100644,000000..100644
--- /dev/null
@@@ -1,60 -1,0 +1,60 @@@
 +#ifndef MESSAGELISTITEM_H
 +#define MESSAGELISTITEM_H
 +
 +#include "extendedlistitem.h"
 +
 +class Notification;
 +
 +/**
 +* @brief Item stores notification data.
 +*
 +* @author Jussi Laitinen - jussi.laitinen (at) ixonos.com
 +*/
 +class NotificationListItem : public ExtendedListItem
 +{
 +public:
 +    /**
 +    * @brief Constructor.
 +    *
 +    * Sets sub items' text width.
 +    */
 +    NotificationListItem();
 +
 +    /**
 +    * @brief Destructor.
 +    */
 +    ~NotificationListItem();
 +
 +/******************************************************************************
 +* MEMBER FUNCTIONS AND SLOTS
 +******************************************************************************/
 +public:
 +    /**
 +    * @brief Returns notification's ID.
 +    *
 +    * @return notification's ID
 +    */
 +    const QString &id() const;
 +
 +    /**
 +    * @brief Sets image for this item.
 +    *
 +    * @param image image
 +    */
 +    void setImage(const QPixmap &image);
 +
 +    /**
-     * @brief Set message data for this item.
++    * @brief Set notification data for this item.
 +    *
-     * @param location Location data
++    * @param notification Notifiation data
 +    */
-     void setNotificationData(const Notification *notification);
++    void setNotificationData(const Notification &notification);
 +
 +/******************************************************************************
 +* DATA MEMBERS
 +******************************************************************************/
 +private:
 +    QString m_id;   ///< Notification's ID
 +};
 +
 +#endif // MESSAGELISTITEM_H
index 7ed8c3e,0000000..566709c
mode 100644,000000..100644
--- /dev/null
@@@ -1,70 -1,0 +1,104 @@@
 +/*
 +    Situare - A location system for Facebook
 +    Copyright (C) 2010  Ixonos Plc. Authors:
 +
 +        Jussi Laitinen - jussi.laitinen@ixonos.com
 +
 +    Situare is free software; you can redistribute it and/or
 +    modify it under the terms of the GNU General Public License
 +    version 2 as published by the Free Software Foundation.
 +
 +    Situare is distributed in the hope that it will be useful,
 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +    GNU General Public License for more details.
 +
 +    You should have received a copy of the GNU General Public License
 +    along with Situare; if not, write to the Free Software
 +    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
 +    USA.
 +*/
 +
 +#include <QDebug>
 +#include <QVBoxLayout>
 +
 +#include "extendedlistitemdelegate.h"
++#include "imagebutton.h"
 +#include "notificationlistitem.h"
 +#include "notificationlistview.h"
 +#include "panelcommon.h"
 +#include "situareservice/notification.h"
 +
 +#include "notificationpanel.h"
 +
 +NotificationPanel::NotificationPanel(QWidget *parent)
 +    : PanelBase(parent)
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
 +
 +    // --- MAIN LAYOUT ---
 +    QVBoxLayout *notificationLayout = new QVBoxLayout;
 +    notificationLayout->setMargin(0);
 +    notificationLayout->setSpacing(0);
 +    setLayout(notificationLayout);
 +
 +    QVBoxLayout *listViewLayout = new QVBoxLayout;
 +    listViewLayout->setContentsMargins(PANEL_MARGIN_LEFT, PANEL_MARGIN_TOP,
 +                                       PANEL_MARGIN_RIGHT, PANEL_MARGIN_BOTTOM);
 +    notificationLayout->addLayout(listViewLayout);
 +
++    ImageButton *refreshNotificationsButton = new ImageButton(":/res/images/refresh.png",
++                                                              ":/res/images/refresh_s.png",
++                                                              "", this);
++    connect(refreshNotificationsButton, SIGNAL(clicked()),
++            this, SIGNAL(requestNotifications()));
++
 +    m_notificationListView = new NotificationListView(this);
 +    m_notificationListView->setItemDelegate(new ExtendedListItemDelegate(this));
 +    listViewLayout->addWidget(m_notificationListView);
++
++    m_genericButtonsLayout->addWidget(refreshNotificationsButton);
++}
++
++void NotificationPanel::anyPanelClosed()
++{
++    qDebug() << __PRETTY_FUNCTION__;
++
++    m_notificationListView->clearItemSelection();
 +}
 +
 +void NotificationPanel::hideEvent(QHideEvent *event)
 +{
 +    qDebug() << __PRETTY_FUNCTION__;
++
++    QWidget::hideEvent(event);
++
++    m_notificationListView->clearItemSelection();
 +}
 +
- void NotificationPanel::populateNotificationListView(QList<Notification*> &notifications)
++void NotificationPanel::populateNotificationListView(QList<Notification> &notifications)
 +{
-     qWarning() << __PRETTY_FUNCTION__ << notifications.count();
++    qWarning() << __PRETTY_FUNCTION__;
 +
 +    m_notificationListView->clearList();
 +
-     foreach (Notification *notification, notifications) {
++    foreach (Notification notification, notifications) {
 +        NotificationListItem *item = new NotificationListItem();
 +        item->setNotificationData(notification);
-         m_notificationListView->addListItem(notification->id(), item);
++        m_notificationListView->addListItem(notification.id(), item);
++    }
++}
++
++void NotificationPanel::setImage(const QString &id, const QPixmap &image)
++{
++    qWarning() << __PRETTY_FUNCTION__ << id;
++
++    NotificationListItem *item = dynamic_cast<NotificationListItem*>(
++            m_notificationListView->listItem(id));
++
++    if (item) {
++        qWarning() << __PRETTY_FUNCTION__ << "item!";
++        item->setImage(image);
 +    }
 +}
++
index b8221b1,0000000..0d78766
mode 100644,000000..100644
--- /dev/null
@@@ -1,81 -1,0 +1,105 @@@
 +/*
 +    Situare - A location system for Facebook
 +    Copyright (C) 2010  Ixonos Plc. Authors:
 +
 +        Jussi Laitinen - jussi.laitinen@ixonos.com
 +
 +    Situare is free software; you can redistribute it and/or
 +    modify it under the terms of the GNU General Public License
 +    version 2 as published by the Free Software Foundation.
 +
 +    Situare is distributed in the hope that it will be useful,
 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +    GNU General Public License for more details.
 +
 +    You should have received a copy of the GNU General Public License
 +    along with Situare; if not, write to the Free Software
 +    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
 +    USA.
 +*/
 +
 +#ifndef NOTIFICATIONPANEL_H
 +#define NOTIFICATIONPANEL_H
 +
 +#include "panelbase.h"
 +
 +class ExtendedListItemDelegate;
 +class ImageButton;
 +class Notification;
 +class NotificationListView;
 +
 +/**
 + * @brief Notification panel
 + *
 + * @author Jussi Laitinen - jussi.laitinen (at) ixonos.com
 + * @author Sami Rämö - sami.ramo (at) ixonos.com
 + */
 +class NotificationPanel : public PanelBase
 +{
 +    Q_OBJECT
 +
 +public:
 +    /**
 +     * @brief Default constructor
 +     *
 +     * @param parent
 +     */
 +    NotificationPanel(QWidget *parent = 0);
 +
 +/*******************************************************************************
 + * BASE CLASS INHERITED AND REIMPLEMENTED MEMBER FUNCTIONS
 + ******************************************************************************/
 +protected:
 +    /**
 +    * @brief Re-implemented from QWidget::hideEvent()
 +    *
 +    * Calls clearListsSelections()
 +    *
 +    * @param event
 +    */
 +    void hideEvent(QHideEvent *event);
 +
 +/*******************************************************************************
 + * MEMBER FUNCTIONS AND SLOTS
 + ******************************************************************************/
 +private slots:
 +    /**
-     * @brief Populates location list view.
++    * @brief Called when any of the panel tabs is closed
 +    *
-     * @param locations list of Location objects
++    * Calls clear item selection to list.
 +    */
-     void populateNotificationListView(QList<Notification*> &notifications);
++    void anyPanelClosed();
++
++    /**
++    * @brief Populates nofification list view.
++    *
++    * @param locations list of Notification objects
++    */
++    void populateNotificationListView(QList<Notification> &notifications);
++
++    /**
++    * @brief Sets person's image.
++    *
++    * @param id image ID
++    * @param image image pixmap
++    */
++    void setImage(const QString &id, const QPixmap &image);
++
++/*******************************************************************************
++ * SIGNALS
++ ******************************************************************************/
++signals:
++    /**
++    * @brief Requests notifications sent to the user.
++    */
++    void requestNotifications();
 +
 +/*******************************************************************************
 + * DATA MEMBERS
 + ******************************************************************************/
 +private:
 +    NotificationListView *m_notificationListView;    ///< Notification list view
 +};
 +
 +#endif // NOTIFICATIONPANEL_H