/****************************************************************************
** Dooble - The Secure Internet Web Browser
**
** Copyright (c) 2008, 2009, 2010, 2011 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 <QBuffer>
#include <QPrinter>
#include <QProcess>
#include <QLineEdit>
#ifdef Q_WS_MAC
#include <QMacStyle>
#elif defined Q_WS_WIN
#include <QWindowsStyle>
#endif
#include <QSettings>
#include <QSplitter>
#include <QSqlQuery>
#include <QWebFrame>
#include <QClipboard>
#include <QFileDialog>
#include <QMessageBox>
#include <QTranslator>
#include <QApplication>
#include <QPrintDialog>
#include <QSqlDatabase>
#include <QNetworkReply>
#include <QAuthenticator>
#include <QDesktopWidget>
#include <QDesktopServices>
#include <QPrintPreviewDialog>

#include "dmisc.h"
#include "dooble.h"
#include "dcookies.h"
#include "dhistory.h"
#include "dsettings.h"
#include "dpagesourcewindow.h"
#include "ui_passwordPrompt.h"

/*
** Global objects.
*/

dcookies *dooble::s_cookies = 0;
dcookiewindow *dooble::s_cookieWindow = 0;
QHash<QString, QVariant> dooble::s_settings;

/*
** Static (local) objects.
*/

static int doobleCounter = 0;
static dhistory *historyWindow = 0;
static dsettings *settingsWindow = 0;
static ddownloadwindow *downloadWindow = 0;

int main(int argc, char *argv[])
{
  QApplication qapp(argc, argv);

  /*
  ** Set the style.
  */

#ifdef Q_WS_MAC
  QApplication::setStyle(new QMacStyle());
#elif defined Q_WS_WIN
  QApplication::setStyle(new QWindowsStyle());
#endif

  /*
  ** Configure translations.
  */

  QTranslator qtTranslator;

  qtTranslator.load("qt_" + QLocale::system().name(), "translations");
  qapp.installTranslator(&qtTranslator);

  QTranslator myappTranslator;

  myappTranslator.load("dooble_" + QLocale::system().name(),
		       "translations");
  qapp.installTranslator(&myappTranslator);

  QDir homeDir(QDir::home());

  homeDir.mkdir(".dooble");

  /*
  ** Disable Web page icons.
  */

  QWebSettings::setIconDatabasePath("");

  /*
  ** Set application attributes.
  */

  QCoreApplication::setApplicationName("Dooble");
  QCoreApplication::setOrganizationName("Dooble");
  QCoreApplication::setOrganizationDomain("dooble.sf.net");
  QSettings::setPath(QSettings::IniFormat,
		     QSettings::UserScope,
		     QDir::homePath() + QDir::separator() + ".dooble");
  QSettings::setDefaultFormat(QSettings::IniFormat);

  /*
  ** Remove old configuration settings.
  */

  QSettings settings;

  settings.remove("mainWindow/pos");
  settings.remove("mainWindow/size");
  settings.remove("mainWindow/searchWidth");
  settings.remove("mainWindow/locationWidth");
  settings.remove("cookieWindow");
  settings.remove("cookiesWindow/size");
  settings.remove("historyWindow/size");
  settings.remove("downloadWindow/pos");
  settings.remove("downloadWindow/size");
  settings.remove("settingsWindow/size");
  settings.remove("settingsWindow/saveHistory");
  settings.remove("settingsWindow/ftpProxyType");
  settings.remove("settingsWindow/ftpProxyUser");
  settings.remove("settingsWindow/privateBrowsing");
  settings.remove("settingsWindow/ftpProxyPassword");
  settings.remove("settingsWindow/browsingProxyEnabled");
  settings.remove("settingsWindow/downloadProxyEnabled");
  settings.remove("settingsWindow/saveHistoryCheckedId");

  QList<QString> list(settings.allKeys());
  QMutableListIterator<QString> it(list);

  while(it.hasNext())
    if(it.next().startsWith("settingsWindow/backgroundImage"))
      settings.remove(it.value());

  list.clear();

  /*
  ** We need to set this before creating some of the support windows.
  */

  if(!settings.contains("iconSet"))
    settings.setValue("iconSet",
		      QString("%1/%2").arg(QDir::currentPath()).
		      arg("Icons/nuovext/configuration.cfg"));

  if(!QFileInfo(settings.value("iconSet").toString()).exists())
    settings.setValue("iconSet",
		      QString("%1/%2").arg(QDir::currentPath()).
		      arg("Icons/nuovext/configuration.cfg"));

  if(!settings.contains("settingsWindow/iconSet1"))
    settings.setValue("settingsWindow/iconSet1", settings.value("iconSet"));

  if(!QFileInfo(settings.value("settingsWindow/iconSet1").toString()).exists())
    settings.setValue("settingsWindow/iconSet1",
		      QString("%1/%2").arg(QDir::currentPath()).
		      arg("Icons/nuovext/configuration.cfg"));

  dooble::s_settings.clear();

  for(int i = 0; i < settings.allKeys().size(); i++)
    dooble::s_settings[settings.allKeys().at(i)] =
      settings.value(settings.allKeys().at(i));

  /*
  ** QWebSettings changes have to be performed after dooble::s_settings
  ** gets populated!
  */

  QWebSettings::globalSettings()->setAttribute
    (QWebSettings::JavaEnabled,
     dooble::s_settings.value("settingsWindow/javaEnabled", false).toBool());
  QWebSettings::globalSettings()->setAttribute
    (QWebSettings::JavascriptEnabled,
     dooble::s_settings.value("settingsWindow/javascriptEnabled",
			      true).toBool());
  QWebSettings::globalSettings()->setAttribute
    (QWebSettings::JavascriptCanOpenWindows,
     dooble::s_settings.value("settingsWindow/javascriptEnabled",
			      true).toBool() &&
     dooble::s_settings.value("settingsWindow/javascriptAllowNewWindows",
			      false).toBool());
  QWebSettings::globalSettings()->setAttribute
    (QWebSettings::AutoLoadImages,
     dooble::s_settings.value("settingsWindow/automaticallyLoadImages",
			      true).toBool());
  QWebSettings::globalSettings()->setAttribute
    (QWebSettings::QWebSettings::PluginsEnabled,
     dooble::s_settings.value("settingsWindow/enablePlugins", true).toBool());
  QWebSettings::globalSettings()->setAttribute
    (QWebSettings::DnsPrefetchEnabled, true);
  QWebSettings::globalSettings()->setAttribute
    (QWebSettings::PrivateBrowsingEnabled, true);
  QWebSettings::globalSettings()->setAttribute
    (QWebSettings::SpatialNavigationEnabled,
     dooble::s_settings.value("settingsWindow/spatialNavigation",
			      false).toBool());

  QFont font;

  if(!font.fromString
     (dooble::s_settings.value("settingsWindow/standardWebFont", "").
      toString()) || font.family().isEmpty())
#ifdef Q_WS_MAC
    font = QFont("Times", 16);
#elif defined Q_WS_WIN
    font = QFont("Serif", 16);
#else
    font = QFont("Serif", 16);
#endif

  font.setWeight(QFont::Normal);
  QWebSettings::globalSettings()->setFontFamily
    (QWebSettings::StandardFont, font.family());
  QWebSettings::globalSettings()->setFontSize
    (QWebSettings::DefaultFontSize, font.pointSize());

  if(!font.fromString(dooble::s_settings.value
		      ("settingsWindow/cursiveWebFont", "").
		      toString()) || font.family().isEmpty())
    font = QFont("Serif");

  font.setWeight(QFont::Normal);
  QWebSettings::globalSettings()->setFontFamily
    (QWebSettings::CursiveFont,
     font.family());

  if(!font.fromString(dooble::s_settings.value
		      ("settingsWindow/fantasyWebFont", "").
		      toString()) || font.family().isEmpty())
    font = QFont("Serif");

  font.setWeight(QFont::Normal);
  QWebSettings::globalSettings()->setFontFamily
    (QWebSettings::FantasyFont,
     font.family());

  if(!font.fromString(dooble::s_settings.value
		      ("settingsWindow/fixedWebFont", "").
		      toString()) || font.family().isEmpty())
#ifdef Q_WS_MAC
    font = QFont("Courier", 13);
#elif defined Q_WS_WIN
    font = QFont("Courier New", 16);
#else
    font = QFont("Courier", 10);
#endif

  font.setWeight(QFont::Normal);
  QWebSettings::globalSettings()->setFontFamily
    (QWebSettings::FixedFont,
     font.family());
  QWebSettings::globalSettings()->setFontSize
    (QWebSettings::DefaultFixedFontSize,
     font.pointSize());

  if(!font.fromString(dooble::s_settings.value
		      ("settingsWindow/sansSerifWebFont", "").
		      toString()) || font.family().isEmpty())
#ifdef Q_WS_MAC
    font = QFont("Helvetica");
#elif defined Q_WS_WIN
    font = QFont("Arial");
#else
    font = QFont("Sans Serif");
#endif

  font.setWeight(QFont::Normal);
  QWebSettings::globalSettings()->setFontFamily
    (QWebSettings::SansSerifFont,
     font.family());

  if(!font.fromString(dooble::s_settings.value
		      ("settingsWindow/serifWebFont", "").
		      toString()) || font.family().isEmpty())
#ifdef Q_WS_MAC
    font = QFont("Times");
#elif defined Q_WS_WIN
    font = QFont("Times New Roman");
#else
    font = QFont("Serif");
#endif

  font.setWeight(QFont::Normal);
  QWebSettings::globalSettings()->setFontFamily
    (QWebSettings::SerifFont,
     font.family());
  QWebSettings::globalSettings()->setFontSize
    (QWebSettings::MinimumFontSize,
     dooble::s_settings.value("settingsWindow/minimumWebFontSize",
			      9).toInt());

  /*
  ** Initialize static members.
  */

  dfilemanager::treeModel = new QFileSystemModel();
  dfilemanager::tableModel = new dfilesystemmodel();
  dfilemanager::treeModel->setReadOnly(false);
  dfilemanager::tableModel->setReadOnly(false);
  dfilemanager::treeModel->setFilter(QDir::Drives | QDir::AllDirs |
				     QDir::System |
				     QDir::NoDotAndDotDot);
  dfilemanager::treeModel->setRootPath(QDir::rootPath());
  dfilemanager::tableModel->setFilter(QDir::Hidden | QDir::AllEntries |
			       QDir::System | QDir::NoDotAndDotDot);
  dfilemanager::tableModel->setRootPath(QDir::rootPath());

  if(dooble::s_settings.value("mainWindow/showHiddenFiles", true).toBool())
    {
      dfilemanager::treeModel->setFilter
	(dfilemanager::treeModel->filter() | QDir::Hidden);
      dfilemanager::tableModel->setFilter
	(dfilemanager::tableModel->filter() | QDir::Hidden);
    }

  /*
  ** Create singular instances.
  */

  if(!font.fromString(dooble::s_settings.value("settingsWindow/globalFont",
					       "").
		      toString()) || font.family().isEmpty())
#ifdef Q_WS_MAC
    font = QFont("Times", 12);
#elif defined Q_WS_WIN
    font = QFont("Arial", 12);
#else
    font = QFont("Serif", 9);
#endif

  font.setWeight(QFont::Normal);
  QApplication::setFont(font);
  historyWindow = new dhistory();
  downloadWindow = new ddownloadwindow();
  settingsWindow = new dsettings();
  dooble::s_cookies = new dcookies();
  dooble::s_cookieWindow = new dcookiewindow();
  QObject::connect(dooble::s_cookies,
		   SIGNAL(cookiesChanged(const QList<QNetworkCookie> &)),
		   dooble::s_cookieWindow,
		   SLOT(slotPopulate(const QList<QNetworkCookie> &)));
  QObject::connect(dooble::s_cookies,
		   SIGNAL(domainsRemoved(const QStringList &)),
		   dooble::s_cookieWindow,
		   SLOT(slotDomainsRemoved(const QStringList &)));
  QObject::connect(dooble::s_cookies,
		   SIGNAL(cookiesChangedForUrl(const
					       QList<QNetworkCookie> &,
					       const QUrl &)),
		   dooble::s_cookieWindow,
		   SLOT(slotUpdateView(const
				       QList<QNetworkCookie> &,
				       const QUrl &)));
  QObject::connect(settingsWindow,
		   SIGNAL(cookieTimerChanged(void)),
		   dooble::s_cookies,
		   SLOT(slotCookieTimerChanged(void)));
  dooble::s_cookies->populate();

  dooble *dbl = 0;
  QString urlText
    (dooble::s_settings.value("settingsWindow/url12").toString());

  if(argc > 1)
    {
      if(QFile(argv[1]).exists() && QFileInfo(argv[1]).isReadable())
	dbl = new dooble(QUrl::fromLocalFile(argv[1]));
      else
	dbl = new dooble(QUrl::fromUserInput(argv[1]));
    }
  else
    dbl = new dooble(urlText);

  qapp.connect(&qapp, SIGNAL(lastWindowClosed(void)), dbl,
	       SLOT(slotQuit(void)));
  return qapp.exec();
}

