/****************************************************************************
** Dooble - The Secure Internet Web Browser
**
** Copyright (c) 2008, 2009, 2010, 2011, 2012 Alexis Megas,
** Gunther van Dooble, and the Dooble Team.
** All rights reserved.
**
** License: GPL2 only:
** 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; version 2 of the License only.
**
** 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
** or see here: http://www.gnu.org/licenses/gpl.html
**
** For the WebKit library, please see: http://webkit.org.
**
** THE CODE IS PROVIDED BY THE AUTHORS ''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 AUTHOR 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 APPLICATION, EVEN IF ADVISED
** OF THE POSSIBILITY OF SUCH DAMAGE.
**
** Please report all praise, requests, bugs, and problems to the project
** team and administrators: http://sf.net/projects/dooble.
**
** You can find us listed at our project page. New team members are welcome.
** The name of the authors should not be used to endorse or promote products
** derived from Dooble without specific prior written permission.
** If you use this code for other projects, please let us know.
**
** Web sites:
**   http://sf.net/projects/dooble
**   http://dooble.sf.net
****************************************************************************/

#include <QDir>
#include <QDateTime>
#include <QKeyEvent>
#include <QSettings>
#include <QSqlIndex>
#include <QSqlQuery>
#include <QMessageBox>
#include <QProgressBar>
#include <QSqlDatabase>
#include <QNetworkReply>
#include <QAuthenticator>

#include "dmisc.h"
#include "dooble.h"
#include "ddownloadprompt.h"
#include "ddownloadwindow.h"
#include "ui_passwordPrompt.h"

ddownloadwindow::ddownloadwindow(void):QMainWindow()
{
  ui.setupUi(this);
#ifdef Q_WS_MAC
  setAttribute(Qt::WA_MacMetalStyle, false);
  statusBar()->setSizeGripEnabled(false);
#endif
  ui.searchLineEdit->setPlaceholderText(tr("Search Downloads"));
  connect(ui.closePushButton, SIGNAL(clicked(void)), this,
	  SLOT(slotClose(void)));
  connect(ui.clearListPushButton, SIGNAL(clicked(void)), this,
	  SLOT(slotClearList(void)));
  connect(ui.enterUrlPushButton, SIGNAL(clicked(void)), this,
	  SLOT(slotEnterUrl(void)));
  connect(ui.cancelPushButton, SIGNAL(clicked(void)), this,
	  SLOT(slotCancelDownloadUrl(void)));
  connect(ui.downloadPushButton, SIGNAL(clicked(void)), this,
	  SLOT(slotDownloadUrl(void)));
  connect(ui.clearPushButton, SIGNAL(clicked(void)), this,
	  SLOT(slotClear(void)));
  connect(this,
	  SIGNAL(iconsChanged(void)),
	  ui.searchLineEdit,
	  SLOT(slotSetIcons(void)));
  connect(ui.searchLineEdit, SIGNAL(textEdited(const QString &)),
	  this, SLOT(slotTextChanged(const QString &)));
  connect(ui.table,
	  SIGNAL(cellDoubleClicked(int, int)),
	  this,
	  SLOT(slotCellDoubleClicked(int, int)));
  slotSetIcons();
  createDownloadDatabase();
}

ddownloadwindow::~ddownloadwindow()
{
  saveState();
}

void ddownloadwindow::purge(void)
{
  {
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "downloads");

    db.setDatabaseName(dooble::s_homePath +
		       QDir::separator() + "downloads.db");

    if(db.open())
      {
	QSqlQuery query(db);

	query.exec("PRAGMA synchronous = OFF");
	query.exec("DELETE FROM downloads");
	query.exec("VACUUM");
      }

    db.close();
  }

  QSqlDatabase::removeDatabase("downloads");
}

