/****************************************************************************
** Dooble - The Secure Internet Web Browser
**
** Copyright (c) 2008, 2009, 2010, 2012 Alexis Megas,
** Gunther van Dooble, and the Dooble Team.
** All rights reserved.
**
** License: GPL2 only:
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; version 2 of the License only.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
** or see here: http://www.gnu.org/licenses/gpl.html
**
** For the WebKit library, please see: http://webkit.org.
**
** THE CODE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY
** EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
** ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
** GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
** IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
** ARISING IN ANY WAY OUT OF THE USE OF THIS APPLICATION, EVEN IF ADVISED
** OF THE POSSIBILITY OF SUCH DAMAGE.
**
** Please report all praise, requests, bugs, and problems to the project
** team and administrators: http://sf.net/projects/dooble.
**
** You can find us listed at our project page. New team members are welcome.
** The name of the authors should not be used to endorse or promote products
** derived from Dooble without specific prior written permission.
** If you use this code for other projects, please let us know.
**
** Web sites:
**   http://sf.net/projects/dooble
**   http://dooble.sf.net
****************************************************************************/

#include <QUrl>
#include <QStyle>
#include <QLocale>
#include <QSettings>
#include <QBoxLayout>
#include <QPushButton>
#include <QResizeEvent>
#include <QAbstractItemView>

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

durlcompleterview::durlcompleterview(void):QTableView()
{
  setMouseTracking(true);
}

void durlcompleterview::wheelEvent(QWheelEvent *event)
{
  QTableView::wheelEvent(event);

  QModelIndex index(indexAt(event->pos()));

  if(index.isValid())
    {
      selectionModel()->blockSignals(true);
      selectRow(index.row());
      selectionModel()->blockSignals(false);

      /*
      ** Call update(), otherwise more than one item may
      ** be selected.
      */

      update();
    }
}

void durlcompleterview::mouseMoveEvent(QMouseEvent *event)
{
  QTableView::mouseMoveEvent(event);

  QModelIndex index(indexAt(event->pos()));

  if(index.isValid())
    {
      selectionModel()->blockSignals(true);
      selectRow(index.row());
      selectionModel()->blockSignals(false);

      /*
      ** Call update(), otherwise more than one item may
      ** be selected.
      */

      update();
    }
}

durlcompleter::durlcompleter(QWidget *parent):QCompleter(parent)
{
  m_model = 0;
  m_tableView = new durlcompleterview();
  m_tableView->setMouseTracking(true);
  m_tableView->setSelectionMode(QAbstractItemView::SingleSelection);
  m_tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
  m_tableView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
  m_tableView->verticalHeader()->setVisible(false);
  m_tableView->horizontalHeader()->setVisible(false);
  m_tableView->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
  setPopup(m_tableView);
}

durlcompleter::~durlcompleter()
{
  clear();

  /*
  ** We don't need to delete m_tableView as setPopup()
  ** forces the completer to take ownership of the view.
  */
}

bool durlcompleter::exists(const QString &text) const
{
  return m_allUrls.contains(text);
}

void durlcompleter::clear(void)
{
  if(m_model)
    m_model->clear();

  while(!m_purgedItems.isEmpty())
    delete m_purgedItems.takeFirst();
}

void durlcompleter::setModel(QStandardItemModel *model)
{
  m_model = model;

  if(m_model)
    m_model->setSortRole(Qt::UserRole);

  QCompleter::setModel(m_model);
}

void durlcompleter::saveItemUrl(const QString &url)
{
  m_allUrls.append(url);
}