void dooble::init(const bool isJavaScriptWindow)
{
  /*
  ** This method is used whenever a new Dooble window
  ** is about to be created.
  */

  m_isJavaScriptWindow = isJavaScriptWindow;
  m_lastReplacedHistoryPosition = 3;
  showFindFrame = false;
  doobleCounter += 1;
  ui.setupUi(this);
#ifdef Q_WS_MAC
  setAttribute(Qt::WA_MacMetalStyle, true);
#endif
  ui.urlFrame->setParent(0);
  ui.toolBar->setVisible(false);
  ui.toolBar->addWidget(ui.urlFrame);
  ui.toolBar->setVisible(true);
#ifdef Q_WS_MAC
  ui.actionFull_Screen_Mode->setShortcut
    (QKeySequence(Qt::ControlModifier + Qt::Key_F11));
#endif
  ui.marker->setVisible(false);
  ui.restoreToolButton->setVisible(false);
  sbWidget = new QWidget(this);
  desktopWidget = new ddesktopwidget(this);
  connect(desktopWidget,
	  SIGNAL(viewEntered(void)),
	  this,
	  SLOT(slotViewEntered(void)));
  sb.setupUi(sbWidget);
  sb.progressBar->setVisible(false);
  sb.statusLabel->setVisible(true);
  ui.findFrame->setVisible(false);
  ui.backToolButton->setMenu(new QMenu(this));
  ui.forwardToolButton->setMenu(new QMenu(this));
  connect(this,
	  SIGNAL(iconsChanged(void)),
	  historyWindow,
	  SLOT(slotSetIcons(void)));
  connect(this,
	  SIGNAL(iconsChanged(void)),
	  downloadWindow,
	  SLOT(slotSetIcons(void)));
  connect(this,
	  SIGNAL(iconsChanged(void)),
	  s_cookieWindow,
	  SLOT(slotSetIcons(void)));
  connect(settingsWindow,
	  SIGNAL(fontChanged(const QFont &)),
	  this,
	  SLOT(slotFontChanged(const QFont &)));
  connect(settingsWindow,
	  SIGNAL(iconsChanged(void)),
	  this,
	  SLOT(slotSetIcons(void)));
  connect(settingsWindow,
	  SIGNAL(showTabBar(const bool)),
	  this,
	  SLOT(slotSetTabBarVisible(const bool)));
  connect(this,
	  SIGNAL(iconsChanged(void)),
	  ui.searchLineEdit,
	  SLOT(slotSetIcons(void)));
  connect(this,
	  SIGNAL(iconsChanged(void)),
	  ui.locationLineEdit,
	  SLOT(slotSetIcons(void)));
  connect(this,
	  SIGNAL(iconsChanged(void)),
	  ui.tabWidget,
	  SLOT(slotSetIcons(void)));
  connect(ui.splitter,
	  SIGNAL(splitterMoved(int, int)),
	  this,
	  SLOT(slotLocationSplitterMoved(int, int)));
  connect(ui.locationLineEdit,
	  SIGNAL(loadPage(const QUrl &)),
	  this,
	  SLOT(slotLoadPage(const QUrl &)));
  connect(desktopWidget,
	  SIGNAL(backgroundImageChanged(void)),
	  this,
	  SLOT(slotChangeDesktopBackgrounds(void)));
  connect(downloadWindow, SIGNAL(saveUrl(const QUrl &)), this,
	  SLOT(slotSaveUrl(const QUrl &)));
  connect(ui.tabWidget, SIGNAL(currentChanged(int)), this,
	  SLOT(slotTabSelected(int)));
  connect(ui.actionNew_Tab, SIGNAL(triggered(void)), this,
	  SLOT(slotNewTab(void)));
  connect(ui.tabWidget, SIGNAL(createTab(void)), this,
	  SLOT(slotNewTab(void)));
  connect(ui.tabWidget, SIGNAL(openInNewWindow(const int)), this,
	  SLOT(slotOpenPageInNewWindow(const int)));
  connect(ui.actionNew_Window, SIGNAL(triggered(void)), this,
	  SLOT(slotNewWindow(void)));
  connect(ui.actionOpen_URL, SIGNAL(triggered(void)), this,
	  SLOT(slotOpenUrl(void)));
  connect(ui.actionClose_Tab, SIGNAL(triggered(void)), this,
	  SLOT(slotCloseTab(void)));
  connect(ui.tabWidget, SIGNAL(closeTab(const int)), this,
	  SLOT(slotCloseTab(const int)));
  connect(ui.tabWidget, SIGNAL(tabMoved(int, int)), this,
	  SLOT(slotTabMoved(int, int)));
  connect(ui.actionClose_Window, SIGNAL(triggered(void)), this,
	  SLOT(slotClose(void)));
  connect(ui.actionQuit, SIGNAL(triggered(void)), this,
	  SLOT(slotQuit(void)));
  connect(ui.locationLineEdit->goButton(), SIGNAL(clicked(void)),
	  this, SLOT(slotLoadPage(void)));
  connect(ui.locationLineEdit, SIGNAL(textEdited(const QString &)),
	  this, SLOT(slotTextChanged(const QString &)));
  connect(ui.locationLineEdit, SIGNAL(returnPressed(void)), this,
	  SLOT(slotLoadPage(void)));
  connect(ui.locationLineEdit, SIGNAL(selectionChanged(void)),
	  this, SLOT(slotSelectionChanged(void)));
  connect(ui.locationLineEdit, SIGNAL(openLinkInNewTab(const QUrl &)), this,
	  SLOT(slotOpenLinkInNewTab(const QUrl &)));
  connect(ui.locationLineEdit, SIGNAL(resetUrl(void)), this,
	  SLOT(slotResetUrl(void)));
  connect(ui.backToolButton, SIGNAL(clicked(void)), this,
	  SLOT(slotBack(void)));
  connect(ui.forwardToolButton, SIGNAL(clicked(void)), this,
	  SLOT(slotForward(void)));
  connect(ui.reloadToolButton, SIGNAL(clicked(void)), this,
	  SLOT(slotReload(void)));
  connect(ui.actionReload, SIGNAL(triggered(void)), this,
	  SLOT(slotReload(void)));
  connect(ui.stopToolButton, SIGNAL(clicked(void)), this,
	  SLOT(slotStop(void)));
  connect(ui.actionStop, SIGNAL(triggered(void)), this,
	  SLOT(slotStop(void)));
  connect(ui.homeToolButton, SIGNAL(clicked(void)), this,
	  SLOT(slotGoHome(void)));
  connect(ui.searchLineEdit, SIGNAL(returnPressed(void)), this,
	  SLOT(slotSearch(void)));
  connect(ui.searchLineEdit->findButton(), SIGNAL(clicked(void)), this,
	  SLOT(slotSearch(void)));
  connect(ui.searchLineEdit, SIGNAL(selectionChanged(void)),
	  this, SLOT(slotSelectionChanged(void)));
  connect(ui.actionAbout_Dooble, SIGNAL(triggered(void)), this,
	  SLOT(slotAbout(void)));
  connect(ui.actionSave_Page, SIGNAL(triggered(void)), this,
	  SLOT(slotSavePage(void)));
  connect(ui.actionDownloads, SIGNAL(triggered(void)), this,
	  SLOT(slotDisplayDownloadWindow(void)));
  connect(ui.actionFind, SIGNAL(triggered(void)), this,
	  SLOT(slotShowFind(void)));
  connect(ui.actionPrint, SIGNAL(triggered(void)), this,
	  SLOT(slotPrint(void)));
  connect(ui.actionPrint_Preview, SIGNAL(triggered(void)), this,
	  SLOT(slotPrintPreview(void)));
  connect(ui.actionPage_Source, SIGNAL(triggered(void)), this,
	  SLOT(slotShowPageSource(void)));
  connect(ui.actionSettings, SIGNAL(triggered(void)), this,
	  SLOT(slotShowSettingsWindow(void)));
  connect(ui.hideFindToolButton, SIGNAL(clicked(void)), this,
	  SLOT(slotHideFind(void)));
  connect(ui.findLineEdit, SIGNAL(returnPressed(void)), this,
	  SLOT(slotFind(void)));
  connect(ui.findLineEdit, SIGNAL(textEdited(const QString &)), this,
	  SLOT(slotFind(void)));
  connect(ui.findLineEdit, SIGNAL(returnPressed(void)), this,
	  SLOT(slotFindNext(void)));
  connect(ui.findLineEdit, SIGNAL(textEdited(const QString &)), this,
	  SLOT(slotFindNext(void)));
  connect(ui.highlightAllCheckBox, SIGNAL(clicked(bool)), this,
	  SLOT(slotFind(void)));
  connect(ui.nextToolButton, SIGNAL(clicked(void)), this,
	  SLOT(slotFindNext(void)));
  connect(ui.previousToolButton, SIGNAL(clicked(void)), this,
	  SLOT(slotFindPrevious(void)));
  connect(ui.desktopToolButton, SIGNAL(clicked(void)), this,
	  SLOT(slotShowDesktopTab(void)));
  connect(ui.actionStatusbar, SIGNAL(triggered(void)), this,
	  SLOT(slotStatusBarDisplay(void)));
  connect(ui.actionShow_Hidden_Files, SIGNAL(triggered(void)), this,
	  SLOT(slotShowHiddenFiles(void)));
  connect(ui.actionOpen_Directory, SIGNAL(triggered(void)), this,
	  SLOT(slotOpenDirectory(void)));
  connect(ui.actionZoom_In, SIGNAL(triggered(void)), this,
	  SLOT(slotViewZoomIn(void)));
  connect(ui.actionZoom_Out, SIGNAL(triggered(void)), this,
	  SLOT(slotViewZoomOut(void)));
  connect(ui.actionReset_Zoom, SIGNAL(triggered(void)), this,
	  SLOT(slotViewResetZoom(void)));
  connect(ui.actionZoom_Text_Only, SIGNAL(toggled(bool)), this,
	  SLOT(slotViewZoomTextOnly(bool)));
  connect(ui.actionMy_Retrieved_Files, SIGNAL(triggered(void)), this,
	  SLOT(slotOpenMyRetrievedFiles(void)));
  connect(ui.actionCopy, SIGNAL(triggered(void)), this,
	  SLOT(slotCopy(void)));
  connect(ui.actionPaste, SIGNAL(triggered(void)), this,
	  SLOT(slotPaste(void)));
  connect(ui.actionSelect_All_Content, SIGNAL(triggered(void)), this,
	  SLOT(slotSelectAllContent(void)));
  connect(ui.actionFull_Screen_Mode, SIGNAL(triggered(void)), this,
	  SLOT(slotFullScreenMode(void)));
  connect(ui.actionApplication_Cookies, SIGNAL(triggered(void)), this,
	  SLOT(slotShowApplicationCookies(void)));
  connect(ui.marker, SIGNAL(markerEntered(void)), this,
	  SLOT(slotMarkerEntered(void)));
  connect(ui.restoreToolButton, SIGNAL(clicked(void)),
	  this, SLOT(slotFullScreenMode(void)));
  ui.actionZoom_Text_Only->setCheckable(true);
  ui.actionZoom_Text_Only->setChecked(false);
  ui.viewMenu->insertSeparator(ui.zoomMenu->menuAction());

  if(ui.historyMenu->actions().isEmpty())
    {
      QSettings settings
	(dooble::s_settings.value("iconSet").toString(), QSettings::IniFormat);

      QAction *action = ui.historyMenu->addAction
	(QIcon(settings.value("mainWindow/historyMenu").toString()),
	 tr("&Clear History"));

      action->setEnabled(false);
      connect(action, SIGNAL(triggered(void)), this,
	      SLOT(slotClearHistory(void)));
      action = ui.historyMenu->addAction
	(QIcon(settings.value("mainWindow/viewHistory").toString()),
	 tr("Show &History"));
      action->setShortcut(QKeySequence(Qt::ControlModifier + Qt::Key_H));
      action->setEnabled(true);
      connect(action, SIGNAL(triggered(void)), this,
	      SLOT(slotShowHistory(void)));
    }

  /*
  ** Add history menu actions, but only if the user wishes
  ** to have a history.
  */

  if(dooble::s_settings.value("settingsWindow/rememberHistory",
			      false).toBool())
    {
      {
	QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "history");

	db.setDatabaseName(QDir::homePath() + QDir::separator() +
			   ".dooble" + QDir::separator() + "history.db");

	if(db.open())
	  {
	    int i = 1;
	    QAction *lastAction = 0;
	    QSqlQuery query(db);

	    query.exec("SELECT url, title, icon FROM history ORDER BY "
		       "last_visited DESC");

	    while(query.next())
	      {
		if(ui.historyMenu->actions().size() == 2)
		  {
		    ui.historyMenu->actions()[0]->setEnabled
		      (ui.historyMenu->isEnabled());
		    ui.historyMenu->actions()[1]->setEnabled(true);
		    ui.historyMenu->addSeparator();
		  }

		QIcon icon;

		if(!query.isNull(2))
		  {
		    QBuffer buffer;
		    QByteArray bytes
		      (QByteArray::fromBase64(query.value(2).toByteArray()));

		    buffer.setBuffer(&bytes);
		    buffer.open(QIODevice::ReadOnly);

		    QDataStream in(&buffer);

		    in >> icon;
		    buffer.close();
		  }

		if(i <= MAX_HISTORY_ITEMS)
		  {
		    QAction *action = 0;
		    QString title(query.value(1).toString().trimmed());

		    if(title.isEmpty())
		      title = query.value(0).toString();

		    if(title.length() > MAX_NUMBER_OF_MENU_TITLE_CHARACTERS)
		      title = title.mid
			(0, MAX_NUMBER_OF_MENU_TITLE_CHARACTERS - 3) +
			"...";

		    if(title.contains("&"))
		      title = title.replace("&", "&&");

		    action = new QAction(icon, title, this);
		    action->setData(query.value(0).toUrl());
		    connect(action, SIGNAL(triggered(void)), this,
			    SLOT(slotLinkActionTriggered(void)));
		    ui.historyMenu->insertAction(lastAction, action);
		    lastAction = action;
		  }

		ui.locationLineEdit->addItem(query.value(0).toString(), icon);
		i += 1;
	      }
	  }

	db.close();
      }

      QSqlDatabase::removeDatabase("history");
    }

  ui.editMenu->setEnabled(false);
  ui.viewMenu->setEnabled(false);
  ui.historyMenu->setEnabled(false);
  ui.actionPrint->setEnabled(false);
  ui.actionPrint_Preview->setEnabled(false);
  ui.actionOpen_URL->setEnabled(false);
  ui.actionShow_Hidden_Files->setEnabled(false);
  ui.actionSave_Page->setEnabled(false);

  for(int i = 0; i < ui.tabWidget->count(); i++)
    if(ui.tabWidget->tabData(i).toString() == "Desktop")
      {
	ui.desktopToolButton->setEnabled(false);
	break;
      }

  /*
  ** According to Qt documentation, resize() followed by move() should
  ** be used to restore a window's geometry. Actual results may vary.
  */

  resize(0, 0);

  /*
  ** I don't know what to do about JavaScript windows that do not resize
  ** themselves.
  */

  if(dooble::s_settings.contains("mainWindow/geometry"))
    {
      if(!m_isJavaScriptWindow)
	{
	  QRect rect
	    (dooble::s_settings.value("mainWindow/geometry").
	     toRect());

	  if(rect.width() >
	     QApplication::desktop()->screenGeometry().width())
	    rect.setWidth
	      (0.85 * QApplication::desktop()->screenGeometry().width());

	  if(rect.height() >
	     QApplication::desktop()->screenGeometry().height())
	    rect.setWidth
	      (0.85 * QApplication::desktop()->screenGeometry().height());

	  setGeometry(rect);
	}
    }
  else if(QApplication::desktop()->screenGeometry().isValid())
    {
      if(!m_isJavaScriptWindow)
	resize(0.85 * QApplication::desktop()->screenGeometry().width(),
	       0.85 * QApplication::desktop()->screenGeometry().height());
      else
	resize(800, 600);
    }
  else
    resize(800, 600);

  if(!m_isJavaScriptWindow)
    restoreState(dooble::s_settings["mainWindow/state"].toByteArray());

  if(dooble::s_settings.contains("mainWindow/splitterState"))
    ui.splitter->restoreState
      (dooble::s_settings.value("mainWindow/splitterState", "").toByteArray());

  statusBar()->addPermanentWidget(sbWidget, 100);
  statusBar()->setStyleSheet("QStatusBar::item {"
			     "border: none; "
			     "}");
  statusBar()->setMaximumHeight(sbWidget->height());
  statusBar()->setVisible
    (dooble::s_settings.value("mainWindow/statusbarDisplay", true).toBool());
  ui.actionStatusbar->setChecked(!statusBar()->isHidden());
  ui.actionShow_Hidden_Files->setChecked
    (dooble::s_settings.value("mainWindow/showHiddenFiles", true).toBool());
  slotSetIcons();
