File indexing completed on 2024-05-12 04:57:57

0001 /* ============================================================
0002 * Falkon - Qt web browser
0003 * Copyright (C) 2010-2014  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 "bookmarksmanager.h"
0019 #include "ui_bookmarksmanager.h"
0020 #include "bookmarksmodel.h"
0021 #include "bookmarkstools.h"
0022 #include "bookmarkitem.h"
0023 #include "bookmarks.h"
0024 #include "mainapplication.h"
0025 #include "browserwindow.h"
0026 #include "iconprovider.h"
0027 #include "qztools.h"
0028 
0029 #include <QMenu>
0030 #include <QTimer>
0031 
0032 BookmarksManager::BookmarksManager(BrowserWindow* window, QWidget* parent)
0033     : QWidget(parent)
0034     , ui(new Ui::BookmarksManager)
0035     , m_window(window)
0036     , m_bookmarks(mApp->bookmarks())
0037     , m_selectedBookmark(nullptr)
0038     , m_blockDescriptionChangedSignal(false)
0039     , m_adjustHeaderSizesOnShow(true)
0040 {
0041     ui->setupUi(this);
0042     ui->tree->setViewType(BookmarksTreeView::BookmarksManagerViewType);
0043 
0044     connect(ui->tree, &BookmarksTreeView::bookmarkActivated, this, &BookmarksManager::bookmarkActivated);
0045     connect(ui->tree, &BookmarksTreeView::bookmarkCtrlActivated, this, &BookmarksManager::bookmarkCtrlActivated);
0046     connect(ui->tree, &BookmarksTreeView::bookmarkShiftActivated, this, &BookmarksManager::bookmarkShiftActivated);
0047     connect(ui->tree, SIGNAL(bookmarksSelected(QList<BookmarkItem*>)), this, SLOT(bookmarksSelected(QList<BookmarkItem*>)));
0048     connect(ui->tree, &BookmarksTreeView::contextMenuRequested, this, &BookmarksManager::createContextMenu);
0049 
0050     // Box for editing bookmarks
0051     updateEditBox(nullptr);
0052     connect(ui->title, &QLineEdit::textEdited, this, &BookmarksManager::bookmarkEdited);
0053     connect(ui->address, &QLineEdit::textEdited, this, &BookmarksManager::bookmarkEdited);
0054     connect(ui->keyword, &QLineEdit::textEdited, this, &BookmarksManager::bookmarkEdited);
0055     connect(ui->description, &QPlainTextEdit::textChanged, this, &BookmarksManager::descriptionEdited);
0056 }
0057 
0058 BookmarksManager::~BookmarksManager()
0059 {
0060     delete ui;
0061 }
0062 
0063 void BookmarksManager::setMainWindow(BrowserWindow* window)
0064 {
0065     if (window) {
0066         m_window = window;
0067     }
0068 }
0069 
0070 void BookmarksManager::search(const QString &string)
0071 {
0072     ui->tree->search(string);
0073 }
0074 
0075 void BookmarksManager::bookmarkActivated(BookmarkItem* item)
0076 {
0077     openBookmark(item);
0078 }
0079 
0080 void BookmarksManager::bookmarkCtrlActivated(BookmarkItem* item)
0081 {
0082     openBookmarkInNewTab(item);
0083 }
0084 
0085 void BookmarksManager::bookmarkShiftActivated(BookmarkItem* item)
0086 {
0087     openBookmarkInNewWindow(item);
0088 }
0089 
0090 void BookmarksManager::bookmarksSelected(const QList<BookmarkItem*> &items)
0091 {
0092     if (items.size() != 1) {
0093         m_selectedBookmark = nullptr;
0094         updateEditBox(nullptr);
0095     }
0096     else {
0097         m_selectedBookmark = items.at(0);
0098         updateEditBox(m_selectedBookmark);
0099     }
0100 }
0101 
0102 void BookmarksManager::createContextMenu(const QPoint &pos)
0103 {
0104     QMenu menu;
0105     QAction* actNewTab = menu.addAction(IconProvider::newTabIcon(), tr("Open in new tab"));
0106     QAction* actNewWindow = menu.addAction(IconProvider::newWindowIcon(), tr("Open in new window"));
0107     QAction* actNewPrivateWindow = menu.addAction(IconProvider::privateBrowsingIcon(), tr("Open in new private window"));
0108 
0109     menu.addSeparator();
0110     QAction *actNewBookmark = menu.addAction(tr("New Bookmark"), this, SLOT(addBookmark()));
0111     QAction *actNewFolder = menu.addAction(tr("New Folder"), this, &BookmarksManager::addFolder);
0112     QAction *actNewSeparator = menu.addAction(tr("New Separator"), this, &BookmarksManager::addSeparator);
0113     menu.addSeparator();
0114     QAction* actDelete = menu.addAction(QIcon::fromTheme(QSL("edit-delete")), tr("Delete"));
0115 
0116     connect(actNewTab, SIGNAL(triggered()), this, SLOT(openBookmarkInNewTab()));
0117     connect(actNewWindow, SIGNAL(triggered()), this, SLOT(openBookmarkInNewWindow()));
0118     connect(actNewPrivateWindow, SIGNAL(triggered()), this, SLOT(openBookmarkInNewPrivateWindow()));
0119     connect(actDelete, &QAction::triggered, this, &BookmarksManager::deleteBookmarks);
0120 
0121     bool canBeDeleted = false;
0122     const QList<BookmarkItem*> items = ui->tree->selectedBookmarks();
0123 
0124     for (BookmarkItem* item : items) {
0125         if (m_bookmarks->canBeModified(item)) {
0126             canBeDeleted = true;
0127             break;
0128         }
0129     }
0130 
0131     if (!canBeDeleted) {
0132         actDelete->setDisabled(true);
0133     }
0134 
0135     if (!m_selectedBookmark || !m_selectedBookmark->isUrl()) {
0136         actNewTab->setDisabled(true);
0137         actNewWindow->setDisabled(true);
0138         actNewPrivateWindow->setDisabled(true);
0139     }
0140 
0141     if (!m_selectedBookmark) {
0142         actNewBookmark->setDisabled(true);
0143         actNewFolder->setDisabled(true);
0144         actNewSeparator->setDisabled(true);
0145     }
0146 
0147     menu.exec(pos);
0148 }
0149 
0150 void BookmarksManager::openBookmark(BookmarkItem* item)
0151 {
0152     item = item ? item : m_selectedBookmark;
0153     BookmarksTools::openBookmark(getWindow(), item);
0154 }
0155 
0156 void BookmarksManager::openBookmarkInNewTab(BookmarkItem* item)
0157 {
0158     item = item ? item : m_selectedBookmark;
0159     BookmarksTools::openBookmarkInNewTab(getWindow(), item);
0160 }
0161 
0162 void BookmarksManager::openBookmarkInNewWindow(BookmarkItem* item)
0163 {
0164     item = item ? item : m_selectedBookmark;
0165     BookmarksTools::openBookmarkInNewWindow(item);
0166 }
0167 
0168 void BookmarksManager::openBookmarkInNewPrivateWindow(BookmarkItem* item)
0169 {
0170     item = item ? item : m_selectedBookmark;
0171     BookmarksTools::openBookmarkInNewPrivateWindow(item);
0172 }
0173 
0174 void BookmarksManager::addBookmark()
0175 {
0176     auto* item = new BookmarkItem(BookmarkItem::Url);
0177     item->setTitle(tr("New Bookmark"));
0178     item->setUrl(QUrl(QSL("http://")));
0179     addBookmark(item);
0180 }
0181 
0182 void BookmarksManager::addFolder()
0183 {
0184     auto* item = new BookmarkItem(BookmarkItem::Folder);
0185     item->setTitle(tr("New Folder"));
0186     addBookmark(item);
0187 }
0188 
0189 void BookmarksManager::addSeparator()
0190 {
0191     auto* item = new BookmarkItem(BookmarkItem::Separator);
0192     addBookmark(item);
0193 }
0194 
0195 void BookmarksManager::deleteBookmarks()
0196 {
0197     const QList<BookmarkItem*> items = ui->tree->selectedBookmarks();
0198 
0199     for (BookmarkItem* item : items) {
0200         if (m_bookmarks->canBeModified(item)) {
0201             m_bookmarks->removeBookmark(item);
0202         }
0203     }
0204 }
0205 
0206 void BookmarksManager::bookmarkEdited()
0207 {
0208     Q_ASSERT(ui->tree->selectedBookmarks().count() == 1);
0209 
0210     BookmarkItem* item = ui->tree->selectedBookmarks().at(0);
0211     item->setTitle(ui->title->text());
0212     item->setUrl(QUrl::fromEncoded(ui->address->text().toUtf8()));
0213     item->setKeyword(ui->keyword->text());
0214     item->setDescription(ui->description->toPlainText());
0215 
0216     m_bookmarks->changeBookmark(item);
0217 }
0218 
0219 void BookmarksManager::descriptionEdited()
0220 {
0221     // There is no textEdited() signal in QPlainTextEdit
0222     // textChanged() is emitted also when text is changed programatically
0223     if (!m_blockDescriptionChangedSignal) {
0224         bookmarkEdited();
0225     }
0226 }
0227 
0228 void BookmarksManager::enableUpdates()
0229 {
0230     setUpdatesEnabled(true);
0231 }
0232 
0233 void BookmarksManager::updateEditBox(BookmarkItem* item)
0234 {
0235     setUpdatesEnabled(false);
0236     m_blockDescriptionChangedSignal = true;
0237 
0238     bool editable = bookmarkEditable(item);
0239     bool showAddressAndKeyword = item && item->isUrl();
0240 
0241     if (!item) {
0242         ui->title->clear();
0243         ui->address->clear();
0244         ui->keyword->clear();
0245         ui->description->clear();
0246     }
0247     else {
0248         ui->title->setText(item->title());
0249         ui->address->setText(QString::fromUtf8(item->url().toEncoded()));
0250         ui->keyword->setText(item->keyword());
0251         ui->description->setPlainText(item->description());
0252 
0253         ui->title->setCursorPosition(0);
0254         ui->address->setCursorPosition(0);
0255         ui->keyword->setCursorPosition(0);
0256         ui->description->moveCursor(QTextCursor::Start);
0257     }
0258 
0259     ui->title->setReadOnly(!editable);
0260     ui->address->setReadOnly(!editable);
0261     ui->keyword->setReadOnly(!editable);
0262     ui->description->setReadOnly(!editable);
0263 
0264     ui->labelAddress->setVisible(showAddressAndKeyword);
0265     ui->address->setVisible(showAddressAndKeyword);
0266     ui->labelKeyword->setVisible(showAddressAndKeyword);
0267     ui->keyword->setVisible(showAddressAndKeyword);
0268 
0269     // Without removing widgets from layout, there is unwanted extra spacing
0270     auto* l = static_cast<QFormLayout*>(ui->editBox->layout());
0271 
0272     if (showAddressAndKeyword) {
0273         // Show Address + Keyword
0274         l->insertRow(1, ui->labelAddress, ui->address);
0275         l->insertRow(2, ui->labelKeyword, ui->keyword);
0276     }
0277     else {
0278         // Hide Address + Keyword
0279         l->removeWidget(ui->labelAddress);
0280         l->removeWidget(ui->labelKeyword);
0281         l->removeWidget(ui->address);
0282         l->removeWidget(ui->keyword);
0283     }
0284 
0285     m_blockDescriptionChangedSignal = false;
0286 
0287     // Prevent flickering
0288     QTimer::singleShot(10, this, &BookmarksManager::enableUpdates);
0289 }
0290 
0291 bool BookmarksManager::bookmarkEditable(BookmarkItem* item) const
0292 {
0293     return item && (item->isFolder() || item->isUrl()) && m_bookmarks->canBeModified(item);
0294 }
0295 
0296 void BookmarksManager::addBookmark(BookmarkItem* item)
0297 {
0298     BookmarkItem* parent = parentForNewBookmark();
0299     Q_ASSERT(parent);
0300 
0301     int row = 0;
0302     if (m_selectedBookmark->isUrl() || m_selectedBookmark->isSeparator()) {
0303         row = m_bookmarks->model()->index(m_selectedBookmark).row();
0304     }
0305     m_bookmarks->insertBookmark(parent, row, item);
0306 
0307     // Select newly added bookmark
0308     ui->tree->selectBookmark(item);
0309     ui->tree->ensureBookmarkVisible(item);
0310 
0311     // Start editing title
0312     if (!item->isSeparator()) {
0313         ui->title->setFocus();
0314         ui->title->selectAll();
0315     }
0316 }
0317 
0318 BookmarkItem* BookmarksManager::parentForNewBookmark() const
0319 {
0320     if (m_selectedBookmark && m_selectedBookmark->isFolder()) {
0321         return m_selectedBookmark;
0322     }
0323 
0324     if (!m_selectedBookmark || m_selectedBookmark->parent() == m_bookmarks->rootItem()) {
0325         return m_bookmarks->unsortedFolder();
0326     }
0327 
0328     return m_selectedBookmark->parent();
0329 }
0330 
0331 void BookmarksManager::keyPressEvent(QKeyEvent* event)
0332 {
0333     switch (event->key()) {
0334     case Qt::Key_Delete:
0335         deleteBookmarks();
0336         break;
0337     }
0338 
0339     QWidget::keyPressEvent(event);
0340 }
0341 
0342 BrowserWindow* BookmarksManager::getWindow()
0343 {
0344     if (!m_window) {
0345         m_window = mApp->getWindow();
0346     }
0347     return m_window.data();
0348 }
0349 
0350 void BookmarksManager::showEvent(QShowEvent* event)
0351 {
0352     QWidget::showEvent(event);
0353 
0354     if (m_adjustHeaderSizesOnShow) {
0355         ui->tree->header()->resizeSection(0, ui->tree->header()->width() / 1.9);
0356         m_adjustHeaderSizesOnShow = false;
0357     }
0358 }