void durlcompleter::setCompletion
(const QString &completion)
{
  if(!m_model)
    return;

  m_model->blockSignals(true);

  while(!m_purgedItems.isEmpty())
    {
      m_model->setRowCount(m_model->rowCount() + 1);
      m_model->setItem(m_model->rowCount() - 1,
		       m_purgedItems.takeFirst());
    }

  QList<QStandardItem *> list;

  if(completion.trimmed().isEmpty())
    {
      for(int i = 0; i < m_model->rowCount(); i++)
	if(m_model->item(i, 0))
	  list.append(m_model->item(i, 0)->clone());
    }
  else
    {
      QString c(completion.toLower().trimmed());
      QMultiMap<int, QStandardItem *> map;

      for(int i = 0; i < m_model->rowCount(); i++)
	if(m_model->item(i, 0))
	  {
	    if(m_model->item(i, 0)->text().toLower().contains(c))
	      map.insert
		(dmisc::levenshteinDistance
		 (m_model->item(i, 0)->text().toLower(), c),
		 m_model->item(i, 0)->clone());
	    else
	      m_purgedItems.append(m_model->item(i, 0)->clone());
	  }

      list << map.values();
    }

  m_model->clear();

  while(list.size() > 1)
    {
      m_model->setRowCount(m_model->rowCount() + 1);
      m_model->setItem(m_model->rowCount() - 1,
		       list.takeFirst());
    }

  /*
  ** Unblock signals on the model and add the last list entry. This little
  ** trick will allow for a smoother update of the table's contents.
  */

  m_model->blockSignals(false);

  while(!list.isEmpty())
    {
      m_model->setRowCount(m_model->rowCount() + 1);
      m_model->setItem(m_model->rowCount() - 1,
		       list.takeFirst());
    }

  if(m_model->rowCount() > 0)
    {
      if(m_model->rowCount() > 10)
	m_tableView->setVerticalScrollBarPolicy
	  (Qt::ScrollBarAlwaysOn);
      else
	m_tableView->setVerticalScrollBarPolicy
	  (Qt::ScrollBarAlwaysOff);

      m_tableView->setFixedHeight
	(qMin(10, m_model->rowCount()) * m_tableView->rowHeight(0));

      /*
      ** The model should only be sorted when the pulldown
      ** is activated. Otherwise, the Levenshtein algorithm
      ** loses its potential.
      */

      if(m_purgedItems.isEmpty())
	m_model->sort(0, Qt::DescendingOrder);

      complete();
    }
  else
    popup()->setVisible(false);
}

void durlcompleter::copyContentsOf(durlcompleter *c)
{
  if(!c)
    return;

  /*
  ** Aha, c's model may be truncated because of filtering.
  ** We'll also need to copy data from m_purgedItems.
  */

  if(m_model && c->m_model)
    {
      for(int i = 0; i < c->m_purgedItems.size(); i++)
	{
	  saveItemUrl
	    (c->m_purgedItems.at(i)->text());
	  m_model->appendRow(c->m_purgedItems.at(i)->clone());
	}

      for(int i = 0; i < c->m_model->rowCount(); i++)
	{
	  saveItemUrl(c->m_model->item(i, 0)->text());
	  m_model->appendRow(c->m_model->item(i, 0)->clone());
	}
    }
}

durlwidgettoolbutton::durlwidgettoolbutton(QWidget *parent):
  QToolButton(parent)
{
}

void durlwidgettoolbutton::mousePressEvent(QMouseEvent *event)
{
  if(event && (event->type() == QEvent::MouseButtonPress ||
	       event->type() == QEvent::MouseButtonDblClick))
    emit clicked();
  else
    QToolButton::mousePressEvent(event);
}