#ifdef Q_WS_MAC
  foreach(QToolButton *toolButton, findChildren<QToolButton *> ())
    if(toolButton == ui.backToolButton ||
       toolButton == ui.forwardToolButton)
      toolButton->setStyleSheet
	("QToolButton {border: none; padding-right: 5px}"
	 "QToolButton::menu-button {border: none;}");
    else if(toolButton == ui.stopToolButton ||
	    toolButton == ui.reloadToolButton ||
	    toolButton == ui.homeToolButton ||
	    toolButton == ui.desktopToolButton ||
	    toolButton == ui.restoreToolButton)
      toolButton->setStyleSheet
	("QToolButton {border: none;}"
	 "QToolButton::menu-button {border: none;}");

  int margins[4];

  centralWidget()->layout()->getContentsMargins(&margins[0], &margins[1],
						&margins[2], &margins[3]);
  centralWidget()->layout()->setContentsMargins(margins[0], 10,
						margins[2], margins[3]);
#endif

  QFont font;

  if(!font.fromString(dooble::s_settings.value("settingsWindow/globalFont",
					       "").
		      toString()) || font.family().isEmpty())
#ifdef Q_WS_MAC
    font = QFont("Times", 12);
#elif defined Q_WS_WIN
    font = QFont("Arial", 12);
#else
    font = QFont("Serif", 9);
#endif

  font.setWeight(QFont::Normal);
  QApplication::setFont(font);

  foreach(QWidget *widget, findChildren<QWidget *> ())
    widget->setFont(font);

  menuBar()->setFont(font);

  foreach(QMenu *menu, menuBar()->findChildren<QMenu *> ())
    {
      menu->setFont(font);

      foreach(QAction *action, menu->actions())
	action->setFont(font);
    }
}

dooble::dooble(const bool isJavaScriptWindow):QMainWindow()
{
  init(isJavaScriptWindow);

  if(!isJavaScriptWindow)
    if(dooble::s_settings.value("settingsWindow/displayDesktopCheckBox",
				false).toBool())
      slotShowDesktopTab(false);

  show();
}

dooble::dooble(const QUrl &url):
  QMainWindow(), dest_url_(url.toString(QUrl::StripTrailingSlash))
{
  init(false);
  newTab(url);

  if(dooble::s_settings.value("settingsWindow/displayDesktopCheckBox",
			      false).toBool())
    slotShowDesktopTab(false);

  show();
}

dooble::dooble(dview *p, const QString &tabTitle):
  QMainWindow(),
  dest_url_(p ? p->url().toString(QUrl::StripTrailingSlash) : "")
{
  /*
  ** This method is called when the user has decided to
  ** change a tab into a window.
  */

  init(false);
  newTab(p, tabTitle);

  if(dooble::s_settings.value("settingsWindow/displayDesktopCheckBox",
			      false).toBool())
    slotShowDesktopTab(false);

  show();
}

dooble::~dooble()
{
  doobleCounter -= 1;
}

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

  ui.backToolButton->setIcon
    (QIcon(settings.value("mainWindow/backToolButton").toString()));
  ui.forwardToolButton->setIcon
    (QIcon(settings.value("mainWindow/forwardToolButton").toString()));
  ui.reloadToolButton->setIcon
    (QIcon(settings.value("mainWindow/reloadToolButton").toString()));
  ui.stopToolButton->setIcon
    (QIcon(settings.value("mainWindow/stopToolButton").toString()));
  ui.homeToolButton->setIcon
    (QIcon(settings.value("mainWindow/homeToolButton").toString()));
  ui.hideFindToolButton->setIcon
    (QIcon(settings.value("mainWindow/hideFindToolButton").toString()));
  ui.actionNew_Tab->setIcon
    (QIcon(settings.value("mainWindow/actionNew_Tab").toString()));
  ui.actionNew_Window->setIcon
    (QIcon(settings.value("mainWindow/actionNew_Window").toString()));
  ui.actionOpen_URL->setIcon
    (QIcon(settings.value("mainWindow/actionOpen_URL").toString()));
  ui.actionClose_Tab->setIcon
    (QIcon(settings.value("mainWindow/actionClose_Tab").toString()));
  ui.actionClose_Window->setIcon
    (QIcon(settings.value("mainWindow/actionClose_Window").toString()));
  ui.actionSave_Page->setIcon
    (QIcon(settings.value("mainWindow/actionSave_Page").toString()));
  ui.actionPrint->setIcon
    (QIcon(settings.value("mainWindow/actionPrint").toString()));
  ui.actionPrint_Preview->setIcon
    (QIcon(settings.value("mainWindow/actionPrint_Preview").toString()));
  ui.actionQuit->setIcon
    (QIcon(settings.value("mainWindow/actionQuit").toString()));
  ui.actionFind->setIcon
    (QIcon(settings.value("mainWindow/actionFind").toString()));
  ui.actionReload->setIcon
    (QIcon(settings.value("mainWindow/actionReload").toString()));
  ui.actionStop->setIcon
    (QIcon(settings.value("mainWindow/actionStop").toString()));
  ui.actionPage_Source->setIcon
    (QIcon(settings.value("mainWindow/actionPage_Source").toString()));
  ui.actionDownloads->
    setIcon(QIcon(settings.value("mainWindow/actionDownloads").toString()));
  ui.actionSettings->setIcon
    (QIcon(settings.value("mainWindow/actionSettings").toString()));
  ui.actionAbout_Dooble->
    setIcon(QIcon(settings.value("mainWindow/actionAbout_Dooble").toString()));
  ui.desktopToolButton->
    setIcon(QIcon(settings.value("mainWindow/desktopToolButton").toString()));
  ui.actionOpen_Directory->setIcon
    (QIcon(settings.value("mainWindow/actionOpen_Directory").toString()));
  ui.actionMy_Retrieved_Files->setIcon
    (QIcon(settings.value("mainWindow/actionMy_Retrieved_Files").toString()));
  ui.restoreToolButton->setIcon
    (QIcon(settings.value("mainWindow/restoreToolButton").toString()));
  ui.actionCopy->setIcon
    (QIcon(settings.value("mainWindow/actionCopy").toString()));
  ui.actionPaste->setIcon
    (QIcon(settings.value("mainWindow/actionPaste").toString()));
  ui.actionSelect_All_Content->setIcon
    (QIcon(settings.value("mainWindow/actionSelect_All_Content").toString()));
  ui.zoomMenu->setIcon
    (QIcon(settings.value("mainWindow/zoomMenu").toString()));
  ui.actionFull_Screen_Mode->setIcon
    (QIcon(settings.value("mainWindow/actionFull_Screen_Mode").toString()));
  ui.nextToolButton->setIcon
    (QIcon(settings.value("mainWindow/nextToolButton").toString()));
  ui.previousToolButton->setIcon
    (QIcon(settings.value("mainWindow/previousToolButton").toString()));
  ui.actionApplication_Cookies->setIcon
    (QIcon(settings.value
	   ("mainWindow/actionApplication_Cookies").toString()));

  if(ui.historyMenu->actions().size() > 0)
    ui.historyMenu->actions()[0]->setIcon
      (QIcon(settings.value("mainWindow/historyMenu").toString()));

  if(ui.historyMenu->actions().size() > 1)
    ui.historyMenu->actions()[1]->setIcon
      (QIcon(settings.value("mainWindow/viewHistory").toString()));

  QMessageBox *mb = findChild<QMessageBox *> ("about");

  if(mb)
    {
      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->setWindowIcon
	(QIcon(settings.value("mainWindow/windowIcon").toString()));
    }

  /*
  ** The 0th tab is not necessarily the Desktop.
  */

  for(int i = 0; i < ui.tabWidget->count(); i++)
    if(ui.tabWidget->tabData(i).toString() == "Desktop")
      {
	ui.tabWidget->setTabIcon
	  (i, QIcon(settings.value("mainWindow/tabWidget").toString()));
	break;
      }

  setWindowIcon(QIcon(settings.value("mainWindow/windowIcon").toString()));
  emit iconsChanged();
}

