File indexing completed on 2024-05-12 04:57:58
0001 /* ============================================================ 0002 * Falkon - Qt web browser 0003 * Copyright (C) 2014-2017 David Rosca <nowrep@gmail.com> 0004 * 0005 * This program is free software: you can redistribute it and/or modify 0006 * it under the terms of the GNU General Public License as published by 0007 * the Free Software Foundation, either version 3 of the License, or 0008 * (at your option) any later version. 0009 * 0010 * This program is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0013 * GNU General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU General Public License 0016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0017 * ============================================================ */ 0018 #include "bookmarkstools.h" 0019 #include "bookmarkitem.h" 0020 #include "bookmarks.h" 0021 #include "mainapplication.h" 0022 #include "iconprovider.h" 0023 #include "enhancedmenu.h" 0024 #include "tabwidget.h" 0025 #include "qzsettings.h" 0026 #include "browserwindow.h" 0027 #include "sqldatabase.h" 0028 0029 #include <iostream> 0030 #include <QDialogButtonBox> 0031 #include <QBoxLayout> 0032 #include <QFormLayout> 0033 #include <QLabel> 0034 #include <QLineEdit> 0035 #include <QPlainTextEdit> 0036 #include <QStyle> 0037 #include <QDialog> 0038 #include <QMessageBox> 0039 0040 // BookmarksFoldersMenu 0041 BookmarksFoldersMenu::BookmarksFoldersMenu(QWidget* parent) 0042 : QMenu(parent) 0043 , m_selectedFolder(nullptr) 0044 { 0045 init(); 0046 } 0047 0048 BookmarkItem* BookmarksFoldersMenu::selectedFolder() const 0049 { 0050 return m_selectedFolder; 0051 } 0052 0053 void BookmarksFoldersMenu::folderChoosed() 0054 { 0055 if (auto* act = qobject_cast<QAction*>(sender())) { 0056 BookmarkItem* folder = static_cast<BookmarkItem*>(act->data().value<void*>()); 0057 Q_EMIT folderSelected(folder); 0058 } 0059 } 0060 0061 void BookmarksFoldersMenu::init() 0062 { 0063 #define ADD_MENU(name) \ 0064 BookmarkItem* f_##name = mApp->bookmarks()->name(); \ 0065 QMenu* m_##name = addMenu(f_##name->icon(), f_##name->title()); \ 0066 createMenu(m_##name, f_##name); 0067 0068 ADD_MENU(toolbarFolder) 0069 ADD_MENU(menuFolder) 0070 ADD_MENU(unsortedFolder) 0071 #undef ADD_MENU 0072 } 0073 0074 void BookmarksFoldersMenu::createMenu(QMenu* menu, BookmarkItem* parent) 0075 { 0076 QAction* act = menu->addAction(tr("Choose %1").arg(parent->title())); 0077 act->setData(QVariant::fromValue<void*>(static_cast<void*>(parent))); 0078 connect(act, &QAction::triggered, this, &BookmarksFoldersMenu::folderChoosed); 0079 0080 menu->addSeparator(); 0081 0082 const auto children = parent->children(); 0083 for (BookmarkItem* child : children) { 0084 if (child->isFolder()) { 0085 QMenu* m = menu->addMenu(child->icon(), child->title()); 0086 createMenu(m, child); 0087 } 0088 } 0089 } 0090 0091 0092 // BookmarksFoldersButton 0093 BookmarksFoldersButton::BookmarksFoldersButton(QWidget* parent, BookmarkItem* folder) 0094 : QPushButton(parent) 0095 , m_menu(new BookmarksFoldersMenu(this)) 0096 , m_selectedFolder(folder ? folder : mApp->bookmarks()->lastUsedFolder()) 0097 { 0098 init(); 0099 0100 connect(m_menu, &BookmarksFoldersMenu::folderSelected, this, &BookmarksFoldersButton::setSelectedFolder); 0101 } 0102 0103 BookmarkItem* BookmarksFoldersButton::selectedFolder() const 0104 { 0105 return m_selectedFolder; 0106 } 0107 0108 void BookmarksFoldersButton::setSelectedFolder(BookmarkItem* folder) 0109 { 0110 Q_ASSERT(folder); 0111 Q_ASSERT(folder->isFolder()); 0112 0113 m_selectedFolder = folder; 0114 setText(folder->title()); 0115 setIcon(folder->icon()); 0116 0117 if (sender()) { 0118 Q_EMIT selectedFolderChanged(folder); 0119 } 0120 } 0121 0122 void BookmarksFoldersButton::init() 0123 { 0124 setMenu(m_menu); 0125 setSelectedFolder(m_selectedFolder); 0126 } 0127 0128 0129 // BookmarksTools 0130 bool BookmarksTools::addBookmarkDialog(QWidget* parent, const QUrl &url, const QString &title, BookmarkItem* folder) 0131 { 0132 if (url.isEmpty() || title.isEmpty()) { 0133 return false; 0134 } 0135 0136 auto* dialog = new QDialog(parent); 0137 auto* layout = new QBoxLayout(QBoxLayout::TopToBottom, dialog); 0138 auto* label = new QLabel(dialog); 0139 auto* edit = new QLineEdit(dialog); 0140 auto* folderButton = new BookmarksFoldersButton(dialog, folder); 0141 0142 auto* box = new QDialogButtonBox(dialog); 0143 box->addButton(QDialogButtonBox::Ok); 0144 box->addButton(QDialogButtonBox::Cancel); 0145 QObject::connect(box, &QDialogButtonBox::rejected, dialog, &QDialog::reject); 0146 QObject::connect(box, &QDialogButtonBox::accepted, dialog, &QDialog::accept); 0147 0148 layout->addWidget(label); 0149 layout->addWidget(edit); 0150 layout->addWidget(folderButton); 0151 layout->addWidget(box); 0152 0153 label->setText(Bookmarks::tr("Choose name and location of this bookmark.")); 0154 edit->setText(title); 0155 edit->setCursorPosition(0); 0156 dialog->setWindowIcon(IconProvider::iconForUrl(url)); 0157 dialog->setWindowTitle(Bookmarks::tr("Add New Bookmark")); 0158 0159 QSize size = dialog->size(); 0160 size.setWidth(350); 0161 dialog->resize(size); 0162 dialog->exec(); 0163 0164 if (dialog->result() == QDialog::Rejected || edit->text().isEmpty()) { 0165 delete dialog; 0166 return false; 0167 } 0168 0169 auto* bookmark = new BookmarkItem(BookmarkItem::Url); 0170 bookmark->setTitle(edit->text()); 0171 bookmark->setUrl(url); 0172 mApp->bookmarks()->addBookmark(folderButton->selectedFolder(), bookmark); 0173 0174 delete dialog; 0175 return true; 0176 } 0177 0178 bool BookmarksTools::bookmarkAllTabsDialog(QWidget* parent, TabWidget* tabWidget, BookmarkItem* folder) 0179 { 0180 Q_ASSERT(tabWidget); 0181 0182 auto* dialog = new QDialog(parent); 0183 auto* layout = new QBoxLayout(QBoxLayout::TopToBottom, dialog); 0184 auto* label = new QLabel(dialog); 0185 auto* folderButton = new BookmarksFoldersButton(dialog, folder); 0186 0187 auto* box = new QDialogButtonBox(dialog); 0188 box->addButton(QDialogButtonBox::Ok); 0189 box->addButton(QDialogButtonBox::Cancel); 0190 QObject::connect(box, &QDialogButtonBox::rejected, dialog, &QDialog::reject); 0191 QObject::connect(box, &QDialogButtonBox::accepted, dialog, &QDialog::accept); 0192 0193 layout->addWidget(label); 0194 layout->addWidget(folderButton); 0195 layout->addWidget(box); 0196 0197 label->setText(Bookmarks::tr("Choose folder for bookmarks:")); 0198 dialog->setWindowTitle(Bookmarks::tr("Bookmark All Tabs")); 0199 0200 QSize size = dialog->size(); 0201 size.setWidth(350); 0202 dialog->resize(size); 0203 dialog->exec(); 0204 0205 if (dialog->result() == QDialog::Rejected) { 0206 return false; 0207 } 0208 0209 const auto allTabs = tabWidget->allTabs(false); 0210 for (WebTab* tab : allTabs) { 0211 if (!tab->url().isEmpty()) { 0212 auto* bookmark = new BookmarkItem(BookmarkItem::Url); 0213 bookmark->setTitle(tab->title()); 0214 bookmark->setUrl(tab->url()); 0215 mApp->bookmarks()->addBookmark(folderButton->selectedFolder(), bookmark); 0216 } 0217 } 0218 0219 delete dialog; 0220 return true; 0221 } 0222 0223 bool BookmarksTools::editBookmarkDialog(QWidget* parent, BookmarkItem *item) 0224 { 0225 auto* dialog = new QDialog(parent); 0226 auto* layout = new QFormLayout(dialog); 0227 0228 auto* title = new QLineEdit; 0229 auto* address = new QLineEdit; 0230 auto* keyword = new QLineEdit; 0231 auto* description = new QPlainTextEdit; 0232 0233 auto* box = new QDialogButtonBox(dialog); 0234 box->addButton(QDialogButtonBox::Ok); 0235 box->addButton(QDialogButtonBox::Cancel); 0236 QObject::connect(box, &QDialogButtonBox::accepted, dialog, &QDialog::accept); 0237 QObject::connect(box, &QDialogButtonBox::rejected, dialog, &QDialog::reject); 0238 0239 layout->addRow(Bookmarks::tr("Title:"), title); 0240 title->setText(item->title()); 0241 if (!item->isFolder()) { 0242 layout->addRow(Bookmarks::tr("Address:"), address); 0243 address->setText(item->urlString()); 0244 layout->addRow(Bookmarks::tr("Keyword:"), keyword); 0245 keyword->setText(item->keyword()); 0246 } 0247 layout->addRow(Bookmarks::tr("Description:"), description); 0248 description->document()->setPlainText(item->description()); 0249 layout->addWidget(box); 0250 0251 dialog->setWindowIcon(item->icon()); 0252 dialog->setWindowTitle(Bookmarks::tr("Edit Bookmark")); 0253 0254 dialog->exec(); 0255 0256 if (dialog->result() == QDialog::Rejected) { 0257 delete dialog; 0258 return false; 0259 } 0260 0261 item->setTitle(title->text()); 0262 if (!item->isFolder()) { 0263 item->setUrl(QUrl::fromEncoded(address->text().toUtf8())); 0264 item->setKeyword(keyword->text()); 0265 } 0266 item->setDescription(description->toPlainText()); 0267 0268 delete dialog; 0269 return true; 0270 } 0271 0272 void BookmarksTools::openBookmark(BrowserWindow* window, BookmarkItem* item) 0273 { 0274 Q_ASSERT(window); 0275 0276 if (!item || !item->isUrl()) { 0277 return; 0278 } 0279 0280 if (item->isFolder()) { 0281 openFolderInTabs(window, item); 0282 } 0283 else if (item->isUrl()) { 0284 item->updateVisitCount(); 0285 window->loadAddress(item->url()); 0286 } 0287 } 0288 0289 void BookmarksTools::openBookmarkInNewTab(BrowserWindow* window, BookmarkItem* item) 0290 { 0291 Q_ASSERT(window); 0292 0293 if (!item) { 0294 return; 0295 } 0296 0297 if (item->isFolder()) { 0298 openFolderInTabs(window, item); 0299 } 0300 else if (item->isUrl()) { 0301 item->updateVisitCount(); 0302 window->tabWidget()->addView(item->url(), item->title(), qzSettings->newTabPosition); 0303 } 0304 } 0305 0306 void BookmarksTools::openBookmarkInNewWindow(BookmarkItem* item) 0307 { 0308 if (!item->isUrl()) { 0309 return; 0310 } 0311 0312 item->updateVisitCount(); 0313 mApp->createWindow(Qz::BW_NewWindow, item->url()); 0314 } 0315 0316 void BookmarksTools::openBookmarkInNewPrivateWindow(BookmarkItem* item) 0317 { 0318 if (!item->isUrl()) { 0319 return; 0320 } 0321 0322 item->updateVisitCount(); 0323 mApp->startPrivateBrowsing(item->url()); 0324 } 0325 0326 void BookmarksTools::openFolderInTabs(BrowserWindow* window, BookmarkItem* folder) 0327 { 0328 Q_ASSERT(window); 0329 Q_ASSERT(folder->isFolder()); 0330 0331 const auto children = folder->children(); 0332 0333 bool showWarning = folder->children().size() > 10; 0334 if (!showWarning) { 0335 for (BookmarkItem* child : children) { 0336 if (child->isFolder()) { 0337 showWarning = true; 0338 break; 0339 } 0340 } 0341 } 0342 0343 if (showWarning) { 0344 const auto button = QMessageBox::warning(window, Bookmarks::tr("Confirmation"), 0345 Bookmarks::tr("Are you sure you want to open all bookmarks from '%1' folder in tabs?").arg(folder->title()), 0346 QMessageBox::Yes | QMessageBox::No); 0347 if (button != QMessageBox::Yes) { 0348 return; 0349 } 0350 } 0351 0352 for (BookmarkItem* child : children) { 0353 if (child->isUrl()) { 0354 openBookmarkInNewTab(window, child); 0355 } 0356 else if (child->isFolder()) { 0357 openFolderInTabs(window, child); 0358 } 0359 } 0360 } 0361 0362 void BookmarksTools::addActionToMenu(QObject* receiver, Menu* menu, BookmarkItem* item) 0363 { 0364 Q_ASSERT(menu); 0365 Q_ASSERT(item); 0366 0367 switch (item->type()) { 0368 case BookmarkItem::Url: 0369 addUrlToMenu(receiver, menu, item); 0370 break; 0371 case BookmarkItem::Folder: 0372 addFolderToMenu(receiver, menu, item); 0373 break; 0374 case BookmarkItem::Separator: 0375 addSeparatorToMenu(menu, item); 0376 break; 0377 default: 0378 break; 0379 } 0380 } 0381 0382 void BookmarksTools::addFolderToMenu(QObject* receiver, Menu* menu, BookmarkItem* folder) 0383 { 0384 Q_ASSERT(menu); 0385 Q_ASSERT(folder); 0386 Q_ASSERT(folder->isFolder()); 0387 0388 Menu* m = new Menu(menu); 0389 QString title = QFontMetrics(m->font()).elidedText(folder->title(), Qt::ElideRight, 250); 0390 m->setTitle(title); 0391 m->setIcon(folder->icon()); 0392 0393 addFolderContentsToMenu(receiver, m, folder); 0394 0395 QAction* act = menu->addMenu(m); 0396 act->setData(QVariant::fromValue<void*>(static_cast<void*>(folder))); 0397 act->setIconVisibleInMenu(true); 0398 } 0399 0400 void BookmarksTools::addUrlToMenu(QObject* receiver, Menu* menu, BookmarkItem* bookmark) 0401 { 0402 Q_ASSERT(menu); 0403 Q_ASSERT(bookmark); 0404 Q_ASSERT(bookmark->isUrl()); 0405 0406 auto* act = new Action(menu); 0407 QString title = QFontMetrics(act->font()).elidedText(bookmark->title(), Qt::ElideRight, 250); 0408 act->setText(title); 0409 act->setData(QVariant::fromValue<void*>(static_cast<void*>(bookmark))); 0410 act->setIconVisibleInMenu(true); 0411 0412 QObject::connect(act, SIGNAL(triggered()), receiver, SLOT(bookmarkActivated())); 0413 QObject::connect(act, SIGNAL(ctrlTriggered()), receiver, SLOT(bookmarkCtrlActivated())); 0414 QObject::connect(act, SIGNAL(shiftTriggered()), receiver, SLOT(bookmarkShiftActivated())); 0415 0416 menu->addAction(act); 0417 } 0418 0419 void BookmarksTools::addSeparatorToMenu(Menu* menu, BookmarkItem* separator) 0420 { 0421 Q_UNUSED(separator) 0422 0423 Q_ASSERT(menu); 0424 Q_ASSERT(separator->isSeparator()); 0425 0426 menu->addSeparator(); 0427 } 0428 0429 void BookmarksTools::addFolderContentsToMenu(QObject *receiver, Menu *menu, BookmarkItem *folder) 0430 { 0431 QObject::connect(menu, SIGNAL(aboutToShow()), receiver, SLOT(menuAboutToShow())); 0432 QObject::connect(menu, SIGNAL(menuMiddleClicked(Menu*)), receiver, SLOT(menuMiddleClicked(Menu*))); 0433 0434 const auto children = folder->children(); 0435 for (BookmarkItem* child : children) { 0436 addActionToMenu(receiver, menu, child); 0437 } 0438 0439 if (menu->isEmpty()) { 0440 menu->addAction(Bookmarks::tr("Empty"))->setDisabled(true); 0441 } 0442 } 0443 0444 bool BookmarksTools::migrateBookmarksIfNecessary(Bookmarks* bookmarks) 0445 { 0446 QSqlQuery query(SqlDatabase::instance()->database()); 0447 query.exec(QSL("SELECT name FROM sqlite_master WHERE type='table' AND name='folders'")); 0448 0449 if (!query.next()) { 0450 return false; 0451 } 0452 0453 std::cout << "Bookmarks: Migrating your bookmarks from SQLite to JSON..." << std::endl; 0454 0455 QHash<QString, BookmarkItem*> folders; 0456 folders.insert(QSL("bookmarksToolbar"), bookmarks->toolbarFolder()); 0457 folders.insert(QSL("bookmarksMenu"), bookmarks->menuFolder()); 0458 folders.insert(QSL("unsorted"), bookmarks->unsortedFolder()); 0459 0460 query.exec(QSL("SELECT name, subfolder FROM folders")); 0461 while (query.next()) { 0462 const QString title = query.value(0).toString(); 0463 bool subfolder = query.value(1).toString() == QLatin1String("yes"); 0464 0465 BookmarkItem* parent = subfolder ? bookmarks->toolbarFolder() : bookmarks->unsortedFolder(); 0466 auto* folder = new BookmarkItem(BookmarkItem::Folder, parent); 0467 folder->setTitle(title); 0468 folders.insert(folder->title(), folder); 0469 } 0470 0471 query.exec(QSL("SELECT title, folder, url FROM bookmarks ORDER BY position ASC")); 0472 while (query.next()) { 0473 const QString title = query.value(0).toString(); 0474 const QString folder = query.value(1).toString(); 0475 const QUrl url = query.value(2).toUrl(); 0476 0477 BookmarkItem* parent = folders.value(folder); 0478 if (!parent) { 0479 parent = bookmarks->unsortedFolder(); 0480 } 0481 Q_ASSERT(parent); 0482 0483 auto* bookmark = new BookmarkItem(BookmarkItem::Url, parent); 0484 bookmark->setTitle(title); 0485 bookmark->setUrl(url); 0486 } 0487 0488 query.exec(QSL("DROP TABLE folders")); 0489 query.exec(QSL("DROP TABLE bookmarks")); 0490 query.exec(QSL("VACUUM")); 0491 0492 std::cout << "Bookmarks: Bookmarks successfully migrated!" << std::endl; 0493 return true; 0494 }