/****************************************************************************
** 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 <QUrl>
#include <QMenu>
#include <QStack>
#include <QStyle>
#include <QWebView>
#include <QFileInfo>
#include <QBoxLayout>
#include <QClipboard>
#include <QPushButton>
#include <QWebHistory>
#include <QResizeEvent>
#include <QNetworkProxy>
#include <QContextMenuEvent>
#include <QFileIconProvider>
#include <QWebHitTestResult>

#include "dmisc.h"
#include "dview.h"
#include "dooble.h"
#include "dwebpage.h"
#include "durlwidget.h"

void dwebview::mousePressEvent(QMouseEvent *event)
{
  /*
  ** We use this method to determine valid popups.
  */

  m_allowPopup = false;

  if(event)
    {
      QWebFrame *frame = page()->currentFrame();

      if(frame)
	{
	  QWebHitTestResult hit = frame->hitTestContent(event->pos());

	  if(hit.linkUrl().isValid())
	    m_allowPopup = true;
	  else if(!hit.isNull())
	    {
	      bool found = false;
	      QWebElementCollection collection = frame->
		documentElement().findAll("input[type=button]");

	      foreach(QWebElement element, collection)
		{
		  if(element == hit.element())
		    {
		      found = true;
		      break;
		    }
		}

	      if(!found)
		{
		  collection = frame->
		    documentElement().findAll("input[type=image]");

		  foreach(QWebElement element, collection)
		    {
		      if(element == hit.element())
			{
			  found = true;
			  break;
			}
		    }
		}

	      if(!found)
		{
		  collection = frame->
		    documentElement().findAll("input[type=submit]");

		  foreach(QWebElement element, collection)
		    {
		      if(element == hit.element())
			{
			  found = true;
			  break;
			}
		    }
		}

	      if(found)
		m_allowPopup = true;
	      else
		{
		  foreach(QWebElement element, frame->documentElement().
			  findAll("*"))
		    if(element.geometry().contains(hit.pos()))
		      if(element.attribute("role").toLower() == "link" ||
			 element.attribute("method").toLower() == "post" ||
			 element.hasAttribute("href") ||
			 element.hasAttribute("onclick") ||
			 (element.hasAttribute("src") &&
			  QUrl(element.attribute("src")).isValid()))
			{
			  found = true;
			  break;
			}

		  if(found)
		    m_allowPopup = true;
		}
	    }
	}
    }

  QWebView::mousePressEvent(event);
}

