diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index 6c0e25c37ad..38d4345bf0a 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -336,6 +336,8 @@ extend_qtc_plugin(QmlDesigner navigatorwidget.cpp navigatorwidget.h choosetexturepropertydialog.cpp choosetexturepropertydialog.h choosetexturepropertydialog.ui + previewtooltip.cpp previewtooltip.h + previewtooltip.ui ) extend_qtc_plugin(QmlDesigner diff --git a/src/plugins/qmldesigner/components/navigator/navigator.pri b/src/plugins/qmldesigner/components/navigator/navigator.pri index 7344f1bc5a0..2453463fe28 100644 --- a/src/plugins/qmldesigner/components/navigator/navigator.pri +++ b/src/plugins/qmldesigner/components/navigator/navigator.pri @@ -6,7 +6,8 @@ SOURCES += navigatorview.cpp \ nameitemdelegate.cpp \ iconcheckboxitemdelegate.cpp \ navigatortreeview.cpp \ - choosetexturepropertydialog.cpp + choosetexturepropertydialog.cpp \ + previewtooltip.cpp HEADERS += navigatorview.h \ navigatortreemodel.h \ @@ -15,8 +16,10 @@ HEADERS += navigatorview.h \ iconcheckboxitemdelegate.h \ navigatortreeview.h \ navigatormodelinterface.h \ - choosetexturepropertydialog.h + choosetexturepropertydialog.h \ + previewtooltip.h RESOURCES += navigator.qrc -FORMS += choosetexturepropertydialog.ui +FORMS += choosetexturepropertydialog.ui \ + previewtooltip.ui diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp index c93b3145e90..f5f420f0f7e 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp @@ -53,6 +53,7 @@ #include #include #include +#include #include @@ -200,6 +201,13 @@ QVariant NavigatorTreeModel::data(const QModelIndex &index, int role) const if (role == ItemIsVisibleRole) //independent of column return m_view->isNodeInvisible(modelNode) ? Qt::Unchecked : Qt::Checked; + auto hasImageToolTip = [modelNode]() -> bool { + if (modelNode.isValid() && modelNode.metaInfo().isValid()) + return modelNode.type() == "QtQuick.Image" || modelNode.type() == "QtQuick3D.Texture"; + else + return false; + }; + if (index.column() == 0) { if (role == Qt::DisplayRole) { return modelNode.displayName(); @@ -212,17 +220,81 @@ QVariant NavigatorTreeModel::data(const QModelIndex &index, int role) const } else if (role == Qt::ToolTipRole) { if (currentQmlObjectNode.hasError()) { QString errorString = currentQmlObjectNode.error(); - if (DesignerSettings::getValue(DesignerSettingsKey::STANDALONE_MODE).toBool() && - currentQmlObjectNode.isRootNode()) + if (DesignerSettings::getValue(DesignerSettingsKey::STANDALONE_MODE).toBool() + && currentQmlObjectNode.isRootNode()) { errorString.append(QString("\n%1").arg(tr("Changing the setting \"%1\" might solve the issue.").arg( tr("Use QML emulation layer that is built with the selected Qt")))); - + } return errorString; } - if (modelNode.metaInfo().isValid()) - return modelNode.type(); - else + + if (modelNode.metaInfo().isValid()) { + if (hasImageToolTip()) + return {}; // Images have special tooltip popup, so suppress regular one + else + return modelNode.type(); + } else { return msgUnknownItem(QString::fromUtf8(modelNode.type())); + } + } else if (role == ToolTipImageRole) { + if (currentQmlObjectNode.hasError()) // Error already shown on regular tooltip + return {}; + + if (hasImageToolTip()) { + VariantProperty prop = modelNode.variantProperty("source"); + QString imageSource = prop.value().toString(); + QFileInfo fi(imageSource); + if (fi.isRelative()) + imageSource = QmlDesignerPlugin::instance()->documentManager().currentFilePath().toFileInfo().dir().absoluteFilePath(imageSource); + fi = QFileInfo(imageSource); + QDateTime modified = fi.lastModified(); + + struct ImageData { + QDateTime time; + QImage image; + QString type; + QString id; + QString info; + }; + + static QHash toolTipImageMap; + + ImageData imageData; + bool reload = true; + if (toolTipImageMap.contains(imageSource)) { + imageData = toolTipImageMap[imageSource]; + if (modified == imageData.time) + reload = false; + } + + if (reload) { + QImage originalImage; + originalImage.load(imageSource); + if (!originalImage.isNull()) { + imageData.image = originalImage.scaled(150, 150, Qt::KeepAspectRatio); + double imgSize = double(fi.size()); + imageData.type = QStringLiteral("%1 (%2)").arg(QString::fromLatin1(modelNode.type())).arg(fi.suffix()); + imageData.id = modelNode.id(); + static QStringList units({tr("B"), tr("KB"), tr("MB"), tr("GB")}); + int unitIndex = 0; + while (imgSize > 1024. && unitIndex < units.size() - 1) { + ++unitIndex; + imgSize /= 1024.; + } + imageData.info = QStringLiteral("%1 x %2 (%3%4)").arg(originalImage.width()).arg(originalImage.height()) + .arg(QString::number(imgSize, 'g', 3)).arg(units[unitIndex]); + toolTipImageMap.insert(imageSource, imageData); + } + } + if (!imageData.image.isNull()) { + QVariantMap map; + map.insert("type", imageData.type); + map.insert("image", QVariant::fromValue(imageData.image)); + map.insert("id", imageData.id); + map.insert("info", imageData.info); + return map; + } + } } else if (role == ModelNodeRole) { return QVariant::fromValue(modelNode); } diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreeview.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreeview.cpp index 6b617eaaf57..33cf991e36d 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreeview.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreeview.cpp @@ -30,6 +30,7 @@ #include "navigatorview.h" #include "navigatortreemodel.h" #include "qproxystyle.h" +#include "previewtooltip.h" #include @@ -42,7 +43,9 @@ #include #include #include - +#include +#include +#include namespace QmlDesigner { @@ -174,5 +177,36 @@ void NavigatorTreeView::drawSelectionBackground(QPainter *painter, const QStyleO painter->restore(); } +bool NavigatorTreeView::viewportEvent(QEvent *event) +{ + if (event->type() == QEvent::ToolTip) { + auto navModel = qobject_cast(model()); + if (navModel) { + QHelpEvent *helpEvent = static_cast(event); + QModelIndex index = indexAt(helpEvent->pos()); + QVariantMap imgMap = navModel->data(index, ToolTipImageRole).toMap(); + + if (!imgMap.isEmpty()) { + if (!m_previewToolTip) + m_previewToolTip = new PreviewToolTip(QApplication::activeWindow()); + m_previewToolTip->setId(imgMap["id"].toString()); + m_previewToolTip->setType(imgMap["type"].toString()); + m_previewToolTip->setInfo(imgMap["info"].toString()); + m_previewToolTip->setImage(imgMap["image"].value()); + m_previewToolTip->move(helpEvent->pos()); + if (!m_previewToolTip->isVisible()) + m_previewToolTip->show(); + } else if (m_previewToolTip) { + m_previewToolTip->hide(); + } + } + } else if (event->type() == QEvent::Leave) { + if (m_previewToolTip) + m_previewToolTip->hide(); + } + + return QTreeView::viewportEvent(event); +} + } diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreeview.h b/src/plugins/qmldesigner/components/navigator/navigatortreeview.h index 1001977b8f8..2d2a11f899c 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreeview.h +++ b/src/plugins/qmldesigner/components/navigator/navigatortreeview.h @@ -29,6 +29,8 @@ namespace QmlDesigner { +class PreviewToolTip; + class NavigatorTreeView : public QTreeView { Q_OBJECT @@ -36,5 +38,9 @@ class NavigatorTreeView : public QTreeView public: NavigatorTreeView(QWidget *parent = nullptr); static void drawSelectionBackground(QPainter *painter, const QStyleOption &option); + bool viewportEvent(QEvent *event) override; + +private: + PreviewToolTip *m_previewToolTip = nullptr; }; } diff --git a/src/plugins/qmldesigner/components/navigator/navigatorview.h b/src/plugins/qmldesigner/components/navigator/navigatorview.h index 72e47935748..c35900059fd 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatorview.h +++ b/src/plugins/qmldesigner/components/navigator/navigatorview.h @@ -48,7 +48,8 @@ class NavigatorTreeModel; enum NavigatorRoles { ItemIsVisibleRole = Qt::UserRole, RowIsPropertyRole = Qt::UserRole + 1, - ModelNodeRole = Qt::UserRole + 2 + ModelNodeRole = Qt::UserRole + 2, + ToolTipImageRole = Qt::UserRole + 3 }; class NavigatorView : public AbstractView diff --git a/src/plugins/qmldesigner/components/navigator/previewtooltip.cpp b/src/plugins/qmldesigner/components/navigator/previewtooltip.cpp new file mode 100644 index 00000000000..fffd9b8992c --- /dev/null +++ b/src/plugins/qmldesigner/components/navigator/previewtooltip.cpp @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "previewtooltip.h" +#include "ui_previewtooltip.h" + +#include + +#include + +namespace QmlDesigner { + +PreviewToolTip::PreviewToolTip(QWidget *parent) + : QWidget(parent) + , m_ui(new Ui::PreviewToolTip) +{ + setAttribute(Qt::WA_TransparentForMouseEvents); + setWindowFlags(Qt::Widget); + m_ui->setupUi(this); + setStyleSheet(QString("QWidget { background-color: %1 }").arg(Utils::creatorTheme()->color(Utils::Theme::BackgroundColorNormal).name())); +} + +PreviewToolTip::~PreviewToolTip() +{ + delete m_ui; +} + +void PreviewToolTip::setId(const QString &id) +{ + m_ui->idLabel->setText(id); +} + +void PreviewToolTip::setType(const QString &type) +{ + m_ui->typeLabel->setText(type); +} + +void PreviewToolTip::setInfo(const QString &info) +{ + m_ui->infoLabel->setText(info); +} + +void PreviewToolTip::setImage(const QImage &image) +{ + m_ui->imageLabel->setPixmap(QPixmap::fromImage(image)); +} + +} diff --git a/src/plugins/qmldesigner/components/navigator/previewtooltip.h b/src/plugins/qmldesigner/components/navigator/previewtooltip.h new file mode 100644 index 00000000000..f9ee98d2c96 --- /dev/null +++ b/src/plugins/qmldesigner/components/navigator/previewtooltip.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include +#include + +namespace QmlDesigner { +namespace Ui { +class PreviewToolTip; +} + +class PreviewToolTip : public QWidget +{ + Q_OBJECT + +public: + explicit PreviewToolTip(QWidget *parent = nullptr); + ~PreviewToolTip(); + + void setId(const QString &id); + void setType(const QString &type); + void setInfo(const QString &info); + void setImage(const QImage &image); + +private: + Ui::PreviewToolTip *m_ui; +}; +} diff --git a/src/plugins/qmldesigner/components/navigator/previewtooltip.ui b/src/plugins/qmldesigner/components/navigator/previewtooltip.ui new file mode 100644 index 00000000000..99263375a5f --- /dev/null +++ b/src/plugins/qmldesigner/components/navigator/previewtooltip.ui @@ -0,0 +1,190 @@ + + + QmlDesigner::PreviewToolTip + + + + 0 + 0 + 400 + 160 + + + + + 0 + 0 + + + + + 200 + 150 + + + + + 1000 + 1000 + + + + + + + false + + + false + + + + 0 + + + 1 + + + 1 + + + 0 + + + 0 + + + + + QFrame::Box + + + QFrame::Plain + + + 1 + + + + 6 + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + 0 + 0 + + + + + 140 + 140 + + + + QFrame::Box + + + QFrame::Plain + + + <image> + + + Qt::AlignCenter + + + + + + + + + + + 0 + 1 + + + + + 0 + 0 + + + + <id label> + + + Qt::AlignCenter + + + + + + + + 0 + 1 + + + + + 0 + 0 + + + + <type label> + + + Qt::AlignCenter + + + + + + + + 0 + 3 + + + + + 0 + 0 + + + + <info label> + + + Qt::AlignCenter + + + + + + + + + + + + + + diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs index 40a26e7392e..8a711f25d32 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.qbs +++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs @@ -613,6 +613,9 @@ Project { "navigator/choosetexturepropertydialog.cpp", "navigator/choosetexturepropertydialog.h", "navigator/choosetexturepropertydialog.ui", + "navigator/previewtooltip.cpp", + "navigator/previewtooltip.h", + "navigator/previewtooltip.ui", "propertyeditor/aligndistribute.cpp", "propertyeditor/aligndistribute.h", "propertyeditor/designerpropertymap.cpp",