File indexing completed on 2024-05-12 04:57:58
0001 /* ============================================================ 0002 * Falkon - Qt web browser 0003 * Copyright (C) 2014-2018 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 "bookmarkstoolbarbutton.h" 0019 #include "bookmarkstools.h" 0020 #include "bookmarksmodel.h" 0021 #include "bookmarkitem.h" 0022 #include "bookmarks.h" 0023 #include "mainapplication.h" 0024 #include "enhancedmenu.h" 0025 0026 #include <QStyle> 0027 #include <QPainter> 0028 #include <QMouseEvent> 0029 #include <QStyleOptionButton> 0030 #include <QDrag> 0031 #include <QMimeData> 0032 #include <QtGuiVersion> 0033 0034 #define MAX_WIDTH 150 0035 #define SEPARATOR_WIDTH 8 0036 #define PADDING 5 0037 0038 BookmarksToolbarButton::BookmarksToolbarButton(BookmarkItem* bookmark, QWidget* parent) 0039 : QPushButton(parent) 0040 , m_bookmark(bookmark) 0041 , m_window(nullptr) 0042 , m_showOnlyIcon(false) 0043 { 0044 init(); 0045 0046 if (m_bookmark->isFolder()) { 0047 setAcceptDrops(true); 0048 } 0049 } 0050 0051 BookmarkItem* BookmarksToolbarButton::bookmark() const 0052 { 0053 return m_bookmark; 0054 } 0055 0056 void BookmarksToolbarButton::setMainWindow(BrowserWindow* window) 0057 { 0058 m_window = window; 0059 } 0060 0061 bool BookmarksToolbarButton::showOnlyIcon() const 0062 { 0063 return m_showOnlyIcon; 0064 } 0065 0066 void BookmarksToolbarButton::setShowOnlyIcon(bool show) 0067 { 0068 m_showOnlyIcon = show; 0069 updateGeometry(); 0070 update(); 0071 } 0072 0073 bool BookmarksToolbarButton::showOnlyText() const 0074 { 0075 return m_showOnlyText; 0076 } 0077 0078 void BookmarksToolbarButton::setShowOnlyText(bool show) 0079 { 0080 m_showOnlyText = show; 0081 updateGeometry(); 0082 update(); 0083 } 0084 0085 QSize BookmarksToolbarButton::sizeHint() const 0086 { 0087 int width = PADDING * 2; 0088 if (!m_showOnlyText) { 0089 width += 16; 0090 } 0091 0092 if (m_bookmark->isSeparator()) { 0093 width = SEPARATOR_WIDTH; 0094 } 0095 else if (!m_showOnlyIcon) { 0096 width += PADDING * 2 + fontMetrics().horizontalAdvance(m_bookmark->title()); 0097 0098 if (menu()) { 0099 width += PADDING + 8; 0100 } 0101 } 0102 0103 QSize s = QPushButton::sizeHint(); 0104 s.setWidth(qMin(width, MAX_WIDTH)); 0105 return s; 0106 } 0107 0108 QSize BookmarksToolbarButton::minimumSizeHint() const 0109 { 0110 int width = PADDING * 2; 0111 if (!m_showOnlyText) { 0112 width += 16; 0113 } 0114 0115 if (m_bookmark->isSeparator()) { 0116 width = SEPARATOR_WIDTH; 0117 } 0118 else if (!m_showOnlyIcon && menu()) { 0119 width += PADDING + 8; 0120 } 0121 0122 QSize s = QPushButton::minimumSizeHint(); 0123 s.setWidth(width); 0124 return s; 0125 } 0126 0127 void BookmarksToolbarButton::createMenu() 0128 { 0129 if (!menu()->isEmpty()) { 0130 return; 0131 } 0132 0133 Menu* m = qobject_cast<Menu*>(menu()); 0134 Q_ASSERT(m); 0135 0136 BookmarksTools::addFolderContentsToMenu(this, m, m_bookmark); 0137 } 0138 0139 void BookmarksToolbarButton::menuAboutToShow() 0140 { 0141 Q_ASSERT(qobject_cast<Menu*>(sender())); 0142 Menu *menu = static_cast<Menu*>(sender()); 0143 0144 const auto menuActions = menu->actions(); 0145 for (QAction *action : menuActions) { 0146 BookmarkItem *item = static_cast<BookmarkItem*>(action->data().value<void*>()); 0147 if (item && item->type() == BookmarkItem::Url && action->icon().isNull()) { 0148 action->setIcon(item->icon()); 0149 } 0150 } 0151 } 0152 0153 void BookmarksToolbarButton::menuMiddleClicked(Menu* menu) 0154 { 0155 BookmarkItem* item = static_cast<BookmarkItem*>(menu->menuAction()->data().value<void*>()); 0156 Q_ASSERT(item); 0157 openFolder(item); 0158 } 0159 0160 void BookmarksToolbarButton::bookmarkActivated(BookmarkItem* item) 0161 { 0162 if (auto* action = qobject_cast<QAction*>(sender())) { 0163 item = static_cast<BookmarkItem*>(action->data().value<void*>()); 0164 } 0165 0166 Q_ASSERT(item); 0167 openBookmark(item); 0168 } 0169 0170 void BookmarksToolbarButton::bookmarkCtrlActivated(BookmarkItem* item) 0171 { 0172 if (auto* action = qobject_cast<QAction*>(sender())) { 0173 item = static_cast<BookmarkItem*>(action->data().value<void*>()); 0174 } 0175 0176 Q_ASSERT(item); 0177 openBookmarkInNewTab(item); 0178 } 0179 0180 void BookmarksToolbarButton::bookmarkShiftActivated(BookmarkItem* item) 0181 { 0182 if (auto* action = qobject_cast<QAction*>(sender())) { 0183 item = static_cast<BookmarkItem*>(action->data().value<void*>()); 0184 } 0185 0186 Q_ASSERT(item); 0187 openBookmarkInNewWindow(item); 0188 } 0189 0190 void BookmarksToolbarButton::openFolder(BookmarkItem* item) 0191 { 0192 Q_ASSERT(item->isFolder()); 0193 0194 if (m_window) { 0195 BookmarksTools::openFolderInTabs(m_window, item); 0196 } 0197 } 0198 0199 void BookmarksToolbarButton::openBookmark(BookmarkItem* item) 0200 { 0201 Q_ASSERT(item->isUrl()); 0202 0203 if (m_window) { 0204 BookmarksTools::openBookmark(m_window, item); 0205 } 0206 } 0207 0208 void BookmarksToolbarButton::openBookmarkInNewTab(BookmarkItem* item) 0209 { 0210 Q_ASSERT(item->isUrl()); 0211 0212 if (m_window) { 0213 BookmarksTools::openBookmarkInNewTab(m_window, item); 0214 } 0215 } 0216 0217 void BookmarksToolbarButton::openBookmarkInNewWindow(BookmarkItem* item) 0218 { 0219 Q_ASSERT(item->isUrl()); 0220 0221 BookmarksTools::openBookmarkInNewWindow(item); 0222 } 0223 0224 void BookmarksToolbarButton::init() 0225 { 0226 Q_ASSERT(m_bookmark); 0227 0228 setFocusPolicy(Qt::NoFocus); 0229 setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); 0230 setToolTip(createTooltip()); 0231 0232 if (m_bookmark->isFolder()) { 0233 Menu* m = new Menu(this); 0234 setMenu(m); 0235 createMenu(); 0236 } 0237 } 0238 0239 QString BookmarksToolbarButton::createTooltip() const 0240 { 0241 if (!m_bookmark->description().isEmpty()) { 0242 if (!m_bookmark->urlString().isEmpty()) { 0243 return QSL("%1\n%2").arg(m_bookmark->description(), m_bookmark->urlString()); 0244 } 0245 return m_bookmark->description(); 0246 } 0247 0248 if (!m_bookmark->title().isEmpty() && !m_bookmark->url().isEmpty()) { 0249 return QSL("%1\n%2").arg(m_bookmark->title(), m_bookmark->urlString()); 0250 } 0251 0252 if (!m_bookmark->title().isEmpty()) { 0253 return m_bookmark->title(); 0254 } 0255 0256 return m_bookmark->urlString(); 0257 } 0258 0259 void BookmarksToolbarButton::enterEvent(QEnterEvent* event) 0260 { 0261 QPushButton::enterEvent(event); 0262 0263 update(); 0264 } 0265 0266 void BookmarksToolbarButton::leaveEvent(QEvent* event) 0267 { 0268 QPushButton::leaveEvent(event); 0269 0270 update(); 0271 } 0272 0273 void BookmarksToolbarButton::mousePressEvent(QMouseEvent* event) 0274 { 0275 if (m_bookmark && m_bookmark->isFolder()) { 0276 if (event->buttons() == Qt::LeftButton && event->modifiers() == Qt::ControlModifier) { 0277 openFolder(m_bookmark); 0278 return; 0279 } 0280 } 0281 0282 m_dragStartPosition = event->position().toPoint(); 0283 0284 QPushButton::mousePressEvent(event); 0285 } 0286 0287 void BookmarksToolbarButton::mouseReleaseEvent(QMouseEvent* event) 0288 { 0289 if (m_bookmark && rect().contains(event->position().toPoint())) { 0290 Qt::MouseButton button = event->button(); 0291 Qt::KeyboardModifiers modifiers = event->modifiers(); 0292 0293 if (m_bookmark->isUrl()) { 0294 if (button == Qt::LeftButton && modifiers == Qt::NoModifier) { 0295 bookmarkActivated(m_bookmark); 0296 } 0297 else if (button == Qt::LeftButton && modifiers == Qt::ShiftModifier) { 0298 bookmarkShiftActivated(m_bookmark); 0299 } 0300 else if (button == Qt::MiddleButton || modifiers == Qt::ControlModifier) { 0301 bookmarkCtrlActivated(m_bookmark); 0302 } 0303 } 0304 else if (m_bookmark->isFolder() && button == Qt::MiddleButton) { 0305 openFolder(m_bookmark); 0306 } 0307 } 0308 0309 QPushButton::mouseReleaseEvent(event); 0310 } 0311 0312 void BookmarksToolbarButton::mouseMoveEvent(QMouseEvent *event) 0313 { 0314 if ((event->position().toPoint() - m_dragStartPosition).manhattanLength() < QApplication::startDragDistance()) { 0315 QPushButton::mouseMoveEvent(event); 0316 return; 0317 } 0318 0319 setDown(false); 0320 0321 auto *drag = new QDrag(this); 0322 auto* mime = new BookmarksButtonMimeData; 0323 mime->setBookmarkItem(m_bookmark); 0324 drag->setMimeData(mime); 0325 drag->setPixmap(grab()); 0326 drag->exec(); 0327 } 0328 0329 void BookmarksToolbarButton::paintEvent(QPaintEvent* event) 0330 { 0331 Q_UNUSED(event) 0332 0333 QPainter p(this); 0334 0335 // Just draw separator 0336 if (m_bookmark->isSeparator()) { 0337 QStyleOption opt; 0338 opt.initFrom(this); 0339 opt.state |= QStyle::State_Horizontal; 0340 style()->drawPrimitive(QStyle::PE_IndicatorToolBarSeparator, &opt, &p); 0341 return; 0342 } 0343 0344 QStyleOptionButton option; 0345 initStyleOption(&option); 0346 0347 // We are manually drawing the arrow 0348 option.features &= ~QStyleOptionButton::HasMenu; 0349 0350 // Draw button base (only under mouse, this is autoraise button) 0351 if (isDown() || hitButton(mapFromGlobal(QCursor::pos()))) { 0352 option.state |= QStyle::State_AutoRaise | QStyle::State_Raised; 0353 style()->drawPrimitive(QStyle::PE_PanelButtonTool, &option, &p, this); 0354 } 0355 0356 const int shiftX = isDown() ? style()->pixelMetric(QStyle::PM_ButtonShiftHorizontal, &option, this) : 0; 0357 const int shiftY = isDown() ? style()->pixelMetric(QStyle::PM_ButtonShiftVertical, &option, this) : 0; 0358 0359 const int height = option.rect.height(); 0360 const int center = height / 2 + option.rect.top() + shiftY; 0361 0362 const int iconSize = 16; 0363 const int iconYPos = center - iconSize / 2; 0364 0365 int leftPosition = PADDING + shiftX; 0366 int rightPosition = option.rect.right() - PADDING; 0367 0368 // Draw icon 0369 if (!m_showOnlyText) { 0370 QRect iconRect(leftPosition, iconYPos, iconSize, iconSize); 0371 p.drawPixmap(QStyle::visualRect(option.direction, option.rect, iconRect), m_bookmark->icon().pixmap(iconSize)); 0372 leftPosition = iconRect.right() + PADDING; 0373 } 0374 0375 // Draw menu arrow 0376 if (!m_showOnlyIcon && menu()) { 0377 const int arrowSize = 8; 0378 QStyleOption opt; 0379 opt.initFrom(this); 0380 const QRect rect = QRect(rightPosition - 8, center - arrowSize / 2, arrowSize, arrowSize); 0381 opt.rect = QStyle::visualRect(option.direction, option.rect, rect); 0382 opt.state &= ~QStyle::State_MouseOver; 0383 style()->drawPrimitive(QStyle::PE_IndicatorArrowDown, &opt, &p, this); 0384 rightPosition = rect.left() - PADDING; 0385 } 0386 0387 // Draw text 0388 if (!m_showOnlyIcon) { 0389 const int textWidth = rightPosition - leftPosition; 0390 const int textYPos = center - fontMetrics().height() / 2; 0391 const QString txt = fontMetrics().elidedText(m_bookmark->title(), Qt::ElideRight, textWidth); 0392 QRect textRect(leftPosition, textYPos, textWidth, fontMetrics().height()); 0393 style()->drawItemText(&p, QStyle::visualRect(option.direction, option.rect, textRect), 0394 Qt::TextSingleLine | Qt::AlignCenter, option.palette, true, txt); 0395 } 0396 } 0397 0398 void BookmarksToolbarButton::dragEnterEvent(QDragEnterEvent *event) 0399 { 0400 const QMimeData* mime = event->mimeData(); 0401 if ((mime->hasUrls() && mime->hasText()) || mime->hasFormat(BookmarksButtonMimeData::mimeType())) { 0402 event->acceptProposedAction(); 0403 setDown(true); 0404 return; 0405 } 0406 0407 QPushButton::dragEnterEvent(event); 0408 } 0409 0410 void BookmarksToolbarButton::dragLeaveEvent(QDragLeaveEvent *event) 0411 { 0412 Q_UNUSED(event); 0413 setDown(false); 0414 } 0415 0416 void BookmarksToolbarButton::dropEvent(QDropEvent *event) 0417 { 0418 setDown(false); 0419 0420 const QMimeData* mime = event->mimeData(); 0421 if (!mime->hasUrls() && !mime->hasFormat(BookmarksButtonMimeData::mimeType())) { 0422 QPushButton::dropEvent(event); 0423 return; 0424 } 0425 0426 BookmarkItem* bookmark = nullptr; 0427 0428 if (mime->hasFormat(BookmarksButtonMimeData::mimeType())) { 0429 const auto* bookmarkMime = static_cast<const BookmarksButtonMimeData*>(mime); 0430 bookmark = bookmarkMime->item(); 0431 0432 if (m_bookmark == bookmark) { 0433 return; 0434 } 0435 } else { 0436 const QUrl url = mime->urls().at(0); 0437 const QString title = mime->hasText() ? mime->text() : QString::fromUtf8(url.toEncoded(QUrl::RemoveScheme)); 0438 0439 bookmark = new BookmarkItem(BookmarkItem::Url); 0440 bookmark->setTitle(title); 0441 bookmark->setUrl(url); 0442 } 0443 0444 mApp->bookmarks()->addBookmark(m_bookmark, bookmark); 0445 }