dview::dview(QWidget *parent):QStackedWidget(parent)
{
  m_action = 0;
  webView = new dwebview(this);
  ftpBrowser = new dftpbrowser(this);
  fileManager = new dfilemanager(this);
  directoryView = new QWebView(this);
  m_history = new dwebhistory();
  m_faviconManager = new QNetworkAccessManager(this);
  directoryView->setVisible(false);
  webView->setPage(new dwebpage(webView));
  webView->page()->networkAccessManager()->setCookieJar(dooble::s_cookies);
  webView->page()->setLinkDelegationPolicy(QWebPage::DontDelegateLinks);
  dooble::s_cookies->setParent(0);
  addWidget(webView);
  addWidget(fileManager);
  addWidget(ftpBrowser);
  setCurrentIndex(0);
  m_pageLoaded = false;
  m_percentLoaded = 0;
  selectedUrl = "";
  selectedImageUrl = "";
  webView->setContextMenuPolicy(Qt::CustomContextMenu);
  connect(webView, SIGNAL(urlChanged(const QUrl &)), this,
	  SLOT(slotUrlChanged(const QUrl &)));
  connect(webView, SIGNAL(titleChanged(const QString &)), this,
	  SLOT(slotTitleChanged(const QString &)));
  connect(webView, SIGNAL(loadFinished(bool)), this,
	  SLOT(slotLoadFinished(bool)));
  connect(webView, SIGNAL(loadStarted(void)), this,
	  SLOT(slotLoadStarted(void)));
  connect(webView, SIGNAL(loadProgress(int)), this,
	  SLOT(slotLoadProgress(int)));
  connect(fileManager, SIGNAL(loadFinished(bool)), this,
	  SLOT(slotLoadFinished(bool)));
  connect(fileManager, SIGNAL(loadStarted(void)), this,
	  SLOT(slotLoadStarted(void)));
  connect(fileManager, SIGNAL(urlChanged(const QUrl &)),
	  this, SLOT(slotUrlChanged(const QUrl &)));
  connect(fileManager, SIGNAL(titleChanged(const QString &)),
	  this, SLOT(slotTitleChanged(const QString &)));
  connect(fileManager, SIGNAL(iconChanged(void)),
	  this, SLOT(slotIconChanged(void)));
  connect(fileManager, SIGNAL(loadProgress(int)),
	  this, SLOT(slotLoadProgress(int)));
  connect(ftpBrowser, SIGNAL(loadFinished(bool)), this,
	  SLOT(slotLoadFinished(bool)));
  connect(ftpBrowser, SIGNAL(loadStarted(void)), this,
	  SLOT(slotLoadStarted(void)));
  connect(ftpBrowser, SIGNAL(urlChanged(const QUrl &)),
	  this, SLOT(slotUrlChanged(const QUrl &)));
  connect(ftpBrowser, SIGNAL(titleChanged(const QString &)),
	  this, SLOT(slotTitleChanged(const QString &)));
  connect(ftpBrowser, SIGNAL(iconChanged(void)),
	  this, SLOT(slotIconChanged(void)));
  connect(ftpBrowser, SIGNAL(saveUrl(const QUrl &)),
	  this, SLOT(slotSaveLink(const QUrl &)));
  connect(ftpBrowser, SIGNAL(copyLink(const QUrl &)),
	  this, SLOT(slotCopyLinkLocation(const QUrl &)));
  connect(ftpBrowser, SIGNAL(openLinkInNewTab(const QUrl &)),
	  this, SLOT(slotOpenLinkInNewTab(const QUrl &)));
  connect(ftpBrowser, SIGNAL(openLinkInNewWindow(const QUrl &)),
	  this, SLOT(slotOpenLinkInNewWindow(const QUrl &)));
  connect(ftpBrowser, SIGNAL(loadProgress(int)), this,
	  SLOT(slotLoadProgress(int)));
  connect(webView, SIGNAL(customContextMenuRequested(const QPoint &)),
	  this, SLOT(slotCustomContextMenuRequested(const QPoint &)));
  connect(webView, SIGNAL(linkClicked(const QUrl &)),
	  this, SLOT(slotLinkClicked(const QUrl &)));
  connect(webView->page()->networkAccessManager(),
	  SIGNAL(sslErrors(QNetworkReply *, const QList<QSslError> &)),
	  this,
	  SLOT(slotSslErrors(QNetworkReply *, const QList<QSslError> &)));
  connect(webView->page(),
	  SIGNAL(unsupportedContent(QNetworkReply *)),
	  this,
	  SLOT(slotHandleUnsupportedContent(QNetworkReply *)));
  connect(webView->page(),
	  SIGNAL(selectionChanged(void)),
	  this,
	  SLOT(slotSelectionChanged(void)));
}

dview::~dview()
{
  if(m_history)
    {
      delete m_history;
      m_history = 0;
    }

  if(m_action)
    m_action->deleteLater();
}

void dview::slotLoadFinished(bool ok)
{
  /*
  ** m_pageLoaded is solely used for determining
  ** if slotLoadFinished() was called.
  */

  m_pageLoaded = true;

  if(ok)
    {
      if(qobject_cast<dfilemanager *> (sender()))
	directoryView->setHtml(fileManager->html());
      else if(qobject_cast<dftpbrowser *> (sender()))
	directoryView->setHtml(ftpBrowser->html());
    }

  emit iconChanged();
  emit loadFinished(ok);
}

void dview::slotLoadStarted(void)
{
  m_pageLoaded = false;

  if(qobject_cast<QWebView *> (sender()))
    m_webViewIcon = QIcon();

  emit iconChanged();
  emit loadStarted();
}

void dview::slotLoadProgress(int progress)
{
  if(progress >= 0)
    m_percentLoaded = progress;

  emit loadProgress(progress);
}

int dview::progress(void) const
{
  return m_percentLoaded;
}

bool dview::isLoaded(void) const
{
  return m_pageLoaded;
}

