diff options
Diffstat (limited to 'src/webengine/ui_delegates_manager.cpp')
-rw-r--r-- | src/webengine/ui_delegates_manager.cpp | 235 |
1 files changed, 193 insertions, 42 deletions
diff --git a/src/webengine/ui_delegates_manager.cpp b/src/webengine/ui_delegates_manager.cpp index 6ff12b53f..a37484023 100644 --- a/src/webengine/ui_delegates_manager.cpp +++ b/src/webengine/ui_delegates_manager.cpp @@ -50,6 +50,10 @@ #include <QQmlContext> #include <QQmlEngine> #include <QQmlProperty> +#include <QCursor> +#include <QList> +#include <QScreen> +#include <QGuiApplication> // Uncomment for QML debugging //#define UI_DELEGATES_DEBUG @@ -77,20 +81,29 @@ static QString fileNameForComponent(UIDelegatesManager::ComponentType type) return QString(); } -static QString getUIDelegatesImportDir(QQmlEngine *engine) { - static QString importDir; - static bool initialized = false; - if (initialized) - return importDir; - Q_FOREACH (const QString &path, engine->importPathList()) { - QFileInfo fi(path % QLatin1String("/QtWebEngine/UIDelegates/")); - if (fi.exists()) { - importDir = fi.absolutePath(); - break; - } - } - initialized = true; - return importDir; +static QPoint calculateToolTipPosition(QPoint &position, QSize &toolTip) { + QRect screen; + QList<QScreen *> screens = QGuiApplication::screens(); + Q_FOREACH (const QScreen *src, screens) + if (src->availableGeometry().contains(position)) + screen = src->availableGeometry(); + + position += QPoint(2, 16); + + if (position.x() + toolTip.width() > screen.x() + screen.width()) + position.rx() -= 4 + toolTip.width(); + if (position.y() + toolTip.height() > screen.y() + screen.height()) + position.ry() -= 24 + toolTip.height(); + if (position.y() < screen.y()) + position.setY(screen.y()); + if (position.x() + toolTip.width() > screen.x() + screen.width()) + position.setX(screen.x() + screen.width() - toolTip.width()); + if (position.x() < screen.x()) + position.setX(screen.x()); + if (position.y() + toolTip.height() > screen.y() + screen.height()) + position.setY(screen.y() + screen.height() - toolTip.height()); + + return position; } const char *defaultPropertyName(QObject *obj) @@ -116,20 +129,37 @@ MenuItemHandler::MenuItemHandler(QObject *parent) UIDelegatesManager::UIDelegatesManager(QQuickWebEngineView *view) : m_view(view) , m_messageBubbleItem(0) + , m_toolTip(nullptr) FOR_EACH_COMPONENT_TYPE(COMPONENT_MEMBER_INIT, NO_SEPARATOR) { } +UIDelegatesManager::~UIDelegatesManager() +{ +} + #define COMPONENT_MEMBER_CASE_STATEMENT(TYPE, COMPONENT) \ case TYPE: \ component = &COMPONENT##Component; \ break; +bool UIDelegatesManager::initializeImportDirs(QStringList &dirs, QQmlEngine *engine) { + foreach (const QString &path, engine->importPathList()) { + QFileInfo fi(path % QLatin1String("/QtWebEngine/Controls1Delegates/")); + if (fi.exists()) { + dirs << fi.absolutePath(); + return true; + } + } + return false; +} + bool UIDelegatesManager::ensureComponentLoaded(ComponentType type) { QQmlEngine* engine = qmlEngine(m_view); - if (getUIDelegatesImportDir(engine).isNull()) + if (m_importDirs.isEmpty() && !initializeImportDirs(m_importDirs, engine)) return false; + QQmlComponent **component; switch (type) { FOR_EACH_COMPONENT_TYPE(COMPONENT_MEMBER_CASE_STATEMENT, NO_SEPARATOR) @@ -146,20 +176,25 @@ bool UIDelegatesManager::ensureComponentLoaded(ComponentType type) #endif if (!engine) return false; - QFileInfo fi(getUIDelegatesImportDir(engine) % QLatin1Char('/') % fileName); - if (!fi.exists()) - return false; - // FIXME: handle async loading - *component = (new QQmlComponent(engine, QUrl::fromLocalFile(fi.absoluteFilePath()), QQmlComponent::PreferSynchronous, m_view)); - - if ((*component)->status() != QQmlComponent::Ready) { - Q_FOREACH (const QQmlError& err, (*component)->errors()) - qWarning("QtWebEngine: component error: %s\n", qPrintable(err.toString())); - delete *component; - *component = 0; - return false; + + foreach (const QString &importDir, m_importDirs) { + QFileInfo fi(importDir % QLatin1Char('/') % fileName); + if (!fi.exists()) + continue; + // FIXME: handle async loading + *component = (new QQmlComponent(engine, QUrl::fromLocalFile(fi.absoluteFilePath()), + QQmlComponent::PreferSynchronous, m_view)); + + if ((*component)->status() != QQmlComponent::Ready) { + foreach (const QQmlError &err, (*component)->errors()) + qWarning("QtWebEngine: component error: %s\n", qPrintable(err.toString())); + delete *component; + *component = nullptr; + return false; + } + return true; } - return true; + return false; } #define CHECK_QML_SIGNAL_PROPERTY(prop, location) \ @@ -211,11 +246,11 @@ QObject *UIDelegatesManager::addMenu(QObject *parentMenu, const QString &title, { Q_ASSERT(parentMenu); if (!ensureComponentLoaded(Menu)) - return 0; + return nullptr; QQmlContext *context = qmlContext(m_view); QObject *menu = menuComponent->beginCreate(context); // set visual parent for non-Window-based menus - if (QQuickItem* item = qobject_cast<QQuickItem*>(menu)) + if (QQuickItem *item = qobject_cast<QQuickItem*>(menu)) item->setParentItem(m_view); if (!title.isEmpty()) @@ -291,7 +326,7 @@ void UIDelegatesManager::showDialog(QSharedPointer<JavaScriptDialogController> d QQmlContext *context = qmlContext(m_view); QObject *dialog = dialogComponent->beginCreate(context); // set visual parent for non-Window-based dialogs - if (QQuickItem* item = qobject_cast<QQuickItem*>(dialog)) + if (QQuickItem *item = qobject_cast<QQuickItem*>(dialog)) item->setParentItem(m_view); dialog->setParent(m_view); QQmlProperty textProp(dialog, QStringLiteral("text")); @@ -317,8 +352,6 @@ void UIDelegatesManager::showDialog(QSharedPointer<JavaScriptDialogController> d CHECK_QML_SIGNAL_PROPERTY(inputSignal, dialogComponent->url()); static int setTextIndex = dialogController->metaObject()->indexOfSlot("textProvided(QString)"); QObject::connect(dialog, inputSignal.method(), dialogController.data(), dialogController->metaObject()->method(setTextIndex)); - QQmlProperty closingSignal(dialog, QStringLiteral("onClosing")); - QObject::connect(dialog, closingSignal.method(), dialogController.data(), dialogController->metaObject()->method(rejectIndex)); } dialogComponent->completeCreate(); @@ -339,7 +372,7 @@ void UIDelegatesManager::showColorDialog(QSharedPointer<ColorChooserController> QQmlContext *context = qmlContext(m_view); QObject *colorDialog = colorDialogComponent->beginCreate(context); - if (QQuickItem* item = qobject_cast<QQuickItem*>(colorDialog)) + if (QQuickItem *item = qobject_cast<QQuickItem*>(colorDialog)) item->setParentItem(m_view); colorDialog->setParent(m_view); @@ -379,7 +412,7 @@ void UIDelegatesManager::showDialog(QSharedPointer<AuthenticationDialogControlle QQmlContext *context = qmlContext(m_view); QObject *authenticationDialog = authenticationDialogComponent->beginCreate(context); // set visual parent for non-Window-based dialogs - if (QQuickItem* item = qobject_cast<QQuickItem*>(authenticationDialog)) + if (QQuickItem *item = qobject_cast<QQuickItem*>(authenticationDialog)) item->setParentItem(m_view); authenticationDialog->setParent(m_view); @@ -412,7 +445,7 @@ void UIDelegatesManager::showDialog(QSharedPointer<AuthenticationDialogControlle QMetaObject::invokeMethod(authenticationDialog, "open"); } -void UIDelegatesManager::showFilePicker(FilePickerController *controller) +void UIDelegatesManager::showFilePicker(QSharedPointer<FilePickerController> controller) { if (!ensureComponentLoaded(FilePicker)) @@ -420,7 +453,7 @@ void UIDelegatesManager::showFilePicker(FilePickerController *controller) QQmlContext *context = qmlContext(m_view); QObject *filePicker = filePickerComponent->beginCreate(context); - if (QQuickItem* item = qobject_cast<QQuickItem*>(filePicker)) + if (QQuickItem *item = qobject_cast<QQuickItem*>(filePicker)) item->setParentItem(m_view); filePicker->setParent(m_view); filePickerComponent->completeCreate(); @@ -442,16 +475,14 @@ void UIDelegatesManager::showFilePicker(FilePickerController *controller) Q_UNREACHABLE(); } - controller->setParent(filePicker); - QQmlProperty filesPickedSignal(filePicker, QStringLiteral("onFilesSelected")); CHECK_QML_SIGNAL_PROPERTY(filesPickedSignal, filePickerComponent->url()); QQmlProperty rejectSignal(filePicker, QStringLiteral("onRejected")); CHECK_QML_SIGNAL_PROPERTY(rejectSignal, filePickerComponent->url()); static int acceptedIndex = controller->metaObject()->indexOfSlot("accepted(QVariant)"); - QObject::connect(filePicker, filesPickedSignal.method(), controller, controller->metaObject()->method(acceptedIndex)); + QObject::connect(filePicker, filesPickedSignal.method(), controller.data(), controller->metaObject()->method(acceptedIndex)); static int rejectedIndex = controller->metaObject()->indexOfSlot("rejected()"); - QObject::connect(filePicker, rejectSignal.method(), controller, controller->metaObject()->method(rejectedIndex)); + QObject::connect(filePicker, rejectSignal.method(), controller.data(), controller->metaObject()->method(rejectedIndex)); // delete when done. static int deleteLaterIndex = filePicker->metaObject()->indexOfSlot("deleteLater()"); @@ -461,6 +492,11 @@ void UIDelegatesManager::showFilePicker(FilePickerController *controller) QMetaObject::invokeMethod(filePicker, "open"); } +void UIDelegatesManager::showMenu(QObject *menu) +{ + QMetaObject::invokeMethod(menu, "popup"); +} + void UIDelegatesManager::showMessageBubble(const QRect &anchor, const QString &mainText, const QString &subText) { if (!ensureComponentLoaded(MessageBubble)) @@ -487,10 +523,125 @@ void UIDelegatesManager::hideMessageBubble() void UIDelegatesManager::moveMessageBubble(const QRect &anchor) { - Q_ASSERT(!m_messageBubbleItem.isNull()); + if (m_messageBubbleItem.isNull()) + return; QQmlProperty(m_messageBubbleItem.data(), QStringLiteral("x")).write(anchor.x()); QQmlProperty(m_messageBubbleItem.data(), QStringLiteral("y")).write(anchor.y() + anchor.size().height()); } +void UIDelegatesManager::showToolTip(const QString &text) +{ + if (!ensureComponentLoaded(ToolTip)) + return; + + if (text.isEmpty()) { + m_toolTip.reset(); + return; + } + + if (!m_toolTip.isNull()) + return; + + QQmlContext *context = qmlContext(m_view); + m_toolTip.reset(toolTipComponent->beginCreate(context)); + if (QQuickItem *item = qobject_cast<QQuickItem *>(m_toolTip.data())) + item->setParentItem(m_view); + m_toolTip->setParent(m_view); + toolTipComponent->completeCreate(); + + QQmlProperty(m_toolTip.data(), QStringLiteral("text")).write(text); + + int height = QQmlProperty(m_toolTip.data(), QStringLiteral("height")).read().toInt(); + int width = QQmlProperty(m_toolTip.data(), QStringLiteral("width")).read().toInt(); + QSize toolTipSize(width, height); + QPoint position = m_view->cursor().pos(); + position = m_view->mapFromGlobal(calculateToolTipPosition(position, toolTipSize)).toPoint(); + + QQmlProperty(m_toolTip.data(), QStringLiteral("x")).write(position.x()); + QQmlProperty(m_toolTip.data(), QStringLiteral("y")).write(position.y()); + + QMetaObject::invokeMethod(m_toolTip.data(), "open"); +} + +UI2DelegatesManager::UI2DelegatesManager(QQuickWebEngineView *view) : UIDelegatesManager(view) +{ + +} + +bool UI2DelegatesManager::initializeImportDirs(QStringList &dirs, QQmlEngine *engine) +{ + foreach (const QString &path, engine->importPathList()) { + QFileInfo fi1(path % QLatin1String("/QtWebEngine/Controls1Delegates/")); + QFileInfo fi2(path % QLatin1String("/QtWebEngine/Controls2Delegates/")); + if (fi1.exists() && fi2.exists()) { + dirs << fi2.absolutePath() << fi1.absolutePath(); + return true; + } + } + return false; +} + +QObject *UI2DelegatesManager::addMenu(QObject *parentMenu, const QString &title, const QPoint &pos) +{ + Q_ASSERT(parentMenu); + if (!ensureComponentLoaded(Menu)) + return nullptr; + QQmlContext *context = qmlContext(m_view); + QObject *menu = menuComponent->beginCreate(context); + + // set visual parent for non-Window-based menus + if (QQuickItem *item = qobject_cast<QQuickItem*>(menu)) + item->setParentItem(m_view); + + if (!title.isEmpty()) + menu->setProperty("title", title); + if (!pos.isNull()) { + menu->setProperty("x", pos.x()); + menu->setProperty("y", pos.y()); + } + + menu->setParent(parentMenu); + QQmlProperty doneSignal(menu, QStringLiteral("onDone")); + CHECK_QML_SIGNAL_PROPERTY(doneSignal, menuComponent->url()) + static int deleteLaterIndex = menu->metaObject()->indexOfSlot("deleteLater()"); + QObject::connect(menu, doneSignal.method(), menu, menu->metaObject()->method(deleteLaterIndex)); + menuComponent->completeCreate(); + return menu; +} + +void UI2DelegatesManager::addMenuItem(MenuItemHandler *menuItemHandler, const QString &text, + const QString &/*iconName*/, bool enabled, + bool checkable, bool checked) +{ + Q_ASSERT(menuItemHandler); + if (!ensureComponentLoaded(MenuItem)) + return; + + QObject *it = menuItemComponent->beginCreate(qmlContext(m_view)); + + it->setProperty("text", text); + it->setProperty("enabled", enabled); + it->setProperty("checked", checked); + it->setProperty("checkable", checkable); + + QQmlProperty signal(it, QStringLiteral("onTriggered")); + CHECK_QML_SIGNAL_PROPERTY(signal, menuItemComponent->url()); + QObject::connect(it, signal.method(), menuItemHandler, + QMetaMethod::fromSignal(&MenuItemHandler::triggered)); + menuItemComponent->completeCreate(); + + QObject *menu = menuItemHandler->parent(); + it->setParent(menu); + + QQmlListReference entries(menu, defaultPropertyName(menu), qmlEngine(m_view)); + if (entries.isValid()) + entries.append(it); +} + +void UI2DelegatesManager::showMenu(QObject *menu) +{ + QMetaObject::invokeMethod(menu, "open"); +} + } // namespace QtWebEngineCore |