durlwidget::durlwidget(QWidget *parent):QLineEdit(parent)
{
  m_counter = 0;
  goToolButton = new QToolButton(this);
  goToolButton->setToolTip(tr("Load"));
  goToolButton->setIconSize(QSize(16, 16));
  goToolButton->setCursor(Qt::ArrowCursor);
  goToolButton->setStyleSheet("QToolButton {"
			      "border: none; "
			      "padding-top: 0px; "
			      "padding-bottom: 0px; "
			      "}");
  bookmarkToolButton = new QToolButton(this);
  bookmarkToolButton->setToolTip(tr("Bookmark"));
  bookmarkToolButton->setIconSize(QSize(16, 16));
  bookmarkToolButton->setCursor(Qt::ArrowCursor);
  iconToolButton = new QToolButton(this);
  iconToolButton->setIconSize(QSize(16, 16));
  iconToolButton->setCursor(Qt::ArrowCursor);
  bookmarkToolButton->setStyleSheet
    ("QToolButton {"
     "border: none; "
     "padding-top: 0px; "
     "padding-bottom: 0px; "
     "}");
  iconToolButton->setStyleSheet
    ("QToolButton {"
     "border: none; "
     "padding-top: 0px; "
     "padding-bottom: 0px; "
     "}");
  m_fakePulldownMenu = new durlwidgettoolbutton(this);
  m_fakePulldownMenu->setCursor(Qt::ArrowCursor);
  m_fakePulldownMenu->setIconSize(QSize(16, 16));
  m_fakePulldownMenu->setArrowType(Qt::DownArrow);
  m_fakePulldownMenu->setStyleSheet
    ("QToolButton {"
     "border: none; "
     "padding-top: 0px; "
     "padding-bottom: 0px; "
     "}"
     "QToolButton::menu-button {border: none;}");
  m_fakePulldownMenu->setPopupMode(QToolButton::InstantPopup);
  slotSetIcons();
  connect(this, SIGNAL(returnPressed(void)), this,
	  SLOT(slotReturnPressed(void)));
  connect(m_fakePulldownMenu, SIGNAL(clicked(void)), this,
	  SLOT(slotPulldownClicked(void)));
  connect(goToolButton, SIGNAL(clicked(void)), this,
	  SLOT(slotLoadPage(void)));
  connect(bookmarkToolButton, SIGNAL(clicked(void)), this,
          SLOT(slotBookmark(void)));

  int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);

  setStyleSheet
    (QString("QLineEdit {padding-right: %1px; padding-left: %2px; "
	     "selection-background-color: darkgray;}").
     arg(goToolButton->sizeHint().width() +
	 m_fakePulldownMenu->sizeHint().width() + frameWidth + 5).
     arg(iconToolButton->sizeHint().width() +
	 bookmarkToolButton->sizeHint().width() + frameWidth + 5));
  setMinimumHeight(sizeHint().height() + 10);
  m_completer = new durlcompleter(this);
  m_completer->setModel(new QStandardItemModel(m_completer));
  m_completer->setModelSorting(QCompleter::UnsortedModel);
  m_completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
  m_completer->setCaseSensitivity(Qt::CaseInsensitive);
  connect(m_completer,
	  SIGNAL(activated(const QString &)),
	  this,
	  SLOT(slotLoadPage(const QString &)));
  setCompleter(m_completer);
}

void durlwidget::addItem(const QString &text)
{
  addItem(text, QIcon());
}

void durlwidget::addItem(const QString &text, const QIcon &icon)
{
  if(text.isEmpty())
    return;

  /*
  ** Some items are not acceptable.
  */

  QString l_text(text.toLower().trimmed());

  if(!(l_text.startsWith("file://") ||
       l_text.startsWith("ftp://") ||
       l_text.startsWith("http://") ||
       l_text.startsWith("https://") ||
       l_text.startsWith("qrc:/")))
    return;

  if(!m_completer)
    return;

  /*
  ** Prevent duplicates. We can't use the model's findItems()
  ** as the model may contain a subset of the completer's
  ** items because of filtering activity.
  */

  if(m_completer->exists(text))
    return;

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

  QStandardItemModel *model = qobject_cast<QStandardItemModel *>
    (m_completer->model());

  if(model)
    {
      m_completer->saveItemUrl(text);

      QStandardItem *item = 0;

      if(icon.isNull())
	{
	  QUrl url(QUrl::fromUserInput(text));

	  url = QUrl::fromEncoded(url.toEncoded(QUrl::StripTrailingSlash));
	  item = new QStandardItem(dmisc::iconForUrl(url), text);
	}
      else
	item = new QStandardItem(icon, text);

      QFont font(item->font());

      font.setPointSize(font.pointSize() + 3);

      if(font.pointSize() <= 0)
	font.setPointSize(QApplication::font().pointSize() + 3);

      item->setFont(font);
      m_counter += 1;
      item->setData(m_counter, Qt::UserRole);
      model->insertRow(0, item);
    }
}

void durlwidget::appendItem(const QString &text, const QIcon &icon)
{
  if(text.isEmpty())
    return;

  if(!m_completer)
    return;

  /*
  ** Prevent duplicates. We can't use the model's findItems()
  ** as the model may contain a subset of the completer's
  ** items because of filtering.
  */

  if(m_completer->exists(text))
    return;

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

  QStandardItemModel *model = qobject_cast<QStandardItemModel *>
    (m_completer->model());

  if(model)
    {
      m_completer->saveItemUrl(text);

      QStandardItem *item = 0;

      if(icon.isNull())
	{
	  QUrl url(QUrl::fromUserInput(text));

	  url = QUrl::fromEncoded(url.toEncoded(QUrl::StripTrailingSlash));
	  item = new QStandardItem(dmisc::iconForUrl(url), text);
	}
      else
	item = new QStandardItem(icon, text);

      QFont font(item->font());

      font.setPointSize(font.pointSize() + 3);

      if(font.pointSize() <= 0)
	font.setPointSize(QApplication::font().pointSize() + 3);

      item->setFont(font);
      m_counter += 1;
      item->setData(m_counter, Qt::UserRole);
      model->appendRow(item);
    }
}

