File indexing completed on 2024-04-28 15:16:04
0001 // SPDX-License-Identifier: LGPL-2.1-or-later 0002 // 0003 // SPDX-FileCopyrightText: 2012 Torsten Rahn <tackat@kde.org> 0004 // SPDX-FileCopyrightText: 2013 Mohammed Nafees <nafees.technocool@gmail.com> 0005 // SPDX-FileCopyrightText: 2012 Dennis Nienhüser <nienhueser@kde.org> 0006 // SPDX-FileCopyrightText: 2012 Illya Kovalevskyy <illya.kovalevskyy@gmail.com> 0007 // 0008 0009 #include "PopupItem.h" 0010 #include "MarbleWidget.h" 0011 0012 #ifdef MARBLE_NO_WEBKITWIDGETS 0013 #include "NullMarbleWebView.h" 0014 #else 0015 #include <QWebEngineView> 0016 #include <QWebEngineHistory> 0017 #include <QWebEngineSettings> 0018 #include "MarbleWebView.h" 0019 #endif 0020 0021 #include <QDebug> 0022 #include <QPointer> 0023 #include <QPrinter> 0024 #include <QPrintDialog> 0025 #include <QMouseEvent> 0026 #include <QApplication> 0027 #include <QDesktopServices> 0028 #include <QPixmapCache> 0029 #include <qdrawutil.h> 0030 #include <QPainter> 0031 0032 namespace Marble 0033 { 0034 0035 PopupItem::PopupItem( QObject* parent ) : 0036 QObject( parent ), 0037 BillboardGraphicsItem(), 0038 m_widget( new QWidget() ), 0039 m_textColor( QColor(Qt::black) ), 0040 m_backColor( QColor(Qt::white) ), 0041 m_needMouseRelease(false) 0042 { 0043 // setCacheMode( ItemCoordinateCache ); 0044 setVisible( false ); 0045 setSize( QSizeF( 300.0, 320.0 ) ); 0046 0047 m_ui.setupUi( m_widget ); 0048 m_ui.goBackButton->setVisible( false ); 0049 connect( m_ui.goBackButton, SIGNAL(clicked()), this, SLOT(goBack()) ); 0050 0051 #ifdef QT_NO_PRINTER 0052 m_ui.printButton->setVisible( false ); 0053 #else 0054 m_ui.printButton->setVisible( true ); 0055 connect( m_ui.printButton, SIGNAL(clicked()), this, SLOT(printContent()) ); 0056 #endif 0057 0058 m_widget->setVisible(true); 0059 m_widget->setAttribute(Qt::WA_DontShowOnScreen); 0060 m_widget->setAttribute( Qt::WA_NoSystemBackground, true ); 0061 m_widget->setAttribute(Qt::WA_QuitOnClose, false); 0062 QPalette palette = m_ui.webView->palette(); 0063 palette.setBrush(QPalette::Base, Qt::transparent); 0064 #ifndef MARBLE_NO_WEBKITWIDGETS 0065 m_ui.webView->setPalette(palette); 0066 m_ui.webView->page()->settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessFileUrls, true); 0067 m_ui.webView->page()->settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, true); 0068 #endif 0069 m_ui.webView->setAttribute(Qt::WA_OpaquePaintEvent, false); 0070 m_ui.webView->setUrl( QUrl( "about:blank" ) ); 0071 0072 connect( m_ui.hideButton, SIGNAL(clicked()), this, SIGNAL(hide()) ); 0073 0074 #ifndef MARBLE_NO_WEBKITWIDGETS 0075 connect( m_ui.webView->page(), SIGNAL(titleChanged(QString)), m_ui.titleText, SLOT(setText(QString)) ); 0076 connect( m_ui.webView->page(), SIGNAL(urlChanged(QUrl)), this, SLOT(updateBackButton()) ); 0077 // Update the popupitem on changes while loading the webpage 0078 connect(m_ui.webView, SIGNAL(loadFinished(bool)), this, SLOT(requestUpdate())); 0079 #endif 0080 } 0081 0082 PopupItem::~PopupItem() 0083 { 0084 delete m_widget; 0085 } 0086 0087 bool PopupItem::isPrintButtonVisible() const 0088 { 0089 return m_ui.printButton->isVisible(); 0090 } 0091 0092 void PopupItem::setPrintButtonVisible( bool display ) 0093 { 0094 m_ui.printButton->setVisible( display ); 0095 } 0096 0097 void PopupItem::setUrl( const QUrl &url ) 0098 { 0099 m_ui.webView->setUrl( url ); 0100 0101 QPalette palette = m_ui.webView->palette(); 0102 palette.setBrush(QPalette::Base, Qt::transparent); 0103 #ifndef MARBLE_NO_WEBKITWIDGETS 0104 m_ui.webView->setPalette(palette); 0105 #endif 0106 m_ui.webView->setAttribute(Qt::WA_OpaquePaintEvent, false); 0107 0108 requestUpdate(); 0109 } 0110 0111 void PopupItem::setContent( const QString &html, const QUrl &baseUrl ) 0112 { 0113 m_content = html; 0114 m_baseUrl = baseUrl; 0115 #ifndef MARBLE_NO_WEBKITWIDGETS 0116 m_ui.webView->setHtml( html, baseUrl ); 0117 #endif 0118 0119 requestUpdate(); 0120 } 0121 0122 void PopupItem::setTextColor(const QColor &color) 0123 { 0124 if(color.isValid() && m_ui.titleText != nullptr) { 0125 m_textColor = color; 0126 QPalette palette(m_ui.titleText->palette()); 0127 palette.setColor(QPalette::WindowText, m_textColor); 0128 m_ui.titleText->setPalette(palette); 0129 0130 requestUpdate(); 0131 } 0132 } 0133 0134 void PopupItem::setBackgroundColor(const QColor &color) 0135 { 0136 if(color.isValid()) { 0137 m_backColor = color; 0138 QPixmapCache::remove( "marble/webpopup/webpopup2" ); 0139 QPixmapCache::remove( "marble/webpopup/arrow2_topleft" ); 0140 QPixmapCache::remove( "marble/webpopup/arrow2_bottomleft" ); 0141 QPixmapCache::remove( "marble/webpopup/arrow2_topright" ); 0142 QPixmapCache::remove( "marble/webpopup/arrow2_bottomright" ); 0143 0144 requestUpdate(); 0145 } 0146 } 0147 0148 void PopupItem::colorize( QImage &img, const QColor &col ) 0149 { 0150 if (img.depth() <= 8) return; 0151 int pixels = img.width()*img.height(); 0152 unsigned int *data = (unsigned int *) img.bits(); 0153 for (int i=0; i < pixels; ++i) { 0154 int val = qGray(data[i]); 0155 data[i] = qRgba(col.red()*val/255,col.green()*val/255, col.blue()*val/255, qAlpha(data[i])); 0156 } 0157 } 0158 0159 void PopupItem::paint( QPainter *painter ) 0160 { 0161 QRect popupRect; 0162 QPixmap image = pixmap("marble/webpopup/arrow2_vertical_topright"); 0163 0164 if ( alignment() & Qt::AlignRight ) { 0165 popupRect.setRect( image.width() - 13, -10, 0166 size().width() - ( image.width() - 3 ), 0167 size().height() ); 0168 qDrawBorderPixmap(painter, popupRect, QMargins( 20, 20, 20, 20 ), 0169 pixmap("marble/webpopup/webpopup2")); 0170 if ( alignment() & Qt::AlignTop ) { 0171 image = pixmap("marble/webpopup/arrow2_bottomleft"); 0172 painter->drawPixmap( 0, size().height() - image.height(), image ); 0173 } else if ( alignment() & Qt::AlignBottom ) { 0174 image = pixmap("marble/webpopup/arrow2_topleft"); 0175 painter->drawPixmap( 0, 0, image ); 0176 } else { // for no horizontal align value and Qt::AlignVCenter 0177 image = pixmap("marble/webpopup/arrow2_topleft"); 0178 painter->drawPixmap( 0, size().height() / 2, image ); 0179 } 0180 m_widget->render( painter, QPoint( image.width() - 3, 0 ) ); 0181 } else if ( alignment() & Qt::AlignLeft ) { 0182 popupRect.setRect( -10, -10, 0183 size().width() - ( image.width() - 3 ), 0184 size().height() ); 0185 qDrawBorderPixmap(painter, popupRect, QMargins( 20, 20, 20, 20 ), 0186 pixmap("marble/webpopup/webpopup2")); 0187 if ( alignment() & Qt::AlignTop ) { 0188 image = pixmap("marble/webpopup/arrow2_bottomright"); 0189 painter->drawPixmap( size().width() - image.width(), 0190 size().height() - image.height(), image ); 0191 } else if ( alignment() & Qt::AlignBottom ) { 0192 image = pixmap("marble/webpopup/arrow2_topright"); 0193 painter->drawPixmap( size().width() - image.width(), 0194 0, image ); 0195 } else { // for no horizontal align value and Qt::AlignVCenter 0196 image = pixmap("marble/webpopup/arrow2_topright"); 0197 painter->drawPixmap( size().width() - image.width(), 0198 size().height() / 2 - image.height() / 2 + 23, image ); 0199 } 0200 m_widget->render( painter, QPoint( 5, 0 ), QRegion() ); 0201 } else if ( alignment() & Qt::AlignHCenter ) 0202 { 0203 if ( alignment() & Qt::AlignTop ) 0204 { 0205 image = pixmap("marble/webpopup/arrow2_vertical_bottomright"); 0206 popupRect.setRect( -10, -10, size().width(), 0207 size().height() - image.height() + 3 ); 0208 qDrawBorderPixmap(painter, popupRect, QMargins( 20, 20, 20, 20 ), 0209 pixmap("marble/webpopup/webpopup2")); 0210 painter->drawPixmap( size().width() / 2 - image.width(), 0211 size().height() - image.height(), image ); 0212 m_widget->render( painter, QPoint( 0, 0 ), QRegion() ); 0213 } else if ( alignment() & Qt::AlignBottom ) { 0214 image = pixmap("marble/webpopup/arrow2_vertical_topleft"); 0215 popupRect.setRect( -10, image.height() - 13, size().width(), 0216 size().height() - image.height() + 3 ); 0217 qDrawBorderPixmap(painter, popupRect, QMargins( 20, 20, 20, 20 ), 0218 pixmap("marble/webpopup/webpopup2")); 0219 painter->drawPixmap( size().width() / 2, 0, image ); 0220 m_widget->render( painter, QPoint( 5, image.height() - 7 ), QRegion() ); 0221 } else { // for no horizontal align value and Qt::AlignVCenter 0222 popupRect.setRect( -10, -10, size().width(), 0223 size().height()); 0224 qDrawBorderPixmap(painter, popupRect, QMargins( 20, 20, 20, 20 ), 0225 pixmap("marble/webpopup/webpopup2")); 0226 m_widget->render( painter, QPoint( 0, 0 ), QRegion() ); 0227 } 0228 } 0229 m_widget->setFixedSize( popupRect.width() - 20, 0230 popupRect.height() - 20 ); 0231 } 0232 0233 bool PopupItem::eventFilter( QObject *object, QEvent *e ) 0234 { 0235 MarbleWidget *widget = dynamic_cast<MarbleWidget*> ( object ); 0236 if ( !widget ) { 0237 return BillboardGraphicsItem::eventFilter( object, e ); 0238 } 0239 0240 if ( e->type() == QEvent::ContextMenu) { 0241 QApplication::sendEvent( m_ui.webView, e ); 0242 return BillboardGraphicsItem::eventFilter( object, e ); 0243 } 0244 0245 if ( e->type() == QEvent::KeyPress ) { 0246 QApplication::sendEvent( m_ui.webView, e ); 0247 return BillboardGraphicsItem::eventFilter( object, e ); 0248 } 0249 0250 if ( e->type() == QEvent::MouseButtonDblClick 0251 || e->type() == QEvent::MouseMove 0252 || e->type() == QEvent::MouseButtonPress 0253 || e->type() == QEvent::MouseButtonRelease ) 0254 { 0255 // Mouse events are forwarded to the underlying widget 0256 QMouseEvent *event = static_cast<QMouseEvent*> ( e ); 0257 QPoint shiftedPos = event->pos(); 0258 QWidget* child = transform( shiftedPos ); 0259 bool const forcedMouseRelease = m_needMouseRelease && e->type() == QEvent::MouseButtonRelease; 0260 if ( child || forcedMouseRelease ) { 0261 if ( !m_needMouseRelease && e->type() == QEvent::MouseButtonPress ) { 0262 m_needMouseRelease = true; 0263 } else if ( forcedMouseRelease ) { 0264 m_needMouseRelease = false; 0265 } 0266 if ( !child ) { 0267 child = m_ui.webView; 0268 } 0269 QMouseEvent shiftedEvent = QMouseEvent( e->type(), shiftedPos, 0270 event->globalPos(), event->button(), event->buttons(), 0271 event->modifiers() ); 0272 if ( QApplication::sendEvent( child, &shiftedEvent ) ) { 0273 widget->setCursor( child->cursor() ); 0274 emit repaintNeeded(); 0275 return true; 0276 } 0277 } 0278 } else if ( e->type() == QEvent::Wheel ) { 0279 // Wheel events are forwarded to the underlying widget 0280 QWheelEvent *event = static_cast<QWheelEvent*> ( e ); 0281 QPoint shiftedPos = event->pos(); 0282 QWidget* child = transform( shiftedPos ); 0283 if ( child ) { 0284 QWheelEvent shiftedEvent = QWheelEvent( shiftedPos, 0285 event->globalPos(), event->delta(), event->buttons(), 0286 event->modifiers() ); 0287 if ( QApplication::sendEvent( child, &shiftedEvent ) ) { 0288 widget->setCursor( child->cursor() ); 0289 emit repaintNeeded(); 0290 return true; 0291 } 0292 } 0293 } 0294 0295 return BillboardGraphicsItem::eventFilter( object, e ); 0296 } 0297 0298 QWidget* PopupItem::transform( QPoint &point ) const 0299 { 0300 /* 0301 * Fixes for mouse events to trigger when the web popup 0302 * is shifted in accordance with the horizontal alignment 0303 */ 0304 if ( alignment() & Qt::AlignRight ) 0305 point -= QPoint( 117, 0 ); 0306 else if ( alignment() & Qt::AlignLeft ) 0307 point -= QPoint( 5, 0 ); 0308 else if ( alignment() & Qt::AlignHCenter ) 0309 { 0310 if ( alignment() & Qt::AlignTop ) 0311 { 0312 point -= QPoint( 0, 0 ); 0313 } else if ( alignment() & Qt::AlignBottom ) 0314 { 0315 point-= QPoint( 5, 57 ); 0316 } else { 0317 point -= QPoint( 0, 0 ); 0318 } 0319 } 0320 0321 const QVector<QPointF> widgetPositions = positions(); 0322 QVector<QPointF>::const_iterator it = widgetPositions.constBegin(); 0323 for( ; it != widgetPositions.constEnd(); ++it ) { 0324 if ( QRectF( *it, size() ).contains( point ) ) { 0325 point -= it->toPoint(); 0326 QWidget* child = m_widget->childAt( point ); 0327 if ( child ) { 0328 point -= child->pos(); 0329 } 0330 return child; 0331 } 0332 } 0333 return nullptr; 0334 } 0335 0336 void PopupItem::clearHistory() 0337 { 0338 m_content.clear(); 0339 m_ui.webView->setUrl( QUrl( "about:blank" ) ); 0340 #ifndef MARBLE_NO_WEBKITWIDGETS 0341 m_ui.webView->history()->clear(); 0342 #endif 0343 } 0344 0345 void PopupItem::requestUpdate() 0346 { 0347 update(); 0348 emit repaintNeeded(); 0349 } 0350 0351 void PopupItem::printContent() const 0352 { 0353 #ifndef QT_NO_PRINTER 0354 #ifndef MARBLE_NO_WEBKITWIDGETS 0355 QPrinter printer; 0356 QPointer<QPrintDialog> dialog = new QPrintDialog(&printer); 0357 if (dialog->exec() == QPrintDialog::Accepted) { 0358 m_ui.webView->page()->print(&printer, [=](bool){}); 0359 } 0360 delete dialog; 0361 #endif 0362 #endif 0363 } 0364 0365 void PopupItem::updateBackButton() 0366 { 0367 #ifndef MARBLE_NO_WEBKITWIDGETS 0368 bool const hasHistory = m_ui.webView->page()->history()->count() > 1; 0369 bool const previousIsHtml = !m_content.isEmpty() && m_ui.webView->page()->history()->currentItemIndex() == 1; 0370 bool const atStart = m_ui.webView->page()->history()->currentItemIndex() <= 1; 0371 bool const currentIsHtml = m_ui.webView->page()->url() == QUrl( "about:blank" ); 0372 0373 m_ui.goBackButton->setVisible( hasHistory && !currentIsHtml && ( previousIsHtml || !atStart ) ); 0374 #endif 0375 } 0376 0377 void PopupItem::goBack() 0378 { 0379 #ifndef MARBLE_NO_WEBKITWIDGETS 0380 if ( m_ui.webView->page()->history()->currentItemIndex() == 1 && !m_content.isEmpty() ) { 0381 m_ui.webView->page()->setHtml( m_content, m_baseUrl ); 0382 } else { 0383 m_ui.webView->back(); 0384 } 0385 updateBackButton(); 0386 #endif 0387 } 0388 0389 void PopupItem::openUrl(const QUrl &url) 0390 { 0391 QDesktopServices::openUrl(url); 0392 } 0393 0394 QPixmap PopupItem::pixmap( const QString &imageId ) const 0395 { 0396 QPixmap result; 0397 if ( !QPixmapCache::find( imageId, &result ) ) { 0398 QImage bottom = QImage(QLatin1String(":/") + imageId + QLatin1String("_shadow.png")); 0399 QImage top = QImage(QLatin1String(":/") + imageId + QLatin1String(".png")); 0400 colorize( top, m_backColor ); 0401 QPainter painter( &bottom ); 0402 painter.drawImage( QPoint(0,0), top ); 0403 0404 result = QPixmap::fromImage( bottom ); 0405 QPixmapCache::insert( imageId, result ); 0406 } 0407 0408 return result; 0409 } 0410 0411 } 0412 0413 #include "moc_PopupItem.cpp"