void ddownloadwindow::populate(void)
{
  for(int i = ui.table->rowCount() - 1; i >= 0; i--)
    {
      ddownloadwindowitem *item = qobject_cast<ddownloadwindowitem *>
	(ui.table->cellWidget(i, 0));

      if(item && !item->isDownloading())
	{
	  /*
	  ** If the user authenticates after a download has been
	  ** initiated for a session-based process, they may
	  ** wish to continue the download.
	  */

	  item->deleteLater();
	  ui.table->removeRow(i);
	}
    }

  if(!dmisc::passphraseWasAuthenticated())
    return;

  {
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "downloads");

    db.setDatabaseName(dooble::s_homePath +
		       QDir::separator() + "downloads.db");

    if(db.open())
      {
	QSqlQuery query(db);

	if(query.exec("SELECT filename, url, "
		      "download_started_date FROM downloads"))
	  while(query.next())
	    {
	      QUrl url;
	      QString fileName("");
	      QDateTime dateTime;

	      url = QUrl::fromEncoded
		(dmisc::decodedString
		 (QByteArray::fromBase64(query.value(1).toByteArray())),
		 QUrl::StrictMode);
	      fileName = QString::fromUtf8
		(dmisc::decodedString
		 (QByteArray::fromBase64(query.value(0).toByteArray())));
	      dateTime = QDateTime::fromString
		(QString::fromUtf8
		 (dmisc::decodedString
		  (QByteArray::fromBase64
		   (query.value(2).toByteArray()))),
		 Qt::ISODate);

	      /*
	      ** These if-statements should take care of
	      ** decoding mishaps.
	      */

	      if(QFileInfo(url.toLocalFile()).exists())
		addFileItem(url.toLocalFile(), fileName, false, dateTime);
	      else if(url.isValid() &&
		      dmisc::isSchemeAcceptedByDooble(url.scheme()))
		addUrlItem(url, fileName, false, dateTime, 0);
	    }
      }

    db.close();
  }

  QSqlDatabase::removeDatabase("downloads");
  slotTextChanged(ui.searchLineEdit->text().trimmed());
}

void ddownloadwindow::addFileItem(const QString &srcFileName,
				  const QString &dstFileName,
				  const bool isNew,
				  const QDateTime &dateTime)
{
  ui.stackedWidget->setCurrentIndex(0);

  ddownloadwindowitem *item = new ddownloadwindowitem(ui.table);

  connect(this,
	  SIGNAL(iconsChanged(void)),
	  item,
	  SLOT(slotSetIcons(void)));
  connect(item,
	  SIGNAL(recordDownload(const QString &,
				const QUrl &,
				const QDateTime &)),
	  this,
	  SLOT(slotRecordDownload(const QString &,
				  const QUrl &,
				  const QDateTime &)));
  connect(item,
	  SIGNAL(downloadFinished(void)),
	  this,
	  SLOT(slotDownloadFinished(void)));
  item->downloadFile(srcFileName, dstFileName, isNew, dateTime);
  ui.table->insertRow(0);
  ui.table->setCellWidget(0, 0, item);
  ui.table->resizeRowToContents(0);
  slotTextChanged(ui.searchLineEdit->text().trimmed());
}

void ddownloadwindow::addUrlItem(const QUrl &url, const QString &dstFileName,
				 const bool isNew,
				 const QDateTime &dateTime,
				 const int choice)
{
  ui.stackedWidget->setCurrentIndex(0);

  ddownloadwindowitem *item = new ddownloadwindowitem(ui.table);

  connect(this,
	  SIGNAL(iconsChanged(void)),
	  item,
	  SLOT(slotSetIcons(void)));
  connect(item,
	  SIGNAL(recordDownload(const QString &,
				const QUrl &,
				const QDateTime &)),
	  this,
	  SLOT(slotRecordDownload(const QString &,
				  const QUrl &,
				  const QDateTime &)));
  connect(item,
	  SIGNAL(downloadFinished(void)),
	  this,
	  SLOT(slotDownloadFinished(void)));
  item->downloadUrl(url, dstFileName, isNew, dateTime,
		    choice);
  connect(item,
	  SIGNAL(authenticationRequired(QNetworkReply *,
					QAuthenticator *)),
	  this,
	  SLOT(slotAuthenticationRequired(QNetworkReply *,
					  QAuthenticator *)));
  connect(item,
	  SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &,
					     QAuthenticator *)),
	  this,
	  SLOT(slotProxyAuthenticationRequired(const QNetworkProxy &,
					       QAuthenticator *)));
  ui.table->insertRow(0);
  ui.table->setCellWidget(0, 0, item);
  ui.table->resizeRowToContents(0);
  slotTextChanged(ui.searchLineEdit->text().trimmed());
}

