Logo Search packages:      
Sourcecode: wally version File versions  Download package

httpengine.cpp

/*
TRANSLATOR HttpEngine::Item
*/
/*
TRANSLATOR HttpEngine::Core
*/
/*
TRANSLATOR HttpEngine::SettingsWidget
*/

/*
 * Wally - Qt4 wallpaper/background changer
 * Copyright (C) 2009  Antonio Di Monaco <tony@becrux.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include <QtCore>
#include <QtGui>
#include <QtNetwork>
#include <QtDebug>

#include "diskinfo.h"
#include "httpex.h"
#include "engine.h"
#include "httpengine.h"

using namespace HttpEngine;

Item::Item()
{
  _savePhotos = false;
  _pageIndex = _pages = 0;
}

Item::Item(Item *item)
{
  _pageIndex = item->_pageIndex;
  _pages = item->_pages;
  _savePhotos = item->_savePhotos;
  _photosPath = item->_photosPath;
}

void Item::loadState(QSettings &settings, const QString &group)
{
  settings.beginGroup(group);

  _pageIndex = settings.value(PAGE_INDEX,0).toInt();
  _pages = settings.value(PAGES,0).toInt();

  doLoadState(settings);

  settings.endGroup();
}

void Item::saveState(QSettings &settings, const QString &engineName, int id) const
{
  settings.beginGroup(QString("%1%2").arg(engineName).arg(id));

  settings.setValue(QString(PAGE_INDEX),QString::number(_pageIndex));
  settings.setValue(QString(PAGES),QString::number(_pages));

  doSaveState(settings);

  settings.endGroup();
}

void Item::loadSettings(QSettings &settings, const QString &group)
{
  settings.beginGroup(group);

  _savePhotos = settings.value("savePhotos",false).toBool();
  _photosPath = settings.value("photosPath",QString()).toString();

  doLoadSettings(settings);

  settings.endGroup();
}

void Item::saveSettings(QSettings &settings, const QString &engineName, int id) const
{
  settings.beginGroup(QString("%1%2").arg(engineName).arg(id));

  settings.setValue("savePhotos",_savePhotos);
  settings.setValue("photosPath",QDir::toNativeSeparators(_photosPath));

  doSaveSettings(settings);

  settings.endGroup();
}

QUrl Item::prepareInit(QHttpRequestHeader &header)
{
  qDebug() << metaObject()->className() << "::prepareInit()";

  return doPrepareInit(header);
}

void Item::processInitResult(const QByteArray &response)
{
  QString debugMsg = QString(metaObject()->className()) + "::processInitResult() ->";

  if (response.size())
    debugMsg += QString("\n") + response.constData();
  else
    debugMsg += " empty";

  qDebug() << debugMsg;

  doProcessInitResult(response);
}

QUrl Item::prepareSearch(bool randomMode, QHttpRequestHeader &header, bool &shouldEncode)
{
  QString debugMsg = QString(metaObject()->className()) + "::doCalculateNextIndex(" + ((randomMode)? "true" : "false") +
                     "," + QString::number(_pageIndex) + "," + QString::number(_pages) + ") ->";

  qDebug() << metaObject()->className() << "::prepareSearch(" << randomMode << ")";

  if (_pages && (_pageIndex >= _pages))
    resetPages();

  _pageIndex = doCalculateNextIndex(randomMode,_pageIndex,_pages);

  qDebug() << debugMsg << _pageIndex;

  return doPrepareSearch(header,shouldEncode);
}

bool Item::processSearchResult(const QByteArray &response)
{
  QString debugMsg = QString(metaObject()->className()) + "::processSearchResult() ->";

  if (response.size())
    debugMsg += QString("\n") + response.constData();
  else
    debugMsg += " empty";

  qDebug() << debugMsg;

  return doProcessSearchResult(response,_pages);
}

QSize Item::processSizeRequestResult(const QByteArray &response)
{
  QString debugMsg = QString(metaObject()->className()) + "::processSizeRequestResult() ->";

  if (response.size())
    debugMsg += QString("\n") + response.constData();
  else
    debugMsg += " empty";

  qDebug() << debugMsg;

  return doProcessSizeRequestResult(response);
}

void Item::processDownloadResult(const QFileInfo &fileInfo, bool belowThreshold)
{
  qDebug() << metaObject()->className()
           << "::processDownloadResult(" << fileInfo.absoluteFilePath().toAscii().constData() << ")";

  if (_savePhotos && !_photosPath.isEmpty())
  {
    if (!belowThreshold)
    {
      QFile::copy(fileInfo.absoluteFilePath(),QFileInfo(_photosPath,
                                                        fileInfo.fileName()).absoluteFilePath());

      qDebug() << "\tfile copied in" << _photosPath.toAscii().constData()
               << "\n\tfree disk space:" << (DiskInfo::freeSpace(fileInfo.absoluteFilePath()) / 1024) << "kbytes";
    }
    else
      qDebug() << "\tcannot copy file, free disk space:" << (DiskInfo::freeSpace(fileInfo.absoluteFilePath()) / 1024) << "kbytes";
  }

  doProcessDownloadResult(fileInfo);
}

PhotoInfo Item::processInfoCollectResult(const QByteArray &response)
{
  QString debugMsg = QString(metaObject()->className()) + "::processInfoCollectResult() ->";

  if (response.size())
    debugMsg += QString("\n") + response.constData();
  else
    debugMsg += " empty";

  qDebug() << debugMsg;

  return doProcessInfoCollectResult(response);
}

Core::Core(const QString &tempStorageDir, QObject *parent) : XtEngine::Core(tempStorageDir,parent),
  httpProxy(QNetworkProxy::NoProxy)
{
  HttpEx::Interface *retry;

  canceling = cancelSignaled = false;
  initHttp = new HttpEx::Timeout(new HttpEx::Log(new HttpEx::Base(new HttpEx::Core(new QHttp(this),this))));
  searchHttp = new HttpEx::Timeout(new HttpEx::Log(new HttpEx::Base(new HttpEx::Core(new QHttp(this),this))));
  sizeRequestHttp = new HttpEx::Timeout(new HttpEx::Log(new HttpEx::Base(new HttpEx::Core(new QHttp(this),this))));
  retry = new HttpEx::Retry(new HttpEx::Log(new HttpEx::Base(new HttpEx::Core(new QHttp(this),this))));
  downloadHttp = new HttpEx::Timeout(retry);
  infoCollectHttp = new HttpEx::Timeout(new HttpEx::Log(new HttpEx::Base(new HttpEx::Core(new QHttp(this),this))));

  connect(initHttp,SIGNAL(done(bool)),this,SLOT(httpInitDone(bool)));
  connect(searchHttp,SIGNAL(done(bool)),this,SLOT(httpSearchDone(bool)));
  connect(sizeRequestHttp,SIGNAL(done(bool)),this,SLOT(httpSizeRequestDone(bool)));
  connect(qobject_cast<HttpEx::Retry *> (retry),SIGNAL(completed(bool, const QByteArray &)),this,SLOT(httpDownloadDone(bool)));
  connect(infoCollectHttp,SIGNAL(done(bool)),this,SLOT(httpInfoCollectDone(bool)));
}

void Core::setProxy(const QNetworkProxy &proxy)
{
  qDebug() << name().toAscii().constData() << "::Core::setProxy(...)";

  httpProxy = proxy;
}

QNetworkProxy Core::guessProxy(const QUrl &url)
{
  QList<QNetworkProxy> proxies = QNetworkProxyFactory::systemProxyForQuery(QNetworkProxyQuery(url));

  if (proxies.size())
  {
    QNetworkProxy localProxy = proxies.at(0);
    localProxy.setUser(httpProxy.user());
    localProxy.setPassword(httpProxy.password());

    qDebug() << name().toAscii().constData() << "::guessProxy()\n"
             << "\tusing proxy "
             << localProxy.user().toAscii().constData() << "@"
             << localProxy.hostName().toAscii().constData() << ":"
             << QString::number(localProxy.port()).toAscii().constData() << "\n"
             << "\tfor " << url.toString().toAscii().constData();

    return localProxy;
  }
  else
    return QNetworkProxy(QNetworkProxy::NoProxy);
}

void Core::init()
{
  QUrl url;
  QString urlStr;
  QHttpRequestHeader header;

  qDebug() << name().toAscii().constData() << "::Core::init()";

  canceling = cancelSignaled = false;

  if (list.size())
  {
    currentItemIndex = (currentItemIndex + 1) % list.size();

    url = qobject_cast<Item *> (list.at(currentItemIndex))->prepareInit(header);

    qDebug() << "\tURL: " << (!(url.isEmpty())? url.toString().toAscii().constData() : "empty");

    if (url.isEmpty())
      emit initCompleted();
    else
    {
      if (!httpProxy.hostName().compare("0.0.0.0"))
        initHttp->setProxy(guessProxy(url));
      else
        initHttp->setProxy(httpProxy);

      initHttp->setHost(url.host());

      urlStr = url.toEncoded();

      if (header.keys().size())
        initHttp->request(header,urlStr.remove(0,url.toString(QUrl::RemoveQuery).size()+1).toAscii());
      else
        initHttp->get(urlStr.remove(0,urlStr.indexOf(url.path())));
    }
  }
  else
    emit initCompleted();
}

void Core::search(bool randomMode)
{
  QUrl url;
  QString urlStr;
  QHttpRequestHeader header;
  bool shouldEncode = true;

  qDebug() << name().toAscii().constData() << "::Core::search(" << randomMode << ")";

  if (list.size())
  {
    url = qobject_cast<Item *> (list.at(currentItemIndex))->prepareSearch(randomMode,header,shouldEncode);

    qDebug() << "\tURL:" << (!(url.isEmpty())? url.toEncoded().constData() : "empty");

    if (url.isEmpty())
      emit searchCompleted(false);
    else if (url.isRelative())
      emit searchCompleted(true);
    else
    {
      if (!httpProxy.hostName().compare("0.0.0.0"))
        searchHttp->setProxy(guessProxy(url));
      else
        searchHttp->setProxy(httpProxy);

      searchHttp->setHost(url.host());

      urlStr = (shouldEncode)? url.toEncoded() : url.toString();

      if (header.keys().size())
        searchHttp->request(header,urlStr.remove(0,url.toString(QUrl::RemoveQuery).size()+1).toAscii());
      else
      {
        if (shouldEncode)
          searchHttp->get(urlStr.remove(0,urlStr.indexOf(url.path())));
        else
          searchHttp->get(url.encodedPath() + urlStr.remove(0,urlStr.indexOf(url.path()) +
                                                            url.path().size()));
      }
    }
  }
  else
    emit searchCompleted(false);
}

void Core::sizeLookup()
{
  Item *item = qobject_cast<Item *> (list.at(currentItemIndex));
  QString urlStr;
  QHttpRequestHeader header;
  QUrl url = item->prepareSizeRequest(header);

  qDebug() << name().toAscii().constData() << "::Core::sizeLookup()";
  qDebug() << "\tURL: " << (!(url.isEmpty())? url.toString().toAscii().constData() : "empty");

  if (url.isEmpty())
    emit sizeLookupCompleted(QSize(-1,-1));
  else if (!url.isRelative())
  {
    if (!httpProxy.hostName().compare("0.0.0.0"))
      sizeRequestHttp->setProxy(guessProxy(url));
    else
      sizeRequestHttp->setProxy(httpProxy);

    sizeRequestHttp->setHost(url.host());

    urlStr = url.toEncoded();

    if (header.keys().size())
      sizeRequestHttp->request(header,urlStr.remove(0,url.toString(QUrl::RemoveQuery).size()+1).toAscii());
    else
      sizeRequestHttp->get(urlStr.remove(0,urlStr.indexOf(url.path())));
  }
  else
    emit sizeLookupCompleted(item->processSizeRequestResult(QByteArray()));
}

void Core::download()
{
  QString urlStr;
  QHttpRequestHeader header;
  QUrl url = qobject_cast<Item *> (list.at(currentItemIndex))->prepareDownload(header);

  httpFile.setFileName(tempStorageDir() + "/" + QFileInfo(url.path()).fileName());

  qDebug() << name().toAscii().constData() << "::Core::download()";
  qDebug() << "\tURL: "
           << (!(url.isEmpty())? url.toString().toAscii().constData() : "empty");

  httpFile.open(QIODevice::WriteOnly);

  if (url.isEmpty())
    emit downloadCompleted(false,QFileInfo());
  else
  {
    if (!httpProxy.hostName().compare("0.0.0.0"))
      downloadHttp->setProxy(guessProxy(url));
    else
      downloadHttp->setProxy(httpProxy);

    downloadHttp->setHost(url.host());

    urlStr = url.toEncoded();

    downloadHttp->get(urlStr.remove(0,urlStr.indexOf(url.encodedPath())),&httpFile);
  }
}

void Core::infoCollect()
{
  Item *item = qobject_cast<Item *> (list.at(currentItemIndex));
  QString urlStr;
  QHttpRequestHeader header;
  QUrl url = item->prepareInfoCollect(header);

  qDebug() << name().toAscii().constData() << "::Core::infoCollect()";
  qDebug() << "\tURL: " << (!(url.isEmpty())? url.toString().toAscii().constData() : "empty");

  if (url.isEmpty())
    emit infoCollectCompleted(PhotoInfo());
  else if (!url.isRelative())
  {
    if (!httpProxy.hostName().compare("0.0.0.0"))
      infoCollectHttp->setProxy(guessProxy(url));
    else
      infoCollectHttp->setProxy(httpProxy);

    infoCollectHttp->setHost(url.host());

    urlStr = url.toEncoded();

    if (header.keys().size())
      infoCollectHttp->request(header,urlStr.remove(0,url.toString(QUrl::RemoveQuery).size()+1).toAscii());
    else
      infoCollectHttp->get(urlStr.remove(0,urlStr.indexOf(url.path())));
  }
  else
    emit infoCollectCompleted(item->processInfoCollectResult(QByteArray()));
}

void Core::cancel()
{
  qDebug() << name().toAscii().constData() << "::Core::cancel()";

  canceling = true;
  cancelSignaled = false;

  initHttp->abort();
  searchHttp->abort();
  sizeRequestHttp->abort();
  downloadHttp->abort();
  infoCollectHttp->abort();
}

void Core::httpInitDone(bool error)
{
  qDebug() << name().toAscii().constData() << "::Core::httpInitDone(" << error << ")";

  if (!error && initHttp->bytesAvailable())
  {
    Item *item = qobject_cast<Item *> (list.at(currentItemIndex));
    item->processInitResult(initHttp->readAll());
  }

  if (canceling)
  {
    if (!cancelSignaled)
    {
      cancelSignaled = true;
      emit cancelCompleted();
    }
  }
  else
    emit initCompleted();
}

void Core::httpSearchDone(bool error)
{
  qDebug() << name().toAscii().constData() << "::Core::httpSearchDone(" << error << ")";

  if (canceling)
  {
    if (!cancelSignaled)
    {
      cancelSignaled = true;
      emit cancelCompleted();
    }
  }
  else if (!error)
  {
    if (searchHttp->bytesAvailable())
    {
      Item *item = qobject_cast<Item *> (list.at(currentItemIndex));
      emit searchCompleted(item->processSearchResult(searchHttp->readAll()));
    }
    else
      emit searchCompleted(false);
  }
  else
    emit searchCompleted(false);
}

void Core::httpSizeRequestDone(bool error)
{
  qDebug() << name().toAscii().constData() << "::Core::httpSizeRequestDone(" << error << ")";

  if (canceling)
  {
    if (!cancelSignaled)
    {
      cancelSignaled = true;
      emit cancelCompleted();
    }
  }
  else if (!error)
  {
    if (sizeRequestHttp->bytesAvailable())
    {
      Item *item = qobject_cast<Item *> (list.at(currentItemIndex));
      emit sizeLookupCompleted(item->processSizeRequestResult(sizeRequestHttp->readAll()));
    }
    else
      emit sizeLookupCompleted(QSize(-1,-1));
  }
  else
    emit sizeLookupCompleted(QSize(-1,-1));
}

void Core::httpDownloadDone(bool error)
{
  httpFile.close();

  qDebug() << name().toAscii().constData() << "::Core::httpDownloadDone(" << error << ")";

  if (canceling)
  {
    if (!cancelSignaled)
    {
      cancelSignaled = true;
      emit cancelCompleted();
    }
  }
  else if (!error)
  {
    QFileInfo httpFileInfo = QFileInfo(httpFile);

    Item *item = qobject_cast<Item *> (list.at(currentItemIndex));
    item->processDownloadResult(httpFileInfo,
                                DiskInfo::freeSpace(httpFileInfo.absoluteFilePath()) <=
                                (_diskSpaceThreshold + httpFileInfo.size()));
    emit downloadCompleted(true,QFileInfo(httpFile));
  }
  else
    emit downloadCompleted(false,QFileInfo());
}

void Core::httpInfoCollectDone(bool error)
{
  qDebug() << name().toAscii().constData() << "::Core::httpInfoCollectDone(" << error << ")";

  if (canceling)
  {
    if (!cancelSignaled)
    {
      cancelSignaled = true;
      emit cancelCompleted();
    }
  }
  else if (!error)
  {
    if (infoCollectHttp->bytesAvailable())
    {
      Item *item = qobject_cast<Item *> (list.at(currentItemIndex));
      emit infoCollectCompleted(item->processInfoCollectResult(infoCollectHttp->readAll()));
    }
    else
      emit infoCollectCompleted(PhotoInfo());
  }
  else
    emit infoCollectCompleted(PhotoInfo());
}

SettingsWidget::SettingsWidget(Engine::Core *core, QWidget *parent)
  : XtEngine::SettingsWidget(core,parent), isRefreshing(false)
{
  QCompleter *completer = new QCompleter(this);
  QDirModel *dirModel = new QDirModel(completer);

  setupUi(this);

  dirModel->setFilter(QDir::AllDirs | QDir::Drives | QDir::NoDotAndDotDot);
  completer->setModel(dirModel);
  lePhotosPath->setCompleter(completer);

  lvSets->setModel(core);
  lvSets->setItemDelegate(new XtEngine::ItemDelegate(this));
  lvSets->setSelectionModel(core->selectionModel());
  connect(core->selectionModel(),SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
          this,SLOT(updateWidgets(QItemSelection,QItemSelection)));
}

void SettingsWidget::on_tbAdd_clicked()
{
  XtEngine::Item *item;

  if ((item = newDialog()->execute()) && item->isValidItem())
  {
    *core() << item;
    emit settingsModified();
  }
}

void SettingsWidget::on_tbDel_clicked()
{
  core()->removeRows(lvSets->selectionModel());
  emit settingsModified();
}

void SettingsWidget::on_lvSets_doubleClicked(const QModelIndex &index)
{
  QVariant var;
  XtEngine::Item *item;
  Engine::Item *newItem;

  if (index.isValid())
  {
    item = qobject_cast <XtEngine::Item *> (core()->data(index,Qt::UserRole).value<Engine::Item *>());

    if ((newItem = newDialog()->execute(item)) && qobject_cast<XtEngine::Item *> (newItem)->isValidItem())
    {
      Item *httpItem = qobject_cast<Item *> (item);

      qobject_cast<Item *> (newItem)->setPhotosPath(httpItem->photosPath());
      qobject_cast<Item *> (newItem)->setSavePhotos(httpItem->arePhotosSaved());
      var.setValue(newItem);
      core()->setData(index,var,Qt::UserRole);
      emit settingsModified();
    }
  }
}

void SettingsWidget::on_tbPhotosPath_clicked()
{
#ifdef Q_WS_X11
  QString dirName = QFileDialog::getExistingDirectory(this,tr("Select a folder"),QDir::homePath(),
                                                      QFileDialog::ShowDirsOnly |
                                                      QFileDialog::DontResolveSymlinks |
                                                      QFileDialog::DontUseNativeDialog);
#else
  QString dirName = QFileDialog::getExistingDirectory(this,tr("Select a folder"),
                                                      QDesktopServices::storageLocation(QDesktopServices::PicturesLocation),
                                                      QFileDialog::ShowDirsOnly |
                                                      QFileDialog::DontResolveSymlinks |
                                                      QFileDialog::DontUseNativeDialog);
#endif

  if (!dirName.isEmpty())
  {
    lePhotosPath->setText(QDir::toNativeSeparators(dirName));
    emit settingsModified();
  }
}

void SettingsWidget::updateWidgets(const QItemSelection & /* selected */,
                                   const QItemSelection & /* deselected */)
{
  gbOptions->setEnabled(lvSets->selectionModel()->selectedRows().size());

  if (lvSets->selectionModel()->selectedRows().size() == 1)
  {
    QModelIndex index = lvSets->selectionModel()->selectedRows().at(0);
    Item *item = qobject_cast<Item *> (core()->data(index,Qt::UserRole).value<Engine::Item *>());

    isRefreshing = true;
    cbSavePhotos->setTristate(false);
    cbSavePhotos->setChecked(item->arePhotosSaved());
    lePhotosPath->setText(QDir::toNativeSeparators(item->photosPath()));
    lePhotosPath->setEnabled(cbSavePhotos->isChecked());
    tbPhotosPath->setEnabled(cbSavePhotos->isChecked());
    isRefreshing = false;
  }
  else if (lvSets->selectionModel()->selectedRows().size() > 1)
  {
    int i;
    bool changed;
    QModelIndex firstIndex = lvSets->selectionModel()->selectedRows().at(0);
    Item *firstItem = qobject_cast<Item *> (core()->data(firstIndex,Qt::UserRole).value<Engine::Item *>());

    for (i = 1, changed = false; (i < lvSets->selectionModel()->selectedRows().size()) && (!changed); ++i)
    {
      QModelIndex index = lvSets->selectionModel()->selectedRows().at(i);
      Item *item = qobject_cast<Item *> (core()->data(index,Qt::UserRole).value<Engine::Item *>());

      changed = (item->arePhotosSaved() != firstItem->arePhotosSaved()) ||
                (QFileInfo(item->photosPath()) != QFileInfo(firstItem->photosPath()));
    }

    isRefreshing = true;
    if (changed)
    {
      cbSavePhotos->setTristate(true);
      cbSavePhotos->setCheckState(Qt::PartiallyChecked);
      lePhotosPath->clear();
      lePhotosPath->setEnabled(false);
      tbPhotosPath->setEnabled(false);
    }
    else
    {
      cbSavePhotos->setTristate(false);
      cbSavePhotos->setChecked(firstItem->arePhotosSaved());
      lePhotosPath->setText(QDir::toNativeSeparators(firstItem->photosPath()));
      lePhotosPath->setEnabled(cbSavePhotos->isChecked());
      tbPhotosPath->setEnabled(cbSavePhotos->isChecked());
    }
    isRefreshing = false;
  }

  tbDel->setEnabled(lvSets->selectionModel()->selectedRows().size());
}

void SettingsWidget::on_cbSavePhotos_stateChanged(int state)
{
  Item *item;

  if (!isRefreshing)
  {
    QListIterator<QModelIndex> index(lvSets->selectionModel()->selectedRows());

    while (index.hasNext())
    {
      item = qobject_cast<Item *> (core()->data(index.next(),Qt::UserRole).value<Engine::Item *>());
      item->setSavePhotos(state == Qt::Checked);
    }

    lePhotosPath->setEnabled(state == Qt::Checked);
    tbPhotosPath->setEnabled(state == Qt::Checked);

    emit settingsModified();
  }
}

void SettingsWidget::on_lePhotosPath_textChanged(const QString &text)
{
  Item *item;

  if (!isRefreshing)
  {
    QListIterator<QModelIndex> index(lvSets->selectionModel()->selectedRows());

    while (index.hasNext())
    {
      item = qobject_cast<Item *> (core()->data(index.next(),Qt::UserRole).value<Engine::Item *>());
      item->setPhotosPath(text);
    }

    emit settingsModified();
  }
}

Generated by  Doxygen 1.6.0   Back to index