Marble

PopupItem.cpp
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 //
3 // SPDX-FileCopyrightText: 2012 Torsten Rahn <[email protected]>
4 // SPDX-FileCopyrightText: 2013 Mohammed Nafees <nafees[email protected]>
5 // SPDX-FileCopyrightText: 2012 Dennis Nienhüser <[email protected]>
6 // SPDX-FileCopyrightText: 2012 Illya Kovalevskyy <[email protected]>
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 
32 namespace Marble
33 {
34 
35 PopupItem::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 
82 PopupItem::~PopupItem()
83 {
84  delete m_widget;
85 }
86 
88 {
89  return m_ui.printButton->isVisible();
90 }
91 
93 {
94  m_ui.printButton->setVisible( display );
95 }
96 
97 void 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 
111 void 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 
122 void 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 
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 
148 void 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 
159 void 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 
233 bool 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 
250  if ( e->type() == QEvent::MouseButtonDblClick
251  || e->type() == QEvent::MouseMove
252  || e->type() == QEvent::MouseButtonPress
253  || e->type() == QEvent::MouseButtonRelease )
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 
298 QWidget* 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 
336 void 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 
345 void PopupItem::requestUpdate()
346 {
347  update();
348  emit repaintNeeded();
349 }
350 
351 void 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 
365 void 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 
377 void 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 
389 void PopupItem::openUrl(const QUrl &url)
390 {
392 }
393 
394 QPixmap 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"
void setBrush(QPalette::ColorRole role, const QBrush &brush)
QEvent::Type type() const const
int width() const const
void setCursor(const QCursor &)
void setColor(QPalette::ColorGroup group, QPalette::ColorRole role, const QColor &color)
void remove(const QString &key)
Binds a QML item to a specific geodetic location in screen coordinates.
int depth() const const
void setUrl(const QUrl &url)
Set URL for web window.
Definition: PopupItem.cpp:97
void setTextColor(const QColor &color)
Sets text color of the header.
Definition: PopupItem.cpp:122
QVector::const_iterator constEnd() const const
QWidget * childAt(int x, int y) const const
bool contains(const QRectF &rectangle) const const
QPixmap fromImage(const QImage &image, Qt::ImageConversionFlags flags)
int height() const const
AlignRight
void setPrintButtonVisible(bool display)
Sets visibility of the print button.
Definition: PopupItem.cpp:92
A widget class that displays a view of the earth.
Definition: MarbleWidget.h:97
virtual bool event(QEvent *e)
int red() const const
int width() const const
void drawPixmap(const QRectF &target, const QPixmap &pixmap, const QRectF &source)
bool sendEvent(QObject *receiver, QEvent *event)
bool isPrintButtonVisible() const
Print button visibility indicator.
Definition: PopupItem.cpp:87
int green() const const
int height() const const
void setBackgroundColor(const QColor &color)
Sets background color of the bubble.
Definition: PopupItem.cpp:134
WA_DontShowOnScreen
int blue() const const
QVector::const_iterator constBegin() const const
int width() const const
void drawImage(const QRectF &target, const QImage &image, const QRectF &source, Qt::ImageConversionFlags flags)
void setRect(int x, int y, int width, int height)
QPixmap * find(const QString &key)
uchar * bits()
This file contains the headers for MarbleWidget.
int height() const const
void setContent(const QString &html, const QUrl &baseUrl=QUrl())
Set content of the popup.
Definition: PopupItem.cpp:111
bool openUrl(const QUrl &url)
bool insert(const QString &key, const QPixmap &pixmap)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
bool isValid() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Mon Nov 29 2021 23:11:04 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.