File indexing completed on 2024-05-12 04:58:13

0001 /* ============================================================
0002 * Falkon - Qt web browser
0003 * Copyright (C) 2010-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 "statusbar.h"
0019 #include "browserwindow.h"
0020 #include "tabwidget.h"
0021 #include "tabbedwebview.h"
0022 #include "mainapplication.h"
0023 #include "webpage.h"
0024 #include "proxystyle.h"
0025 #include "qztools.h"
0026 #include "abstractbuttoninterface.h"
0027 #include "clickablelabel.h"
0028 
0029 #include <QStyleOptionFrame>
0030 #include <QToolTip>
0031 #include <QStylePainter>
0032 #include <QTimer>
0033 #include <QMouseEvent>
0034 
0035 class StatusBarButton : public ClickableLabel
0036 {
0037 public:
0038     explicit StatusBarButton(AbstractButtonInterface *button, QWidget *parent = nullptr);
0039 
0040 private:
0041     void clicked();
0042     void updateIcon();
0043     void updateToolTip();
0044 
0045     AbstractButtonInterface *m_button;
0046 };
0047 
0048 StatusBarButton::StatusBarButton(AbstractButtonInterface *button, QWidget *parent)
0049     : ClickableLabel(parent)
0050     , m_button(button)
0051 {
0052     setFixedSize(16, 16);
0053     setCursor(Qt::PointingHandCursor);
0054 
0055     updateIcon();
0056     updateToolTip();
0057     setVisible(m_button->isVisible());
0058 
0059     connect(this, &ClickableLabel::clicked, this, &StatusBarButton::clicked);
0060     connect(m_button, &AbstractButtonInterface::iconChanged, this, &StatusBarButton::updateIcon);
0061     connect(m_button, &AbstractButtonInterface::activeChanged, this, &StatusBarButton::updateIcon);
0062     connect(m_button, &AbstractButtonInterface::toolTipChanged, this, &StatusBarButton::updateToolTip);
0063     connect(m_button, &AbstractButtonInterface::badgeTextChanged, this, &StatusBarButton::updateToolTip);
0064     connect(m_button, &AbstractButtonInterface::visibleChanged, this, &StatusBarButton::setVisible);
0065 }
0066 
0067 void StatusBarButton::clicked()
0068 {
0069     auto *c = new AbstractButtonInterface::ClickController;
0070     c->visualParent = this;
0071     c->popupPosition = [=](const QSize &size) {
0072         QPoint pos = mapToGlobal(rect().topRight());
0073         if (QApplication::isRightToLeft()) {
0074             pos.setX(pos.x() - rect().width());
0075         } else {
0076             pos.setX(pos.x() - size.width());
0077         }
0078         pos.setY(pos.y() - size.height());
0079         c->popupOpened = true;
0080         return pos;
0081     };
0082     c->popupClosed = [=]() {
0083         delete c;
0084     };
0085     Q_EMIT m_button->clicked(c);
0086     if (!c->popupOpened) {
0087         c->popupClosed();
0088     }
0089 }
0090 
0091 void StatusBarButton::updateIcon()
0092 {
0093     const QIcon::Mode mode = m_button->isActive() ? QIcon::Normal : QIcon::Disabled;
0094     const QImage img = m_button->icon().pixmap(size(), mode).toImage();
0095     setPixmap(QPixmap::fromImage(img, Qt::MonoOnly));
0096 }
0097 
0098 void StatusBarButton::updateToolTip()
0099 {
0100     QString text = m_button->toolTip();
0101     if (!m_button->badgeText().isEmpty()) {
0102         text.append(QSL(" (%1)").arg(m_button->badgeText()));
0103     }
0104     setToolTip(text);
0105 }
0106 
0107 TipLabel::TipLabel(QWidget* parent)
0108     : SqueezeLabelV1(parent)
0109 {
0110     setWindowFlags(Qt::ToolTip);
0111     setForegroundRole(QPalette::ToolTipText);
0112     setBackgroundRole(QPalette::ToolTipBase);
0113     setPalette(QToolTip::palette());
0114     ensurePolished();
0115     setFrameStyle(QFrame::NoFrame);
0116     setContentsMargins(3, 3, 3, 3);
0117 
0118     m_timer = new QTimer(this);
0119     m_timer->setSingleShot(true);
0120     m_timer->setInterval(500);
0121     connect(m_timer, &QTimer::timeout, this, &QWidget::hide);
0122 }
0123 
0124 void TipLabel::show(QWidget* widget)
0125 {
0126     m_timer->stop();
0127 
0128     widget->installEventFilter(this);
0129     SqueezeLabelV1::show();
0130 }
0131 
0132 void TipLabel::hideDelayed()
0133 {
0134     m_timer->start();
0135 }
0136 
0137 void TipLabel::paintEvent(QPaintEvent* ev)
0138 {
0139     QStylePainter p(this);
0140     QStyleOptionFrame opt;
0141     opt.initFrom(this);
0142     p.drawPrimitive(QStyle::PE_PanelTipLabel, opt);
0143     p.end();
0144 
0145     SqueezeLabelV1::paintEvent(ev);
0146 }
0147 
0148 bool TipLabel::eventFilter(QObject* o, QEvent* e)
0149 {
0150     Q_UNUSED(o);
0151 
0152     switch (e->type()) {
0153     case QEvent::Leave:
0154     case QEvent::WindowDeactivate:
0155     case QEvent::Wheel:
0156         hide();
0157         break;
0158 
0159     case QEvent::MouseMove:
0160     case QEvent::MouseButtonPress:
0161     case QEvent::MouseButtonRelease:
0162         if (o == this)
0163             hide();
0164         break;
0165 
0166     default:
0167         break;
0168     }
0169 
0170     return false;
0171 }
0172 
0173 StatusBar::StatusBar(BrowserWindow* window)
0174     : m_window(window)
0175     , m_statusBarText(new TipLabel(window))
0176 {
0177 }
0178 
0179 void StatusBar::showMessage(const QString &message, int timeout)
0180 {
0181     if (isVisible()) {
0182         const static QChar LRE(0x202a);
0183         QStatusBar::showMessage(message.isRightToLeft() ? message : (LRE + message), timeout);
0184         return;
0185     }
0186 
0187     if (mApp->activeWindow() != m_window) {
0188         return;
0189     }
0190 
0191     WebView* view = m_window->weView();
0192 
0193     const int verticalScrollSize = view->scrollBarGeometry(Qt::Vertical).width();;
0194     const int horizontalScrollSize = view->scrollBarGeometry(Qt::Horizontal).height();
0195 
0196     m_statusBarText->setText(message);
0197     m_statusBarText->setMaximumWidth(view->width() - verticalScrollSize);
0198     m_statusBarText->resize(m_statusBarText->sizeHint());
0199 
0200     QPoint position(0, view->height() - horizontalScrollSize - m_statusBarText->height());
0201     const QRect statusRect = QRect(view->mapToGlobal(QPoint(0, position.y())), m_statusBarText->size());
0202 
0203     if (statusRect.contains(QCursor::pos())) {
0204         position.setY(position.y() - m_statusBarText->height());
0205     }
0206 
0207     m_statusBarText->move(view->mapToGlobal(position));
0208     m_statusBarText->show(view);
0209 }
0210 
0211 void StatusBar::clearMessage()
0212 {
0213     QStatusBar::clearMessage();
0214     m_statusBarText->hideDelayed();
0215 }
0216 
0217 void StatusBar::addButton(AbstractButtonInterface *button)
0218 {
0219     if (!button || !button->isValid()) {
0220         return;
0221     }
0222 
0223     auto *widget = new StatusBarButton(button, this);
0224     widget->setProperty("button-id", button->id());
0225 
0226     WidgetData data;
0227     data.id = button->id();
0228     data.widget = widget;
0229     data.button = button;
0230     m_widgets[data.id] = data;
0231 
0232     addPermanentWidget(widget);
0233 }
0234 
0235 void StatusBar::removeButton(AbstractButtonInterface *button)
0236 {
0237     if (!button || !m_widgets.contains(button->id())) {
0238         return;
0239     }
0240 
0241     delete m_widgets.take(button->id()).widget;
0242 }
0243 
0244 void StatusBar::mousePressEvent(QMouseEvent *event)
0245 {
0246     if (event->button() == Qt::RightButton) {
0247         QMenu context;
0248         context.addAction(tr("Hide"), m_window, &BrowserWindow::toggleShowStatusBar);
0249         context.exec(QCursor::pos());
0250     }
0251 
0252     QStatusBar::mousePressEvent(event);
0253 }