void ddownloadwindow::addHtmlItem(const QString &html,
				  const QString &dstFileName)
{
  ui.stackedWidget->setCurrentIndex(0);

  ddownloadwindowitem *item = new ddownloadwindowitem(ui.table);

  connect(this,
	  SIGNAL(iconsChanged(void)),
	  item,
	  SLOT(slotSetIcons(void)));
  connect(item,
	  SIGNAL(recordDownload(const QString &,
				const QUrl &,
				const QDateTime &)),
	  this,
	  SLOT(slotRecordDownload(const QString &,
				  const QUrl &,
				  const QDateTime &)));
  item->downloadHtml(html, dstFileName);
  ui.table->insertRow(0);
  ui.table->setCellWidget(0, 0, item);
  ui.table->resizeRowToContents(0);
  slotTextChanged(ui.searchLineEdit->text().trimmed());
}

void ddownloadwindow::slotClose(void)
{
  close();
}

void ddownloadwindow::closeEvent(QCloseEvent *event)
{
  saveState();
  QMainWindow::closeEvent(event);
}

void ddownloadwindow::show(void)
{
  if(!isVisible())
   {
     /*
     ** Don't annoy the user.
     */

     if(dooble::s_settings.contains("downloadWindow/geometry"))
       {
	 if(dmisc::isGnome())
	   setGeometry(dooble::s_settings.value("downloadWindow/geometry",
						QRect(100, 100, 800, 600)).
		       toRect());
	 else
	   {
	     QByteArray g(dooble::s_settings.value("downloadWindow/geometry").
			  toByteArray());

	     if(!restoreGeometry(g))
	       setGeometry(100, 100, 800, 600);
	   }
       }
     else
       setGeometry(100, 100, 800, 600);
   }

  showNormal();
  raise();

  if(ui.stackedWidget->currentIndex() == 1)
    ui.urlLineEdit->setFocus();
  else
    ui.closePushButton->setFocus();
}

bool ddownloadwindow::isActive(void) const
{
  for(int i = ui.table->rowCount() - 1; i >= 0; i--)
    {
      ddownloadwindowitem *item =
	qobject_cast<ddownloadwindowitem *> (ui.table->cellWidget(i, 0));

      if(item && item->isDownloading())
	return true;
    }

  return false;
}

void ddownloadwindow::slotClearList(void)
{
  if(dmisc::passphraseWasAuthenticated())
    {
      QStringList fileNames;

      for(int i = ui.table->rowCount() - 1; i >= 0; i--)
	if(!ui.table->isRowHidden(i))
	  {
	    ddownloadwindowitem *item = qobject_cast<ddownloadwindowitem *>
	      (ui.table->cellWidget(i, 0));

	    if(item && !item->isDownloading())
	      {
		fileNames.append(item->fileName());
		item->deleteLater();
		ui.table->removeRow(i);
	      }
	  }

      if(!fileNames.isEmpty())
	{
	  {
	    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE",
							"downloads");

	    db.setDatabaseName(dooble::s_homePath +
			       QDir::separator() + "downloads.db");

	    if(db.open())
	      {
		QSqlQuery query(db);

		if(query.exec("SELECT filename FROM downloads"))
		  while(query.next())
		    {
		      QString fileName
			(QString::fromUtf8
			 (dmisc::decodedString
			  (QByteArray::fromBase64(query.value(0).
						  toByteArray()))));

		      if(!fileNames.contains(fileName))
			continue;
		      else
			fileNames.removeOne(fileName);

		      QSqlQuery deleteQuery(db);

		      deleteQuery.exec("PRAGMA synchronous = OFF");
		      deleteQuery.prepare("DELETE FROM downloads WHERE "
					  "filename = ?");
		      deleteQuery.bindValue(0, query.value(0));
		      deleteQuery.exec();

		      if(fileNames.isEmpty())
			break;
		    }
	      }

	    db.close();
	  }

	  QSqlDatabase::removeDatabase("downloads");
	}
    }
  else
    {
      for(int i = ui.table->rowCount() - 1; i >= 0; i--)
	if(!ui.table->isRowHidden(i))
	  {
	    ddownloadwindowitem *item = qobject_cast<ddownloadwindowitem *>
	      (ui.table->cellWidget(i, 0));

	    if(item && !item->isDownloading())
	      {
		item->deleteLater();
		ui.table->removeRow(i);
	      }
	  }
    }
}