void dview::slotCustomContextMenuRequested(const QPoint &pos)
{
  QMenu menu(this);
  QWebHitTestResult result = webView->page()->currentFrame()->
    hitTestContent(pos);

  if(!result.linkUrl().isEmpty())
    {
      selectedUrl = result.linkUrl();
      menu.addAction(tr("Copy &Link Location"),
		     this, SLOT(slotCopyLinkLocation(void)));
      menu.addAction(tr("Copy &Selected Text"),
		     this, SLOT(slotCopySelectedText(void)));
      menu.addSeparator();
      menu.addAction(tr("Open Link in New &Tab"),
		     this, SLOT(slotOpenLinkInNewTab(void)));
      menu.addAction(tr("Open Link in &New Window"),
		     this, SLOT(slotOpenLinkInNewWindow(void)));
      menu.addSeparator();
      menu.addAction(tr("&Save Link"),
		     this, SLOT(slotSaveLink(void)));
    }
  else
    {
      if(!webView->selectedText().isEmpty())
	menu.addAction(tr("&Copy"),
		       this,
		       SLOT(slotCopySelectedText(void)));

      if(!QApplication::clipboard()->text().isEmpty())
	menu.addAction(tr("&Paste"),
		       this,
		       SLOT(slotPaste(void)));

      if(!menu.actions().isEmpty())
	menu.addSeparator();

      menu.addAction(tr("&Reload"),
		     this,
		     SLOT(slotReload(void)));
    }

  if(!result.imageUrl().isEmpty())
    {
      selectedImageUrl = result.imageUrl();

      if(!result.linkUrl().isEmpty())
	menu.addSeparator();

      menu.addSeparator();
      menu.addAction(tr("Copy &Image Location"),
		     this, SLOT(slotCopyImageLocation(void)));
      menu.addAction(tr("Sa&ve Image"),
		     this, SLOT(slotSaveImage(void)));
      menu.addAction(tr("View I&mage"),
		     this, SLOT(slotViewImage(void)));
      menu.addAction(tr("View Im&age in New Tab"),
		     this, SLOT(slotOpenImageInNewTab(void)));
      menu.addAction(tr("View Ima&ge in New Window"),
		     this, SLOT(slotOpenImageInNewWindow(void)));
    }

  if(!menu.isEmpty())
    {
      menu.exec(mapToGlobal(pos));
      return;
    }
}

void dview::slotAdBlock(void)
{
  /*
  ** Soon.
  */
}

void dview::slotViewImage(void)
{
  emit viewImage(selectedImageUrl);
}

void dview::slotOpenLinkInNewTab(void)
{
  emit openLinkInNewTab(selectedUrl);
}

void dview::slotOpenLinkInNewTab(const QUrl &url)
{
  emit openLinkInNewTab(url);
}

void dview::slotOpenLinkInNewWindow(void)
{
  emit openLinkInNewWindow(selectedUrl);
}

void dview::slotOpenLinkInNewWindow(const QUrl &url)
{
  emit openLinkInNewWindow(url);
}

void dview::slotOpenImageInNewTab(void)
{
  emit openLinkInNewTab(selectedImageUrl);
}

void dview::slotOpenImageInNewWindow(void)
{
  emit openLinkInNewWindow(selectedImageUrl);
}

void dview::slotCopyLinkLocation(void)
{
  emit copyLink(selectedUrl);
}

void dview::slotCopyLinkLocation(const QUrl &url)
{
  emit copyLink(url);
}

void dview::slotCopyImageLocation(void)
{
  emit copyLink(selectedImageUrl);
}

void dview::slotSaveLink(void)
{
  emit saveUrl(selectedUrl);
}

void dview::slotSaveLink(const QUrl &url)
{
  emit saveUrl(url);
}

void dview::slotSaveImage(void)
{
  emit saveUrl(selectedImageUrl);
}

void dview::slotClearHistory(void)
{
  m_history->clear();
  webView->history()->clear();
  ftpBrowser->history()->clear();
  fileManager->history()->clear();
}

void dview::load(const QUrl &url)
{
  if(url.isEmpty() || !url.isValid())
    {
      emit loadFinished(false);
      return;
    }

  int index = indexForUrl(url);

  if(index == -1)
    {
      emit loadFinished(false);
      return;
    }

  foreach(QNetworkReply *reply,
	  m_faviconManager->findChildren<QNetworkReply *> ())
    {
      reply->abort();
      reply->deleteLater();
    }

  webView->stop();
  ftpBrowser->stop();
  setCurrentIndex(index);

  if(index == 0)
    {
      m_webViewIcon = QIcon();
      webView->page()->networkAccessManager()->setProxy
	(dmisc::proxyByUrl(url));

      if(url.hasFragment())
	webView->load(url);
      else
	webView->setUrl(url);
    }
  else if(index == 1)
    fileManager->load(url);
  else if(index == 2)
    ftpBrowser->load(url);
}

