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 "MarbleWebView.h"
16#include <QWebEngineHistory>
17#include <QWebEngineSettings>
18#include <QWebEngineView>
19#endif
20
21#include <QApplication>
22#include <QDebug>
23#include <QDesktopServices>
24#include <QMouseEvent>
25#include <QPainter>
26#include <QPixmapCache>
27#include <QPointer>
28#include <QPrintDialog>
29#include <QPrinter>
30#include <qdrawutil.h>
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, &QAbstractButton::clicked, this, &PopupItem::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, &QAbstractButton::clicked, this, &PopupItem::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(QStringLiteral("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(QStringLiteral("marble/webpopup/webpopup2"));
139 QPixmapCache::remove(QStringLiteral("marble/webpopup/arrow2_topleft"));
140 QPixmapCache::remove(QStringLiteral("marble/webpopup/arrow2_bottomleft"));
141 QPixmapCache::remove(QStringLiteral("marble/webpopup/arrow2_topright"));
142 QPixmapCache::remove(QStringLiteral("marble/webpopup/arrow2_bottomright"));
143
144 requestUpdate();
145 }
146}
147
148void PopupItem::colorize(QImage &img, const QColor &col)
149{
150 if (img.depth() <= 8)
151 return;
152 int pixels = img.width() * img.height();
153 auto data = (unsigned int *)img.bits();
154 for (int i = 0; i < pixels; ++i) {
155 int val = qGray(data[i]);
156 data[i] = qRgba(col.red() * val / 255, col.green() * val / 255, col.blue() * val / 255, qAlpha(data[i]));
157 }
158}
159
160void PopupItem::paint(QPainter *painter)
161{
162 QRect popupRect;
163 QPixmap image = pixmap(QStringLiteral("marble/webpopup/arrow2_vertical_topright"));
164
165 if (alignment() & Qt::AlignRight) {
166 popupRect.setRect(image.width() - 13, -10, size().width() - (image.width() - 3), size().height());
167 qDrawBorderPixmap(painter, popupRect, QMargins(20, 20, 20, 20), pixmap(QStringLiteral("marble/webpopup/webpopup2")));
168 if (alignment() & Qt::AlignTop) {
169 image = pixmap(QStringLiteral("marble/webpopup/arrow2_bottomleft"));
170 painter->drawPixmap(0, size().height() - image.height(), image);
171 } else if (alignment() & Qt::AlignBottom) {
172 image = pixmap(QStringLiteral("marble/webpopup/arrow2_topleft"));
173 painter->drawPixmap(0, 0, image);
174 } else { // for no horizontal align value and Qt::AlignVCenter
175 image = pixmap(QStringLiteral("marble/webpopup/arrow2_topleft"));
176 painter->drawPixmap(0, size().height() / 2, image);
177 }
178 m_widget->render(painter, QPoint(image.width() - 3, 0));
179 } else if (alignment() & Qt::AlignLeft) {
180 popupRect.setRect(-10, -10, size().width() - (image.width() - 3), size().height());
181 qDrawBorderPixmap(painter, popupRect, QMargins(20, 20, 20, 20), pixmap(QStringLiteral("marble/webpopup/webpopup2")));
182 if (alignment() & Qt::AlignTop) {
183 image = pixmap(QStringLiteral("marble/webpopup/arrow2_bottomright"));
184 painter->drawPixmap(size().width() - image.width(), size().height() - image.height(), image);
185 } else if (alignment() & Qt::AlignBottom) {
186 image = pixmap(QStringLiteral("marble/webpopup/arrow2_topright"));
187 painter->drawPixmap(size().width() - image.width(), 0, image);
188 } else { // for no horizontal align value and Qt::AlignVCenter
189 image = pixmap(QStringLiteral("marble/webpopup/arrow2_topright"));
190 painter->drawPixmap(size().width() - image.width(), size().height() / 2 - image.height() / 2 + 23, image);
191 }
192 m_widget->render(painter, QPoint(5, 0), QRegion());
193 } else if (alignment() & Qt::AlignHCenter) {
194 if (alignment() & Qt::AlignTop) {
195 image = pixmap(QStringLiteral("marble/webpopup/arrow2_vertical_bottomright"));
196 popupRect.setRect(-10, -10, size().width(), size().height() - image.height() + 3);
197 qDrawBorderPixmap(painter, popupRect, QMargins(20, 20, 20, 20), pixmap(QStringLiteral("marble/webpopup/webpopup2")));
198 painter->drawPixmap(size().width() / 2 - image.width(), size().height() - image.height(), image);
199 m_widget->render(painter, QPoint(0, 0), QRegion());
200 } else if (alignment() & Qt::AlignBottom) {
201 image = pixmap(QStringLiteral("marble/webpopup/arrow2_vertical_topleft"));
202 popupRect.setRect(-10, image.height() - 13, size().width(), size().height() - image.height() + 3);
203 qDrawBorderPixmap(painter, popupRect, QMargins(20, 20, 20, 20), pixmap(QStringLiteral("marble/webpopup/webpopup2")));
204 painter->drawPixmap(size().width() / 2, 0, image);
205 m_widget->render(painter, QPoint(5, image.height() - 7), QRegion());
206 } else { // for no horizontal align value and Qt::AlignVCenter
207 popupRect.setRect(-10, -10, size().width(), size().height());
208 qDrawBorderPixmap(painter, popupRect, QMargins(20, 20, 20, 20), pixmap(QStringLiteral("marble/webpopup/webpopup2")));
209 m_widget->render(painter, QPoint(0, 0), QRegion());
210 }
211 }
212 m_widget->setFixedSize(popupRect.width() - 20, popupRect.height() - 20);
213}
214
215bool PopupItem::eventFilter(QObject *object, QEvent *e)
216{
217 auto widget = dynamic_cast<MarbleWidget *>(object);
218 if (!widget) {
219 return BillboardGraphicsItem::eventFilter(object, e);
220 }
221
222 if (e->type() == QEvent::ContextMenu) {
223 QApplication::sendEvent(m_ui.webView, e);
224 return BillboardGraphicsItem::eventFilter(object, e);
225 }
226
227 if (e->type() == QEvent::KeyPress) {
228 QApplication::sendEvent(m_ui.webView, e);
229 return BillboardGraphicsItem::eventFilter(object, e);
230 }
231
233 || e->type() == QEvent::MouseButtonRelease) {
234 // Mouse events are forwarded to the underlying widget
235 auto event = static_cast<QMouseEvent *>(e);
236 QPoint shiftedPos = event->pos();
237 QWidget *child = transform(shiftedPos);
238 bool const forcedMouseRelease = m_needMouseRelease && e->type() == QEvent::MouseButtonRelease;
239 if (child || forcedMouseRelease) {
240 if (!m_needMouseRelease && e->type() == QEvent::MouseButtonPress) {
241 m_needMouseRelease = true;
242 } else if (forcedMouseRelease) {
243 m_needMouseRelease = false;
244 }
245 if (!child) {
246 child = m_ui.webView;
247 }
248 QMouseEvent shiftedEvent = QMouseEvent(e->type(), shiftedPos, event->globalPos(), event->button(), event->buttons(), event->modifiers());
249 if (QApplication::sendEvent(child, &shiftedEvent)) {
250 widget->setCursor(child->cursor());
251 Q_EMIT repaintNeeded();
252 return true;
253 }
254 }
255 } else if (e->type() == QEvent::Wheel) {
256 // Wheel events are forwarded to the underlying widget
257 auto event = static_cast<QWheelEvent *>(e);
258 QPoint shiftedPos = event->position().toPoint();
259 QWidget *child = transform(shiftedPos);
260 if (child) {
261 QWheelEvent shiftedEvent = QWheelEvent(QPointF(shiftedPos),
262 event->globalPosition(),
263 QPoint(),
264 event->angleDelta(),
265 event->buttons(),
266 event->modifiers(),
268 false);
269 if (QApplication::sendEvent(child, &shiftedEvent)) {
270 widget->setCursor(child->cursor());
271 Q_EMIT repaintNeeded();
272 return true;
273 }
274 }
275 }
276
277 return BillboardGraphicsItem::eventFilter(object, e);
278}
279
280QWidget *PopupItem::transform(QPoint &point) const
281{
282 /*
283 * Fixes for mouse events to trigger when the web popup
284 * is shifted in accordance with the horizontal alignment
285 */
286 if (alignment() & Qt::AlignRight)
287 point -= QPoint(117, 0);
288 else if (alignment() & Qt::AlignLeft)
289 point -= QPoint(5, 0);
290 else if (alignment() & Qt::AlignHCenter) {
291 if (alignment() & Qt::AlignTop) {
292 point -= QPoint(0, 0);
293 } else if (alignment() & Qt::AlignBottom) {
294 point -= QPoint(5, 57);
295 } else {
296 point -= QPoint(0, 0);
297 }
298 }
299
300 const QList<QPointF> widgetPositions = positions();
301 QList<QPointF>::const_iterator it = widgetPositions.constBegin();
302 for (; it != widgetPositions.constEnd(); ++it) {
303 if (QRectF(*it, size()).contains(point)) {
304 point -= it->toPoint();
305 QWidget *child = m_widget->childAt(point);
306 if (child) {
307 point -= child->pos();
308 }
309 return child;
310 }
311 }
312 return nullptr;
313}
314
315void PopupItem::clearHistory()
316{
317 m_content.clear();
318 m_ui.webView->setUrl(QUrl(QStringLiteral("about:blank")));
319#ifndef MARBLE_NO_WEBKITWIDGETS
320 m_ui.webView->history()->clear();
321#endif
322}
323
324void PopupItem::requestUpdate()
325{
326 update();
327 Q_EMIT repaintNeeded();
328}
329
330void PopupItem::printContent() const
331{
332#ifndef QT_NO_PRINTER
333#ifndef MARBLE_NO_WEBKITWIDGETS
334 QPrinter printer;
335 QPointer<QPrintDialog> dialog = new QPrintDialog(&printer);
336 if (dialog->exec() == QPrintDialog::Accepted) {
337 m_ui.webView->print(&printer);
338 }
339 delete dialog;
340#endif
341#endif
342}
343
344void PopupItem::updateBackButton()
345{
346#ifndef MARBLE_NO_WEBKITWIDGETS
347 bool const hasHistory = m_ui.webView->page()->history()->count() > 1;
348 bool const previousIsHtml = !m_content.isEmpty() && m_ui.webView->page()->history()->currentItemIndex() == 1;
349 bool const atStart = m_ui.webView->page()->history()->currentItemIndex() <= 1;
350 bool const currentIsHtml = m_ui.webView->page()->url() == QUrl(QStringLiteral("about:blank"));
351
352 m_ui.goBackButton->setVisible(hasHistory && !currentIsHtml && (previousIsHtml || !atStart));
353#endif
354}
355
356void PopupItem::goBack()
357{
358#ifndef MARBLE_NO_WEBKITWIDGETS
359 if (m_ui.webView->page()->history()->currentItemIndex() == 1 && !m_content.isEmpty()) {
360 m_ui.webView->page()->setHtml(m_content, m_baseUrl);
361 } else {
362 m_ui.webView->back();
363 }
364 updateBackButton();
365#endif
366}
367
368void PopupItem::openUrl(const QUrl &url)
369{
371}
372
373QPixmap PopupItem::pixmap(const QString &imageId) const
374{
375 QPixmap result;
376 if (!QPixmapCache::find(imageId, &result)) {
377 QImage bottom = QImage(QLatin1StringView(":/") + imageId + QLatin1StringView("_shadow.png"));
378 QImage top = QImage(QLatin1StringView(":/") + imageId + QLatin1StringView(".png"));
379 colorize(top, m_backColor);
380 QPainter painter(&bottom);
381 painter.drawImage(QPoint(0, 0), top);
382
383 result = QPixmap::fromImage(bottom);
384 QPixmapCache::insert(imageId, result);
385 }
386
387 return result;
388}
389
390}
391
392#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.
void clicked(bool checked)
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
NoScrollPhase
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 Sat Dec 21 2024 17:04:14 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.