MeeGo 1.2 Harmattan Developer Documentation Develop for the Nokia N9

flickrdemo.cpp Example File

flickrdemo/flickrdemo.cpp
 /****************************************************************************
 **
 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
 ** All rights reserved.
 ** Contact: Nokia Corporation (qt-info@nokia.com)
 **
 ** This file is part of the examples of the Qt Mobility Components.
 **
 ** $QT_BEGIN_LICENSE:BSD$
 ** You may use this file under the terms of the BSD license as follows:
 **
 ** "Redistribution and use in source and binary forms, with or without
 ** modification, are permitted provided that the following conditions are
 ** met:
 **   * Redistributions of source code must retain the above copyright
 **     notice, this list of conditions and the following disclaimer.
 **   * Redistributions in binary form must reproduce the above copyright
 **     notice, this list of conditions and the following disclaimer in
 **     the documentation and/or other materials provided with the
 **     distribution.
 **   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
 **     the names of its contributors may be used to endorse or promote
 **     products derived from this software without specific prior written
 **     permission.
 **
 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
 ** $QT_END_LICENSE$
 **
 ****************************************************************************/

 #include "flickrdemo.h"
 #include <QDomDocument>

 #include <qnmeapositioninfosource.h>
 #include <qgeopositioninfosource.h>
 #include <qgeosatelliteinfosource.h>
 #include <qgeopositioninfo.h>
 #include <qgeosatelliteinfo.h>
 #include <qnetworkconfigmanager.h>
 #include <qnetworksession.h>

 #include <QAction>
 #include <QApplication>
 #include <QDialogButtonBox>
 #include <QDir>
 #include <QFile>
 #include <QLabel>
 #include <QMenuBar>
 #include <QMessageBox>
 #include <QNetworkAccessManager>
 #include <QNetworkRequest>
 #include <QProgressDialog>
 #include <QPushButton>
 #include <QTimer>
 #include <QVBoxLayout>
 #include <QWidget>

 // static constant initialization

 const QSize FlickrDemo::gridSize = QSize(52, 52);
 const QSize FlickrDemo::thumbnailSize = QSize(50, 50);
 const QSize FlickrDemo::imageSize = QSize(150, 150);
 const QString FlickrDemo::apikey = QString("e36784df8a03fea04c22ed93318b291c");

 FlickrDemo::FlickrDemo(QWidget* parent) :
         QMainWindow(parent),
         m_logfileInUse(false),
         m_session(0),
         m_pictureListReply(0),
         m_thumbnailReply(0),
         m_pictureReply(0),
         m_pages(0),
         m_page(1),
         m_satellitesInView(0),
         m_satellitesUsed(0),
         m_latitude(-1000),
         m_longitude(-1000),
         m_downloadPictureList(true),
         m_shuttingDown(false)
 {
     resize(252, 344);

     locationLabel = new QLabel(tr("Lat: Long:"));
     satellitesLabel = new QLabel(tr("Using 0 of 0 satellites"));
     listWidget = new XQListWidget();
     downloadButton = new QPushButton(tr("Download Picture List"));

     QVBoxLayout *verticalLayout = new QVBoxLayout();
     verticalLayout->addWidget(locationLabel);
     verticalLayout->addWidget(satellitesLabel);
     verticalLayout->addWidget(listWidget);
     verticalLayout->addWidget(downloadButton);

     QWidget *centralWidget = new QWidget;
     centralWidget->setLayout(verticalLayout);
     setCentralWidget(centralWidget);

     createMenus();
     listWidget->setGridSize(gridSize);
     listWidget->setIconSize(thumbnailSize);
     m_progressDialog = new QProgressDialog(this);
     m_progressDialog->setModal(true);
     connect(m_progressDialog, SIGNAL(canceled()), this, SLOT(cancelDownload()));

     setWindowTitle(tr("Flickr Demo"));

     // QGeoPositionInfoSource
     m_location = QGeoPositionInfoSource::createDefaultSource(this);

     if (m_location == 0) {
         QNmeaPositionInfoSource *nmeaLocation = new QNmeaPositionInfoSource(QNmeaPositionInfoSource::SimulationMode, this);
         QFile *logFile = new QFile(QApplication::applicationDirPath()
                                    + QDir::separator() + "nmealog.txt", this);
         nmeaLocation->setDevice(logFile);
         m_location = nmeaLocation;
         m_logfileInUse = true;
     }

     // Listen gps position changes
     connect(m_location, SIGNAL(positionUpdated(QGeoPositionInfo)),
             this, SLOT(positionUpdated(QGeoPositionInfo)));

     // QGeoSatelliteInfoSource
     m_satellite = QGeoSatelliteInfoSource::createDefaultSource(this);
     // Listen satellite status changes
     if (m_satellite != 0) {
         connect(m_satellite, SIGNAL(satellitesInViewUpdated(const QList<QGeoSatelliteInfo>&)),
                 this, SLOT(satellitesInViewUpdated(const QList<QGeoSatelliteInfo>&)));
         connect(m_satellite, SIGNAL(satellitesInUseUpdated(const QList<QGeoSatelliteInfo>&)),
                 this, SLOT(satellitesInUseUpdated(const QList<QGeoSatelliteInfo>&)));
     }

     m_nam = new QNetworkAccessManager(this);

     QTimer::singleShot(0, this, SLOT(delayedInit()));
 }

 FlickrDemo::~FlickrDemo()
 {
     m_shuttingDown = true;

     m_location->stopUpdates();
     if (m_satellite)
         m_satellite->stopUpdates();

     if (m_pictureListReply) {
         m_pictureListReply->abort();
         delete m_pictureListReply;
     }
     if (m_thumbnailReply) {
         m_thumbnailReply->abort();
         delete m_thumbnailReply;
     }
     if (m_pictureReply) {
         m_pictureReply->abort();
         delete m_pictureReply;
     }

     if (m_session)
         m_session->close();
 }

 void FlickrDemo::delayedInit()
 {
     if (m_logfileInUse) {
         QMessageBox::information(this, tr("Flickr Demo"),
                                  tr("No GPS support detected, using GPS data from a sample log file instead."));
     }

 #ifdef BEARER_IN_QTNETWORK
     QNetworkConfigurationManager manager;
     const bool canStartIAP = (manager.capabilities()
                               & QNetworkConfigurationManager::CanStartAndStopInterfaces);
     QNetworkConfiguration cfg = manager.defaultConfiguration();
     if (!cfg.isValid() || (!canStartIAP && cfg.state() != QNetworkConfiguration::Active)) {
 #else
     QTM_PREPEND_NAMESPACE(QNetworkConfigurationManager) manager;
     const bool canStartIAP = (manager.capabilities()
                               & QTM_PREPEND_NAMESPACE(QNetworkConfigurationManager)::CanStartAndStopInterfaces);
     QTM_PREPEND_NAMESPACE(QNetworkConfiguration) cfg = manager.defaultConfiguration();
     if (!cfg.isValid() || (!canStartIAP && cfg.state() != QTM_PREPEND_NAMESPACE(QNetworkConfiguration)::Active)) {
 #endif
         QMessageBox::information(this, tr("Flickr Demo"), tr("Available Access Points not found."));
         qApp->quit();
     }

     m_session = new QNetworkSession(cfg, this);
     m_connectivityHelper = new ConnectivityHelper(m_session, this);
     connect(m_session, SIGNAL(opened()), this, SLOT(networkSessionOpened()));
     connect(m_connectivityHelper, SIGNAL(networkingCancelled()), qApp, SLOT(quit()));

     m_session->open();
 }

 void FlickrDemo::networkSessionOpened()
 {
     connect(downloadButton, SIGNAL(clicked()), this, SLOT(downloadButtonClicked()));

     // Start listening GPS position updates
     m_location->startUpdates();

     // Start listening GPS satellite status changes
     if (m_satellite != 0) {
         m_satellite->startUpdates();
     } else {
         satellitesLabel->setText(tr("GPS not detected, replaying coordinates from sample log file."));
     }
 }

 void FlickrDemo::createMenus()
 {
     m_downloadAct = new QAction(tr("Download Picture List"), this);
 #if defined(Q_OS_SYMBIAN) || defined(Q_OS_WINCE_WM) || defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6)
     menuBar()->addAction(m_downloadAct);
 #endif
     connect(m_downloadAct, SIGNAL(triggered()), this, SLOT(downloadButtonClicked()));

     QAction* exitAct = new QAction(tr("Exit"), this);
 #if defined(Q_OS_SYMBIAN) || defined(Q_OS_WINCE_WM) || defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6)
     menuBar()->addAction(exitAct);
 #endif
     connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
 }

 void FlickrDemo::positionUpdated(const QGeoPositionInfo &gpsPos)
 {
     if (gpsPos.isValid()) {
         QGeoCoordinate coord = gpsPos.coordinate();
         m_latitude = coord.latitude();
         m_longitude = coord.longitude();

         locationLabel->setText(tr("Lat: %1 Long: %2").arg(QString::number(m_latitude),
                                QString::number(m_longitude)));
     }
 }

 void FlickrDemo::satellitesInViewUpdated(const QList<QGeoSatelliteInfo> &satellites)
 {
     m_satellitesInView = satellites.count();
     viewSatelliteInfo();
 }
 void FlickrDemo::satellitesInUseUpdated(const QList<QGeoSatelliteInfo> &satellites)
 {
     m_satellitesUsed = satellites.count();
     viewSatelliteInfo();
 }

 void FlickrDemo::viewSatelliteInfo()
 {
     if (m_satellite != 0) {
         satellitesLabel->setText(tr("Using %1 of %2 satellites").arg(QString::number(m_satellitesUsed), QString::number(m_satellitesInView)));
     } else {
         satellitesLabel->setText(tr("GPS not detected, replaying coordinates from sample log file."));
     }
 }

 void FlickrDemo::downloadButtonClicked()
 {
     if (m_downloadPictureList) {
         downloadFlickerPictureList();
     } else {
         downloadPictureFromFlickr();
     }
 }

 void FlickrDemo::downloadFlickerPictureList()
 {
     if (m_latitude == -1000 || m_longitude == -1000) {
         if (QMessageBox::question(this,
                                   tr("Flickr Demo"),
                                   tr("No satellite connection.\n""Use hard coded coordinates?"),
                                   QMessageBox::Ok | QMessageBox::Cancel,
                                   QMessageBox::Cancel)
                 == QMessageBox::Cancel) {
             return;
         }
         // If GPS signal is not detected, Tampere area is used as default location
         m_latitude = 61.4500;
         m_longitude = 23.8502;
     }

     // Set IAP name
     satellitesLabel->setText(tr("Access Point: %1").arg(m_session->configuration().name()));
     locationLabel->setText(tr("Lat: %1 Long: %2").arg(QString::number(m_latitude),
                            QString::number(m_longitude)));

     QString
     urlstring =
         "http://api.flickr.com/services/rest/?min_taken_date=2000-01-01+0:00:00&extras=date_taken&method=flickr.photos.search&per_page=30&sort=date-taken-desc";
     urlstring.append("&api_key=");
     urlstring.append(apikey);
     urlstring.append("&lat=");
     urlstring.append(QString::number(m_latitude));
     urlstring.append("&lon=");
     urlstring.append(QString::number(m_longitude));
     urlstring.append("&page=");
     urlstring.append(QString::number(m_page));

     QUrl url(urlstring);

     QNetworkRequest req(url);
     m_pictureListReply = m_nam->get(req);
     connect(m_pictureListReply,
             SIGNAL(downloadProgress(qint64, qint64)),
             this,
             SLOT(pictureListDownloadProgress(qint64, qint64)));
     connect(m_pictureListReply,
             SIGNAL(finished()),
             this,
             SLOT(pictureListFinished()));
     connect(m_pictureListReply,
             SIGNAL(error(QNetworkReply::NetworkError)),
             this,
             SLOT(pictureListError(QNetworkReply::NetworkError)));

     m_progressDialog->setWindowTitle(tr("FlickrDemo"));
     m_progressDialog->setLabelText(tr("Downloading\nPicture List."));
     m_progressDialog->setMaximum(10);
     m_progressDialog->setValue(0);
     m_progressDialog->show();
 }

 bool FlickrDemo::parsePictureList(QString xmlString)
 {
     QString errorStr;
     int errorLine;
     int errorColumn;

     QDomDocument domDocument;
     if (!domDocument.setContent(xmlString, true, &errorStr, &errorLine, &errorColumn)) {
         QMessageBox::information(window(),
                                  tr("Flickr Demo"),
                                  tr("XML Parse error at line %1, column %2:\n%3").arg(errorLine).arg(errorColumn).arg(errorStr));
         return false;
     }
     QDomElement root = domDocument.documentElement();

     if (root.tagName() != "rsp") {
         QMessageBox::information(window(), tr("Flickr Demo"), tr("Invalid XML format."));
         return false;
     }
     if (root.attribute("stat") != "ok") {
         QMessageBox::information(window(), tr("Flickr Demo"), tr("Query failed."));
         return false;
     }

     listWidget->clear();
     QListWidgetItem* listItem;
     QDomElement photosElement = root.firstChildElement("photos");
     if (!photosElement.isNull()) {
         m_pages = (photosElement.attribute("pages")).toInt();
         m_page = (photosElement.attribute("page")).toInt();

         QDomElement child = photosElement.firstChildElement("photo");
         while (!child.isNull()) {
             QString url = "http://farm";
             url.append(child.attribute("farm"));
             url.append(".static.flickr.com/");
             url.append(child.attribute("server"));
             url.append("/");
             url.append(child.attribute("id"));
             url.append("_");
             url.append(child.attribute("secret"));

             m_names << url;

             listItem = new QListWidgetItem(child.attribute("title"));
             QImage image(thumbnailSize, QImage::Format_Mono);
             image.fill(1);
             listItem->setIcon(QPixmap::fromImage(image));
             listItem->setData(Qt::UserRole, url);
             listWidget->addItem(listItem);

             child = child.nextSiblingElement("photo");
         }
     } else {
         return false;
     }
     m_nameCounter = -1;
     downloadNextThumbnail();

     return true;
 }

 void FlickrDemo::downloadPictureFromFlickr()
 {
     QListWidgetItem* item = listWidget->currentItem();
     if (!item) {
         return;
     }
     QString pictureUrl = item->data(Qt::UserRole).toString();
     pictureUrl.append("_m.jpg");

     QUrl url(pictureUrl);

     QNetworkRequest req(url);
     m_pictureReply = m_nam->get(req);
     connect(m_pictureReply,
             SIGNAL(downloadProgress(qint64, qint64)),
             this,
             SLOT(pictureDownloadProgress(qint64, qint64)));
     connect(m_pictureReply,
             SIGNAL(finished()),
             this,
             SLOT(pictureFinished()));
     connect(m_pictureReply,
             SIGNAL(error(QNetworkReply::NetworkError)),
             this,
             SLOT(pictureError(QNetworkReply::NetworkError)));

     m_progressDialog->setWindowTitle(tr("Flickr Demo"));
     m_progressDialog->setLabelText(tr("Downloading:\n%1").arg(pictureUrl));
     m_progressDialog->setMaximum(10);
     m_progressDialog->setValue(0);
     m_progressDialog->show();

     downloadButton->setEnabled(false);
 }

 void FlickrDemo::cancelDownload()
 {
     if (m_pictureListReply) {
         m_pictureListReply->abort();
         delete m_pictureListReply;
         m_pictureListReply = 0;
     }

     if (m_pictureReply) {
         m_pictureReply->abort();
         delete m_pictureReply;
         m_pictureReply = 0;
     }

     downloadButton->setEnabled(true);
 }

 void FlickrDemo::pictureListDownloadProgress(qint64 bytesReceived, qint64 bytesTotal)
 {
     m_progressDialog->setMaximum(bytesTotal);
     m_progressDialog->setValue(bytesReceived);
 }

 void FlickrDemo::pictureListFinished()
 {
     m_progressDialog->hide();
     if (parsePictureList(QString::fromUtf8(m_pictureListReply->readAll()))) {
         m_downloadPictureList = false;
         downloadButton->setText(tr("Download Selected Picture"));
         m_downloadAct->setText(tr("Download Selected Picture"));
     }

     downloadButton->setEnabled(true);

     QTimer::singleShot(0, this, SLOT(clearPictureListRequest()));
 }

 void FlickrDemo::pictureListError(QNetworkReply::NetworkError /*code*/)
 {
     if (m_shuttingDown)
         return;

     m_progressDialog->hide();
     QMessageBox::information(this,
                              tr("Flickr Demo"),
                              tr("Error downloading picture list: %1.").arg(m_pictureListReply->errorString()));

     QTimer::singleShot(0, this, SLOT(clearPictureListRequest()));
 }

 void FlickrDemo::clearPictureListRequest()
 {
     delete m_pictureListReply;
     m_pictureListReply = 0;
 }

 void FlickrDemo::thumbnailFinished()
 {
     QByteArray picture = m_thumbnailReply->readAll();
     if (!picture.isNull() && picture.size() > 0) {
         QListWidgetItem* item = listWidget->item(m_nameCounter);
         QImage image;
         if (image.loadFromData(picture, "jpg")) {
             item->setIcon(QPixmap::fromImage(
                               image.scaled(thumbnailSize,
                                            Qt::KeepAspectRatio,
                                            Qt::SmoothTransformation)));
             listWidget->update();
         }
     }
     downloadNextThumbnail();
 }

 void FlickrDemo::thumbnailError(QNetworkReply::NetworkError /*code*/)
 {
     if (m_shuttingDown)
         return;

     QMessageBox::information(this,
                              tr("Flickr Demo"),
                              tr("Error downloading thumbnails: %1.").arg(m_thumbnailReply->errorString()));

     QTimer::singleShot(0, this, SLOT(clearThumbnailRequest()));
 }

 void FlickrDemo::clearThumbnailRequest()
 {
     delete m_thumbnailReply;
     m_thumbnailReply = 0;
 }

 void FlickrDemo::pictureDownloadProgress(qint64 bytesReceived, qint64 bytesTotal)
 {
     m_progressDialog->setMaximum(bytesTotal);
     m_progressDialog->setValue(bytesReceived);
 }

 void FlickrDemo::pictureFinished()
 {
     m_progressDialog->hide();
     downloadButton->setEnabled(true);

     QByteArray picture = m_pictureReply->readAll();

     if (picture.isNull() || picture.size() <= 0)
         return;

     QImage image;
     if (!image.loadFromData(picture, "jpg"))
         return;

     QPixmap pixmap = QPixmap::fromImage(
                          image.scaled(imageSize,
                                       Qt::KeepAspectRatio,
                                       Qt::SmoothTransformation));

     displayImage(pixmap);

     QTimer::singleShot(0, this, SLOT(clearPictureRequest()));
 }

 void FlickrDemo::pictureError(QNetworkReply::NetworkError /*code*/)
 {
     if (m_shuttingDown)
         return;

     m_progressDialog->hide();
     QMessageBox::information(this,
                              tr("Flickr Demo"),
                              tr("Error downloading picture: %1.").arg(m_pictureReply->errorString()));

     downloadButton->setEnabled(true);

     QTimer::singleShot(0, this, SLOT(clearPictureRequest()));
 }

 void FlickrDemo::clearPictureRequest()
 {
     delete m_pictureReply;
     m_pictureReply = 0;
 }

 void FlickrDemo::displayImage(const QPixmap &pixmap)
 {
     PictureDialog dialog(pixmap, listWidget->currentItem()->text(), this);
 #if defined(Q_OS_SYMBIAN) || defined(Q_OS_WINCE_WM) || defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6)
     dialog.showMaximized();
 #endif
     dialog.exec();
 }

 void FlickrDemo::downloadNextThumbnail()
 {
     m_nameCounter++;
     if (m_nameCounter < m_names.count()) {
         QString pictureUrl = m_names[m_nameCounter];
         pictureUrl.append("_s.jpg");
         QUrl url(pictureUrl);

         QNetworkRequest req(url);
         m_thumbnailReply = m_nam->get(req);
         connect(m_thumbnailReply,
                 SIGNAL(finished()),
                 this,
                 SLOT(thumbnailFinished()));
         connect(m_thumbnailReply,
                 SIGNAL(error(QNetworkReply::NetworkError)),
                 this,
                 SLOT(thumbnailError(QNetworkReply::NetworkError)));
     } else {
         QTimer::singleShot(0, this, SLOT(clearThumbnailRequest()));
     }
 }

 PictureDialog::PictureDialog(const QPixmap& pixmap, const QString& pictureName, QWidget* parent) :
         QDialog(parent)
 {
     resize(252, 361);
     QVBoxLayout *verticalLayout = new QVBoxLayout();
     verticalLayout->setSpacing(6);
     verticalLayout->setContentsMargins(11, 11, 11, 11);

     label = new QLabel();
     label->setText(tr("Downloaded:\n%1").arg(pictureName));

     QSizePolicy sizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred);
     sizePolicy.setHorizontalStretch(0);
     sizePolicy.setVerticalStretch(0);
     sizePolicy.setHeightForWidth(label->sizePolicy().hasHeightForWidth());
     label->setSizePolicy(sizePolicy);

     verticalLayout->addWidget(label);

     imageLabel = new QLabel();
     imageLabel->setPixmap(pixmap);

     verticalLayout->addWidget(imageLabel);

     buttonBox = new QDialogButtonBox();
     buttonBox->setStandardButtons(QDialogButtonBox::Close);
     connect(buttonBox, SIGNAL(rejected()), this, SLOT(accept()));

     verticalLayout->addWidget(buttonBox);

     setLayout(verticalLayout);

     setWindowTitle(tr("Flickr Demo"));
 }