QIcon dview::icon(void) const
{
  if(currentIndex() == 0)
    {
      if(!m_webViewIcon.isNull())
	return m_webViewIcon;
    }

  return dmisc::iconForUrl(url());
}

void dview::slotCopySelectedText(void)
{
  webView->triggerPageAction(QWebPage::Copy);
}

dwebpage *dview::page(void) const
{
  return qobject_cast<dwebpage *> (webView->page());
}

QUrl dview::url(void) const
{
  if(currentIndex() == 0)
    return webView->url();
  else if(currentIndex() == 1)
    return fileManager->url();
  else if(currentIndex() == 2)
    return ftpBrowser->url();
  else
    return QUrl();
}

void dview::stop(void)
{
  m_pageLoaded = false;

  foreach(QNetworkReply *reply,
	  m_faviconManager->findChildren<QNetworkReply *> ())
    {
      reply->abort();
      reply->deleteLater();
    }

  m_webViewIcon = QIcon();
  webView->stop();
  ftpBrowser->stop();
}

void dview::reload(void)
{
  if(currentIndex() == 0)
    {
      webView->page()->networkAccessManager()->setProxy 	 
	(dmisc::proxyByUrl(webView->url())); 	 
      webView->reload();
    }
  else if(currentIndex() == 1)
    fileManager->reload();
  else if(currentIndex() == 2)
    ftpBrowser->reload();
}

void dview::back(void)
{
  int index = -1;
  dwebhistoryitem item(m_history->back());

  if((index = indexForUrl(item.url())) == -1)
    {
      emit loadFinished(false);
      return;
    }

  foreach(QNetworkReply *reply,
	  m_faviconManager->findChildren<QNetworkReply *> ())
    {
      reply->abort();
      reply->deleteLater();
    }

  webView->stop();
  ftpBrowser->stop();

  int prevIndex = currentIndex();

  setCurrentIndex(index);

  if(index == 0)
    {
      bool again = false;

      if(item.url() != webView->history()->backItem().url())
	/*
	** Handle broken QWebView.
	*/

	again = true;

      m_webViewIcon = QIcon();

      if(prevIndex == currentIndex())
	{
	  bool emitSignals = false;
	  QUrl url1(webView->url());
	  QUrl url2(webView->history()->backItem().url());

	  /*
	  ** If we're going from an URL that has a fragment
	  ** to an URL that is equal to the current URL without
	  ** the fragment, we need to emit signals. Similarly,
	  ** for the reverse.
	  */

	  if(url1.hasFragment())
	    url1.setFragment(QString());

	  if(url2.hasFragment())
	    url2.setFragment(QString());

	  if(url1 == url2 ||
	     url2.isEmpty())
	    emitSignals = true;

	  webView->back();

	  if(emitSignals)
	    emit loadFinished(true);
	}

      if(again)
	load(item.url());
    }
  else if(index == 1)
    {
      if(prevIndex == currentIndex())
	fileManager->back();
      else
	load(item.url());
    }
  else if(index == 2)
    {
      if(prevIndex == currentIndex())
	ftpBrowser->back();
      else
	load(item.url());
    }
}

void dview::forward(void)
{
  int index = -1;
  dwebhistoryitem item(m_history->forward());

  if((index = indexForUrl(item.url())) == -1)
    {
      emit loadFinished(false);
      return;
    }

  foreach(QNetworkReply *reply,
	  m_faviconManager->findChildren<QNetworkReply *> ())
    {
      reply->abort();
      reply->deleteLater();
    }

  webView->stop();
  ftpBrowser->stop();

  int prevIndex = currentIndex();

  setCurrentIndex(index);

  if(index == 0)
    {
      bool again = false;

      if(item.url() != webView->history()->forwardItem().url())
	/*
	** Handle broken QWebView.
	*/

	again = true;

      m_webViewIcon = QIcon();

      if(prevIndex == currentIndex())
	{
	  bool emitSignals = false;
	  QUrl url1(webView->url());
	  QUrl url2(webView->history()->forwardItem().url());

	  if(url1.hasFragment())
	    url1.setFragment(QString());

	  if(url2.hasFragment())
	    url2.setFragment(QString());

	  if(url1 == url2 ||
	     url2.isEmpty())
	    emitSignals = true;

	  webView->forward();

	  if(emitSignals)
	    emit loadFinished(true);
	}

      if(again)
	load(item.url());
    }
  else if(index == 1)
    {
      if(prevIndex == currentIndex())
	fileManager->forward();
      else
	load(item.url());
    }
  else if(index == 2)
    {
      if(prevIndex == currentIndex())
	ftpBrowser->forward();
      else
	load(item.url());
    }
}