void durlwidget::setIcon(const QIcon &icon)
{
  if(icon.isNull())
    {
      QUrl url(QUrl::fromUserInput(text()));

      url = QUrl::fromEncoded(url.toEncoded(QUrl::StripTrailingSlash));
      iconToolButton->setIcon(dmisc::iconForUrl(url));
    }
  else
    iconToolButton->setIcon(icon);
}

void durlwidget::setText(const QString &text)
{
  QLineEdit::setText(text);
  setCursorPosition(0);
}

void durlwidget::selectAll(void)
{
  setCursorPosition(text().length());
  cursorBackward(true, text().length());
}

void durlwidget::resizeEvent(QResizeEvent *event)
{
  int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
  QSize size1 = goToolButton->sizeHint();
  QSize size2 = iconToolButton->sizeHint();
  QSize size3 = bookmarkToolButton->sizeHint();
  QSize size4 = m_fakePulldownMenu->sizeHint();

  goToolButton->move
    (rect().right() - size1.width() - size4.width() - 5,
     (rect().bottom() + 2 - size1.height()) / 2);
  iconToolButton->move
    (frameWidth - rect().left() + size3.width() + 5,
     (rect().bottom() + 2 - size2.height()) / 2);
  bookmarkToolButton->move
    (frameWidth - rect().left() + 6,
     (rect().bottom() + 2 - size3.height()) / 2);
  m_fakePulldownMenu->move
    (rect().right() - frameWidth - size4.width() - 5,
     (rect().bottom() + 2 - size4.height()) / 2);

  if(selectedText().isEmpty())
    setCursorPosition(0);

  QLineEdit::resizeEvent(event);
}

void durlwidget::setItemIcon(const int index , const QIcon &icon)
{
  if(!m_completer)
    return;

  QStandardItemModel *model = qobject_cast<QStandardItemModel *>
    (m_completer->model());

  if(!model)
    return;

  QStandardItem *item = model->item(index, 0);

  if(item)
    {
      if(icon.isNull())
	{
	  QUrl url(QUrl::fromUserInput(item->text()));

	  url = QUrl::fromEncoded(url.toEncoded(QUrl::StripTrailingSlash));
	  item->setIcon(dmisc::iconForUrl(url));
	}
      else
	item->setIcon(icon);
    }
}

void durlwidget::slotPulldownClicked(void)
{
  if(!m_completer)
    return;

  m_completer->setCompletion("");

  /*
  ** I'm not sure why I need to do this. It appears
  ** that the activated() signal is lost whenever
  ** m_completer's model has changed.
  */

  disconnect(m_completer,
	     SIGNAL(activated(const QString &)),
	     this,
	     SLOT(slotLoadPage(const QString &)));
  connect(m_completer,
	  SIGNAL(activated(const QString &)),
	  this,
	  SLOT(slotLoadPage(const QString &)));
}

int durlwidget::findText(const QString &text) const
{
  int index = -1;

  if(text.isEmpty())
    return index;

  if(!m_completer)
    return index;

  QStandardItemModel *model = qobject_cast<QStandardItemModel *>
    (m_completer->model());

  if(!model)
    return index;

  QList<QStandardItem *> list(model->findItems(text));

  if(!list.isEmpty())
    index = list.at(0)->row();

  return index;
}

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

  settings.beginGroup("urlWidget");
  goToolButton->setIcon(QIcon(settings.value("goToolButton").toString()));
  bookmarkToolButton->setIcon
    (QIcon(settings.value("bookmarkToolButton").toString()));

  if(iconToolButton->icon().isNull())
    iconToolButton->setIcon
      (QIcon(settings.value("emptyIcon").toString()));
}

void durlwidget::slotBookmark(void)
{
  emit bookmark();
}