void dooble::newTabInit(dview *p, const QString &tabTitle)
{
  if(!p)
    return;

  connect(p, SIGNAL(urlChanged(const QUrl &)), this,
	  SLOT(slotUrlChanged(const QUrl &)));
  connect(p, SIGNAL(titleChanged(const QString &)), this,
	  SLOT(slotTitleChanged(const QString &)));
  connect(p, SIGNAL(loadFinished(bool)), this,
	  SLOT(slotLoadFinished(bool)));
  connect(p, SIGNAL(loadProgress(int)), this,
	  SLOT(slotLoadProgress(int)));
  connect(p, SIGNAL(iconChanged(void)), this,
	  SLOT(slotIconChanged(void)));
  connect(p, SIGNAL(loadStarted(void)), this,
	  SLOT(slotLoadStarted(void)));
  connect(p, SIGNAL(openLinkInNewTab(const QUrl &)), this,
	  SLOT(slotOpenLinkInNewTab(const QUrl &)));
  connect(p, SIGNAL(openLinkInNewWindow(const QUrl &)), this,
	  SLOT(slotOpenLinkInNewWindow(const QUrl &)));
  connect(p, SIGNAL(copyLink(const QUrl &)), this,
	  SLOT(slotCopyLink(const QUrl &)));
  connect(p, SIGNAL(saveUrl(const QUrl &)), this,
	  SLOT(slotSaveUrl(const QUrl &)));
  connect(p, SIGNAL(saveFile(const QString &, QNetworkReply *)), this,
	  SLOT(slotSaveFile(const QString &, QNetworkReply *)));
  connect(p, SIGNAL(viewImage(const QUrl &)), this,
	  SLOT(slotLoadPage(const QUrl &)));
  connect(p->page(),
	  SIGNAL(linkHovered(const QString &, const QString &,
			     const QString &)),
	  this,
	  SLOT(slotLinkHovered(const QString &, const QString &,
			       const QString &)));
  connect(p->page(),
	  SIGNAL(unsupportedContent(QNetworkReply *)),
	  this,
	  SLOT(slotUnsupportedContent(QNetworkReply *)));
  connect(p->page()->networkAccessManager(),
	  SIGNAL(authenticationRequired(QNetworkReply *, QAuthenticator *)),
	  this,
	  SLOT(slotAuthenticationRequired(QNetworkReply *, QAuthenticator *)));
  connect(p->page(), SIGNAL(windowCloseRequested(void)),
	  this, SLOT(slotCloseWindow(void)));
  connect(p->page(), SIGNAL(menuBarVisibilityChangeRequested(bool)),
	  this, SLOT(slotHideMenuBar(void)));
  connect(p->page(), SIGNAL(statusBarVisibilityChangeRequested(bool)),
	  this, SLOT(slotHideStatusBar(void)));
  connect(p->page(), SIGNAL(toolBarVisibilityChangeRequested(bool)),
	  this, SLOT(slotHideToolBar(void)));
  connect(p->page(), SIGNAL(printRequested(QWebFrame *)),
	  this, SLOT(slotPrintRequested(QWebFrame *)));
  connect(p->page(), SIGNAL(geometryChangeRequested(const QRect &)),
	  this, SLOT(slotGeometryChangeRequested(const QRect &)));
  connect(this,
	  SIGNAL(clearHistory(void)),
	  p,
	  SLOT(slotClearHistory(void)));
  connect(p, SIGNAL(viewEntered(void)), this,
	  SLOT(slotViewEntered(void)));
  connect(p, SIGNAL(selectionChanged(const QString &)),
	  this, SLOT(slotSelectionChanged(const QString &)));
  ui.tabWidget->addTab(p, p->icon(), tabTitle);
  sb.statusLabel->clear();
  ui.tabWidget->setTabsClosable(ui.tabWidget->count() > 1);
  ui.actionClose_Tab->setEnabled(ui.tabWidget->count() > 1);
  ui.tabWidget->cornerWidget(Qt::TopRightCorner)->setEnabled
    (ui.tabWidget->count() > 1);

  if(ui.tabWidget->count() == 1)
    ui.tabWidget->setBarVisible
      (dooble::s_settings.value("settingsWindow/alwaysShowTabBar",
				true).toBool());
  else
    ui.tabWidget->setBarVisible(true);
}

dview *dooble::newTab(dview *p, const QString &tabTitle)
{
  if(p)
    {
      p->setParent(this);

      QString title(tabTitle);

      if(title.isEmpty())
	title = p->url().toString(QUrl::StripTrailingSlash);

      if(title.length() > MAX_NUMBER_OF_MENU_TITLE_CHARACTERS)
	title = title.mid
	  (0, MAX_NUMBER_OF_MENU_TITLE_CHARACTERS - 3) +
	  "...";

      if(title.contains("&"))
	title = title.replace("&", "&&");

      if(title.isEmpty())
	title = tr("Dooble Web Browser");

      newTabInit(p, title);

      QAction *action = new QAction(p->icon(), title, this);

      action->setData(p->url());
      connect(action, SIGNAL(triggered(void)), this,
	      SLOT(slotLinkActionTriggered(void)));
      ui.menu_Tabs->addAction(action);
      p->setTabAction(action);
    }

  return p;
}

dview *dooble::newTab(const QUrl &url)
{
  dview *p = new dview(this);

  newTabInit(p, tr("(Untitled)"));

  if(p == ui.tabWidget->currentWidget())
    {
      ui.locationLineEdit->blockSignals(true);
      ui.locationLineEdit->setText(url.toString());
      ui.locationLineEdit->blockSignals(false);
    }

  p->load(url);
  prepareWidgetsBasedOnView(p);

  QAction *action = new QAction(p->icon(), tr("(Untitled)"), this);

  action->setData(url);
  connect(action, SIGNAL(triggered(void)), this,
	  SLOT(slotLinkActionTriggered(void)));
  ui.menu_Tabs->addAction(action);
  p->setTabAction(action);
  return p;
}

void dooble::slotQuit(void)
{
  historyWindow->deleteLater();
  downloadWindow->deleteLater();
  dooble::s_cookies->deleteLater();
  dooble::s_cookieWindow->deleteLater();
  saveSettings();

  foreach(QWidget *widget, QApplication::allWidgets())
    if(qobject_cast<dooble *> (widget))
      qobject_cast<dooble *> (widget)->deleteLater();

  QApplication::instance()->exit(0);
}

void dooble::saveSettings(void)
{
  if(!m_isJavaScriptWindow && !isFullScreen())
    {
      QSettings settings;

      settings.setValue("mainWindow/state", saveState());
      settings.setValue("mainWindow/geometry", geometry());
      settings.setValue("mainWindow/searchWidth",
			ui.searchLineEdit->width());
      settings.setValue("mainWindow/locationWidth",
			ui.locationLineEdit->width());
      settings.setValue
	("mainWindow/ftpManagerColumnsState",
	 dooble::s_settings.value
	 ("mainWindow/ftpManagerColumnsState").toByteArray());
      settings.setValue
	("mainWindow/fileManagerColumnsState",
	 dooble::s_settings.value
	 ("mainWindow/fileManagerColumnsState").toByteArray());
      dooble::s_settings["mainWindow/state"] = saveState();
      dooble::s_settings["mainWindow/geometry"] = geometry();
      dooble::s_settings["mainWindow/searchWidth"] =
	ui.searchLineEdit->width();
      dooble::s_settings["mainWindow/locationWidth"] =
	ui.locationLineEdit->width();
    }
}

void dooble::loadPage(const QUrl &url)
{
  if(!url.isValid())
    {
      /*
      ** Prevent the user from loading an invalid URL.
      */

      slotResetUrl();
      return;
    }

  sb.statusLabel->clear();

  dview *p = qobject_cast<dview *> (ui.tabWidget->currentWidget());

  if(p)
    {
      QString str(url.toString(QUrl::StripTrailingSlash).trimmed());

      ui.locationLineEdit->blockSignals(true);
      ui.locationLineEdit->setText(str);
      ui.locationLineEdit->blockSignals(false);
      sb.progressBar->setVisible(true);
      ui.reloadStopWidget->setCurrentIndex(0);
      ui.stopToolButton->setEnabled(true);
      ui.actionStop->setEnabled(true);
      ui.zoomMenu->setEnabled(!p->isDir() && !p->isFtp());
      ui.actionSelect_All_Content->setEnabled
	(!p->isDir() && !p->isFtp());

      QString title(url.toString(QUrl::StripTrailingSlash));

      ui.tabWidget->setTabText(ui.tabWidget->indexOf(p), title);
      p->load(QUrl(str));
      ui.locationLineEdit->setIcon(p->icon());
      ui.actionFind->setEnabled(!p->isDir() && !p->isFtp());

      if(p->isDir() || p->isFtp())
	ui.findFrame->setVisible(false);
      else
	ui.findFrame->setVisible(showFindFrame);
    }
  else
    newTab(url);
}

void dooble::slotLoadPage(void)
{
  loadPage(QUrl::fromUserInput(ui.locationLineEdit->text().trimmed()));

  dview *p = qobject_cast<dview *> (ui.tabWidget->currentWidget());

  if(p)
    p->setFocus();
}

void dooble::slotLoadPage(bool)
{
  loadPage(QUrl(dest_url_));
}

void dooble::slotLoadPage(const QUrl &url)
{
  loadPage(url);
}

void dooble::slotNewTab(void)
{
  QUrl url(dooble::s_settings.value("settingsWindow/url12").toString());
  dview *p = newTab(url);

  if(p)
    ui.tabWidget->setCurrentWidget(p);
}

void dooble::slotNewWindow(void)
{
  QUrl url(dooble::s_settings.value("settingsWindow/url12").toString());

  if(dooble::s_settings.value("settingsWindow/openUserWindowsInNewProcesses",
			      false).toBool())
    launchDooble(url);
  else
    {
      Q_UNUSED(new dooble(url));
    }
}

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

void dooble::closeEvent(QCloseEvent *event)
{
  Q_UNUSED(event);
  deleteLater();

  if(doobleCounter <= 1)
    slotQuit();
}

void dooble::slotStop(void)
{
  dview *p = qobject_cast<dview *> (ui.tabWidget->currentWidget());

  if(p)
    p->stop();

  sb.progressBar->setVisible(false);
  ui.reloadStopWidget->setCurrentIndex(1);
  ui.stopToolButton->setEnabled(false);
  ui.actionStop->setEnabled(false);
}

void dooble::slotReload(void)
{
  dview *p = qobject_cast<dview *> (ui.tabWidget->currentWidget());

  if(p)
    {
      sb.progressBar->setVisible(true); 	 
      ui.reloadStopWidget->setCurrentIndex(0); 	 
      ui.stopToolButton->setEnabled(true); 	 
      ui.actionStop->setEnabled(true);
      p->reload();
    }
}

void dooble::slotBack(void)
{
  dview *p = qobject_cast<dview *> (ui.tabWidget->currentWidget());

  if(p)
    {
      ui.forwardToolButton->setEnabled(p->canGoForward());
      sb.progressBar->setVisible(true);
      ui.reloadStopWidget->setCurrentIndex(0); 	 
      ui.stopToolButton->setEnabled(true); 	 
      ui.actionStop->setEnabled(true);
      p->back();
    }
}

void dooble::slotForward(void)
{
  dview *p = qobject_cast<dview *> (ui.tabWidget->currentWidget());

  if(p)
    {
      ui.backToolButton->setEnabled(p->canGoBack());
      sb.progressBar->setVisible(true);
      ui.reloadStopWidget->setCurrentIndex(0); 	 
      ui.stopToolButton->setEnabled(true); 	 
      ui.actionStop->setEnabled(true);
      p->forward();
    }
}

void dooble::slotTabSelected(const int index)
{
  dview *p = qobject_cast<dview *> (ui.tabWidget->widget(index));

  if(p)
    {
      ui.toolBar->setVisible(!isFullScreen());
      ui.forwardToolButton->setEnabled(true);
      ui.backToolButton->setEnabled(true);
      ui.stopToolButton->setEnabled(true);
      ui.reloadToolButton->setEnabled(true);
      ui.homeToolButton->setEnabled(true);
      ui.searchLineEdit->setVisible(true);
      ui.locationLineEdit->setVisible(true);
      ui.reloadToolButton->setEnabled(true);
      ui.homeToolButton->setEnabled(true);
      ui.searchLineEdit->setEnabled(true);
      ui.editMenu->setEnabled(true);
      ui.viewMenu->setEnabled(true);
      ui.historyMenu->setEnabled(true);
      ui.actionPrint->setEnabled(true);
      ui.actionPrint_Preview->setEnabled(true);
      ui.actionOpen_URL->setEnabled(true);
      ui.actionSave_Page->setEnabled(true);

      if(p->title().isEmpty())
	setWindowTitle(tr("Dooble Web Browser"));
      else
	setWindowTitle(p->title() + tr(" - Dooble Web Browser"));

      sb.progressBar->setVisible(!p->isLoaded());
      sb.progressBar->setValue(p->progress());
      ui.reloadStopWidget->setCurrentIndex(p->isLoaded());
      ui.stopToolButton->setEnabled(!p->isLoaded());
      ui.actionStop->setEnabled(!p->isLoaded());
      ui.backToolButton->setEnabled(p->canGoBack());
      ui.forwardToolButton->setEnabled(p->canGoForward());
      ui.locationLineEdit->setIcon(p->icon());
      ui.locationLineEdit->blockSignals(true);
      ui.locationLineEdit->setText
	(p->url().toString(QUrl::StripTrailingSlash));
      ui.locationLineEdit->blockSignals(false);
      prepareNavigationButtonMenus(p);
      statusBar()->setVisible(ui.actionStatusbar->isChecked() &&
			      !isFullScreen());
      prepareWidgetsBasedOnView(p);
      p->setFocus();
    }
  else
    {
      setWindowTitle(tr("Dooble Web Browser"));
      ui.forwardToolButton->setEnabled(false);
      ui.backToolButton->setEnabled(false);
      ui.stopToolButton->setEnabled(false);
      ui.reloadToolButton->setEnabled(false);
      ui.homeToolButton->setEnabled(false);
      ui.searchLineEdit->setVisible(false);
      ui.locationLineEdit->setVisible(false);
      ui.editMenu->setEnabled(false);
      ui.viewMenu->setEnabled(false);
      ui.historyMenu->setEnabled(false);
      ui.actionPrint->setEnabled(false);
      ui.actionPrint_Preview->setEnabled(false);
      ui.actionOpen_URL->setEnabled(false);
      ui.actionSave_Page->setEnabled(false);
      ui.searchLineEdit->clear();
      ui.findFrame->setVisible(false);
      sb.statusLabel->clear();
      sb.progressBar->setValue(0);
      sb.progressBar->setVisible(false);
      statusBar()->setVisible(false);
    }
}