QString dview::title(void) const
{
  if(currentIndex() == 0)
    return webView->title().trimmed();
  else if(currentIndex() == 1)
    return fileManager->title().trimmed();
  else if(currentIndex() == 2)
    return ftpBrowser->title().trimmed();
  else
    return QString();
}

void dview::slotUrlChanged(const QUrl &url)
{
  /*
  ** What about anchors?
  */

  bool fragment = false;
  QUrl url1(url);
  QUrl url2(m_history->currentItem().url());

  if(url1.hasFragment())
    {
      fragment = true;
      url1.setFragment(QString());
    }

  if(url2.hasFragment())
    {
      fragment = true;
      url2.setFragment(QString());
    }

  downloadFavicon(url);
  m_history->add(url);
  emit urlChanged(url);

  if(fragment &&
     url1 == url2)
    /*
    ** Required for populating navigation menus.
    */

    emit loadFinished(true);
}

void dview::slotTitleChanged(const QString &title)
{
  emit titleChanged(title);
}

void dview::slotIconChanged(void)
{
  emit iconChanged();
}

bool dview::canGoBack(void) const
{
  return m_history->canGoBack();
}

bool dview::canGoForward(void) const
{
  return m_history->canGoForward();
}

QList<dwebhistoryitem> dview::backItems(const int n) const
{
  return m_history->backItems(n);
}

QList<dwebhistoryitem> dview::forwardItems(const int n) const
{
  return m_history->forwardItems(n);
}

void dview::print(QPrinter *printer)
{
  if(!printer)
    return;

  QWebFrame *frame = currentFrame();

  if(frame)
    frame->print(printer);
}

QWebFrame *dview::currentFrame(void) const
{
  if(currentIndex() == 0)
    return webView->page()->currentFrame();
  else if(currentIndex() == 1)
    {
      directoryView->setHtml(fileManager->html());
      return directoryView->page()->currentFrame();
    }
  else if(currentIndex() == 2)
    {
      directoryView->setHtml(ftpBrowser->html());
      return directoryView->page()->currentFrame();
    }
  else
    return 0;
}

QString dview::html(void) const
{
  if(currentIndex() == 0)
    return webView->page()->currentFrame()->toHtml();
  else if(currentIndex() == 1)
    {
      directoryView->setHtml(fileManager->html());
      return directoryView->page()->currentFrame()->toHtml();
    }
  else if(currentIndex() == 2)
    {
      directoryView->setHtml(ftpBrowser->html());
      return directoryView->page()->currentFrame()->toHtml();
    }
  else
    return "";
}

void dview::slotReload(void)
{
  reload();
}

bool dview::isDir(void) const
{
  if(QFileInfo(url().toLocalFile()).isDir())
    return true;
  else
    return false;
}

bool dview::isFtp(void) const
{
  if(url().scheme().toLower() == "ftp")
    return true;
  else
    return false;
}

void dview::slotSslErrors(QNetworkReply *reply,
			  const QList<QSslError> &errors)
{
  /*
  ** Dooble must, at some point, allow the user to configure SSL
  ** certificates.
  */

  Q_UNUSED(errors);

  if(!reply)
    return;

  reply->ignoreSslErrors();
}

void dview::setFocus(void)
{
  if(currentIndex() == 0)
    webView->setFocus();
  else if(currentIndex() == 1)
    fileManager->setFocus();
  else if(currentIndex() == 2)
    ftpBrowser->setFocus();
}