void ddownloadwindow::slotEnterUrl(void)
{
  ui.stackedWidget->setCurrentIndex(1);
  ui.urlLineEdit->setFocus();
}

void ddownloadwindow::slotCancelDownloadUrl(void)
{
  ui.stackedWidget->setCurrentIndex(0);
}

void ddownloadwindow::slotDownloadUrl(void)
{
  QUrl url(dmisc::correctedUrlPath(QUrl::fromUserInput(ui.
						       urlLineEdit->
						       text().trimmed())));

  if(url.isValid())
    {
      url = QUrl::fromEncoded(url.toEncoded(QUrl::StripTrailingSlash));
      emit saveUrl(url, 0);
    }
}

void ddownloadwindow::slotSetIcons(void)
{
  QSettings settings
    (dooble::s_settings.value("iconSet").toString(), QSettings::IniFormat);

  setWindowIcon
    (QIcon(settings.value("downloadWindow/windowIcon").toString()));
  ui.closePushButton->setIcon
    (QIcon(settings.value("cancelButtonIcon").toString()));
  ui.cancelPushButton->setIcon
    (QIcon(settings.value("cancelButtonIcon").toString()));
  ui.clearPushButton->setIcon
    (QIcon(settings.value("downloadWindow/clearListButtonIcon").toString()));
  ui.clearListPushButton->setIcon
    (QIcon(settings.value("downloadWindow/clearListButtonIcon").toString()));
  ui.downloadPushButton->setIcon
    (QIcon(settings.value("downloadWindow/downloadButtonIcon").toString()));
  ui.enterUrlPushButton->setIcon
    (QIcon(settings.value("downloadWindow/enterUrlButtonIcon").
	   toString()));
  emit iconsChanged();
}

void ddownloadwindow::slotClear(void)
{
  ui.urlLineEdit->clear();
  ui.urlLineEdit->setFocus();
}

void ddownloadwindow::createDownloadDatabase(void)
{
  if(!dooble::s_settings.value("settingsWindow/rememberDownloads",
			       true).toBool())
    return;

  {
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "downloads");

    db.setDatabaseName(dooble::s_homePath +
		       QDir::separator() + "downloads.db");

    if(db.open())
      {
	QSqlQuery query(db);

	query.exec("CREATE TABLE IF NOT EXISTS downloads ("
		   "filename TEXT PRIMARY KEY NOT NULL, "
		   "url TEXT NOT NULL, "
		   "download_started_date TEXT NOT NULL DEFAULT '')");
      }

    db.close();
  }

  QSqlDatabase::removeDatabase("downloads");
}

void ddownloadwindow::slotRecordDownload(const QString &fileName,
					 const QUrl &url,
					 const QDateTime &dateTime)
{
  if(!dooble::s_settings.value("settingsWindow/rememberDownloads",
			       true).toBool())
    ui.table->scrollToTop();

  if(!dmisc::passphraseWasAuthenticated())
    return;

  if(!dooble::s_settings.value("settingsWindow/rememberDownloads",
			       true).toBool())
    return;

  createDownloadDatabase();

  {
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "downloads");

    db.setDatabaseName(dooble::s_homePath +
		       QDir::separator() + "downloads.db");

    if(db.open())
      {
	QSqlQuery query(db);

	if(query.exec("SELECT filename FROM downloads"))
	  while(query.next())
	    {
	      QString l_fileName
		(QString::fromUtf8
		 (dmisc::decodedString
		  (QByteArray::fromBase64(query.value(0).
					  toByteArray()))));

	      if(fileName != l_fileName)
		continue;

	      QSqlQuery deleteQuery(db);

	      deleteQuery.exec("PRAGMA synchronous = OFF");
	      deleteQuery.prepare("DELETE FROM downloads WHERE "
				  "filename = ?");
	      deleteQuery.bindValue(0, query.value(0));
	      deleteQuery.exec();
	      break;
	    }

	query.exec("PRAGMA synchronous = OFF");
	query.prepare
	  ("INSERT OR REPLACE INTO downloads "
	   "(filename, url, download_started_date) "
	   "VALUES (?, ?, ?)");
	query.bindValue
	  (0,
	   dmisc::encodedString(fileName.toUtf8(),
				true).toBase64());
	query.bindValue
	  (1,
	   dmisc::encodedString
	   (url.toEncoded(QUrl::StripTrailingSlash), true).toBase64());
	query.bindValue
	  (2,
	   dmisc::encodedString(dateTime.toString(Qt::ISODate).
				toUtf8(), true).toBase64());
	query.exec();
      }

    db.close();
  }

  QSqlDatabase::removeDatabase("downloads");
}

