Falkon Develop
Cross-platform Qt-based web browser
bookmarkstoolbar.cpp
Go to the documentation of this file.
1/* ============================================================
2* Falkon - Qt web browser
3* Copyright (C) 2010-2018 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 "bookmarkstoolbar.h"
20#include "bookmarkstools.h"
21#include "bookmarksmodel.h"
22#include "bookmarkitem.h"
23#include "bookmarks.h"
24#include "mainapplication.h"
25#include "iconprovider.h"
26#include "qztools.h"
27
28#include <QDragEnterEvent>
29#include <QHBoxLayout>
30#include <QMimeData>
31#include <QTimer>
32#include <QFrame>
33#include <QInputDialog>
34
36 : QWidget(parent)
37 , m_window(window)
38 , m_bookmarks(mApp->bookmarks())
39 , m_clickedBookmark(nullptr)
40 , m_dropRow(-1)
41{
42 setObjectName("bookmarksbar");
43 setAcceptDrops(true);
44 setContextMenuPolicy(Qt::CustomContextMenu);
45
46 m_layout = new QHBoxLayout(this);
47 auto contentsMargin = style()->pixelMetric(QStyle::PM_ToolBarItemMargin, nullptr, this)
48 + style()->pixelMetric(QStyle::PM_ToolBarFrameWidth, nullptr, this);
49 m_layout->setContentsMargins(contentsMargin, contentsMargin, contentsMargin, contentsMargin);
50 m_layout->setSpacing(style()->pixelMetric(QStyle::PM_ToolBarItemSpacing, nullptr, this));
51 setLayout(m_layout);
52
53 m_updateTimer = new QTimer(this);
54 m_updateTimer->setInterval(300);
55 m_updateTimer->setSingleShot(true);
56 connect(m_updateTimer, &QTimer::timeout, this, &BookmarksToolbar::refresh);
57
58 connect(m_bookmarks, &Bookmarks::bookmarkAdded, this, &BookmarksToolbar::bookmarksChanged);
59 connect(m_bookmarks, &Bookmarks::bookmarkRemoved, this, &BookmarksToolbar::bookmarksChanged);
60 connect(m_bookmarks, &Bookmarks::bookmarkChanged, this, &BookmarksToolbar::bookmarksChanged);
61 connect(m_bookmarks, &Bookmarks::showOnlyIconsInToolbarChanged, this, &BookmarksToolbar::showOnlyIconsChanged);
62 connect(m_bookmarks, &Bookmarks::showOnlyTextInToolbarChanged, this, &BookmarksToolbar::showOnlyTextChanged);
63 connect(this, &QWidget::customContextMenuRequested, this, &BookmarksToolbar::contextMenuRequested);
64
65 refresh();
66}
67
68void BookmarksToolbar::contextMenuRequested(const QPoint &pos)
69{
70 BookmarksToolbarButton* button = buttonAt(pos);
71 m_clickedBookmark = button ? button->bookmark() : nullptr;
72
73 QMenu menu;
74 QAction* actNewTab = menu.addAction(IconProvider::newTabIcon(), tr("Open in new tab"));
75 QAction* actNewWindow = menu.addAction(IconProvider::newWindowIcon(), tr("Open in new window"));
76 QAction* actNewPrivateWindow = menu.addAction(IconProvider::privateBrowsingIcon(), tr("Open in new private window"));
77 menu.addSeparator();
78 QAction* actNewFolder = menu.addAction(QIcon::fromTheme(QSL("folder-new")), tr("New Folder"));
79 QAction* actEdit = menu.addAction(tr("Edit"));
80 QAction* actDelete = menu.addAction(QIcon::fromTheme(QSL("edit-delete")), tr("Delete"));
81 menu.addSeparator();
82 m_actShowOnlyIcons = menu.addAction(tr("Show Only Icons"));
83 m_actShowOnlyIcons->setCheckable(true);
84 m_actShowOnlyIcons->setChecked(m_bookmarks->showOnlyIconsInToolbar());
85 connect(m_actShowOnlyIcons, &QAction::toggled, m_bookmarks, &Bookmarks::setShowOnlyIconsInToolbar);
86 m_actShowOnlyText = menu.addAction(tr("Show Only Text"));
87 m_actShowOnlyText->setCheckable(true);
88 m_actShowOnlyText->setChecked(m_bookmarks->showOnlyTextInToolbar());
89 connect(m_actShowOnlyText, &QAction::toggled, m_bookmarks, &Bookmarks::setShowOnlyTextInToolbar);
90
91 connect(actNewTab, &QAction::triggered, this, &BookmarksToolbar::openBookmarkInNewTab);
92 connect(actNewWindow, &QAction::triggered, this, &BookmarksToolbar::openBookmarkInNewWindow);
93 connect(actNewPrivateWindow, &QAction::triggered, this, &BookmarksToolbar::openBookmarkInNewPrivateWindow);
94 connect(actNewFolder, &QAction::triggered, this, &BookmarksToolbar::createNewFolder);
95 connect(actEdit, &QAction::triggered, this, &BookmarksToolbar::editBookmark);
96 connect(actDelete, &QAction::triggered, this, &BookmarksToolbar::deleteBookmark);
97
98 actEdit->setEnabled(m_clickedBookmark && m_bookmarks->canBeModified(m_clickedBookmark));
99 actDelete->setEnabled(m_clickedBookmark && m_bookmarks->canBeModified(m_clickedBookmark));
100 actNewTab->setEnabled(m_clickedBookmark && m_clickedBookmark->isUrl());
101 actNewWindow->setEnabled(m_clickedBookmark && m_clickedBookmark->isUrl());
102 actNewPrivateWindow->setEnabled(m_clickedBookmark && m_clickedBookmark->isUrl());
103
104 menu.exec(mapToGlobal(pos));
105
106 if (button) {
107 // Clear mouseover state after closing menu
108 button->update();
109 }
110
111 m_clickedBookmark = nullptr;
112 m_actShowOnlyIcons = nullptr;
113 m_actShowOnlyText = nullptr;
114}
115
116void BookmarksToolbar::refresh()
117{
118 clear();
119
120 BookmarkItem* folder = mApp->bookmarks()->toolbarFolder();
121
122 const auto children = folder->children();
123 for (BookmarkItem* child : children) {
124 addItem(child);
125 }
126
127 m_layout->addStretch();
128}
129
130void BookmarksToolbar::bookmarksChanged()
131{
132 m_updateTimer->start();
133}
134
135void BookmarksToolbar::showOnlyIconsChanged(bool state)
136{
137 if (state && m_actShowOnlyText) {
138 m_actShowOnlyText->setChecked(false);
139 }
140
141 for (int i = 0; i < m_layout->count(); ++i) {
142 auto* b = qobject_cast<BookmarksToolbarButton*>(m_layout->itemAt(i)->widget());
143 if (b) {
144 b->setShowOnlyIcon(state);
145 }
146 }
147}
148
149void BookmarksToolbar::showOnlyTextChanged(bool state)
150{
151 if (state && m_actShowOnlyIcons) {
152 m_actShowOnlyIcons->setChecked(false);
153 }
154
155 for (int i = 0; i < m_layout->count(); ++i) {
156 auto* b = qobject_cast<BookmarksToolbarButton*>(m_layout->itemAt(i)->widget());
157 if (b) {
158 b->setShowOnlyText(state);
159 }
160 }
161}
162
163void BookmarksToolbar::openBookmarkInNewTab()
164{
165 if (m_clickedBookmark) {
166 BookmarksTools::openBookmarkInNewTab(m_window, m_clickedBookmark);
167 }
168}
169
170void BookmarksToolbar::openBookmarkInNewWindow()
171{
172 if (m_clickedBookmark) {
174 }
175}
176
177void BookmarksToolbar::openBookmarkInNewPrivateWindow()
178{
179 if (m_clickedBookmark) {
181 }
182}
183
184void BookmarksToolbar::createNewFolder()
185{
186 QString name = QInputDialog::getText(nullptr, tr("New Folder"), tr("Enter Folder Name:"));
187
188 if (!name.isEmpty()) {
189 BookmarkItem* parent;
190
191 if (m_clickedBookmark && m_clickedBookmark->isFolder()) {
192 parent = m_clickedBookmark;
193 } else {
194 parent = m_bookmarks->toolbarFolder();
195 }
196
197 auto folder = new BookmarkItem(BookmarkItem::Folder);
198 folder->setTitle(name);
199 m_bookmarks->addBookmark(parent, folder);
200 }
201}
202
203void BookmarksToolbar::editBookmark()
204{
205 if (m_clickedBookmark) {
206 BookmarksTools::editBookmarkDialog(this, m_clickedBookmark);
207 m_bookmarks->changeBookmark(m_clickedBookmark);
208 }
209}
210
211void BookmarksToolbar::deleteBookmark()
212{
213 if (m_clickedBookmark) {
214 m_bookmarks->removeBookmark(m_clickedBookmark);
215 }
216}
217
218void BookmarksToolbar::clear()
219{
220 int count = m_layout->count();
221
222 for (int i = 0; i < count; ++i) {
223 QLayoutItem* item = m_layout->takeAt(0);
224 delete item->widget();
225 delete item;
226 }
227
228 Q_ASSERT(m_layout->isEmpty());
229}
230
231void BookmarksToolbar::addItem(BookmarkItem* item)
232{
233 Q_ASSERT(item);
234
235 auto* button = new BookmarksToolbarButton(item, this);
236 button->setMainWindow(m_window);
237 button->setShowOnlyIcon(m_bookmarks->showOnlyIconsInToolbar());
238 button->setShowOnlyText(m_bookmarks->showOnlyTextInToolbar());
239 m_layout->addWidget(button);
240}
241
242BookmarksToolbarButton* BookmarksToolbar::buttonAt(const QPoint &pos)
243{
244 return qobject_cast<BookmarksToolbarButton*>(QApplication::widgetAt(mapToGlobal(pos)));
245}
246
247QSize BookmarksToolbar::minimumSizeHint() const
248{
249 QSize size = QWidget::minimumSizeHint();
250 size.setHeight(qMax(20, size.height()));
251 return size;
252}
253
254void BookmarksToolbar::dropEvent(QDropEvent* e)
255{
256 int row = m_dropRow;
257 clearDropIndicator();
258
259 const QMimeData* mime = e->mimeData();
260
261 if (!mime->hasUrls() && !mime->hasFormat(BookmarksButtonMimeData::mimeType())) {
262 QWidget::dropEvent(e);
263 return;
264 }
265
266 BookmarkItem* parent = m_bookmarks->toolbarFolder();
267 BookmarkItem* bookmark = nullptr;
268
269 if (mime->hasFormat(BookmarksButtonMimeData::mimeType())) {
270 const auto* bookmarkMime = static_cast<const BookmarksButtonMimeData*>(mime);
271 bookmark = bookmarkMime->item();
272 const int initialIndex = bookmark->parent()->children().indexOf(bookmark);
273 BookmarksToolbarButton* current = buttonAt(m_dropPos);
274 if (initialIndex < m_layout->indexOf(current)) {
275 row -= 1;
276 }
277 } else {
278 const QUrl url = mime->urls().at(0);
279 const QString title = mime->hasText() ? mime->text() : QString::fromUtf8(url.toEncoded(QUrl::RemoveScheme));
280
281 bookmark = new BookmarkItem(BookmarkItem::Url);
282 bookmark->setTitle(title);
283 bookmark->setUrl(url);
284 }
285
286 if (row >= 0) {
287 m_bookmarks->insertBookmark(parent, row, bookmark);
288 } else {
289 m_bookmarks->addBookmark(parent, bookmark);
290 }
291}
292
293void BookmarksToolbar::dragEnterEvent(QDragEnterEvent* e)
294{
295 const QMimeData* mime = e->mimeData();
296
297 if ((mime->hasUrls() && mime->hasText()) || mime->hasFormat(BookmarksButtonMimeData::mimeType())) {
298 e->acceptProposedAction();
299 return;
300 }
301
302 QWidget::dragEnterEvent(e);
303}
304
305void BookmarksToolbar::dragMoveEvent(QDragMoveEvent *e)
306{
307 int eventX = e->position().toPoint().x();
308 BookmarksToolbarButton* button = buttonAt(e->position().toPoint());
309 m_dropPos = e->position().toPoint();
310 m_dropRow = m_layout->indexOf(button);
311 if (button) {
312 bool res = eventX - button->x() < button->x() + button->width() -eventX;
313 m_dropRow = res ? m_dropRow : m_dropRow + 1;
314 } else {
315 m_dropRow = -1;
316 }
317
318 update();
319}
320
321void BookmarksToolbar::dragLeaveEvent(QDragLeaveEvent *e)
322{
323 Q_UNUSED(e);
324 clearDropIndicator();
325}
326
327void BookmarksToolbar::clearDropIndicator()
328{
329 m_dropRow = -1;
330 update();
331}
332
333void BookmarksToolbar::paintEvent(QPaintEvent *p)
334{
335 QWidget::paintEvent(p);
336
337 // Draw drop indicator
338 if (m_dropRow != -1) {
339 BookmarksToolbarButton* button = buttonAt(m_dropPos);
340 if (button) {
341 if (button->bookmark()->isFolder()) {
342 return;
343 }
344 const QRect tr = QRect(button->x(), 0, button->width(), height());
345 QRect r;
346
347 if (m_dropRow == m_layout->indexOf(button)) {
348 r = QRect(qMax(0, tr.left() - 2), tr.top(), 3, tr.height());
349 } else {
350 r = QRect(tr.right() + 0, tr.top(), 3, tr.height());
351 }
352
354 }
355 }
356}
bool isFolder() const
bool isUrl() const
BookmarkItem * parent() const
QList< BookmarkItem * > children() const
void setUrl(const QUrl &url)
void setTitle(const QString &title)
static QString mimeType()
void changeBookmark(BookmarkItem *item)
Definition: bookmarks.cpp:170
void bookmarkRemoved(BookmarkItem *item)
void showOnlyIconsInToolbarChanged(bool show)
void addBookmark(BookmarkItem *parent, BookmarkItem *item)
Definition: bookmarks.cpp:135
void setShowOnlyTextInToolbar(bool state)
Definition: bookmarks.cpp:185
bool showOnlyTextInToolbar() const
Definition: bookmarks.cpp:64
bool showOnlyIconsInToolbar() const
Definition: bookmarks.cpp:59
void bookmarkAdded(BookmarkItem *item)
void bookmarkChanged(BookmarkItem *item)
bool canBeModified(BookmarkItem *item) const
Definition: bookmarks.cpp:104
bool removeBookmark(BookmarkItem *item)
Definition: bookmarks.cpp:157
BookmarkItem * toolbarFolder() const
Definition: bookmarks.cpp:74
void insertBookmark(BookmarkItem *parent, int row, BookmarkItem *item)
Definition: bookmarks.cpp:144
void setShowOnlyIconsInToolbar(bool state)
Definition: bookmarks.cpp:178
void showOnlyTextInToolbarChanged(bool show)
void setMainWindow(BrowserWindow *window)
BookmarkItem * bookmark() const
BookmarksToolbar(BrowserWindow *window, QWidget *parent=nullptr)
static void openBookmarkInNewTab(BrowserWindow *window, BookmarkItem *item)
static void openBookmarkInNewPrivateWindow(BookmarkItem *item)
static bool editBookmarkDialog(QWidget *parent, BookmarkItem *item)
static void openBookmarkInNewWindow(BookmarkItem *item)
static QIcon privateBrowsingIcon()
static QIcon newWindowIcon()
static QIcon newTabIcon()
static void paintDropIndicator(QWidget *widget, const QRect &r)
Definition: qztools.cpp:1023
#define mApp
i
Definition: i18n.py:23
State state
#define QSL(x)
Definition: qzcommon.h:40