void dooble::slotTextChanged(const QString &text)
{
  dest_url_ = text;

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

  icon = QIcon(settings.value("urlWidget/emptyIcon").toString());
  ui.locationLineEdit->setIcon(icon);
}

void dooble::slotUrlChanged(const QUrl &url)
{
  QString urlText(url.toString(QUrl::StripTrailingSlash));

  if(ui.locationLineEdit->findText(urlText) == -1)
    ui.locationLineEdit->addItem(urlText);

  dview *p = qobject_cast<dview *> (sender());

  prepareWidgetsBasedOnView(p);

  /*
  ** The URL widget's text should not be changed if the
  ** completer's popup is visible.
  */

  if(!ui.locationLineEdit->completer()->popup()->isVisible())
    if(p == qobject_cast<dview *> (ui.tabWidget->currentWidget()))
      {
	ui.locationLineEdit->blockSignals(true);
	ui.locationLineEdit->setText(urlText);
	ui.locationLineEdit->blockSignals(false);
      }

  if(p && p->tabAction())
    p->tabAction()->setData(url);
}

void dooble::slotTitleChanged(const QString &titleArg)
{
  dview *p = qobject_cast<dview *> (sender());
  QString title(titleArg.trimmed());

  if(p == qobject_cast<dview *> (ui.tabWidget->currentWidget()))
    {
      if(title.isEmpty())
	setWindowTitle(tr("Dooble Web Browser"));
      else
	setWindowTitle(title + tr(" - Dooble Web Browser"));
    }

  if(p)
    {
      if(title.isEmpty())
	/*
	** The tab's title will be set to the URL.
	*/

	title = p->url().toString(QUrl::StripTrailingSlash);

      ui.tabWidget->setTabText(ui.tabWidget->indexOf(p),
			       title.replace("&", "&&"));
      ui.tabWidget->setTabToolTip(ui.tabWidget->indexOf(p),
				  p->title());

      if(p->tabAction())
	{
	  title = titleArg.trimmed();

	  if(title.isEmpty())
	    title = p->url().toString(QUrl::StripTrailingSlash);

	  if(title.length() > MAX_NUMBER_OF_MENU_TITLE_CHARACTERS)
	    title = title.mid
	      (0, MAX_NUMBER_OF_MENU_TITLE_CHARACTERS - 3) +
	      "...";

	  if(title.contains("&"))
	    title = title.replace("&", "&&");

	  if(title.isEmpty())
	    title = tr("Dooble Web Browser");

	  p->tabAction()->setText(title);
	}
    }
}

void dooble::slotIconChanged(void)
{
  QIcon icon;
  dview *p = qobject_cast<dview *> (sender());

  if(p)
    icon = p->icon();

  if(p == qobject_cast<dview *> (ui.tabWidget->currentWidget()))
    ui.locationLineEdit->setIcon(icon);

  if(p)
    {
      int index = ui.locationLineEdit->findText
	(p->url().toString(QUrl::StripTrailingSlash));

      if(index > -1)
	ui.locationLineEdit->setItemIcon(index, icon);

      ui.tabWidget->setTabIcon(ui.tabWidget->indexOf(p), icon);

      if(p->tabAction())
	p->tabAction()->setIcon(icon);
    }
}

void dooble::slotLoadProgress(int progress)
{
  dview *p = qobject_cast<dview *> (sender());

  if(p == qobject_cast<dview *> (ui.tabWidget->currentWidget()))
    {
      if(progress < 0)
	{
	  sb.progressBar->setMaximum(0);
	  sb.progressBar->setMinimum(0);
	}
      else
	{
	  sb.progressBar->setMaximum(100);
	  sb.progressBar->setValue(progress >= 0 ? progress : 0);
	}
    }
}

void dooble::slotUnsupportedContent(QNetworkReply *reply)
{
  Q_UNUSED(reply);
}

void dooble::slotLoadFinished(bool ok)
{
  dview *p = qobject_cast<dview *> (sender());

  if(p == qobject_cast<dview *> (ui.tabWidget->currentWidget()))
    {
      sb.progressBar->setVisible(false);
      ui.reloadStopWidget->setCurrentIndex(1);
      ui.stopToolButton->setEnabled(false);
      ui.actionStop->setEnabled(false);
      ui.backToolButton->setEnabled(p->canGoBack());
      ui.forwardToolButton->setEnabled(p->canGoForward());
    }

  if(!ok)
    return;

  QIcon icon;

  if(p)
    {
      icon = p->icon();

      int index = ui.locationLineEdit->findText
	(p->url().toString(QUrl::StripTrailingSlash));

      if(index > -1)
	ui.locationLineEdit->setItemIcon(index, icon);

      ui.tabWidget->setTabIcon(ui.tabWidget->indexOf(p), icon);
      saveHistoryItem(p->currentItem());
    }

  /*
  ** Add items to the history menu.
  */

  if(dooble::s_settings.value("settingsWindow/rememberHistory",
			      false).toBool() && p)
    {
      bool actionExists = false;
      QList<QAction *> actions = ui.historyMenu->actions();

      for(int i = 0; i < actions.size(); i++)
	if(actions.at(i)->data().toString() == p->url().toString
	   (QUrl::StripTrailingSlash))
	  {
	    actions.at(i)->setIcon(icon);
	    actionExists = true;
	    break;
	  }

      actions.clear();

      if(!actionExists)
	{
	  if(ui.historyMenu->actions().size() == 2)
	    {
	      ui.historyMenu->addSeparator();
	      ui.historyMenu->actions()[0]->setEnabled
		(ui.historyMenu->isEnabled());
	      ui.historyMenu->actions()[1]->setEnabled(true);
	    }

	  QString title(p->title());

	  if(title.isEmpty())
	    title = p->url().toString(QUrl::StripTrailingSlash);

	  if(title.contains("&"))
	    title = title.replace("&", "&&");

	  if(title.length() > MAX_NUMBER_OF_MENU_TITLE_CHARACTERS)
	    title = title.mid
	      (0, MAX_NUMBER_OF_MENU_TITLE_CHARACTERS - 3) +
	      "...";

	  /*
	  ** 3 = Clear History, Show History, and a separator.
	  */

	  QAction *action = 0;

	  if(ui.historyMenu->actions().size() >= 3 + MAX_HISTORY_ITEMS)
	    {
	      if(m_lastReplacedHistoryPosition >=
		 ui.historyMenu->actions().size())
		m_lastReplacedHistoryPosition = 3;

	      action = ui.historyMenu->actions().at
		(m_lastReplacedHistoryPosition);
	      m_lastReplacedHistoryPosition += 1;
	    }
	  else
	    action = ui.historyMenu->addAction
	      (icon, title, this,
	       SLOT(slotLinkActionTriggered(void)));

	  if(action)
	    {
	      action->setEnabled(ui.historyMenu->isEnabled());
	      action->setData
		(QVariant(p->url().toString(QUrl::StripTrailingSlash)));
	      action->setIcon(icon);
	      action->setText(title);
	    }
	}
    }

  prepareNavigationButtonMenus(p);

  if(p == qobject_cast<dview *> (ui.tabWidget->currentWidget()))
    {
      if(p->isDir() || !p->url().toLocalFile().isEmpty())
	slotOpenUrl();
    }
}

void dooble::prepareNavigationButtonMenus(dview *p)
{
  if(!p)
    return;

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

  while(!ui.backToolButton->menu()->actions().isEmpty())
    ui.backToolButton->menu()->removeAction
      (ui.backToolButton->menu()->actions().takeFirst());

  QList<dwebhistoryitem> list(p->backItems(MAX_HISTORY_ITEMS));

  for(int i = 0; i < list.size(); i++)
    {
      QString title(list.at(i).title());

      if(title.length() > MAX_NUMBER_OF_MENU_TITLE_CHARACTERS)
	title = title.mid(0, MAX_NUMBER_OF_MENU_TITLE_CHARACTERS - 3) +
	  "...";

      if(title.contains("&"))
	title = title.replace("&", "&&");

      QIcon icon(list.at(i).icon());

      if(icon.isNull())
	icon = dmisc::iconForUrl(list.at(i).url());

      QAction *action = ui.backToolButton->menu()->addAction
	(icon, title, this, SLOT(slotLinkActionTriggered(void)));

      if(action)
	action->setData
	  (QVariant(list.at(i).url().toString(QUrl::StripTrailingSlash)));
    }

  list.clear();

  while(!ui.forwardToolButton->menu()->actions().isEmpty())
    ui.forwardToolButton->menu()->removeAction
      (ui.forwardToolButton->menu()->actions().takeFirst());

  /*
  ** Forward items must be reversed for display purposes.
  */

  list = p->forwardItems(MAX_HISTORY_ITEMS);

  for(int i = list.size() - 1; i >= 0; i--)
    {
      QString title(list.at(i).title());

      if(title.length() > MAX_NUMBER_OF_MENU_TITLE_CHARACTERS)
	title = title.mid
	  (0, MAX_NUMBER_OF_MENU_TITLE_CHARACTERS - 3) + "...";

      if(title.contains("&"))
	title = title.replace("&", "&&");

      QIcon icon(list.at(i).icon());

      if(icon.isNull())
	icon = dmisc::iconForUrl(list.at(i).url());

      QAction *action = ui.forwardToolButton->menu()->addAction
	(icon, title, this, SLOT(slotLinkActionTriggered(void)));

      if(action)
	action->setData
	  (QVariant(list.at(i).url().toString(QUrl::StripTrailingSlash)));
    }

  list.clear();
}

void dooble::slotGoHome(void)
{
  QStringList allKeys = dooble::s_settings.keys();

  for(int i = 0; i < allKeys.size(); i++)
    {
      if(!(allKeys[i].startsWith("settingsWindow/url") ||
	   allKeys[i].startsWith("settingsWindow/myRetrievedFiles")))
	continue;

      QUrl url(QUrl::fromUserInput(dooble::s_settings.value
				   (allKeys[i],
				    "").toString().trimmed()));

      if(url.isValid())
	{
	  bool urlFound = false;

	  for(int j = 0; j < ui.tabWidget->count(); j++)
	    {
	      dview *p = qobject_cast<dview *> (ui.tabWidget->widget(j));

	      if(p && p->url().toString(QUrl::StripTrailingSlash) ==
		 url.toString(QUrl::StripTrailingSlash))
		{
		  urlFound = true;
		  break;
		}
	    }

	  if(!urlFound)
	    newTab(url);
	}
    }

  allKeys.clear();
}

void dooble::closeTab(const int index)
{
  int count = 0;

  if(index > -1)
    {
      if((count = ui.tabWidget->count()) > 1)
	{
	  dview *p = qobject_cast<dview *> (ui.tabWidget->widget(index));

	  if(p)
	    {
	      p->stop();
	      p->deleteLater();
	    }
	  else
	    closeDesktop();

	  count -= 1;
	}
    }

  ui.tabWidget->setTabsClosable(count > 1);
  ui.actionClose_Tab->setEnabled(count > 1);
  ui.tabWidget->cornerWidget(Qt::TopRightCorner)->setEnabled(count > 1);

  if(count == 1)
    ui.tabWidget->setBarVisible
      (dooble::s_settings.value("settingsWindow/alwaysShowTabBar",
				true).toBool());
  else
    ui.tabWidget->setBarVisible(true);
}

void dooble::slotCloseTab(void)
{
  closeTab(ui.tabWidget->currentIndex());
}

