Falkon Develop
Cross-platform Qt-based web browser
bookmarkstoolbarbutton.cpp
Go to the documentation of this file.
1/* ============================================================
2* Falkon - Qt web browser
3* Copyright (C) 2014-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* ============================================================ */
19#include "bookmarkstools.h"
20#include "bookmarksmodel.h"
21#include "bookmarkitem.h"
22#include "bookmarks.h"
23#include "mainapplication.h"
24#include "enhancedmenu.h"
25
26#include <QStyle>
27#include <QPainter>
28#include <QMouseEvent>
29#include <QStyleOptionButton>
30#include <QDrag>
31#include <QMimeData>
32#include <QtGuiVersion>
33
34#define MAX_WIDTH 150
35#define SEPARATOR_WIDTH 8
36#define PADDING 5
37
39 : QPushButton(parent)
40 , m_bookmark(bookmark)
41 , m_window(nullptr)
42 , m_showOnlyIcon(false)
43{
44 init();
45
46 if (m_bookmark->isFolder()) {
47 setAcceptDrops(true);
48 }
49}
50
52{
53 return m_bookmark;
54}
55
57{
58 m_window = window;
59}
60
62{
63 return m_showOnlyIcon;
64}
65
67{
68 m_showOnlyIcon = show;
69 updateGeometry();
70 update();
71}
72
74{
75 return m_showOnlyText;
76}
77
79{
80 m_showOnlyText = show;
81 updateGeometry();
82 update();
83}
84
86{
87 int width = PADDING * 2;
88 if (!m_showOnlyText) {
89 width += 16;
90 }
91
92 if (m_bookmark->isSeparator()) {
93 width = SEPARATOR_WIDTH;
94 }
95 else if (!m_showOnlyIcon) {
96 width += PADDING * 2 + fontMetrics().horizontalAdvance(m_bookmark->title());
97
98 if (menu()) {
99 width += PADDING + 8;
100 }
101 }
102
103 QSize s = QPushButton::sizeHint();
104 s.setWidth(qMin(width, MAX_WIDTH));
105 return s;
106}
107
109{
110 int width = PADDING * 2;
111 if (!m_showOnlyText) {
112 width += 16;
113 }
114
115 if (m_bookmark->isSeparator()) {
116 width = SEPARATOR_WIDTH;
117 }
118 else if (!m_showOnlyIcon && menu()) {
119 width += PADDING + 8;
120 }
121
122 QSize s = QPushButton::minimumSizeHint();
123 s.setWidth(width);
124 return s;
125}
126
127void BookmarksToolbarButton::createMenu()
128{
129 if (!menu()->isEmpty()) {
130 return;
131 }
132
133 Menu* m = qobject_cast<Menu*>(menu());
134 Q_ASSERT(m);
135
136 BookmarksTools::addFolderContentsToMenu(this, m, m_bookmark);
137}
138
139void BookmarksToolbarButton::menuAboutToShow()
140{
141 Q_ASSERT(qobject_cast<Menu*>(sender()));
142 Menu *menu = static_cast<Menu*>(sender());
143
144 const auto menuActions = menu->actions();
145 for (QAction *action : menuActions) {
146 BookmarkItem *item = static_cast<BookmarkItem*>(action->data().value<void*>());
147 if (item && item->type() == BookmarkItem::Url && action->icon().isNull()) {
148 action->setIcon(item->icon());
149 }
150 }
151}
152
153void BookmarksToolbarButton::menuMiddleClicked(Menu* menu)
154{
155 BookmarkItem* item = static_cast<BookmarkItem*>(menu->menuAction()->data().value<void*>());
156 Q_ASSERT(item);
157 openFolder(item);
158}
159
160void BookmarksToolbarButton::bookmarkActivated(BookmarkItem* item)
161{
162 if (auto* action = qobject_cast<QAction*>(sender())) {
163 item = static_cast<BookmarkItem*>(action->data().value<void*>());
164 }
165
166 Q_ASSERT(item);
167 openBookmark(item);
168}
169
170void BookmarksToolbarButton::bookmarkCtrlActivated(BookmarkItem* item)
171{
172 if (auto* action = qobject_cast<QAction*>(sender())) {
173 item = static_cast<BookmarkItem*>(action->data().value<void*>());
174 }
175
176 Q_ASSERT(item);
177 openBookmarkInNewTab(item);
178}
179
180void BookmarksToolbarButton::bookmarkShiftActivated(BookmarkItem* item)
181{
182 if (auto* action = qobject_cast<QAction*>(sender())) {
183 item = static_cast<BookmarkItem*>(action->data().value<void*>());
184 }
185
186 Q_ASSERT(item);
187 openBookmarkInNewWindow(item);
188}
189
190void BookmarksToolbarButton::openFolder(BookmarkItem* item)
191{
192 Q_ASSERT(item->isFolder());
193
194 if (m_window) {
195 BookmarksTools::openFolderInTabs(m_window, item);
196 }
197}
198
199void BookmarksToolbarButton::openBookmark(BookmarkItem* item)
200{
201 Q_ASSERT(item->isUrl());
202
203 if (m_window) {
204 BookmarksTools::openBookmark(m_window, item);
205 }
206}
207
208void BookmarksToolbarButton::openBookmarkInNewTab(BookmarkItem* item)
209{
210 Q_ASSERT(item->isUrl());
211
212 if (m_window) {
214 }
215}
216
217void BookmarksToolbarButton::openBookmarkInNewWindow(BookmarkItem* item)
218{
219 Q_ASSERT(item->isUrl());
220
222}
223
224void BookmarksToolbarButton::init()
225{
226 Q_ASSERT(m_bookmark);
227
228 setFocusPolicy(Qt::NoFocus);
229 setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
230 setToolTip(createTooltip());
231
232 if (m_bookmark->isFolder()) {
233 Menu* m = new Menu(this);
234 setMenu(m);
235 createMenu();
236 }
237}
238
239QString BookmarksToolbarButton::createTooltip() const
240{
241 if (!m_bookmark->description().isEmpty()) {
242 if (!m_bookmark->urlString().isEmpty()) {
243 return QSL("%1\n%2").arg(m_bookmark->description(), m_bookmark->urlString());
244 }
245 return m_bookmark->description();
246 }
247
248 if (!m_bookmark->title().isEmpty() && !m_bookmark->url().isEmpty()) {
249 return QSL("%1\n%2").arg(m_bookmark->title(), m_bookmark->urlString());
250 }
251
252 if (!m_bookmark->title().isEmpty()) {
253 return m_bookmark->title();
254 }
255
256 return m_bookmark->urlString();
257}
258
259void BookmarksToolbarButton::enterEvent(QEnterEvent* event)
260{
261 QPushButton::enterEvent(event);
262
263 update();
264}
265
266void BookmarksToolbarButton::leaveEvent(QEvent* event)
267{
268 QPushButton::leaveEvent(event);
269
270 update();
271}
272
273void BookmarksToolbarButton::mousePressEvent(QMouseEvent* event)
274{
275 if (m_bookmark && m_bookmark->isFolder()) {
276 if (event->buttons() == Qt::LeftButton && event->modifiers() == Qt::ControlModifier) {
277 openFolder(m_bookmark);
278 return;
279 }
280 }
281
282 m_dragStartPosition = event->position().toPoint();
283
284 QPushButton::mousePressEvent(event);
285}
286
287void BookmarksToolbarButton::mouseReleaseEvent(QMouseEvent* event)
288{
289 if (m_bookmark && rect().contains(event->position().toPoint())) {
290 Qt::MouseButton button = event->button();
291 Qt::KeyboardModifiers modifiers = event->modifiers();
292
293 if (m_bookmark->isUrl()) {
294 if (button == Qt::LeftButton && modifiers == Qt::NoModifier) {
295 bookmarkActivated(m_bookmark);
296 }
297 else if (button == Qt::LeftButton && modifiers == Qt::ShiftModifier) {
298 bookmarkShiftActivated(m_bookmark);
299 }
300 else if (button == Qt::MiddleButton || modifiers == Qt::ControlModifier) {
301 bookmarkCtrlActivated(m_bookmark);
302 }
303 }
304 else if (m_bookmark->isFolder() && button == Qt::MiddleButton) {
305 openFolder(m_bookmark);
306 }
307 }
308
309 QPushButton::mouseReleaseEvent(event);
310}
311
312void BookmarksToolbarButton::mouseMoveEvent(QMouseEvent *event)
313{
314 if ((event->position().toPoint() - m_dragStartPosition).manhattanLength() < QApplication::startDragDistance()) {
315 QPushButton::mouseMoveEvent(event);
316 return;
317 }
318
319 setDown(false);
320
321 auto *drag = new QDrag(this);
322 auto* mime = new BookmarksButtonMimeData;
323 mime->setBookmarkItem(m_bookmark);
324 drag->setMimeData(mime);
325 drag->setPixmap(grab());
326 drag->exec();
327}
328
329void BookmarksToolbarButton::paintEvent(QPaintEvent* event)
330{
331 Q_UNUSED(event)
332
333 QPainter p(this);
334
335 // Just draw separator
336 if (m_bookmark->isSeparator()) {
337 QStyleOption opt;
338 opt.initFrom(this);
339 opt.state |= QStyle::State_Horizontal;
340 style()->drawPrimitive(QStyle::PE_IndicatorToolBarSeparator, &opt, &p);
341 return;
342 }
343
344 QStyleOptionButton option;
345 initStyleOption(&option);
346
347 // We are manually drawing the arrow
348 option.features &= ~QStyleOptionButton::HasMenu;
349
350 // Draw button base (only under mouse, this is autoraise button)
351 if (isDown() || hitButton(mapFromGlobal(QCursor::pos()))) {
352 option.state |= QStyle::State_AutoRaise | QStyle::State_Raised;
353 style()->drawPrimitive(QStyle::PE_PanelButtonTool, &option, &p, this);
354 }
355
356 const int shiftX = isDown() ? style()->pixelMetric(QStyle::PM_ButtonShiftHorizontal, &option, this) : 0;
357 const int shiftY = isDown() ? style()->pixelMetric(QStyle::PM_ButtonShiftVertical, &option, this) : 0;
358
359 const int height = option.rect.height();
360 const int center = height / 2 + option.rect.top() + shiftY;
361
362 const int iconSize = 16;
363 const int iconYPos = center - iconSize / 2;
364
365 int leftPosition = PADDING + shiftX;
366 int rightPosition = option.rect.right() - PADDING;
367
368 // Draw icon
369 if (!m_showOnlyText) {
370 QRect iconRect(leftPosition, iconYPos, iconSize, iconSize);
371 p.drawPixmap(QStyle::visualRect(option.direction, option.rect, iconRect), m_bookmark->icon().pixmap(iconSize));
372 leftPosition = iconRect.right() + PADDING;
373 }
374
375 // Draw menu arrow
376 if (!m_showOnlyIcon && menu()) {
377 const int arrowSize = 8;
378 QStyleOption opt;
379 opt.initFrom(this);
380 const QRect rect = QRect(rightPosition - 8, center - arrowSize / 2, arrowSize, arrowSize);
381 opt.rect = QStyle::visualRect(option.direction, option.rect, rect);
382 opt.state &= ~QStyle::State_MouseOver;
383 style()->drawPrimitive(QStyle::PE_IndicatorArrowDown, &opt, &p, this);
384 rightPosition = rect.left() - PADDING;
385 }
386
387 // Draw text
388 if (!m_showOnlyIcon) {
389 const int textWidth = rightPosition - leftPosition;
390 const int textYPos = center - fontMetrics().height() / 2;
391 const QString txt = fontMetrics().elidedText(m_bookmark->title(), Qt::ElideRight, textWidth);
392 QRect textRect(leftPosition, textYPos, textWidth, fontMetrics().height());
393 style()->drawItemText(&p, QStyle::visualRect(option.direction, option.rect, textRect),
394 Qt::TextSingleLine | Qt::AlignCenter, option.palette, true, txt);
395 }
396}
397
398void BookmarksToolbarButton::dragEnterEvent(QDragEnterEvent *event)
399{
400 const QMimeData* mime = event->mimeData();
401 if ((mime->hasUrls() && mime->hasText()) || mime->hasFormat(BookmarksButtonMimeData::mimeType())) {
402 event->acceptProposedAction();
403 setDown(true);
404 return;
405 }
406
407 QPushButton::dragEnterEvent(event);
408}
409
410void BookmarksToolbarButton::dragLeaveEvent(QDragLeaveEvent *event)
411{
412 Q_UNUSED(event);
413 setDown(false);
414}
415
416void BookmarksToolbarButton::dropEvent(QDropEvent *event)
417{
418 setDown(false);
419
420 const QMimeData* mime = event->mimeData();
421 if (!mime->hasUrls() && !mime->hasFormat(BookmarksButtonMimeData::mimeType())) {
422 QPushButton::dropEvent(event);
423 return;
424 }
425
426 BookmarkItem* bookmark = nullptr;
427
428 if (mime->hasFormat(BookmarksButtonMimeData::mimeType())) {
429 const auto* bookmarkMime = static_cast<const BookmarksButtonMimeData*>(mime);
430 bookmark = bookmarkMime->item();
431
432 if (m_bookmark == bookmark) {
433 return;
434 }
435 } else {
436 const QUrl url = mime->urls().at(0);
437 const QString title = mime->hasText() ? mime->text() : QString::fromUtf8(url.toEncoded(QUrl::RemoveScheme));
438
440 bookmark->setTitle(title);
441 bookmark->setUrl(url);
442 }
443
444 mApp->bookmarks()->addBookmark(m_bookmark, bookmark);
445}
#define MAX_WIDTH
#define PADDING
#define SEPARATOR_WIDTH
bool isFolder() const
QString urlString() const
bool isSeparator() const
QString description() const
QUrl url() const
void setIcon(const QIcon &icon)
bool isUrl() const
QString title() const
void setUrl(const QUrl &url)
Type type() const
void setTitle(const QString &title)
void setBookmarkItem(BookmarkItem *item)
static QString mimeType()
BookmarksToolbarButton(BookmarkItem *bookmark, QWidget *parent=nullptr)
QSize minimumSizeHint() const override
void setMainWindow(BrowserWindow *window)
BookmarkItem * bookmark() const
QSize sizeHint() const override
static void openBookmarkInNewTab(BrowserWindow *window, BookmarkItem *item)
static void openBookmark(BrowserWindow *window, BookmarkItem *item)
static void openFolderInTabs(BrowserWindow *window, BookmarkItem *folder)
static void openBookmarkInNewWindow(BookmarkItem *item)
static void addFolderContentsToMenu(QObject *receiver, Menu *menu, BookmarkItem *folder)
#define mApp
#define QSL(x)
Definition: qzcommon.h:40