bool durlwidget::event(QEvent *e)
{
  if(e && e->type() == QEvent::KeyPress &&
     static_cast<QKeyEvent *> (e)->key() == Qt::Key_Tab)
    {
      QTableView *table = qobject_cast<QTableView *> (m_completer->popup());

      if(table && table->isVisible())
	{
	  int row = 0;

	  if(table->selectionModel()->
	     isRowSelected(table->currentIndex().row(),
			   table->rootIndex()))
	    {
	      row = table->currentIndex().row() + 1;

	      if(row >= m_completer->model()->rowCount())
		row = 0;
	    }

	  table->selectRow(row);
	  return true;
	}
    }

  return QLineEdit::event(e);
}

void durlwidget::keyPressEvent(QKeyEvent *event)
{
  bool delegateKeyPressEvent = true;

  if(event)
    {
      QKeySequence userKeys(event->modifiers() + event->key());

      if(event->key() == Qt::Key_Up || event->key() == Qt::Key_Down)
	slotPulldownClicked();
      else if(userKeys == QKeySequence(Qt::AltModifier + Qt::Key_Enter) ||
	      userKeys == QKeySequence(Qt::AltModifier + Qt::Key_Return))
	{
	  delegateKeyPressEvent = false;

	  QUrl url(QUrl::fromUserInput(text().trimmed()));

	  url = QUrl::fromEncoded(url.toEncoded(QUrl::StripTrailingSlash));
	  emit openLinkInNewTab(url);
	}
      else if(userKeys == QKeySequence(Qt::ControlModifier +
				       Qt::Key_Enter) ||
	      userKeys == QKeySequence(Qt::ControlModifier +
				       Qt::Key_Return))
	{
	  QUrl url(QUrl::fromUserInput(text().trimmed()));

	  url = QUrl::fromEncoded(url.toEncoded(QUrl::StripTrailingSlash));

	  if(!url.host().isEmpty())
	    if(!url.host().endsWith(".com"))
	      url.setHost(url.host() + ".com");

	  emit loadPage(url);
	}
      else if(userKeys == QKeySequence(Qt::ShiftModifier + Qt::Key_Enter) ||
	      userKeys == QKeySequence(Qt::ShiftModifier + Qt::Key_Return))
	{
	  QUrl url(QUrl::fromUserInput(text().trimmed()));

	  url = QUrl::fromEncoded(url.toEncoded(QUrl::StripTrailingSlash));

	  if(!url.host().isEmpty())
	    if(!url.host().endsWith(".net"))
	      url.setHost(url.host() + ".net");

	  emit loadPage(url);
	}
      else if(userKeys ==
	      QKeySequence(Qt::ControlModifier + Qt::ShiftModifier +
			   Qt::Key_Enter) ||
	      userKeys ==
	      QKeySequence(Qt::ControlModifier + Qt::ShiftModifier +
			   Qt::Key_Return))
	{
	  QUrl url(QUrl::fromUserInput(text().trimmed()));

	  url = QUrl::fromEncoded(url.toEncoded(QUrl::StripTrailingSlash));

	  if(!url.host().isEmpty())
	    if(!url.host().endsWith(".org"))
	      url.setHost(url.host() + ".org");

	  emit loadPage(url);
	}
      else if(userKeys == QKeySequence(Qt::Key_Escape))
	emit resetUrl();
      else if(userKeys == QKeySequence(Qt::ControlModifier +
				       Qt::Key_L))
	{
	  setFocus();
	  selectAll();
	  update();
	}
      else if(event->key() == Qt::Key_Enter ||
	      event->key() == Qt::Key_Return)
	{
	  /*
	  ** Let the parent handle the event.
	  */

	  QLineEdit::keyPressEvent(event);
	  return;
	}
    }

  if(delegateKeyPressEvent)
    QLineEdit::keyPressEvent(event);
  else if(m_completer)
    m_completer->popup()->setVisible(false);

  if(delegateKeyPressEvent && !text().trimmed().isEmpty() &&
     event &&
     event->key() != Qt::Key_Left &&
     event->key() != Qt::Key_Right &&
     event->key() != Qt::Key_Escape &&
     event->modifiers() == Qt::NoModifier &&
     m_completer)
    {
      m_completer->setCompletion(text().trimmed());

      /*
      ** I'm not sure why I need to do this. It appears
      ** that the activated() signal is lost whenever
      ** m_completer's model has changed.
      */

      disconnect(m_completer,
		 SIGNAL(activated(const QString &)),
		 this,
		 SLOT(slotLoadPage(const QString &)));
      connect(m_completer,
	      SIGNAL(activated(const QString &)),
	      this,
	      SLOT(slotLoadPage(const QString &)));
    }
}