void ddownloadwindow::saveState(void)
{
  /*
  ** geometry() may return (0, 0) coordinates if the window is
  ** not visible.
  */

  if(!isVisible())
    return;

  if(dmisc::isGnome())
    dooble::s_settings["downloadWindow/geometry"] = geometry();
  else
    dooble::s_settings["downloadWindow/geometry"] = saveGeometry();

  QSettings settings;

  if(dmisc::isGnome())
    settings.setValue("downloadWindow/geometry", geometry());
  else
    settings.setValue("downloadWindow/geometry", saveGeometry());
}

void ddownloadwindow::slotDownloadFinished(void)
{
  ddownloadwindowitem *item = qobject_cast<ddownloadwindowitem *> (sender());

  if(!item)
    return;

  if(item->choice() == 2)
    {
      /*
      ** Open the file, if we can.
      */

      QString action("");
      QString suffix(QFileInfo(item->fileName()).suffix().trimmed());

      if(dooble::s_applicationsActions.contains(suffix))
	{
	  action = dooble::s_applicationsActions[suffix];
	  dmisc::launchApplication(action, QStringList(item->fileName()));
	}
    }

  if(!dooble::s_settings.value("settingsWindow/closeDownloads",
			       false).toBool())
    return;

  if(item && item->abortedByUser())
    /*
    ** If the item that emitted the downloadFinished() signal did so because
    ** of user interaction, the Downloads window should not be closed.
    ** Note, if the user aborts a download and another download completes
    ** within some minute amount of time, the Downloads window will be closed.
    */

    return;

  foreach(ddownloadwindowitem *item, findChildren<ddownloadwindowitem *> ())
    if(item->isDownloading())
      return;

  close();
}

void ddownloadwindow::keyPressEvent(QKeyEvent *event)
{
  if(event && event->key() == Qt::Key_Escape)
    close();
  else if(event &&
	  event->key() == Qt::Key_F &&
	  event->modifiers() == Qt::ControlModifier)
    {
      ui.searchLineEdit->setFocus();
      ui.searchLineEdit->selectAll();
    }
  else if(event && event->key() == Qt::Key_Delete &&
	  ui.stackedWidget->currentIndex() == 0 &&
	  ui.table->currentRow() > -1)
    {
      ddownloadwindowitem *item = qobject_cast<ddownloadwindowitem *>
	(ui.table->cellWidget(ui.table->currentRow(), 0));

      if(item && !item->isDownloading() &&
	 !ui.table->isRowHidden(ui.table->currentRow()))
	{
	  QString l_fileName(item->fileName());

	  ui.table->removeRow(ui.table->currentRow());
	  item->deleteLater();

	  if(dmisc::passphraseWasAuthenticated())
	    {
	      {
		QSqlDatabase db = QSqlDatabase::addDatabase
		  ("QSQLITE", "downloads");

		db.setDatabaseName(dooble::s_homePath +
				   QDir::separator() + "downloads.db");

		if(db.open())
		  {
		    QSqlQuery query(db);

		    if(query.exec("SELECT filename FROM downloads"))
		      while(query.next())
			{
			  QString fileName
			    (QString::fromUtf8
			     (dmisc::decodedString
			      (QByteArray::fromBase64(query.value(0).
						      toByteArray()))));

			  if(fileName != l_fileName)
			    continue;

			  QSqlQuery deleteQuery(db);

			  deleteQuery.exec("PRAGMA synchronous = OFF");
			  deleteQuery.prepare("DELETE FROM downloads WHERE "
					      "filename = ?");
			  deleteQuery.bindValue(0, query.value(0));
			  deleteQuery.exec();
			  break;
			}
		  }

		db.close();
	      }

	      QSqlDatabase::removeDatabase("downloads");
	    }
	}
    }

  QMainWindow::keyPressEvent(event);
}

