From eb7de9a104c44b49859ed2e3a58058941dcbdced Mon Sep 17 00:00:00 2001 From: nowrep Date: Tue, 6 Mar 2012 15:28:52 +0100 Subject: [PATCH] Various enhancements in Bookmark Importing. - when importing from Html file, also bookmark folders are imported - bookmark tree now shows folder structure - fixed importing from UTF8 files - loading icons in own thread = dialog won't freeze anymore --- src/lib/bookmarks/bookmarksmodel.cpp | 28 ++-- src/lib/bookmarks/bookmarksmodel.h | 1 + .../bookmarksimport/bookmarksimportdialog.cpp | 120 +++++++++--------- .../bookmarksimport/bookmarksimportdialog.h | 11 +- .../bookmarksimporticonfetcher.cpp | 84 ++++++++++++ .../bookmarksimporticonfetcher.h | 63 +++++++++ src/lib/bookmarksimport/chromeimporter.cpp | 2 +- src/lib/bookmarksimport/htmlimporter.cpp | 93 +++++++++++--- src/lib/bookmarksimport/operaimporter.cpp | 2 +- src/lib/lib.pro | 6 +- src/lib/preferences/pluginlistdelegate.cpp | 2 +- src/lib/tools/iconfetcher.cpp | 7 +- src/lib/tools/iconfetcher.h | 12 +- 13 files changed, 326 insertions(+), 105 deletions(-) create mode 100644 src/lib/bookmarksimport/bookmarksimporticonfetcher.cpp create mode 100644 src/lib/bookmarksimport/bookmarksimporticonfetcher.h diff --git a/src/lib/bookmarks/bookmarksmodel.cpp b/src/lib/bookmarks/bookmarksmodel.cpp index 36cd080d4..375e598ca 100644 --- a/src/lib/bookmarks/bookmarksmodel.cpp +++ b/src/lib/bookmarks/bookmarksmodel.cpp @@ -63,6 +63,16 @@ void BookmarksModel::setShowingOnlyIconsInToolbar(bool state) m_showOnlyIconsInToolbar = state; } +bool BookmarksModel::isFolder(const QString &name) +{ + QSqlQuery query; + query.prepare("SELECT name FROM folders WHERE name = ?"); + query.bindValue(0, name); + query.exec(); + + return query.next(); +} + void BookmarksModel::setLastFolder(const QString &folder) { Settings settings; @@ -154,6 +164,10 @@ bool BookmarksModel::saveBookmark(const QUrl &url, const QString &title, const Q image = QWebSettings::webGraphic(QWebSettings::DefaultFrameIconGraphic).toImage(); } + if (!isFolder(folder)) { + createFolder(folder); + } + QSqlQuery query; query.prepare("INSERT INTO bookmarks (url, title, folder, icon) VALUES (?,?,?,?)"); query.bindValue(0, url.toString()); @@ -292,14 +306,11 @@ bool BookmarksModel::editBookmark(int id, const QString &title, const QUrl &url, bool BookmarksModel::createFolder(const QString &name) { - QSqlQuery query; - query.prepare("SELECT name FROM folders WHERE name = ?"); - query.bindValue(0, name); - query.exec(); - if (query.next()) { + if (isFolder(name)) { return false; } + QSqlQuery query; query.prepare("INSERT INTO folders (name, subfolder) VALUES (?, 'no')"); query.bindValue(0, name); if (!query.exec()) { @@ -397,14 +408,11 @@ QList BookmarksModel::folderBookmarks(const QString &name) bool BookmarksModel::createSubfolder(const QString &name) { - QSqlQuery query; - query.prepare("SELECT name FROM folders WHERE name = ?"); - query.bindValue(0, name); - query.exec(); - if (query.next()) { + if (isFolder(name)) { return false; } + QSqlQuery query; query.prepare("INSERT INTO folders (name, subfolder) VALUES (?, 'yes')"); query.bindValue(0, name); if (!query.exec()) { diff --git a/src/lib/bookmarks/bookmarksmodel.h b/src/lib/bookmarks/bookmarksmodel.h index f557225bf..9a5a17d41 100644 --- a/src/lib/bookmarks/bookmarksmodel.h +++ b/src/lib/bookmarks/bookmarksmodel.h @@ -68,6 +68,7 @@ public: bool isShowingOnlyIconsInToolbar() { return m_showOnlyIconsInToolbar; } void setShowingOnlyIconsInToolbar(bool state); + bool isFolder(const QString &name); QString lastFolder() { return m_lastFolder; } void setLastFolder(const QString &folder); diff --git a/src/lib/bookmarksimport/bookmarksimportdialog.cpp b/src/lib/bookmarksimport/bookmarksimportdialog.cpp index d8e6db0b2..14fdcaf48 100644 --- a/src/lib/bookmarksimport/bookmarksimportdialog.cpp +++ b/src/lib/bookmarksimport/bookmarksimportdialog.cpp @@ -22,18 +22,21 @@ #include "operaimporter.h" #include "htmlimporter.h" #include "mainapplication.h" -#include "iconfetcher.h" +#include "bookmarksimporticonfetcher.h" #include "iconprovider.h" #include "networkmanager.h" #include #include #include +#include BookmarksImportDialog::BookmarksImportDialog(QWidget* parent) : QDialog(parent) , ui(new Ui::BookmarksImportDialog) , m_currentPage(0) + , m_fetcher(0) + , m_fetcherThread(0) { setAttribute(Qt::WA_DeleteOnClose); ui->setupUi(this); @@ -96,28 +99,53 @@ void BookmarksImportDialog::startFetchingIcons() ui->progressBar->setValue(0); ui->progressBar->setMaximum(m_exportedBookmarks.count()); - int i = 0; + m_fetcherThread = new QThread(); + m_fetcher = new BookmarksImportIconFetcher(); + m_fetcher->moveToThread(m_fetcherThread); + + QIcon defaultIcon = QIcon(QWebSettings::globalSettings()->webGraphic(QWebSettings::DefaultFrameIconGraphic)); + QIcon folderIcon = style()->standardIcon(QStyle::SP_DirIcon); + QHash hash; + foreach(const Bookmark & b, m_exportedBookmarks) { - QTreeWidgetItem* item = new QTreeWidgetItem(); + QTreeWidgetItem* item; + QTreeWidgetItem* findParent = hash[b.folder]; + if (findParent) { + item = new QTreeWidgetItem(findParent); + } + else { + QTreeWidgetItem* newParent = new QTreeWidgetItem(ui->treeWidget); + newParent->setText(0, b.folder); + newParent->setIcon(0, folderIcon); + ui->treeWidget->addTopLevelItem(newParent); + hash[b.folder] = newParent; + + item = new QTreeWidgetItem(newParent); + } + + QVariant bookmarkVariant = qVariantFromValue(b); item->setText(0, b.title); - item->setIcon(0, QWebSettings::globalSettings()->webGraphic(QWebSettings::DefaultFrameIconGraphic)); + if (b.image.isNull()) { + item->setIcon(0, defaultIcon); + } + else { + item->setIcon(0, QIcon(QPixmap::fromImage(b.image))); + } item->setText(1, b.url.toString()); - item->setWhatsThis(0, QString::number(i)); + item->setData(0, Qt::UserRole + 10, bookmarkVariant); ui->treeWidget->addTopLevelItem(item); - i++; - IconFetcher* fetcher = new IconFetcher(this); - fetcher->setNetworkAccessManager(mApp->networkManager()); - connect(fetcher, SIGNAL(finished()), this, SLOT(loadFinished())); - connect(fetcher, SIGNAL(iconFetched(QIcon)), this, SLOT(iconFetched(QIcon))); - fetcher->fetchIcon(b.url); - - QPair pair; - pair.first = fetcher; - pair.second = b.url; - m_fetchers.append(pair); + m_fetcher->addEntry(b.url, item); } + + ui->treeWidget->expandAll(); + + connect(m_fetcher, SIGNAL(iconFetched(QImage, QTreeWidgetItem*)), this, SLOT(iconFetched(QImage, QTreeWidgetItem*))); + connect(m_fetcher, SIGNAL(oneFinished()), this, SLOT(loadFinished())); + + m_fetcherThread->start(); + m_fetcher->startFetching(); } void BookmarksImportDialog::stopDownloading() @@ -139,43 +167,15 @@ void BookmarksImportDialog::loadFinished() } } -void BookmarksImportDialog::iconFetched(const QIcon &icon) +void BookmarksImportDialog::iconFetched(const QImage &image, QTreeWidgetItem* item) { - IconFetcher* fetcher = qobject_cast(sender()); - if (!fetcher) { - return; - } + item->setIcon(0, QIcon(QPixmap::fromImage(image))); - QUrl url; - for (int i = 0; i < m_fetchers.count(); i++) { - QPair pair = m_fetchers.at(i); - if (pair.first == fetcher) { - url = pair.second; - break; - } - } + Bookmark b = item->data(0, Qt::UserRole + 10).value(); - if (url.isEmpty()) { - return; - } - - QList items = ui->treeWidget->findItems(url.toString(), Qt::MatchExactly, 1); - if (items.count() == 0) { - return; - } - - foreach(QTreeWidgetItem * item, items) { - item->setIcon(0, icon); - - foreach(Bookmark b, m_exportedBookmarks) { - if (b.url == url) { - m_exportedBookmarks.removeOne(b); - b.image = icon.pixmap(16, 16).toImage(); - m_exportedBookmarks.append(b); - break; - } - } - } + m_exportedBookmarks.removeOne(b); + b.image = image; + m_exportedBookmarks.append(b); } bool BookmarksImportDialog::exportedOK() @@ -263,10 +263,6 @@ void BookmarksImportDialog::addExportedBookmarks() BookmarksModel* model = mApp->bookmarksModel(); - if (m_exportedBookmarks.count() > 0) { - model->createFolder(m_exportedBookmarks.at(0).folder); - } - foreach(const Bookmark & b, m_exportedBookmarks) { model->saveBookmark(b.url, b.title, IconProvider::iconFromImage(b.image), b.folder); } @@ -349,13 +345,13 @@ void BookmarksImportDialog::setupBrowser(Browser browser) BookmarksImportDialog::~BookmarksImportDialog() { - if (m_fetchers.count() > 0) { - for (int i = 0; i < m_fetchers.count(); i++) { - tr(""); - IconFetcher* fetcher = m_fetchers.at(i).first; - fetcher->deleteLater(); - } - } - delete ui; + + if (m_fetcherThread) { + m_fetcherThread->exit(); + m_fetcherThread->wait(); + + m_fetcherThread->deleteLater(); + m_fetcher->deleteLater(); + } } diff --git a/src/lib/bookmarksimport/bookmarksimportdialog.h b/src/lib/bookmarksimport/bookmarksimportdialog.h index 047256200..a2015a30f 100644 --- a/src/lib/bookmarksimport/bookmarksimportdialog.h +++ b/src/lib/bookmarksimport/bookmarksimportdialog.h @@ -29,7 +29,11 @@ namespace Ui class BookmarksImportDialog; } -class IconFetcher; +class QTreeWidgetItem; +class QThread; + +class BookmarksImportIconFetcher; + class QT_QUPZILLA_EXPORT BookmarksImportDialog : public QDialog { Q_OBJECT @@ -43,7 +47,7 @@ private slots: void setFile(); void stopDownloading(); - void iconFetched(const QIcon &icon); + void iconFetched(const QImage &image, QTreeWidgetItem* item); void loadFinished(); private: @@ -68,7 +72,8 @@ private: QList m_exportedBookmarks; - QList > m_fetchers; + BookmarksImportIconFetcher* m_fetcher; + QThread* m_fetcherThread; }; #endif // BOOKMARKSIMPORTDIALOG_H diff --git a/src/lib/bookmarksimport/bookmarksimporticonfetcher.cpp b/src/lib/bookmarksimport/bookmarksimporticonfetcher.cpp new file mode 100644 index 000000000..62f34cde1 --- /dev/null +++ b/src/lib/bookmarksimport/bookmarksimporticonfetcher.cpp @@ -0,0 +1,84 @@ +/* ============================================================ +* QupZilla - WebKit based browser +* Copyright (C) 2010-2012 David Rosca +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* ============================================================ */ +#include "bookmarksimporticonfetcher.h" +#include "iconfetcher.h" + +#include +#include + +BookmarksImportIconFetcher::BookmarksImportIconFetcher(QObject* parent) + : QObject(parent) +{ +} + +void BookmarksImportIconFetcher::addEntry(const QUrl &url, QTreeWidgetItem* item) +{ + Pair pair; + pair.url = url; + pair.item = item; + + m_pairs.append(pair); +} + +void BookmarksImportIconFetcher::startFetching() +{ + QTimer::singleShot(0, this, SLOT(slotStartFetching())); +} + +void BookmarksImportIconFetcher::slotIconFetched(const QImage &image) +{ + IconFetcher* fetcher = qobject_cast(sender()); + if (!fetcher) { + return; + } + + QTreeWidgetItem* itemPointer = static_cast(fetcher->data().value()); + + emit iconFetched(image, itemPointer); +} + +void BookmarksImportIconFetcher::slotFetcherFinished() +{ + IconFetcher* fetcher = qobject_cast(sender()); + if (!fetcher) { + return; + } + + m_fetchers.removeOne(fetcher); + + emit oneFinished(); +} + +void BookmarksImportIconFetcher::slotStartFetching() +{ + QNetworkAccessManager* manager = new QNetworkAccessManager(this); + + foreach(const Pair & pair, m_pairs) { + QVariant itemPointer = qVariantFromValue((void*) pair.item); + + IconFetcher* fetcher = new IconFetcher(this); + fetcher->setNetworkAccessManager(manager); + fetcher->setData(itemPointer); + fetcher->fetchIcon(pair.url); + + connect(fetcher, SIGNAL(iconFetched(QImage)), this, SLOT(slotIconFetched(QImage))); + connect(fetcher, SIGNAL(finished()), this, SLOT(slotFetcherFinished())); + + m_fetchers.append(fetcher); + } +} diff --git a/src/lib/bookmarksimport/bookmarksimporticonfetcher.h b/src/lib/bookmarksimport/bookmarksimporticonfetcher.h new file mode 100644 index 000000000..5d672c56f --- /dev/null +++ b/src/lib/bookmarksimport/bookmarksimporticonfetcher.h @@ -0,0 +1,63 @@ +/* ============================================================ +* QupZilla - WebKit based browser +* Copyright (C) 2010-2012 David Rosca +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* ============================================================ */ +#ifndef BOOKMARKSIMPORTICONFETCHER_H +#define BOOKMARKSIMPORTICONFETCHER_H + +#include +#include +#include + +#include "qz_namespace.h" + +class QNetworkAccessManager; +class QTreeWidgetItem; +class QImage; + +class IconFetcher; + +class QT_QUPZILLA_EXPORT BookmarksImportIconFetcher : public QObject +{ + Q_OBJECT +public: + struct Pair { + QUrl url; + QTreeWidgetItem* item; + }; + + explicit BookmarksImportIconFetcher(QObject* parent = 0); + + void addEntry(const QUrl &url, QTreeWidgetItem* item); + void startFetching(); + +signals: + void iconFetched(const QImage &image, QTreeWidgetItem* item); + void oneFinished(); + +private slots: + void slotStartFetching(); + + void slotIconFetched(const QImage &image); + void slotFetcherFinished(); + +private: + QList m_pairs; + QList m_fetchers; + +}; + +#endif // BOOKMARKSIMPORTICONFETCHER_H diff --git a/src/lib/bookmarksimport/chromeimporter.cpp b/src/lib/bookmarksimport/chromeimporter.cpp index 5218ea3cb..68f523343 100644 --- a/src/lib/bookmarksimport/chromeimporter.cpp +++ b/src/lib/bookmarksimport/chromeimporter.cpp @@ -53,7 +53,7 @@ QList ChromeImporter::exportBookmarks() { QList list; - QString bookmarks = m_file.readAll(); + QString bookmarks = QString::fromUtf8(m_file.readAll()); m_file.close(); QStringList parsedBookmarks; diff --git a/src/lib/bookmarksimport/htmlimporter.cpp b/src/lib/bookmarksimport/htmlimporter.cpp index 850d602ad..b9f3aad0a 100644 --- a/src/lib/bookmarksimport/htmlimporter.cpp +++ b/src/lib/bookmarksimport/htmlimporter.cpp @@ -45,40 +45,91 @@ bool HtmlImporter::openFile() return true; } +int qzMin(int a, int b) +{ + if (a > -1 && b > -1) { + return qMin(a, b); + } + + if (a > -1) { + return a; + } + else { + return b; + } +} + QList HtmlImporter::exportBookmarks() { QList list; - QString bookmarks = m_file.readAll(); + QString bookmarks = QString::fromUtf8(m_file.readAll()); m_file.close(); - QRegExp rx("", Qt::CaseInsensitive); - rx.setMinimal(true); + bookmarks = bookmarks.mid(0, bookmarks.lastIndexOf("

