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 }