void durlwidget::slotLoadPage(void)
{
  QUrl url(QUrl::fromUserInput(text().trimmed()));

  url = QUrl::fromEncoded(url.toEncoded(QUrl::StripTrailingSlash));
  emit loadPage(url);
}

void durlwidget::slotLoadPage(const QString &urlText)
{
#ifdef Q_WS_MAC
  if(m_completer)
    m_completer->popup()->setVisible(false);
#endif

  QUrl url(QUrl::fromUserInput(urlText));

  url = QUrl::fromEncoded(url.toEncoded(QUrl::StripTrailingSlash));
  emit loadPage(url);
}

void durlwidget::clearHistory(void)
{
  m_counter = 0;

  if(m_completer)
    m_completer->clear();
}

void durlwidget::slotReturnPressed(void)
{
  if(m_completer)
    m_completer->popup()->setVisible(false);
}

void durlwidget::setSecureColor(const bool isHttps)
{
  if(isHttps)
    iconToolButton->setStyleSheet
      ("QToolButton {"
       "border: none; "
       "border-radius: 4px; "
       "background: qlineargradient(spread:reflect, x1:0.023,"
       "y1:0.988636, x2:0.028, y2:0.011,"
       "stop:1 rgba(0, 153, 153, 255),"
       "stop:0 rgba(255, 255, 255, 255)); "
       "padding-top: 0px; "
       "padding-bottom: 0px; "
       "}");
  else
    iconToolButton->setStyleSheet
      ("QToolButton {"
       "border: none; "
       "background: white; "
       "padding-top: 0px; "
       "padding-bottom: 0px; "
       "}");
}

void durlwidget::setBookmarkColor(const bool isBookmarked)
{
  if(isBookmarked)
    bookmarkToolButton->setStyleSheet
      ("QToolButton {"
       "border: none; "
       "border-radius: 4px; "
       "background: qlineargradient(spread:reflect, x1:0.023,"
       "y1:0.988636, x2:0.028, y2:0.011,"
       "stop:1 rgba(255, 215, 0, 255),"
       "stop:0 rgba(255, 255, 255, 255)); "
       "padding-top: 0px; "
       "padding-bottom: 0px; "
       "}");
  else
    bookmarkToolButton->setStyleSheet
      ("QToolButton {"
       "border: none; "
       "background: white; "
       "padding-top: 0px; "
       "padding-bottom: 0px; "
       "}");
}

void durlwidget::copyContentsOf(durlwidget *c)
{
  if(m_completer && c->m_completer)
    m_completer->copyContentsOf(c->m_completer);
}

void durlwidget::appendItems
(const QMultiMap<QDateTime, QVariantList> &items)
{
  QStandardItemModel *model = qobject_cast<QStandardItemModel *>
    (m_completer->model());

  if(model)
    {
      QMapIterator<QDateTime, QVariantList> i(items);

      while(i.hasNext())
	{
	  i.next();

	  if(i.value().size() < 2)
	    continue;

	  QString text(i.value().at(0).toUrl().
		       toString(QUrl::StripTrailingSlash));

	  if(m_completer->exists(text))
	    continue;

	  m_completer->saveItemUrl(text);

	  QFont font;
	  QIcon icon(i.value().at(1).value<QIcon> ());

	  if(icon.isNull())
	    icon = dmisc::iconForUrl(i.value().at(0).toUrl());

	  QStandardItem *item = new QStandardItem(icon, text);

	  font = item->font();
	  font.setPointSize(font.pointSize() + 3);

	  if(font.pointSize() <= 0)
	    font.setPointSize(QApplication::font().pointSize() + 3);

	  item->setFont(font);
	  m_counter += 1;
	  item->setData(m_counter, Qt::UserRole);
	  model->appendRow(item);
	}
    }
}

void durlwidget::setBookmarkButtonEnabled(const bool state)
{
  bookmarkToolButton->setEnabled(state);
}

QPoint durlwidget::bookmarkButtonPopupPosition(void) const
{
  QPoint point(bookmarkToolButton->pos());

  point.setY(point.y() + bookmarkToolButton->height());
  return point;
}

bool durlwidget::isBookmarkeButtonEnabled(void) const
{
  return bookmarkToolButton->isEnabled();
}