void dooble::slotCloseTab(const int index)
{
  closeTab(index);
}

void dooble::slotOpenUrl(void)
{
  if(isFullScreen())
    slotMarkerEntered();

  ui.locationLineEdit->setFocus();
  ui.locationLineEdit->selectAll();
  update();
}

void dooble::slotLinkActionTriggered(void)
{
  QAction *action = qobject_cast<QAction *> (sender());

  if(action)
    {
      bool doLoad = true;
      QList<QWidget *> list(action->associatedWidgets());

      for(int i = 0; i < list.size(); i++)
	if(qobject_cast<dview *> (list.at(i)))
	  {
	    doLoad = false;
	    ui.tabWidget->setCurrentWidget(list.at(i));
	    break;
	  }

      list.clear();

      if(doLoad)
	loadPage(action->data().toUrl());
    }
}

void dooble::slotLoadStarted(void)
{
  QUrl url(QUrl::fromUserInput(ui.locationLineEdit->text()));
  QIcon icon(dmisc::iconForUrl(QUrl()));
  dview *p = qobject_cast<dview *> (sender());

  if(p)
    {
      if(url.host() == p->url().host())
	icon = p->icon();

      int index = ui.locationLineEdit->findText
	(p->url().toString(QUrl::StripTrailingSlash));

      if(index > -1)
	ui.locationLineEdit->setItemIcon(index, icon);

      ui.tabWidget->setTabIcon(ui.tabWidget->indexOf(p), icon);
    }

  if(p == qobject_cast<dview *> (ui.tabWidget->currentWidget()))
    {
      sb.statusLabel->clear();
      sb.progressBar->setVisible(true);
      ui.reloadStopWidget->setCurrentIndex(0);
      ui.stopToolButton->setEnabled(true);
      ui.actionStop->setEnabled(true);
      ui.backToolButton->setEnabled(p->canGoBack());
      ui.forwardToolButton->setEnabled(p->canGoForward());
      ui.locationLineEdit->setIcon(icon);
    }
}

void dooble::slotSearch(void)
{
  dview *p = qobject_cast<dview *> (ui.tabWidget->currentWidget());

  if(p)
    {
      QString urlText("");
      QString searchName(ui.searchLineEdit->type());

      if(searchName == "bing")
	urlText = QString("http://www.bing.com/search?q=%1").arg
	  (ui.searchLineEdit->text().trimmed().replace(" ", "+"));
      else if(searchName == "dogpile")
	urlText = QString("http://www.dogpile.com/dogpile_other/ws/results/"
			  "Web/%1/1/417/TopNavigation/Relevance/iq=true/"
			  "zoom=off/_iceUrlFlag=7?_IceUrl=true").arg
	  (ui.searchLineEdit->text().trimmed());
      else if(searchName == "duckduckgo")
	urlText = QString("https://www.duckduckgo.com?q=%1").arg
	  (ui.searchLineEdit->text().trimmed().replace(" ", "+"));
      else if(searchName == "google")
        urlText = QString("https://www.google.com/search?q=%1").arg
	  (ui.searchLineEdit->text().trimmed().replace(" ", "+"));
      else if(searchName == "wikipedia")
	{
	  QLocale locale;

	  urlText = QString
	    ("http://%1.wikipedia.org/wiki/Special:"
	     "Search?search=%2").
	    arg(locale.name().left(2)).
	    arg(ui.searchLineEdit->text().trimmed().replace(" ", "+"));
	}
      else
	/*
	** Unknown!
	*/

	return;

      ui.tabWidget->setTabText(ui.tabWidget->indexOf(p),
			       tr("Loading..."));
      p->load(QUrl(urlText));
      p->setFocus();
    }
}

void dooble::slotCopyLink(const QUrl &url)
{
  QApplication::clipboard()->setText(url.toString(QUrl::StripTrailingSlash));
}

void dooble::slotOpenLinkInNewTab(const QUrl &url)
{
  dview *p = newTab(url);

  if(p)
    if(dooble::s_settings.value("settingsWindow/proceedToNewTab",
				true).toBool())
      ui.tabWidget->setCurrentWidget(p);
}

void dooble::slotOpenLinkInNewWindow(const QUrl &url)
{
  if(dooble::s_settings.value("settingsWindow/openUserWindowsInNewProcesses",
			      false).toBool())
    launchDooble(url);
  else
    {
      Q_UNUSED(new dooble(url));
    }
}

void dooble::slotOpenPageInNewWindow(const int index)
{
  dview *p = qobject_cast<dview *> (ui.tabWidget->widget(index));

  if(p)
    {
      int count = ui.tabWidget->count() - 1;

      if(dooble::s_settings.value
	 ("settingsWindow/openUserWindowsInNewProcesses",
	  false).toBool())
	{
	  launchDooble(p->url());
	  p->deleteLater();
	}
      else
	{
	  Q_UNUSED(new dooble(p, ui.tabWidget->tabText(index)));
	}

      ui.tabWidget->setTabsClosable(count > 1);
      ui.actionClose_Tab->setEnabled(count > 1);
      ui.tabWidget->cornerWidget(Qt::TopRightCorner)->setEnabled
	(count > 1);
    }
}

void dooble::slotLinkHovered(const QString &link, const QString &title,
			     const QString &textContent)
{
  Q_UNUSED(title);
  Q_UNUSED(textContent);

  if(link.isEmpty())
    sb.statusLabel->clear();
  else
    sb.statusLabel->setText(link.trimmed().mid(0, 100));
}

void dooble::slotAbout(void)
{
  QMessageBox *mb = findChild<QMessageBox *> ("about");

  if(!mb)
    {
      mb = new QMessageBox(this);
      mb->setObjectName("about");
    }

  mb->setWindowModality(Qt::NonModal);
  mb->setStyleSheet("QMessageBox {background: white;}");
  mb->setWindowTitle(tr("Dooble Web Browser: About"));
  mb->setTextFormat(Qt::RichText);
  mb->setText("<html>"
	      "Version 1.20.1.<br>"
	      "Dooble is the little Web browser that absolutely can.<br>"
	      "Poignant software for Linux, Mac, and Windows.<br>"
	      "Copyright (c) 2008 - 2011 Hinagiku."
	      "<hr>"
	      "Please visit <a href='http://dooble.sf.net'>"
	      "http://dooble.sf.net</a> for more information."
	      "</html>");
  mb->setStandardButtons(QMessageBox::Ok);

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

  mb->setWindowIcon
    (QIcon(settings.value("mainWindow/windowIcon").toString()));

  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->setIconPixmap(QPixmap("Icons/AxB/dooble.png"));
  mb->show();
}

void dooble::slotSavePage(void)
{
  dview *p = qobject_cast<dview *> (ui.tabWidget->currentWidget());

  if(p)
    {
      if(p->isDir() || p->isFtp())
	saveHandler(p->url(), p->html(), "", 0);
      else
	saveHandler(p->url(), "", "", 0);
    }
}

void dooble::slotSaveUrl(const QUrl &url)
{
  saveHandler(url, "", "", 0);
}

void dooble::slotSaveFile(const QString &fileName, QNetworkReply *reply)
{
  saveHandler(QUrl(), "", fileName, reply);
}

void dooble::saveHandler(const QUrl &url, const QString &html,
			 const QString &fileName, QNetworkReply *reply)
{
  QString path("");

  if(dooble::s_settings.contains("settingsWindow/myRetrievedFiles"))
    path = dooble::s_settings.value("settingsWindow/myRetrievedFiles").
      toString();
  else
    {
      path = QDesktopServices::storageLocation
	(QDesktopServices::DesktopLocation);

      if(path.isEmpty() || !QFile::exists(path) ||
	 !QFileInfo(path).isReadable())
	path = QDir::homePath();
    }

  QWidget *parent = qobject_cast<QWidget *> (sender());

  if(!parent)
    parent = this;

  QFileDialog fileDialog(parent);

#ifdef Q_WS_MAC
  fileDialog.setAttribute(Qt::WA_MacMetalStyle, true);
#endif
  fileDialog.setWindowTitle(tr("Dooble Web Browser: Save As"));
  fileDialog.setFileMode(QFileDialog::AnyFile);
  fileDialog.setDirectory(path);
  fileDialog.setLabelText(QFileDialog::Accept, tr("&Save"));
  fileDialog.setAcceptMode(QFileDialog::AcceptSave);

#ifdef Q_WS_MAC
  /*
  ** Attempt to find the QLineEdit widget.
  */

  QLineEdit *lineEdit = fileDialog.findChild<QLineEdit *> ("fileNameEdit");

  if(!lineEdit)
    lineEdit = fileDialog.findChild<QLineEdit *> ();
#endif

  if(url.path().isEmpty() || url.path() == "/")
#ifdef Q_WS_MAC
    {
      if(lineEdit)
	{
	  if(fileName.isEmpty())
	    lineEdit->setText("index.html");
	  else
	    lineEdit->setText(fileName);
	}
    }
#else
    {
      if(fileName.isEmpty())
	fileDialog.selectFile("index.html");
      else
	fileDialog.selectFile(fileName);
    }
#endif
  else if(url.path().contains("/"))
    {
      QString fileName = QFileInfo(url.path()).fileName();

      if(fileName.isEmpty())
	fileName = "index.html";

#ifdef Q_WS_MAC
      if(lineEdit)
	lineEdit->setText(fileName);
#else
      fileDialog.selectFile(fileName);
#endif
    }

  fileDialog.setWindowModality(Qt::WindowModal);

  if(fileDialog.exec())
    {
      QStringList list(fileDialog.selectedFiles());

      if(!list.isEmpty())
	{
	  downloadWindow->show();

	  if(reply)
	    downloadWindow->addFileItem(reply, list[0]);
	  else if(!html.isEmpty())
	    downloadWindow->addHtmlItem(html, list[0]);
	  else if(!url.scheme().toLower().startsWith("file"))
	    downloadWindow->addUrlItem(url, list[0]);
	  else
	    downloadWindow->addFileItem(url.toLocalFile(), list[0]);

	  list.clear();
	}
    }
}

void dooble::slotDisplayDownloadWindow(void)
{
  downloadWindow->show();
}

void dooble::slotShowFind(void)
{
  if(ui.tabWidget->
     tabData(ui.tabWidget->currentIndex()).toString() != "Desktop")
    {
      dview *p = qobject_cast<dview *> (ui.tabWidget->currentWidget());

      if(p && (p->isDir() || p->isFtp()))
	ui.findFrame->setVisible(false);
      else
	{
	  showFindFrame = true;
	  ui.findFrame->setVisible(true);
	}

      if(p)
	ui.actionFind->setEnabled(!p->isDir() && !p->isFtp());
    }

  if(ui.tabWidget->isVisible())
    {
      ui.findLineEdit->setFocus();
      ui.findLineEdit->selectAll();
      update();
    }
}

void dooble::slotHideFind(void)
{
  showFindFrame = false;
  ui.findFrame->setVisible(false);
}

void dooble::slotFindNext(void)
{
  find(QWebPage::FindWrapsAroundDocument);
}

void dooble::slotFindPrevious(void)
{
  find(QWebPage::FindBackward | QWebPage::FindWrapsAroundDocument);
}

void dooble::slotFind(void)
{
  dview *p = qobject_cast<dview *> (ui.tabWidget->currentWidget());

  if(p)
    {
      p->page()->findText(QString(), QWebPage::HighlightAllOccurrences);

      if(ui.highlightAllCheckBox->isChecked())
	find(QWebPage::HighlightAllOccurrences);
    }
}

void dooble::find(QWebPage::FindFlags flags)
{
  QString text(ui.findLineEdit->text().trimmed());
  dview *p = qobject_cast<dview *> (ui.tabWidget->currentWidget());
  static QPalette lineEditPalette(ui.findLineEdit->palette());

  if(p && !p->page()->findText(text, flags))
    {
      if(!text.isEmpty())
	{
	  QColor color(240, 128, 128); // Light Coral
	  QPalette palette(ui.findLineEdit->palette());

	  palette.setColor(ui.findLineEdit->backgroundRole(), color);
	  ui.findLineEdit->setPalette(palette);
	}
      else
	ui.findLineEdit->setPalette(lineEditPalette);
    }
  else
    ui.findLineEdit->setPalette(lineEditPalette);
}