void ddownloadwindow::slotTextChanged(const QString &text)
{
  /*
  ** Search text changed.
  */

  for(int i = 0; i < ui.table->rowCount(); i++)
    {
      ddownloadwindowitem *item =
	qobject_cast<ddownloadwindowitem *> (ui.table->cellWidget(i, 0));

      if(item)
	{
	  if(item->text().toLower().contains(text.toLower().trimmed()))
	    ui.table->showRow(i);
	  else
	    ui.table->hideRow(i);
	}
      else
	ui.table->hideRow(i);
    }
}

void ddownloadwindow::reencode(QProgressBar *progress)
{
  if(!dmisc::passphraseWasAuthenticated())
    return;

  /*
  ** This method assumes that the respective container
  ** is as current as possible. It will use the container's
  ** contents to create new database.
  ** Obsolete data will be deleted via the purge method.
  */

  purge();

  if(progress)
    {
      progress->setMaximum(ui.table->rowCount());
      progress->setVisible(true);
    }

  for(int i = ui.table->rowCount() - 1, j = 1; i >= 0; i--, j++)
    {
      ddownloadwindowitem *item =
	qobject_cast<ddownloadwindowitem *> (ui.table->cellWidget(i, 0));

      if(item)
	slotRecordDownload(item->fileName(),
			   item->url(),
			   item->dateTime());

      if(progress)
	progress->setValue(j);
    }

  if(progress)
    progress->setVisible(false);
}

void ddownloadwindow::slotAuthenticationRequired
(QNetworkReply *reply, QAuthenticator *authenticator)
{
  if(!reply || !authenticator)
    return;

  QDialog dialog(this);
  Ui_passwordDialog ui_p;

  ui_p.setupUi(&dialog);
#ifdef Q_WS_MAC
  dialog.setAttribute(Qt::WA_MacMetalStyle, false);
#endif
  ui_p.messageLabel->setText
    (QString(tr("The site %1 is requesting "
		"credentials.").
	     arg(reply->url().
		 toString(QUrl::RemovePath | QUrl::StripTrailingSlash))));

  QSettings settings(dooble::s_settings.value("iconSet").toString(),
		     QSettings::IniFormat);

  dialog.setWindowIcon
    (QIcon(settings.value("mainWindow/windowIcon").toString()));

  for(int i = 0; i < ui_p.buttonBox->buttons().size(); i++)
    if(ui_p.buttonBox->buttonRole(ui_p.buttonBox->buttons().at(i)) ==
       QDialogButtonBox::YesRole)
      {
	if(qobject_cast<QPushButton *> (ui_p.buttonBox->buttons().at(i)))
	  qobject_cast<QPushButton *> (ui_p.buttonBox->buttons().at(i))->
	    setDefault(true);

	ui_p.buttonBox->buttons().at(i)->setIcon
	  (QIcon(settings.value("okButtonIcon").toString()));
	ui_p.buttonBox->buttons().at(i)->setIconSize(QSize(16, 16));
      }
    else
      {
	if(qobject_cast<QPushButton *> (ui_p.buttonBox->buttons().at(i)))
	  qobject_cast<QPushButton *> (ui_p.buttonBox->buttons().at(i))->
	    setDefault(false);

	ui_p.buttonBox->buttons().at(i)->setIcon
	  (QIcon(settings.value("cancelButtonIcon").toString()));
	ui_p.buttonBox->buttons().at(i)->setIconSize(QSize(16, 16));
      }

  if(dialog.exec() == QDialog::Accepted)
    {
      authenticator->setUser(ui_p.usernameLineEdit->text());
      authenticator->setPassword(ui_p.passwordLineEdit->text());
    }
}

