Falkon Develop
Cross-platform Qt-based web browser
bookmarkstools.cpp
Go to the documentation of this file.
1/* ============================================================
2* Falkon - Qt web browser
3* Copyright (C) 2014-2017 David Rosca <nowrep@gmail.com>
4*
5* This program is free software: you can redistribute it and/or modify
6* it under the terms of the GNU General Public License as published by
7* the Free Software Foundation, either version 3 of the License, or
8* (at your option) any later version.
9*
10* This program is distributed in the hope that it will be useful,
11* but WITHOUT ANY WARRANTY; without even the implied warranty of
12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13* GNU General Public License for more details.
14*
15* You should have received a copy of the GNU General Public License
16* along with this program. If not, see <http://www.gnu.org/licenses/>.
17* ============================================================ */
18#include "bookmarkstools.h"
19#include "bookmarkitem.h"
20#include "bookmarks.h"
21#include "mainapplication.h"
22#include "iconprovider.h"
23#include "enhancedmenu.h"
24#include "tabwidget.h"
25#include "qzsettings.h"
26#include "browserwindow.h"
27#include "sqldatabase.h"
28
29#include <iostream>
30#include <QDialogButtonBox>
31#include <QBoxLayout>
32#include <QFormLayout>
33#include <QLabel>
34#include <QLineEdit>
35#include <QPlainTextEdit>
36#include <QStyle>
37#include <QDialog>
38#include <QMessageBox>
39
40// BookmarksFoldersMenu
42 : QMenu(parent)
43 , m_selectedFolder(nullptr)
44{
45 init();
46}
47
49{
50 return m_selectedFolder;
51}
52
53void BookmarksFoldersMenu::folderChoosed()
54{
55 if (auto* act = qobject_cast<QAction*>(sender())) {
56 BookmarkItem* folder = static_cast<BookmarkItem*>(act->data().value<void*>());
57 Q_EMIT folderSelected(folder);
58 }
59}
60
61void BookmarksFoldersMenu::init()
62{
63#define ADD_MENU(name) \
64 BookmarkItem* f_##name = mApp->bookmarks()->name(); \
65 QMenu* m_##name = addMenu(f_##name->icon(), f_##name->title()); \
66 createMenu(m_##name, f_##name);
67
68 ADD_MENU(toolbarFolder)
69 ADD_MENU(menuFolder)
70 ADD_MENU(unsortedFolder)
71#undef ADD_MENU
72}
73
74void BookmarksFoldersMenu::createMenu(QMenu* menu, BookmarkItem* parent)
75{
76 QAction* act = menu->addAction(tr("Choose %1").arg(parent->title()));
77 act->setData(QVariant::fromValue<void*>(static_cast<void*>(parent)));
78 connect(act, &QAction::triggered, this, &BookmarksFoldersMenu::folderChoosed);
79
80 menu->addSeparator();
81
82 const auto children = parent->children();
83 for (BookmarkItem* child : children) {
84 if (child->isFolder()) {
85 QMenu* m = menu->addMenu(child->icon(), child->title());
86 createMenu(m, child);
87 }
88 }
89}
90
91
92// BookmarksFoldersButton
94 : QPushButton(parent)
95 , m_menu(new BookmarksFoldersMenu(this))
96 , m_selectedFolder(folder ? folder : mApp->bookmarks()->lastUsedFolder())
97{
98 init();
99
101}
102
104{
105 return m_selectedFolder;
106}
107
109{
110 Q_ASSERT(folder);
111 Q_ASSERT(folder->isFolder());
112
113 m_selectedFolder = folder;
114 setText(folder->title());
115 setIcon(folder->icon());
116
117 if (sender()) {
118 Q_EMIT selectedFolderChanged(folder);
119 }
120}
121
122void BookmarksFoldersButton::init()
123{
124 setMenu(m_menu);
125 setSelectedFolder(m_selectedFolder);
126}
127
128
129// BookmarksTools
130bool BookmarksTools::addBookmarkDialog(QWidget* parent, const QUrl &url, const QString &title, BookmarkItem* folder)
131{
132 if (url.isEmpty() || title.isEmpty()) {
133 return false;
134 }
135
136 auto* dialog = new QDialog(parent);
137 auto* layout = new QBoxLayout(QBoxLayout::TopToBottom, dialog);
138 auto* label = new QLabel(dialog);
139 auto* edit = new QLineEdit(dialog);
140 auto* folderButton = new BookmarksFoldersButton(dialog, folder);
141
142 auto* box = new QDialogButtonBox(dialog);
143 box->addButton(QDialogButtonBox::Ok);
144 box->addButton(QDialogButtonBox::Cancel);
145 QObject::connect(box, &QDialogButtonBox::rejected, dialog, &QDialog::reject);
146 QObject::connect(box, &QDialogButtonBox::accepted, dialog, &QDialog::accept);
147
148 layout->addWidget(label);
149 layout->addWidget(edit);
150 layout->addWidget(folderButton);
151 layout->addWidget(box);
152
153 label->setText(Bookmarks::tr("Choose name and location of this bookmark."));
154 edit->setText(title);
155 edit->setCursorPosition(0);
156 dialog->setWindowIcon(IconProvider::iconForUrl(url));
157 dialog->setWindowTitle(Bookmarks::tr("Add New Bookmark"));
158
159 QSize size = dialog->size();
160 size.setWidth(350);
161 dialog->resize(size);
162 dialog->exec();
163
164 if (dialog->result() == QDialog::Rejected || edit->text().isEmpty()) {
165 delete dialog;
166 return false;
167 }
168
169 auto* bookmark = new BookmarkItem(BookmarkItem::Url);
170 bookmark->setTitle(edit->text());
171 bookmark->setUrl(url);
172 mApp->bookmarks()->addBookmark(folderButton->selectedFolder(), bookmark);
173
174 delete dialog;
175 return true;
176}
177
178bool BookmarksTools::bookmarkAllTabsDialog(QWidget* parent, TabWidget* tabWidget, BookmarkItem* folder)
179{
180 Q_ASSERT(tabWidget);
181
182 auto* dialog = new QDialog(parent);
183 auto* layout = new QBoxLayout(QBoxLayout::TopToBottom, dialog);
184 auto* label = new QLabel(dialog);
185 auto* folderButton = new BookmarksFoldersButton(dialog, folder);
186
187 auto* box = new QDialogButtonBox(dialog);
188 box->addButton(QDialogButtonBox::Ok);
189 box->addButton(QDialogButtonBox::Cancel);
190 QObject::connect(box, &QDialogButtonBox::rejected, dialog, &QDialog::reject);
191 QObject::connect(box, &QDialogButtonBox::accepted, dialog, &QDialog::accept);
192
193 layout->addWidget(label);
194 layout->addWidget(folderButton);
195 layout->addWidget(box);
196
197 label->setText(Bookmarks::tr("Choose folder for bookmarks:"));
198 dialog->setWindowTitle(Bookmarks::tr("Bookmark All Tabs"));
199
200 QSize size = dialog->size();
201 size.setWidth(350);
202 dialog->resize(size);
203 dialog->exec();
204
205 if (dialog->result() == QDialog::Rejected) {
206 return false;
207 }
208
209 const auto allTabs = tabWidget->allTabs(false);
210 for (WebTab* tab : allTabs) {
211 if (!tab->url().isEmpty()) {
212 auto* bookmark = new BookmarkItem(BookmarkItem::Url);
213 bookmark->setTitle(tab->title());
214 bookmark->setUrl(tab->url());
215 mApp->bookmarks()->addBookmark(folderButton->selectedFolder(), bookmark);
216 }
217 }
218
219 delete dialog;
220 return true;
221}
222
224{
225 auto* dialog = new QDialog(parent);
226 auto* layout = new QFormLayout(dialog);
227
228 auto* title = new QLineEdit;
229 auto* address = new QLineEdit;
230 auto* keyword = new QLineEdit;
231 auto* description = new QPlainTextEdit;
232
233 auto* box = new QDialogButtonBox(dialog);
234 box->addButton(QDialogButtonBox::Ok);
235 box->addButton(QDialogButtonBox::Cancel);
236 QObject::connect(box, &QDialogButtonBox::accepted, dialog, &QDialog::accept);
237 QObject::connect(box, &QDialogButtonBox::rejected, dialog, &QDialog::reject);
238
239 layout->addRow(Bookmarks::tr("Title:"), title);
240 title->setText(item->title());
241 if (!item->isFolder()) {
242 layout->addRow(Bookmarks::tr("Address:"), address);
243 address->setText(item->urlString());
244 layout->addRow(Bookmarks::tr("Keyword:"), keyword);
245 keyword->setText(item->keyword());
246 }
247 layout->addRow(Bookmarks::tr("Description:"), description);
248 description->document()->setPlainText(item->description());
249 layout->addWidget(box);
250
251 dialog->setWindowIcon(item->icon());
252 dialog->setWindowTitle(Bookmarks::tr("Edit Bookmark"));
253
254 dialog->exec();
255
256 if (dialog->result() == QDialog::Rejected) {
257 delete dialog;
258 return false;
259 }
260
261 item->setTitle(title->text());
262 if (!item->isFolder()) {
263 item->setUrl(QUrl::fromEncoded(address->text().toUtf8()));
264 item->setKeyword(keyword->text());
265 }
266 item->setDescription(description->toPlainText());
267
268 delete dialog;
269 return true;
270}
271
273{
274 Q_ASSERT(window);
275
276 if (!item || !item->isUrl()) {
277 return;
278 }
279
280 if (item->isFolder()) {
281 openFolderInTabs(window, item);
282 }
283 else if (item->isUrl()) {
284 item->updateVisitCount();
285 window->loadAddress(item->url());
286 }
287}
288
290{
291 Q_ASSERT(window);
292
293 if (!item) {
294 return;
295 }
296
297 if (item->isFolder()) {
298 openFolderInTabs(window, item);
299 }
300 else if (item->isUrl()) {
301 item->updateVisitCount();
302 window->tabWidget()->addView(item->url(), item->title(), qzSettings->newTabPosition);
303 }
304}
305
307{
308 if (!item->isUrl()) {
309 return;
310 }
311
312 item->updateVisitCount();
313 mApp->createWindow(Qz::BW_NewWindow, item->url());
314}
315
317{
318 if (!item->isUrl()) {
319 return;
320 }
321
322 item->updateVisitCount();
323 mApp->startPrivateBrowsing(item->url());
324}
325
327{
328 Q_ASSERT(window);
329 Q_ASSERT(folder->isFolder());
330
331 const auto children = folder->children();
332
333 bool showWarning = folder->children().size() > 10;
334 if (!showWarning) {
335 for (BookmarkItem* child : children) {
336 if (child->isFolder()) {
337 showWarning = true;
338 break;
339 }
340 }
341 }
342
343 if (showWarning) {
344 const auto button = QMessageBox::warning(window, Bookmarks::tr("Confirmation"),
345 Bookmarks::tr("Are you sure you want to open all bookmarks from '%1' folder in tabs?").arg(folder->title()),
346 QMessageBox::Yes | QMessageBox::No);
347 if (button != QMessageBox::Yes) {
348 return;
349 }
350 }
351
352 for (BookmarkItem* child : children) {
353 if (child->isUrl()) {
354 openBookmarkInNewTab(window, child);
355 }
356 else if (child->isFolder()) {
357 openFolderInTabs(window, child);
358 }
359 }
360}
361
362void BookmarksTools::addActionToMenu(QObject* receiver, Menu* menu, BookmarkItem* item)
363{
364 Q_ASSERT(menu);
365 Q_ASSERT(item);
366
367 switch (item->type()) {
369 addUrlToMenu(receiver, menu, item);
370 break;
372 addFolderToMenu(receiver, menu, item);
373 break;
375 addSeparatorToMenu(menu, item);
376 break;
377 default:
378 break;
379 }
380}
381
382void BookmarksTools::addFolderToMenu(QObject* receiver, Menu* menu, BookmarkItem* folder)
383{
384 Q_ASSERT(menu);
385 Q_ASSERT(folder);
386 Q_ASSERT(folder->isFolder());
387
388 Menu* m = new Menu(menu);
389 QString title = QFontMetrics(m->font()).elidedText(folder->title(), Qt::ElideRight, 250);
390 m->setTitle(title);
391 m->setIcon(folder->icon());
392
393 addFolderContentsToMenu(receiver, m, folder);
394
395 QAction* act = menu->addMenu(m);
396 act->setData(QVariant::fromValue<void*>(static_cast<void*>(folder)));
397 act->setIconVisibleInMenu(true);
398}
399
400void BookmarksTools::addUrlToMenu(QObject* receiver, Menu* menu, BookmarkItem* bookmark)
401{
402 Q_ASSERT(menu);
403 Q_ASSERT(bookmark);
404 Q_ASSERT(bookmark->isUrl());
405
406 auto* act = new Action(menu);
407 QString title = QFontMetrics(act->font()).elidedText(bookmark->title(), Qt::ElideRight, 250);
408 act->setText(title);
409 act->setData(QVariant::fromValue<void*>(static_cast<void*>(bookmark)));
410 act->setIconVisibleInMenu(true);
411
412 QObject::connect(act, SIGNAL(triggered()), receiver, SLOT(bookmarkActivated()));
413 QObject::connect(act, SIGNAL(ctrlTriggered()), receiver, SLOT(bookmarkCtrlActivated()));
414 QObject::connect(act, SIGNAL(shiftTriggered()), receiver, SLOT(bookmarkShiftActivated()));
415
416 menu->addAction(act);
417}
418
420{
421 Q_UNUSED(separator)
422
423 Q_ASSERT(menu);
424 Q_ASSERT(separator->isSeparator());
425
426 menu->addSeparator();
427}
428
429void BookmarksTools::addFolderContentsToMenu(QObject *receiver, Menu *menu, BookmarkItem *folder)
430{
431 QObject::connect(menu, SIGNAL(aboutToShow()), receiver, SLOT(menuAboutToShow()));
432 QObject::connect(menu, SIGNAL(menuMiddleClicked(Menu*)), receiver, SLOT(menuMiddleClicked(Menu*)));
433
434 const auto children = folder->children();
435 for (BookmarkItem* child : children) {
436 addActionToMenu(receiver, menu, child);
437 }
438
439 if (menu->isEmpty()) {
440 menu->addAction(Bookmarks::tr("Empty"))->setDisabled(true);
441 }
442}
443
445{
446 QSqlQuery query(SqlDatabase::instance()->database());
447 query.exec(QSL("SELECT name FROM sqlite_master WHERE type='table' AND name='folders'"));
448
449 if (!query.next()) {
450 return false;
451 }
452
453 std::cout << "Bookmarks: Migrating your bookmarks from SQLite to JSON..." << std::endl;
454
455 QHash<QString, BookmarkItem*> folders;
456 folders.insert(QSL("bookmarksToolbar"), bookmarks->toolbarFolder());
457 folders.insert(QSL("bookmarksMenu"), bookmarks->menuFolder());
458 folders.insert(QSL("unsorted"), bookmarks->unsortedFolder());
459
460 query.exec(QSL("SELECT name, subfolder FROM folders"));
461 while (query.next()) {
462 const QString title = query.value(0).toString();
463 bool subfolder = query.value(1).toString() == QLatin1String("yes");
464
465 BookmarkItem* parent = subfolder ? bookmarks->toolbarFolder() : bookmarks->unsortedFolder();
466 auto* folder = new BookmarkItem(BookmarkItem::Folder, parent);
467 folder->setTitle(title);
468 folders.insert(folder->title(), folder);
469 }
470
471 query.exec(QSL("SELECT title, folder, url FROM bookmarks ORDER BY position ASC"));
472 while (query.next()) {
473 const QString title = query.value(0).toString();
474 const QString folder = query.value(1).toString();
475 const QUrl url = query.value(2).toUrl();
476
477 BookmarkItem* parent = folders.value(folder);
478 if (!parent) {
479 parent = bookmarks->unsortedFolder();
480 }
481 Q_ASSERT(parent);
482
483 auto* bookmark = new BookmarkItem(BookmarkItem::Url, parent);
484 bookmark->setTitle(title);
485 bookmark->setUrl(url);
486 }
487
488 query.exec(QSL("DROP TABLE folders"));
489 query.exec(QSL("DROP TABLE bookmarks"));
490 query.exec(QSL("VACUUM"));
491
492 std::cout << "Bookmarks: Bookmarks successfully migrated!" << std::endl;
493 return true;
494}
#define ADD_MENU(name)
QString keyword() const
bool isFolder() const
void setDescription(const QString &description)
QString urlString() const
bool isSeparator() const
QString description() const
QUrl url() const
void setKeyword(const QString &keyword)
void updateVisitCount()
bool isUrl() const
QList< BookmarkItem * > children() const
QString title() const
void setUrl(const QUrl &url)
Type type() const
void setTitle(const QString &title)
BookmarkItem * selectedFolder() const
BookmarksFoldersButton(QWidget *parent, BookmarkItem *folder=nullptr)
void selectedFolderChanged(BookmarkItem *folder)
void setSelectedFolder(BookmarkItem *folder)
void folderSelected(BookmarkItem *folder)
BookmarksFoldersMenu(QWidget *parent=nullptr)
BookmarkItem * selectedFolder() const
BookmarkItem * menuFolder() const
Definition: bookmarks.cpp:79
BookmarkItem * unsortedFolder() const
Definition: bookmarks.cpp:84
BookmarkItem * toolbarFolder() const
Definition: bookmarks.cpp:74
static void addUrlToMenu(QObject *receiver, Menu *menu, BookmarkItem *bookmark)
static bool bookmarkAllTabsDialog(QWidget *parent, TabWidget *tabWidget, BookmarkItem *folder=nullptr)
static void addSeparatorToMenu(Menu *menu, BookmarkItem *separator)
static void openBookmarkInNewTab(BrowserWindow *window, BookmarkItem *item)
static void openBookmark(BrowserWindow *window, BookmarkItem *item)
static void openBookmarkInNewPrivateWindow(BookmarkItem *item)
static void addFolderToMenu(QObject *receiver, Menu *menu, BookmarkItem *folder)
static bool addBookmarkDialog(QWidget *parent, const QUrl &url, const QString &title, BookmarkItem *folder=nullptr)
static bool editBookmarkDialog(QWidget *parent, BookmarkItem *item)
static void openFolderInTabs(BrowserWindow *window, BookmarkItem *folder)
static bool migrateBookmarksIfNecessary(Bookmarks *bookmarks)
static void openBookmarkInNewWindow(BookmarkItem *item)
static void addFolderContentsToMenu(QObject *receiver, Menu *menu, BookmarkItem *folder)
static void addActionToMenu(QObject *receiver, Menu *menu, BookmarkItem *item)
TabWidget * tabWidget() const
void loadAddress(const QUrl &url)
static QIcon iconForUrl(const QUrl &url, bool allowNull=false)
static SqlDatabase * instance()
int addView(const LoadRequest &req, const Qz::NewTabPositionFlags &openFlags, bool selectLine=false, bool pinned=false)
Definition: tabwidget.cpp:314
QList< WebTab * > allTabs(bool withPinned=true)
Definition: tabwidget.cpp:833
Definition: webtab.h:40
#define mApp
@ BW_NewWindow
Definition: qzcommon.h:67
#define QSL(x)
Definition: qzcommon.h:40
#define qzSettings
Definition: qzsettings.h:69