void dooble::keyPressEvent(QKeyEvent *event)
{
  if(event)
    {
      if(event->key() == Qt::Key_Escape && ui.findFrame->isVisible())
	{
	  showFindFrame = false;
	  ui.findFrame->setVisible(false);
	}
      else if(event->key() == Qt::Key_Escape)
	{
	  slotStop();

	  if(isFullScreen())
	    slotViewEntered();
	}
      else if(event->key() == Qt::Key_X &&
	      event->modifiers() == Qt::AltModifier)
	showMinimized();
      else if(QKeySequence(event->modifiers() + event->key()) ==
	      QKeySequence(Qt::ControlModifier + Qt::ShiftModifier +
			   Qt::Key_Plus))
	ui.actionZoom_In->trigger();

      if(isFullScreen() || m_isJavaScriptWindow)
	{
	  /*
	  ** OK, this is going to be tricky.
	  ** Grab all the actions.
	  ** For every action that is enabled, determine
	  ** its shortcuts. If a shortcut matches the event's key
	  ** and the event's modifier, issue the action's trigger() method.
	  */

#ifdef Q_WS_X11
	  if(QKeySequence(event->modifiers() + event->key()) ==
	     QKeySequence(Qt::ControlModifier + Qt::Key_Equal) ||
	     QKeySequence(event->modifiers() + event->key()) ==
	     QKeySequence(Qt::ControlModifier + Qt::ShiftModifier +
			  Qt::Key_Plus))
	    {
	      ui.actionZoom_In->trigger();
	      return;
	    }
#endif

	  QKeySequence shortcut(event->modifiers() + event->key());

	  foreach(QAction *action, findChildren<QAction *> ())
	    if(action->isEnabled() && !action->shortcuts().isEmpty())
	      {
		QList<QKeySequence> shortcuts(action->shortcuts());

		for(int i = 0; i < shortcuts.size(); i++)
		  if(shortcut == shortcuts.at(i))
		    {
		      action->trigger();
		      break;
		    }

		shortcuts.clear();
	      }
	}
    }

  QMainWindow::keyPressEvent(event);
}

void dooble::slotPrint(void)
{
  QPrinter printer;
  QPrintDialog printDialog(&printer, this);

#ifdef Q_WS_MAC
  printDialog.setAttribute(Qt::WA_MacMetalStyle, true);
#endif
  printDialog.setSizeGripEnabled(true);

  if(printDialog.exec() == QDialog::Accepted)
    {
      dview *p = qobject_cast<dview *> (ui.tabWidget->currentWidget());

      if(p)
	p->print(&printer);
    }
}

void dooble::slotPrintRequested(QWebFrame *frame)
{
  if(frame)
    {
      QPrinter printer;
      QPrintDialog printDialog(&printer, this);

#ifdef Q_WS_MAC
      printDialog.setAttribute(Qt::WA_MacMetalStyle, true);
#endif
      printDialog.setSizeGripEnabled(true);

      if(printDialog.exec() == QDialog::Accepted)
	frame->print(&printer);
    }
}

void dooble::slotPrintPreview(void)
{
  dview *p = qobject_cast<dview *> (ui.tabWidget->currentWidget());

  if(p && p->currentFrame())
    {
      QPrinter printer;
      QPrintPreviewDialog printDialog(&printer, this);

#ifdef Q_WS_MAC
      printDialog.setAttribute(Qt::WA_MacMetalStyle, true);
#endif
      printDialog.setWindowModality(Qt::WindowModal);
      printDialog.setSizeGripEnabled(true);
      connect(&printDialog,
	      SIGNAL(paintRequested(QPrinter *)),
	      p->currentFrame(),
	      SLOT(print(QPrinter *)));

      if(printDialog.exec() == QDialog::Accepted)
	p->print(&printer);
    }
}

void dooble::slotShowDesktopTab(const bool state)
{
  bool desktopFound = false;

  for(int i = 0; i < ui.tabWidget->count(); i++)
    if(ui.tabWidget->tabData(i).toString() == "Desktop")
      {
	desktopFound = true;

	if(state)
	  ui.tabWidget->setCurrentIndex(i);

	break;
      }

  if(!desktopFound)
    {
      QSettings settings
	(dooble::s_settings.value("iconSet").toString(), QSettings::IniFormat);

      settings.beginGroup("mainWindow");
      ui.tabWidget->addTab(desktopWidget,
			   QIcon(settings.value("tabWidget").toString()),
			   tr("Dooble Desktop"));
      ui.tabWidget->setTabData(ui.tabWidget->count() - 1,
			       QVariant("Desktop"));
      ui.tabWidget->setTabToolTip(ui.tabWidget->count() - 1,
				  tr("Dooble Desktop"));
      ui.desktopToolButton->setEnabled(false);
      ui.tabWidget->setTabsClosable(ui.tabWidget->count() > 1);
      ui.actionClose_Tab->setEnabled(ui.tabWidget->count() > 1);
      ui.tabWidget->cornerWidget(Qt::TopRightCorner)->setEnabled
	(ui.tabWidget->count() > 1);

      QAction *action = new QAction(tr("Dooble Desktop"), this);

      action->setData("Desktop");
      action->setIcon
	(QIcon(settings.value("actionDesktop").toString()));
      connect(action, SIGNAL(triggered(void)), this,
	      SLOT(slotShowDesktopTab(void)));
      ui.menu_Tabs->addAction(action);

      if(state)
	ui.tabWidget->setCurrentWidget(desktopWidget);

      if(ui.tabWidget->count() == 1)
	ui.tabWidget->setBarVisible
	  (dooble::s_settings.value("settingsWindow/alwaysShowTabBar",
				    true).toBool());
      else
	ui.tabWidget->setBarVisible(true);
    }
}

void dooble::slotShowPageSource(void)
{
  dview *p = qobject_cast<dview *> (ui.tabWidget->currentWidget());

  if(p && p->currentFrame())
    {
      dpagesourcewindow *ps = new dpagesourcewindow
	(p->url(),
	 p->currentFrame()->toHtml());

      connect(this,
	      SIGNAL(iconsChanged(void)),
	      ps,
	      SLOT(slotSetIcons(void)));

      /*
      ** The dpagesourcewindow object automatically destroys
      ** itself whenever it is closed.
      */
    }
}

void dooble::slotClearHistory(void)
{
  /*
  ** Clear histories.
  */

  foreach(QWidget *widget, QApplication::topLevelWidgets())
    if(qobject_cast<dooble *> (widget))
      {
	dooble *d = qobject_cast<dooble *> (widget);

	if(!d)
	  continue;

	/*
	** Clear the location widget histories.
	*/

	d->ui.locationLineEdit->clearHistory();

	/*
	** Clear every page's history.
	*/

	emit d->clearHistory();

	/*
	** Remove all but the non-history actions.
	*/

	d->m_lastReplacedHistoryPosition = 3;

	while(d->ui.historyMenu->actions().size() > 2)
	  d->ui.historyMenu->removeAction(d->ui.historyMenu->actions().last());

	if(!d->ui.historyMenu->actions().isEmpty())
	  {
	    d->ui.historyMenu->actions().at(0)->setEnabled(false);
	    d->ui.historyMenu->actions().at(1)->setEnabled(true);
	  }

	/*
	** Clear the history of the back and forward buttons' menus.
	*/

	d->ui.backToolButton->menu()->clear();
	d->ui.forwardToolButton->menu()->clear();
	d->ui.backToolButton->setEnabled(false);
	d->ui.forwardToolButton->setEnabled(false);
      }

  /*
  ** Clear the contents of the history database.
  */

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

    db.setDatabaseName(QDir::homePath() + QDir::separator() +
		       ".dooble" + QDir::separator() + "history.db");

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

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

    db.close();
  }

  QSqlDatabase::removeDatabase("history");
  QFile::remove(QDir::homePath() + QDir::separator() +
		".dooble" + QDir::separator() + "history.db");
}

void dooble::slotShowSettingsWindow(void)
{
  settingsWindow->exec(this);
}

void dooble::slotViewZoomIn(void)
{
  dview *p = qobject_cast<dview *> (ui.tabWidget->currentWidget());

  if(p && p->page() && p->page()->currentFrame())
    {
      p->page()->currentFrame()->setZoomFactor
	(p->page()->currentFrame()->zoomFactor() + 0.1);
      update();
    }
}

void dooble::slotViewZoomOut(void)
{
  dview *p = qobject_cast<dview *> (ui.tabWidget->currentWidget());
	
  if(p && p->page() && p->page()->currentFrame())
    {
      p->page()->currentFrame()->setZoomFactor
	(p->page()->currentFrame()->zoomFactor() - 0.1);
      update();
    }
}

void dooble::slotViewResetZoom(void)
{
  dview *p = qobject_cast<dview *> (ui.tabWidget->currentWidget());

  if(p && p->page()->currentFrame())
    {
      p->page()->currentFrame()->setZoomFactor(1.0);
      update();
    }
}

void dooble::slotViewZoomTextOnly(bool enable)
{
  dview *p = qobject_cast<dview *> (ui.tabWidget->currentWidget());

  if(p && p->page()->currentFrame())
    {
      p->page()->currentFrame()->page()->settings()->setAttribute
	(QWebSettings::ZoomTextOnly, enable);
      update();
    }
}

void dooble::slotStatusBarDisplay(void)
{
  if(isFullScreen())
    return;

  statusBar()->setVisible(ui.actionStatusbar->isChecked());

  QSettings settings;

  settings.setValue("mainWindow/statusbarDisplay", statusBar()->isVisible());
  dooble::s_settings["mainWindow/statusbarDisplay"] =
    statusBar()->isVisible();
}

void dooble::slotShowHiddenFiles(void)
{
  QSettings settings;

  settings.setValue("mainWindow/showHiddenFiles",
		    ui.actionShow_Hidden_Files->isChecked());
  dooble::s_settings["mainWindow/showHiddenFiles"] =
    ui.actionShow_Hidden_Files->isChecked();

  if(dooble::s_settings.value("mainWindow/showHiddenFiles", true).toBool())
    {
      dfilemanager::treeModel->setFilter
	(dfilemanager::treeModel->filter() | QDir::Hidden);
      dfilemanager::tableModel->setFilter
	(dfilemanager::tableModel->filter() | QDir::Hidden);
    }
  else
    {
      dfilemanager::treeModel->setFilter
	(dfilemanager::treeModel->filter() & ~QDir::Hidden);
      dfilemanager::tableModel->setFilter
	(dfilemanager::tableModel->filter() & ~QDir::Hidden);
    }
}

void dooble::closeDesktop(void)
{
  /*
  ** Destroy the widget that is housing the Desktop.
  */

  for(int i = 0; i < ui.tabWidget->count(); i++)
    if(ui.tabWidget->tabData(i).toString() == "Desktop")
      {
	ui.tabWidget->removeTab(i);
	ui.desktopToolButton->setEnabled(true);
	break;
      }

  for(int i = 0; i < ui.menu_Tabs->actions().size(); i++)
    if(ui.menu_Tabs->actions().at(i)->data().toString() == "Desktop")
      {
	ui.menu_Tabs->actions().at(i)->deleteLater();
	break;
      }

  ui.tabWidget->setTabsClosable(ui.tabWidget->count() > 1);
  ui.actionClose_Tab->setEnabled(ui.tabWidget->count() > 1);
  ui.tabWidget->cornerWidget(Qt::TopRightCorner)->setEnabled
    (ui.tabWidget->count() > 1);
}

void dooble::slotOpenDirectory(void)
{
  QFileDialog fileDialog(this);

#ifdef Q_WS_MAC
  fileDialog.setAttribute(Qt::WA_MacMetalStyle, true);
#endif
  fileDialog.setWindowModality(Qt::WindowModal);
  fileDialog.setWindowTitle(tr("Dooble Web Browser: Open Directory"));
  fileDialog.setFileMode(QFileDialog::Directory);
  fileDialog.setDirectory(QDir::homePath());
  fileDialog.setLabelText(QFileDialog::Accept, tr("&Open"));
  fileDialog.setAcceptMode(QFileDialog::AcceptOpen);

  if(fileDialog.exec() == QDialog::Accepted)
    {
      QStringList list(fileDialog.selectedFiles());

      if(!list.isEmpty())
	{
	  if(ui.tabWidget->
	     tabData(ui.tabWidget->currentIndex()).toString() == "Desktop")
	    desktopWidget->showFileManagerWindow
	      (QUrl::fromLocalFile(list[0]));
	  else
	    loadPage(QUrl::fromLocalFile(list[0]));

	  list.clear();
	}
    }
}

void dooble::slotOpenMyRetrievedFiles(void)
{
  if(ui.tabWidget->
     tabData(ui.tabWidget->currentIndex()).toString() == "Desktop")
    desktopWidget->showFileManagerWindow();
  else
    {
      QString path("");

      if(dooble::s_settings.contains("settingsWindow/myRetrievedFiles"))
	path = dooble::s_settings.value
	  ("settingsWindow/myRetrievedFiles").toString();
      else
	{
	  QString path = QDesktopServices::storageLocation
	    (QDesktopServices::DesktopLocation);

	  if(path.isEmpty() || !QFile::exists(path))
	    path = QDir::homePath();
	}

      loadPage(QUrl::fromLocalFile(path));
    }
}