")); + int start = bookmarks.indexOf("

", Qt::CaseInsensitive); - int pos = 0; - while ((pos = rx.indexIn(bookmarks, pos)) != -1) { - QString string = rx.cap(0); - pos += rx.matchedLength(); + QStringList folders("Html Import"); - QRegExp rx2(">(.*)", Qt::CaseInsensitive); - rx2.setMinimal(true); - rx2.indexIn(string); - QString name = rx2.cap(1); + while (start > 0) { + QString string = bookmarks.mid(start); - rx2.setPattern("href=\"(.*)\""); - rx2.indexIn(string); - QUrl url = QUrl::fromEncoded(rx2.cap(1).toUtf8()); + int posOfFolder = string.indexOf("

", Qt::CaseInsensitive); + int posOfLink = string.indexOf("

(.*)", Qt::CaseInsensitive); + rx.setMinimal(true); + rx.indexIn(string); - list.append(b); +// QString arguments = rx.cap(1); + QString folderName = rx.cap(2); + + folders.append(folderName); + + start += posOfFolder + rx.cap(0).size(); + } + else if (nearest == posOfEndFolder) { + // Next is end of folder + folders.removeLast(); + + start += posOfEndFolder + 8; + } + else { + // Next is link + QRegExp rx("
(.*)", Qt::CaseInsensitive); + rx.setMinimal(true); + rx.indexIn(string); + + QString arguments = rx.cap(1); + QString linkName = rx.cap(2); + + QRegExp rx2("HREF=\"(.*)\"", Qt::CaseInsensitive); + rx2.setMinimal(true); + rx2.indexIn(arguments); + + QUrl url = QUrl::fromEncoded(rx2.cap(1).toUtf8()); + + start += posOfLink + rx.cap(0).size(); + + if (linkName.isEmpty() || url.isEmpty() || url.scheme() == "place" || url.scheme() == "about") { + continue; + } + + BookmarksModel::Bookmark b; + b.folder = folders.last(); + b.title = linkName; + b.url = url; + + list.append(b); + } } return list; diff --git a/src/lib/bookmarksimport/operaimporter.cpp b/src/lib/bookmarksimport/operaimporter.cpp index c85e77768..8156a9e93 100644 --- a/src/lib/bookmarksimport/operaimporter.cpp +++ b/src/lib/bookmarksimport/operaimporter.cpp @@ -47,7 +47,7 @@ QList OperaImporter::exportBookmarks() { QList list; - QString bookmarks = m_file.readAll(); + QString bookmarks = QString::fromUtf8(m_file.readAll()); m_file.close(); QRegExp rx("#URL(.*)CREATED", Qt::CaseSensitive); diff --git a/src/lib/lib.pro b/src/lib/lib.pro index 2e3a4c571..8e1f8e1c3 100644 --- a/src/lib/lib.pro +++ b/src/lib/lib.pro @@ -164,7 +164,8 @@ SOURCES += \ webview/webviewsettings.cpp \ preferences/pluginlistdelegate.cpp \ popupwindow/popupstatusbarmessage.cpp \ - other/licenseviewer.cpp + other/licenseviewer.cpp \ + bookmarksimport/bookmarksimporticonfetcher.cpp HEADERS += \ 3rdparty/qtwin.h \ @@ -300,7 +301,8 @@ HEADERS += \ webview/webviewsettings.h \ preferences/pluginlistdelegate.h \ popupwindow/popupstatusbarmessage.h \ - other/licenseviewer.h + other/licenseviewer.h \ + bookmarksimport/bookmarksimporticonfetcher.h FORMS += \ preferences/autofillmanager.ui \ diff --git a/src/lib/preferences/pluginlistdelegate.cpp b/src/lib/preferences/pluginlistdelegate.cpp index 892885b95..846966a52 100644 --- a/src/lib/preferences/pluginlistdelegate.cpp +++ b/src/lib/preferences/pluginlistdelegate.cpp @@ -76,7 +76,7 @@ QSize PluginListDelegate::sizeHint(const QStyleOptionViewItem &option, const QMo { const int textMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin, 0) + 1; - QSize size = QItemDelegate::sizeHint(option, index); + QSize size; size.setWidth(m_listWidget->width() - 10); // ( height of font * 3 = 3 lines ) + ( text margins ) + ( 2 free lines = every line is 3px ) diff --git a/src/lib/tools/iconfetcher.cpp b/src/lib/tools/iconfetcher.cpp index 26d192cb7..99cca2d15 100644 --- a/src/lib/tools/iconfetcher.cpp +++ b/src/lib/tools/iconfetcher.cpp @@ -33,6 +33,8 @@ void IconFetcher::fetchIcon(const QUrl &url) FollowRedirectReply* reply = new FollowRedirectReply(url, m_manager); connect(reply, SIGNAL(finished()), this, SLOT(pageDownloaded())); + + m_url = url; } void IconFetcher::pageDownloaded() @@ -95,9 +97,8 @@ void IconFetcher::iconDownloaded() if (!response.isEmpty()) { QImage image; image.loadFromData(response); - QIcon icon = QIcon(QPixmap::fromImage(image)); - if (!icon.isNull()) { - emit iconFetched(icon); + if (!image.isNull()) { + emit iconFetched(image); } } diff --git a/src/lib/tools/iconfetcher.h b/src/lib/tools/iconfetcher.h index 2e81bc104..7ef6aafa2 100644 --- a/src/lib/tools/iconfetcher.h +++ b/src/lib/tools/iconfetcher.h @@ -22,6 +22,8 @@ #include #include +#include +#include class QNetworkAccessManager; class QUrl; @@ -36,8 +38,13 @@ public: void setNetworkAccessManager(QNetworkAccessManager* manager) { m_manager = manager; } void fetchIcon(const QUrl &url); + void setData(const QVariant &data) { m_data = data; } + QVariant data() { return m_data; } + + QUrl url() { return m_url; } + signals: - void iconFetched(QIcon); + void iconFetched(QImage); void finished(); public slots: @@ -49,6 +56,9 @@ private slots: private: QNetworkAccessManager* m_manager; + QVariant m_data; + QUrl m_url; + }; #endif // ICONFETCHER_H