Marble

PopupItem.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later
2//
3// SPDX-FileCopyrightText: 2012 Torsten Rahn <tackat@kde.org>
4// SPDX-FileCopyrightText: 2013 Mohammed Nafees <nafees.technocool@gmail.com>
5// SPDX-FileCopyrightText: 2012 Dennis Nienhüser <nienhueser@kde.org>
6// SPDX-FileCopyrightText: 2012 Illya Kovalevskyy <illya.kovalevskyy@gmail.com>
7//
8
9#include "PopupItem.h"
10#include "MarbleWidget.h"
11
12#ifdef MARBLE_NO_WEBKITWIDGETS
13#include "NullMarbleWebView.h"
14#else
15#include <QWebEngineView>
16#include <QWebEngineHistory>
17#include <QWebEngineSettings>
18#include "MarbleWebView.h"
19#endif
20
21#include <QDebug>
22#include <QPointer>
23#include <QPrinter>
24#include <QPrintDialog>
25#include <QMouseEvent>
26#include <QApplication>
27#include <QDesktopServices>
28#include <QPixmapCache>
29#include <qdrawutil.h>
30#include <QPainter>
31
32namespace Marble
33{
34
35PopupItem::PopupItem( QObject* parent ) :
36 QObject( parent ),
37 BillboardGraphicsItem(),
38 m_widget( new QWidget() ),
39 m_textColor( QColor(Qt::black) ),
40 m_backColor( QColor(Qt::white) ),
41 m_needMouseRelease(false)
42{
43// setCacheMode( ItemCoordinateCache );
44 setVisible( false );
45 setSize( QSizeF( 300.0, 320.0 ) );
46
47 m_ui.setupUi( m_widget );
48 m_ui.goBackButton->setVisible( false );
49 connect( m_ui.goBackButton, SIGNAL(clicked()), this, SLOT(goBack()) );
50
51#ifdef QT_NO_PRINTER
52 m_ui.printButton->setVisible( false );
53#else
54 m_ui.printButton->setVisible( true );
55 connect( m_ui.printButton, SIGNAL(clicked()), this, SLOT(printContent()) );
56#endif
57
58 m_widget->setVisible(true);
59 m_widget->setAttribute(Qt::WA_DontShowOnScreen);
60 m_widget->setAttribute( Qt::WA_NoSystemBackground, true );
61 m_widget->setAttribute(Qt::WA_QuitOnClose, false);
62 QPalette palette = m_ui.webView->palette();
64#ifndef MARBLE_NO_WEBKITWIDGETS
65 m_ui.webView->setPalette(palette);
66 m_ui.webView->page()->settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessFileUrls, true);
67 m_ui.webView->page()->settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, true);
68#endif
69 m_ui.webView->setAttribute(Qt::WA_OpaquePaintEvent, false);
70 m_ui.webView->setUrl( QUrl( "about:blank" ) );
71
72 connect( m_ui.hideButton, SIGNAL(clicked()), this, SIGNAL(hide()) );
73
74#ifndef MARBLE_NO_WEBKITWIDGETS
75 connect( m_ui.webView->page(), SIGNAL(titleChanged(QString)), m_ui.titleText, SLOT(setText(QString)) );
76 connect( m_ui.webView->page(), SIGNAL(urlChanged(QUrl)), this, SLOT(updateBackButton()) );
77 // Update the popupitem on changes while loading the webpage
78 connect(m_ui.webView, SIGNAL(loadFinished(bool)), this, SLOT(requestUpdate()));
79#endif
80}
81
82PopupItem::~PopupItem()
83{
84 delete m_widget;
85}
86
87bool PopupItem::isPrintButtonVisible() const
88{
89 return m_ui.printButton->isVisible();
90}
91
92void PopupItem::setPrintButtonVisible( bool display )
93{
94 m_ui.printButton->setVisible( display );
95}
96
97void PopupItem::setUrl( const QUrl &url )
98{
99 m_ui.webView->setUrl( url );
100
101 QPalette palette = m_ui.webView->palette();
103#ifndef MARBLE_NO_WEBKITWIDGETS
104 m_ui.webView->setPalette(palette);
105#endif
106 m_ui.webView->setAttribute(Qt::WA_OpaquePaintEvent, false);
107
108 requestUpdate();
109}
110
111void PopupItem::setContent( const QString &html, const QUrl &baseUrl )
112{
113 m_content = html;
114 m_baseUrl = baseUrl;
115#ifndef MARBLE_NO_WEBKITWIDGETS
116 m_ui.webView->setHtml( html, baseUrl );
117#endif
118
119 requestUpdate();
120}
121
122void PopupItem::setTextColor(const QColor &color)
123{
124 if(color.isValid() && m_ui.titleText != nullptr) {
125 m_textColor = color;
126 QPalette palette(m_ui.titleText->palette());
127 palette.setColor(QPalette::WindowText, m_textColor);
128 m_ui.titleText->setPalette(palette);
129
130 requestUpdate();
131 }
132}
133
134void PopupItem::setBackgroundColor(const QColor &color)
135{
136 if(color.isValid()) {
137 m_backColor = color;
138 QPixmapCache::remove( "marble/webpopup/webpopup2" );
139 QPixmapCache::remove( "marble/webpopup/arrow2_topleft" );
140 QPixmapCache::remove( "marble/webpopup/arrow2_bottomleft" );
141 QPixmapCache::remove( "marble/webpopup/arrow2_topright" );
142 QPixmapCache::remove( "marble/webpopup/arrow2_bottomright" );
143
144 requestUpdate();
145 }
146}
147
148void PopupItem::colorize( QImage &img, const QColor &col )
149{
150 if (img.depth() <= 8) return;
151 int pixels = img.width()*img.height();
152 unsigned int *data = (unsigned int *) img.bits();
153 for (int i=0; i < pixels; ++i) {
154 int val = qGray(data[i]);
155 data[i] = qRgba(col.red()*val/255,col.green()*val/255, col.blue()*val/255, qAlpha(data[i]));
156 }
157}
158
159void PopupItem::paint( QPainter *painter )
160{
161 QRect popupRect;
162 QPixmap image = pixmap("marble/webpopup/arrow2_vertical_topright");
163
164 if ( alignment() & Qt::AlignRight ) {
165 popupRect.setRect( image.width() - 13, -10,
166 size().width() - ( image.width() - 3 ),
167 size().height() );
168 qDrawBorderPixmap(painter, popupRect, QMargins( 20, 20, 20, 20 ),
169 pixmap("marble/webpopup/webpopup2"));
170 if ( alignment() & Qt::AlignTop ) {
171 image = pixmap("marble/webpopup/arrow2_bottomleft");
172 painter->drawPixmap( 0, size().height() - image.height(), image );
173 } else if ( alignment() & Qt::AlignBottom ) {
174 image = pixmap("marble/webpopup/arrow2_topleft");
175 painter->drawPixmap( 0, 0, image );
176 } else { // for no horizontal align value and Qt::AlignVCenter
177 image = pixmap("marble/webpopup/arrow2_topleft");
178 painter->drawPixmap( 0, size().height() / 2, image );
179 }
180 m_widget->render( painter, QPoint( image.width() - 3, 0 ) );
181 } else if ( alignment() & Qt::AlignLeft ) {
182 popupRect.setRect( -10, -10,
183 size().width() - ( image.width() - 3 ),
184 size().height() );
185 qDrawBorderPixmap(painter, popupRect, QMargins( 20, 20, 20, 20 ),
186 pixmap("marble/webpopup/webpopup2"));
187 if ( alignment() & Qt::AlignTop ) {
188 image = pixmap("marble/webpopup/arrow2_bottomright");
189 painter->drawPixmap( size().width() - image.width(),
190 size().height() - image.height(), image );
191 } else if ( alignment() & Qt::AlignBottom ) {
192 image = pixmap("marble/webpopup/arrow2_topright");
193 painter->drawPixmap( size().width() - image.width(),
194 0, image );
195 } else { // for no horizontal align value and Qt::AlignVCenter
196 image = pixmap("marble/webpopup/arrow2_topright");
197 painter->drawPixmap( size().width() - image.width(),
198 size().height() / 2 - image.height() / 2 + 23, image );
199 }
200 m_widget->render( painter, QPoint( 5, 0 ), QRegion() );
201 } else if ( alignment() & Qt::AlignHCenter )
202 {
203 if ( alignment() & Qt::AlignTop )
204 {
205 image = pixmap("marble/webpopup/arrow2_vertical_bottomright");
206 popupRect.setRect( -10, -10, size().width(),
207 size().height() - image.height() + 3 );
208 qDrawBorderPixmap(painter, popupRect, QMargins( 20, 20, 20, 20 ),
209 pixmap("marble/webpopup/webpopup2"));
210 painter->drawPixmap( size().width() / 2 - image.width(),
211 size().height() - image.height(), image );
212 m_widget->render( painter, QPoint( 0, 0 ), QRegion() );
213 } else if ( alignment() & Qt::AlignBottom ) {
214 image = pixmap("marble/webpopup/arrow2_vertical_topleft");
215 popupRect.setRect( -10, image.height() - 13, size().width(),
216 size().height() - image.height() + 3 );
217 qDrawBorderPixmap(painter, popupRect, QMargins( 20, 20, 20, 20 ),
218 pixmap("marble/webpopup/webpopup2"));
219 painter->drawPixmap( size().width() / 2, 0, image );
220 m_widget->render( painter, QPoint( 5, image.height() - 7 ), QRegion() );
221 } else { // for no horizontal align value and Qt::AlignVCenter
222 popupRect.setRect( -10, -10, size().width(),
223 size().height());
224 qDrawBorderPixmap(painter, popupRect, QMargins( 20, 20, 20, 20 ),
225 pixmap("marble/webpopup/webpopup2"));
226 m_widget->render( painter, QPoint( 0, 0 ), QRegion() );
227 }
228 }
229 m_widget->setFixedSize( popupRect.width() - 20,
230 popupRect.height() - 20 );
231}
232
233bool PopupItem::eventFilter( QObject *object, QEvent *e )
234{
235 MarbleWidget *widget = dynamic_cast<MarbleWidget*> ( object );
236 if ( !widget ) {
237 return BillboardGraphicsItem::eventFilter( object, e );
238 }
239
240 if ( e->type() == QEvent::ContextMenu) {
241 QApplication::sendEvent( m_ui.webView, e );
242 return BillboardGraphicsItem::eventFilter( object, e );
243 }
244
245 if ( e->type() == QEvent::KeyPress ) {
246 QApplication::sendEvent( m_ui.webView, e );
247 return BillboardGraphicsItem::eventFilter( object, e );
248 }
249
251 || e->type() == QEvent::MouseMove
254 {
255 // Mouse events are forwarded to the underlying widget
256 QMouseEvent *event = static_cast<QMouseEvent*> ( e );
257 QPoint shiftedPos = event->pos();
258 QWidget* child = transform( shiftedPos );
259 bool const forcedMouseRelease = m_needMouseRelease && e->type() == QEvent::MouseButtonRelease;
260 if ( child || forcedMouseRelease ) {
261 if ( !m_needMouseRelease && e->type() == QEvent::MouseButtonPress ) {
262 m_needMouseRelease = true;
263 } else if ( forcedMouseRelease ) {
264 m_needMouseRelease = false;
265 }
266 if ( !child ) {
267 child = m_ui.webView;
268 }
269 QMouseEvent shiftedEvent = QMouseEvent( e->type(), shiftedPos,
270 event->globalPos(), event->button(), event->buttons(),
271 event->modifiers() );
272 if ( QApplication::sendEvent( child, &shiftedEvent ) ) {
273 widget->setCursor( child->cursor() );
274 emit repaintNeeded();
275 return true;
276 }
277 }
278 } else if ( e->type() == QEvent::Wheel ) {
279 // Wheel events are forwarded to the underlying widget
280 QWheelEvent *event = static_cast<QWheelEvent*> ( e );
281 QPoint shiftedPos = event->pos();
282 QWidget* child = transform( shiftedPos );
283 if ( child ) {
284 QWheelEvent shiftedEvent = QWheelEvent( shiftedPos,
285 event->globalPos(), event->delta(), event->buttons(),
286 event->modifiers() );
287 if ( QApplication::sendEvent( child, &shiftedEvent ) ) {
288 widget->setCursor( child->cursor() );
289 emit repaintNeeded();
290 return true;
291 }
292 }
293 }
294
295 return BillboardGraphicsItem::eventFilter( object, e );
296}
297
298QWidget* PopupItem::transform( QPoint &point ) const
299{
300 /*
301 * Fixes for mouse events to trigger when the web popup
302 * is shifted in accordance with the horizontal alignment
303 */
304 if ( alignment() & Qt::AlignRight )
305 point -= QPoint( 117, 0 );
306 else if ( alignment() & Qt::AlignLeft )
307 point -= QPoint( 5, 0 );
308 else if ( alignment() & Qt::AlignHCenter )
309 {
310 if ( alignment() & Qt::AlignTop )
311 {
312 point -= QPoint( 0, 0 );
313 } else if ( alignment() & Qt::AlignBottom )
314 {
315 point-= QPoint( 5, 57 );
316 } else {
317 point -= QPoint( 0, 0 );
318 }
319 }
320
321 const QVector<QPointF> widgetPositions = positions();
322 QVector<QPointF>::const_iterator it = widgetPositions.constBegin();
323 for( ; it != widgetPositions.constEnd(); ++it ) {
324 if ( QRectF( *it, size() ).contains( point ) ) {
325 point -= it->toPoint();
326 QWidget* child = m_widget->childAt( point );
327 if ( child ) {
328 point -= child->pos();
329 }
330 return child;
331 }
332 }
333 return nullptr;
334}
335
336void PopupItem::clearHistory()
337{
338 m_content.clear();
339 m_ui.webView->setUrl( QUrl( "about:blank" ) );
340#ifndef MARBLE_NO_WEBKITWIDGETS
341 m_ui.webView->history()->clear();
342#endif
343}
344
345void PopupItem::requestUpdate()
346{
347 update();
348 emit repaintNeeded();
349}
350
351void PopupItem::printContent() const
352{
353#ifndef QT_NO_PRINTER
354#ifndef MARBLE_NO_WEBKITWIDGETS
355 QPrinter printer;
356 QPointer<QPrintDialog> dialog = new QPrintDialog(&printer);
357 if (dialog->exec() == QPrintDialog::Accepted) {
358 m_ui.webView->page()->print(&printer, [=](bool){});
359 }
360 delete dialog;
361#endif
362#endif
363}
364
365void PopupItem::updateBackButton()
366{
367#ifndef MARBLE_NO_WEBKITWIDGETS
368 bool const hasHistory = m_ui.webView->page()->history()->count() > 1;
369 bool const previousIsHtml = !m_content.isEmpty() && m_ui.webView->page()->history()->currentItemIndex() == 1;
370 bool const atStart = m_ui.webView->page()->history()->currentItemIndex() <= 1;
371 bool const currentIsHtml = m_ui.webView->page()->url() == QUrl( "about:blank" );
372
373 m_ui.goBackButton->setVisible( hasHistory && !currentIsHtml && ( previousIsHtml || !atStart ) );
374#endif
375}
376
377void PopupItem::goBack()
378{
379#ifndef MARBLE_NO_WEBKITWIDGETS
380 if ( m_ui.webView->page()->history()->currentItemIndex() == 1 && !m_content.isEmpty() ) {
381 m_ui.webView->page()->setHtml( m_content, m_baseUrl );
382 } else {
383 m_ui.webView->back();
384 }
385 updateBackButton();
386#endif
387}
388
389void PopupItem::openUrl(const QUrl &url)
390{
392}
393
394QPixmap PopupItem::pixmap( const QString &imageId ) const
395{
396 QPixmap result;
397 if ( !QPixmapCache::find( imageId, &result ) ) {
398 QImage bottom = QImage(QLatin1String(":/") + imageId + QLatin1String("_shadow.png"));
399 QImage top = QImage(QLatin1String(":/") + imageId + QLatin1String(".png"));
400 colorize( top, m_backColor );
401 QPainter painter( &bottom );
402 painter.drawImage( QPoint(0,0), top );
403
404 result = QPixmap::fromImage( bottom );
405 QPixmapCache::insert( imageId, result );
406 }
407
408 return result;
409}
410
411}
412
413#include "moc_PopupItem.cpp"
This file contains the headers for MarbleWidget.
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
void update(Part *part, const QByteArray &data, qint64 dataSize)
KDOCTOOLS_EXPORT QString transform(const QString &file, const QString &stylesheet, const QList< const char * > &params=QList< const char * >())
Binds a QML item to a specific geodetic location in screen coordinates.
int blue() const const
int green() const const
bool isValid() const const
int red() const const
bool sendEvent(QObject *receiver, QEvent *event)
bool openUrl(const QUrl &url)
Type type() const const
uchar * bits()
int depth() const const
int height() const const
int width() const const
const_iterator constBegin() const const
const_iterator constEnd() const const
void drawImage(const QPoint &point, const QImage &image)
void drawPixmap(const QPoint &point, const QPixmap &pixmap)
void setBrush(ColorGroup group, ColorRole role, const QBrush &brush)
void setColor(ColorGroup group, ColorRole role, const QColor &color)
QPixmap fromImage(QImage &&image, Qt::ImageConversionFlags flags)
int height() const const
int width() const const
bool find(const Key &key, QPixmap *pixmap)
Key insert(const QPixmap &pixmap)
void remove(const Key &key)
int height() const const
void setRect(int x, int y, int width, int height)
int width() const const
AlignRight
WA_DontShowOnScreen
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QWidget * childAt(const QPoint &p) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:18:17 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.