summaryrefslogtreecommitdiffstats
path: root/src/webengine/ui_delegates_manager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/webengine/ui_delegates_manager.cpp')
-rw-r--r--src/webengine/ui_delegates_manager.cpp235
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