void dview::slotHandleUnsupportedContent(QNetworkReply *reply)
{
  if(reply && reply->error() == QNetworkReply::NoError)
    {
      if(reply->rawHeader("Content-Disposition").contains("inline") ||
	 reply->rawHeader("Content-Disposition").contains("attachment"))
	{
	  QString fileName(reply->rawHeader("Content-Disposition"));

	  if(fileName.indexOf('"') != -1 &&
	     fileName.lastIndexOf('"') != -1 &&
	     fileName.indexOf('"') != fileName.lastIndexOf('"'))
	    {
	      fileName = fileName.mid(fileName.indexOf('"') + 1);
	      fileName = fileName.mid(0, fileName.indexOf('"'));
	    }
	  else if(fileName.indexOf('<') != -1 &&
		  fileName.lastIndexOf('>') != -1 &&
		  fileName.indexOf('<') != fileName.lastIndexOf('>'))
	    {
	      fileName = fileName.mid(fileName.indexOf('<') + 1);
	      fileName = fileName.mid(0, fileName.indexOf('>'));
	    }
	  else
	    fileName = tr("File");

	  reply->abort();
	  emit saveFile(fileName, reply);
	}
      else
	{
	  if(reply->rawHeader("Content-Type").trimmed().toLower() ==
	     "application/octet-stream" &&
	     reply->rawHeader("Content-Length").toLongLong() > 0)
	    {
	      reply->abort();
	      emit saveUrl(reply->url());
	    }
	  else if(reply->rawHeader("Content-Type").trimmed().contains("text"))
	    {
	      reply->abort();
	      emit saveUrl(reply->url());
	    }
	  else if(reply->rawHeader("Content-Type").trimmed().contains
		  ("application"))
	    {
	      reply->abort();
	      emit saveUrl(reply->url());
	    }
	  else
	    reply->abort();
	}
    }
  else if(reply)
    reply->abort();
}

void dview::enterEvent(QEvent *event)
{
  QStackedWidget::enterEvent(event);
  emit viewEntered();
}

void dview::slotSelectionChanged(void)
{
  emit selectionChanged(webView->selectedText());
}

dwebhistoryitem dview::currentItem(void) const
{
  dwebhistoryitem item(url());

  if(currentIndex() == 0)
    {
      item.setIcon(icon());
      item.setTitle(title());
    }
  else
    item.setIcon(icon());

  return item;
}

int dview::indexForUrl(const QUrl &url) const
{
  /*
  ** Determine the stack widget's correct
  ** index based on the provided url.
  */

  if(url.isEmpty() || !url.isValid())
    return -1;

  if(url.scheme().toLower() == "http" ||
     url.scheme().toLower() == "https" ||
     (url.scheme().toLower() == "file" &&
      QFileInfo(url.toLocalFile()).isFile()))
    return 0;
  else if(url.scheme().toLower() == "file")
    return 1;
  else if(url.scheme().toLower() == "ftp")
    return 2;
  else
    return 0;
}

void dview::slotPaste(void)
{
  webView->triggerPageAction(QWebPage::Paste);
}

void dview::setTabAction(QAction *action)
{
  if(m_action)
    removeAction(m_action);

  m_action = action;

  if(m_action)
    addAction(m_action);
}

QAction *dview::tabAction(void) const
{
  return m_action;
}

void dview::slotIconDownloadFinished(void)
{
  QNetworkReply *reply = qobject_cast<QNetworkReply *> (sender());

  if(reply)
    {
      QPixmap pixmap;
      QByteArray bytes(reply->readAll());

      if(pixmap.loadFromData(bytes, "gif"))
	m_webViewIcon = QIcon(pixmap);
      else if(pixmap.loadFromData(bytes, "ico"))
	m_webViewIcon = QIcon(pixmap);
      else if(pixmap.loadFromData(bytes, "jpg"))
	m_webViewIcon = QIcon(pixmap);
      else if(pixmap.loadFromData(bytes, "jpeg"))
	m_webViewIcon = QIcon(pixmap);
      else if(pixmap.loadFromData(bytes, "png"))
	m_webViewIcon = QIcon(pixmap);
      else
	m_webViewIcon = QIcon();

      reply->deleteLater();
      emit iconChanged();
    }
}

void dview::downloadFavicon(const QUrl &url)
{
  if(url.scheme() == "http" ||
     url.scheme() == "https")
    {
      foreach(QNetworkReply *reply,
	      m_faviconManager->findChildren<QNetworkReply *> ())
	{
	  reply->abort();
	  reply->deleteLater();
	}

      QUrl faviconUrl;

      faviconUrl.setHost(url.host());
      faviconUrl.setPath("favicon.ico");
      faviconUrl.setScheme(url.scheme());
      m_faviconManager->setProxy
	(dmisc::proxyByUrl(faviconUrl));

      QNetworkReply *reply = m_faviconManager->get
	(QNetworkRequest(faviconUrl));

      reply->ignoreSslErrors();
      connect(reply, SIGNAL(finished(void)),
	      this, SLOT(slotIconDownloadFinished(void)));
    }
}

void dview::slotLinkClicked(const QUrl &url)
{
  /*
  ** Not yet used.
  */

  load(url);
}