void dooble::slotChangeDesktopBackgrounds(void)
{
  foreach(QWidget *widget, QApplication::topLevelWidgets())
    if(qobject_cast<dooble *> (widget))
      {
	dooble *d = qobject_cast<dooble *> (widget);

	emit d->updateDesktopBackground();
      }
}

void dooble::saveHistoryItem(const dwebhistoryitem &item)
{
  if(!item.isValid())
    return;

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

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

    db.setDatabaseName(QDir::homePath() + QDir::separator() +
		       ".dooble" + QDir::separator() + "history.db");

    if(db.open())
      {
	int count = 1;
	QSqlQuery query(db);

	query.exec("CREATE TABLE IF NOT EXISTS history ("
		   "title TEXT, "
		   "url TEXT PRIMARY KEY NOT NULL, "
		   "host TEXT NOT NULL, "
		   "last_visited TEXT NOT NULL, "
		   "icon BLOB DEFAULT NULL, "
		   "visits INTEGER NOT NULL)");

	if(query.exec(QString("SELECT visits FROM history WHERE url = "
			      "'%1'").
		      arg(item.url().toString(QUrl::StripTrailingSlash))))
	  if(query.next())
	    count = query.value(0).toInt() + 1;

	query.exec("PRAGMA synchronous = OFF");
	query.prepare
	  ("INSERT OR REPLACE INTO history "
	   "(url, host, icon, last_visited, title, visits) "
	   "VALUES (?, ?, ?, ?, ?, ?)");
	query.bindValue(0, item.url().toString(QUrl::StripTrailingSlash));
	query.bindValue(1, item.url().host());

	QBuffer buffer;
	QByteArray bytes;

	buffer.setBuffer(&bytes);
	buffer.open(QIODevice::WriteOnly);

	QDataStream out(&buffer);

	out << item.icon();
	query.bindValue(2, bytes.toBase64());
	buffer.close();
	query.bindValue(3, item.visitDate().toString(Qt::ISODate));

	if(item.title().trimmed().isEmpty())
	  query.bindValue(4, item.url().toString(QUrl::StripTrailingSlash));
	else
	  query.bindValue(4, item.title());

	query.bindValue(5, count);
	query.exec();
      }

    db.close();
  }

  QSqlDatabase::removeDatabase("history");
}

void dooble::slotCopy(void)
{
  if(ui.searchLineEdit->hasFocus() &&
     !ui.searchLineEdit->selectedText().isEmpty())
    ui.searchLineEdit->copy();
  else if(ui.locationLineEdit->hasFocus() &&
	  !ui.locationLineEdit->selectedText().isEmpty())
    ui.locationLineEdit->copy();
  else
    {
      dview *p = qobject_cast<dview *> (ui.tabWidget->currentWidget());

      if(p && !p->isDir() && !p->isFtp())
	p->page()->triggerAction(QWebPage::Copy);
    }
}

void dooble::slotPaste(void)
{
  if(ui.searchLineEdit->hasFocus())
    ui.searchLineEdit->paste();
  else if(ui.locationLineEdit->hasFocus())
    ui.locationLineEdit->paste();
  else
    {
      dview *p = qobject_cast<dview *> (ui.tabWidget->currentWidget());

      if(p && !p->isDir() && !p->isFtp())
	p->page()->triggerAction(QWebPage::Paste);
    }
}

void dooble::slotSelectAllContent(void)
{
  dview *p = qobject_cast<dview *> (ui.tabWidget->currentWidget());

  if(p)
    p->page()->triggerAction(QWebPage::SelectAll);
}

void dooble::slotAuthenticationRequired(QNetworkReply *reply,
					QAuthenticator *authenticator)
{
  /*
  ** We should inspect the reply object. However, based on the
  ** name of the signal authenticationRequired and the capabilities of
  ** QAuthenticator, we can conclude that credentials are sought.
  */

  Q_UNUSED(reply);
  QDialog dialog(this);
  Ui_passwordDialog ui;

  ui.setupUi(&dialog);
#ifdef Q_WS_MAC
  dialog.setAttribute(Qt::WA_MacMetalStyle, true);
#endif

  if(dialog.exec() == QDialog::Accepted)
    {
      authenticator->setUser(ui.usernameLineEdit->text());
      authenticator->setPassword(ui.passwordLineEdit->text());
    }
  else
    {
      /*
      ** Abort the load if the user has rejected the dialog.
      */

      QNetworkAccessManager *networkAccessManager =
	qobject_cast<QNetworkAccessManager *> (sender());

      if(networkAccessManager)
	{
	  QWebPage *webPage = qobject_cast<QWebPage *>
	    (networkAccessManager->parent());

	  if(webPage)
	    {
	      QWebView *webView = qobject_cast<QWebView *> (webPage->parent());

	      if(webView)
		webView->stop();
	    }
	}
    }
}

void dooble::slotFullScreenMode(void)
{
  bool setVisible = false;
  static QSize m_size = size();

  if(ui.actionFull_Screen_Mode->text().contains("Full"))
    {
      setVisible = false;
      ui.actionFull_Screen_Mode->setText("Normal Screen Mode");
    }
  else
    {
      setVisible = true;
      ui.actionFull_Screen_Mode->setText("Full Screen Tablet Mode");
    }

  if(!setVisible)
    {
      m_size = size();
      showFullScreen();
    }
  else
    {
      showNormal();
      resize(m_size);
    }

  if(m_isJavaScriptWindow)
    ui.toolBar->setVisible(setVisible);
  else
    {
      menuBar()->setVisible(setVisible);
      ui.actionStatusbar->setEnabled(setVisible);

      if(qobject_cast<dview *> (ui.tabWidget->currentWidget()))
	{
	  statusBar()->setVisible(ui.actionStatusbar->isChecked() &&
				  setVisible);
	  ui.toolBar->setVisible(setVisible);
	}
      else
	{
	  statusBar()->setVisible(false);
	  ui.toolBar->setVisible(false);
	}
    }

  ui.marker->setVisible(!setVisible);
  ui.tabWidget->setBarVisible(setVisible);
  ui.restoreToolButton->setVisible(!setVisible);
  activateWindow();
}

void dooble::slotMarkerEntered(void)
{
  ui.marker->setVisible(false);
  ui.toolBar->setVisible(true);
  ui.tabWidget->setBarVisible(true);
  ui.restoreToolButton->setVisible(true);
}

void dooble::slotViewEntered(void)
{
  if(isFullScreen())
    {
      ui.toolBar->setVisible(false);
      ui.tabWidget->setBarVisible(false);
      ui.restoreToolButton->setVisible(false);
      ui.marker->setVisible(true);
    }
}

void dooble::slotFontChanged(const QFont &font)
{
  QApplication::setFont(font);

  foreach(QWidget *widget, QApplication::allWidgets())
    widget->setFont(font);

  menuBar()->setFont(font);

  foreach(QMenu *menu, menuBar()->findChildren<QMenu *> ())
    {
      menu->setFont(font);

      foreach(QAction *action, menu->actions())
	action->setFont(font);
    }
}

void dooble::slotSelectionChanged(const QString &text)
{
  Q_UNUSED(text);
}

void dooble::slotSelectionChanged(void)
{
}

void dooble::slotEnablePaste(void)
{
}

void dooble::slotShowHistory(void)
{
  /*
  ** The current window should be the artificial parent.
  */

  disconnect(historyWindow, SIGNAL(open(const QUrl &)),
	     this, SLOT(slotLoadPage(const QUrl &)));
  disconnect(historyWindow, SIGNAL(createTab(const QUrl &)),
	     this, SLOT(slotOpenLinkInNewTab(const QUrl &)));
  disconnect(historyWindow, SIGNAL(openInNewWindow(const QUrl &)),
	     this, SLOT(slotOpenLinkInNewWindow(const QUrl &)));
  connect(historyWindow, SIGNAL(open(const QUrl &)),
	  this, SLOT(slotLoadPage(const QUrl &)));
  connect(historyWindow, SIGNAL(createTab(const QUrl &)),
	  this, SLOT(slotOpenLinkInNewTab(const QUrl &)));
  connect(historyWindow, SIGNAL(openInNewWindow(const QUrl &)),
	  this, SLOT(slotOpenLinkInNewWindow(const QUrl &)));
  historyWindow->show(this);
}

void dooble::slotResetUrl(void)
{
  dview *p = qobject_cast<dview *> (ui.tabWidget->currentWidget());

  if(p)
    {
      ui.locationLineEdit->blockSignals(true);
      ui.locationLineEdit->setText
	(p->url().toString(QUrl::StripTrailingSlash));
      ui.locationLineEdit->blockSignals(false);
      ui.locationLineEdit->setIcon(p->icon());
      slotOpenUrl();
    }
}

void dooble::slotCloseWindow(void)
{
  if(sender() && sender()->parent() && ui.tabWidget->count() > 1)
    {
      dview *p = qobject_cast<dview *> (sender()->parent()->parent());

      if(p)
	slotCloseTab(ui.tabWidget->indexOf(p));
    }
  else
    close();
}

void dooble::launchDooble(const QUrl &url)
{
  QProcess *process = new QProcess();

  process->start(QCoreApplication::applicationDirPath() +
		 QDir::separator() + QCoreApplication::applicationName(),
		 QStringList(url.toString(QUrl::StripTrailingSlash)));
}

void dooble::slotTabMoved(int from, int to)
{
  if(from < 0 || to < 0)
    return;

  if(from < ui.menu_Tabs->actions().size() &&
     to < ui.menu_Tabs->actions().size())
    {
      QAction *toAction = ui.menu_Tabs->actions().at(to);
      QAction *fromAction = ui.menu_Tabs->actions().at(from);

      if(to < from)
	{
	  ui.menu_Tabs->removeAction(fromAction);
	  ui.menu_Tabs->insertAction(toAction, fromAction);
	}
      else
	{
	  ui.menu_Tabs->removeAction(toAction);
	  ui.menu_Tabs->insertAction(fromAction, toAction);
	}
    }
}

void dooble::slotGeometryChangeRequested(const QRect &geometry)
{
  if(ui.tabWidget->count() == 1)
    if(dooble::s_settings.value("settingsWindow/javascriptEnabled",
				true).toBool() &&
       dooble::s_settings.value
       ("settingsWindow/javascriptAcceptGeometryChangeRequests",
	false).toBool())
      setGeometry(geometry);
}

void dooble::slotHideMenuBar(void)
{
  if(ui.tabWidget->count() == 1)
    if(dooble::s_settings.value("settingsWindow/javascriptEnabled",
				true).toBool() &&
       dooble::s_settings.value("settingsWindow/javascriptAllowMenuBarHiding",
				false).toBool())
      menuBar()->setVisible(false);
}

void dooble::slotHideStatusBar(void)
{
  if(ui.tabWidget->count() == 1)
    if(dooble::s_settings.value("settingsWindow/javascriptEnabled",
				true).toBool() &&
       dooble::s_settings.value
       ("settingsWindow/javascriptAllowStatusBarHiding",
	false).toBool())
      statusBar()->setVisible(false);
}

void dooble::slotHideToolBar(void)
{
  if(ui.tabWidget->count() == 1)
    if(dooble::s_settings.value("settingsWindow/javascriptEnabled",
				true).toBool() &&
       dooble::s_settings.value("settingsWindow/javascriptAllowToolBarHiding",
				false).toBool())
      {
	ui.backToolButton->setVisible(false);
	ui.forwardToolButton->setVisible(false);
	ui.homeToolButton->setVisible(false);
	ui.reloadStopWidget->setVisible(false);
	ui.desktopToolButton->setVisible(false);
	ui.searchLineEdit->setVisible(false);
      }
}

void dooble::slotSetTabBarVisible(const bool state)
{
  if(ui.tabWidget->count() == 1)
    ui.tabWidget->setBarVisible(state);
}

void dooble::slotShowApplicationCookies(void)
{
  dooble::s_cookieWindow->show(this);
}

void dooble::prepareWidgetsBasedOnView(dview *p)
{
  if(!p)
    return;

  ui.zoomMenu->setEnabled(!p->isDir() && !p->isFtp());
  ui.actionFind->setEnabled(!p->isDir() && !p->isFtp());
  ui.actionSelect_All_Content->setEnabled(!p->isDir() && !p->isFtp());
  ui.actionShow_Hidden_Files->setEnabled(p->isDir());

  if(p->isDir() || p->isFtp())
    ui.findFrame->setVisible(false);
  else
    ui.findFrame->setVisible(showFindFrame);
}

void dooble::slotLocationSplitterMoved(int pos, int index)
{
  Q_UNUSED(pos);
  Q_UNUSED(index);

  if(!m_isJavaScriptWindow)
    {
      QSettings settings;

      settings.setValue("mainWindow/splitterState",
			ui.splitter->saveState());
      dooble::s_settings["mainWindow/splitterState"] =
	ui.splitter->saveState();
    }
}

void dooble::setCurrentPage(dview *p)
{
  if(p)
    ui.tabWidget->setCurrentWidget(p);
}