void ddownloadwindow::slotProxyAuthenticationRequired
(const QNetworkProxy &proxy, QAuthenticator *authenticator)
{
  if(!authenticator)
    return;

  Q_UNUSED(proxy);
  QDialog dialog(this);
  Ui_passwordDialog ui_p;

  ui_p.setupUi(&dialog);
#ifdef Q_WS_MAC
  dialog.setAttribute(Qt::WA_MacMetalStyle, false);
#endif
  ui_p.messageLabel->setText
    (QString(tr("The proxy %1:%2 is requesting "
		"credentials.").
	     arg(proxy.hostName()).
	     arg(proxy.port())));

  QSettings settings(dooble::s_settings.value("iconSet").toString(),
		     QSettings::IniFormat);

  dialog.setWindowIcon
    (QIcon(settings.value("mainWindow/windowIcon").toString()));

  for(int i = 0; i < ui_p.buttonBox->buttons().size(); i++)
    if(ui_p.buttonBox->buttonRole(ui_p.buttonBox->buttons().at(i)) ==
       QDialogButtonBox::YesRole)
      {
	if(qobject_cast<QPushButton *> (ui_p.buttonBox->buttons().at(i)))
	  qobject_cast<QPushButton *> (ui_p.buttonBox->buttons().at(i))->
	    setDefault(true);

	ui_p.buttonBox->buttons().at(i)->setIcon
	  (QIcon(settings.value("okButtonIcon").toString()));
	ui_p.buttonBox->buttons().at(i)->setIconSize(QSize(16, 16));
      }
    else
      {
	if(qobject_cast<QPushButton *> (ui_p.buttonBox->buttons().at(i)))
	  qobject_cast<QPushButton *> (ui_p.buttonBox->buttons().at(i))->
	    setDefault(false);

	ui_p.buttonBox->buttons().at(i)->setIcon
	  (QIcon(settings.value("cancelButtonIcon").toString()));
	ui_p.buttonBox->buttons().at(i)->setIconSize(QSize(16, 16));
      }

  if(dialog.exec() == QDialog::Accepted)
    {
      authenticator->setUser(ui_p.usernameLineEdit->text());
      authenticator->setPassword(ui_p.passwordLineEdit->text());
    }
}

void ddownloadwindow::slotCellDoubleClicked(int row, int col)
{
  ddownloadwindowitem *item = qobject_cast<ddownloadwindowitem *>
    (ui.table->cellWidget(row, col));

  if(item && !item->isDownloading())
    {
      QFileInfo fileInfo(item->fileName());

      if(!fileInfo.isReadable())
	{
	  QMessageBox mb(this);

#ifdef Q_WS_MAC
	  mb.setAttribute(Qt::WA_MacMetalStyle, false);
#endif
	  mb.setIcon(QMessageBox::Information);
	  mb.setWindowTitle(tr("Dooble Web Browser: Information"));
	  mb.setStandardButtons(QMessageBox::Ok);
	  mb.setText(QString(tr("The file %1 is not accessible.").
			     arg(item->fileName())));

	  QSettings settings(dooble::s_settings.value("iconSet").toString(),
			     QSettings::IniFormat);

	  for(int i = 0; i < mb.buttons().size(); i++)
	    if(mb.buttonRole(mb.buttons().at(i)) == QMessageBox::AcceptRole)
	      {
		mb.buttons().at(i)->setIcon
		  (QIcon(settings.value("okButtonIcon").toString()));
		mb.buttons().at(i)->setIconSize(QSize(16, 16));
	      }

	  mb.setWindowIcon
	    (QIcon(settings.value("mainWindow/windowIcon").toString()));
	  mb.exec();
	}
      else
	{
	  ddownloadprompt dialog(this, item->fileName(),
				 ddownloadprompt::SingleChoice);

	  if(dialog.exec() != QDialog::Rejected)
	    {
	      QString action("");
	      QString suffix(QFileInfo(item->fileName()).suffix().trimmed());

	      if(dooble::s_applicationsActions.contains(suffix))
		{
		  action = dooble::s_applicationsActions[suffix];
		  dmisc::launchApplication
		    (action, QStringList(item->fileName()));
		}
	    }
	}
    }
}

void ddownloadwindow::clear(void)
{
  for(int i = ui.table->rowCount() - 1; i >= 0; i--)
    {
      ddownloadwindowitem *item = qobject_cast<ddownloadwindowitem *>
	(ui.table->cellWidget(i, 0));

      if(item && !item->isDownloading())
	{
	  item->deleteLater();
	  ui.table->removeRow(i);
	}
    }

  if(dmisc::passphraseWasAuthenticated())
    purge();
}
