diff --git a/CMakeLists.txt b/CMakeLists.txt index 25feed4..d2b7bf2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,142 +1,142 @@ cmake_minimum_required(VERSION 3.5) set(KF5_VERSION "5.57.0") # handled by release scripts set(KF5_DEP_VERSION "5.56.0") # handled by release scripts project(KDeclarative VERSION ${KF5_VERSION}) # Dependencies include(FeatureSummary) find_package(ECM 5.56.0 NO_MODULE) set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://projects.kde.org/projects/kdesupport/extra-cmake-modules") feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES) set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) set(REQUIRED_QT_VERSION 5.10.0) find_package(Qt5 ${REQUIRED_QT_VERSION} NO_MODULE REQUIRED Qml Quick Gui) include(KDEInstallDirs) include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) include(KDECMakeSettings) find_package(KF5Config ${KF5_DEP_VERSION} REQUIRED) find_package(KF5I18n ${KF5_DEP_VERSION} REQUIRED) find_package(KF5IconThemes ${KF5_DEP_VERSION} REQUIRED) find_package(KF5KIO ${KF5_DEP_VERSION} REQUIRED) find_package(KF5WidgetsAddons ${KF5_DEP_VERSION} REQUIRED) find_package(KF5WindowSystem ${KF5_DEP_VERSION} REQUIRED) find_package(KF5GlobalAccel ${KF5_DEP_VERSION} REQUIRED) find_package(KF5GuiAddons ${KF5_DEP_VERSION} REQUIRED) find_package(KF5Package ${KF5_DEP_VERSION} REQUIRED) ######################################################################### add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0) #add_definitions(-Wno-deprecated) # Includes include(GenerateExportHeader) include(ECMSetupVersion) include(ECMGenerateHeaders) include(CMakePackageConfigHelpers) include(ECMAddQch) option(BUILD_EXAMPLES "Build and install examples." OFF) option(BUILD_QCH "Build API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)" OFF) add_feature_info(QCH ${BUILD_QCH} "API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)") # ECM setup ecm_setup_version( PROJECT VARIABLE_PREFIX KDECLARATIVE VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kdeclarative_version.h" PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5DeclarativeConfigVersion.cmake" SOVERSION 5) # Subdirectories add_definitions(-DTRANSLATION_DOMAIN=\"kdeclarative5\") if (IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/po") ki18n_install(po) endif() find_package(epoxy) set_package_properties(epoxy PROPERTIES DESCRIPTION "libepoxy" URL "http://github.com/anholt/libepoxy" TYPE OPTIONAL PURPOSE "OpenGL dispatch library" ) set(HAVE_EPOXY 0) if(epoxy_FOUND) set(HAVE_EPOXY 1) endif() - +add_definitions(-DQT_NO_FOREACH) add_subdirectory(src) if (BUILD_TESTING) add_subdirectory(autotests) add_subdirectory(tests) endif() # Create a Config.cmake and a ConfigVersion.cmake file and install them set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KF5Declarative") if (BUILD_QCH) ecm_install_qch_export( TARGETS KF5Declarative_QCH FILE KF5DeclarativeQchTargets.cmake DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) set(PACKAGE_INCLUDE_QCHTARGETS "include(\"\${CMAKE_CURRENT_LIST_DIR}/KF5DeclarativeQchTargets.cmake\")") endif() configure_package_config_file( "${CMAKE_CURRENT_SOURCE_DIR}/KF5DeclarativeConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/KF5DeclarativeConfig.cmake" INSTALL_DESTINATION "${CMAKECONFIG_INSTALL_DIR}" ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/KF5DeclarativeConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/KF5DeclarativeConfigVersion.cmake" DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) install(EXPORT KF5DeclarativeTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE KF5DeclarativeTargets.cmake NAMESPACE KF5:: COMPONENT Devel ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/kdeclarative_version.h" DESTINATION "${KDE_INSTALL_INCLUDEDIR_KF5}" COMPONENT Devel ) feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) if(KF5Config_FOUND AND KF5I18n_FOUND AND KF5IconThemes_FOUND AND KF5KIO_FOUND) message("Dependencies for libkdeclarative found: it will be built") else() message("In order to build libkdeclarative you need KF5Config, KF5I18n, KF5IconThemes and KF5KIO") endif() if(KF5I18n_FOUND AND KF5WidgetsAddons_FOUND AND KF5WindowSystem_FOUND AND KF5GlobalAccel_FOUND AND KF5KIO_FOUND AND KF5GuiAddons_FOUND) message("Dependencies for KQuickControls found: it will be built") else() message("In order to build KQuickControls you need KF5I18n, KF5WidgetsAddons, KF5WindowSystem, KF5GlobalAccel, KF5KIO and KF5GuiAddons") endif() if(KF5CoreAddons_FOUND) message("Dependencies for KCoreAddons QML bindings found; it will be built") else() message("In order to build KCoreAddons QML bindings you need KCoreAddons") endif() diff --git a/src/kdeclarative/configpropertymap.cpp b/src/kdeclarative/configpropertymap.cpp index 80c6e28..06b5db4 100644 --- a/src/kdeclarative/configpropertymap.cpp +++ b/src/kdeclarative/configpropertymap.cpp @@ -1,136 +1,137 @@ /* * Copyright 2013 Marco Martin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "configpropertymap.h" #include #include #include #include namespace KDeclarative { class ConfigPropertyMapPrivate { public: ConfigPropertyMapPrivate(ConfigPropertyMap *map) : q(map) { } enum LoadConfigOption { DontEmitValueChanged, EmitValueChanged }; void loadConfig(LoadConfigOption option); void writeConfig(); void writeConfigValue(const QString &key, const QVariant &value); ConfigPropertyMap *q; QPointer config; }; ConfigPropertyMap::ConfigPropertyMap(KCoreConfigSkeleton *config, QObject *parent) : QQmlPropertyMap(this, parent), d(new ConfigPropertyMapPrivate(this)) { d->config = config; //FIXME: find a prettier way to connect without lambdas connect(config, &KCoreConfigSkeleton::configChanged, this, std::bind(&ConfigPropertyMapPrivate::loadConfig, d, ConfigPropertyMapPrivate::EmitValueChanged)); connect(this, &ConfigPropertyMap::valueChanged, this, [this](const QString &key, const QVariant &value){d->writeConfigValue(key, value);}); d->loadConfig(ConfigPropertyMapPrivate::DontEmitValueChanged); } ConfigPropertyMap::~ConfigPropertyMap() { d->writeConfig(); delete d; } QVariant ConfigPropertyMap::updateValue(const QString &key, const QVariant &input) { Q_UNUSED(key); if (input.userType() == qMetaTypeId()) { return input.value().toVariant(); } return input; } bool ConfigPropertyMap::isImmutable(const QString &key) const { KConfigSkeletonItem *item = d->config.data()->findItem(key); if (item) { return item->isImmutable(); } return false; } void ConfigPropertyMapPrivate::loadConfig(ConfigPropertyMapPrivate::LoadConfigOption option) { if (!config) { return; } const auto &items = config.data()->items(); for (KConfigSkeletonItem *item : items) { q->insert(item->key(), item->property()); if (option == EmitValueChanged) { emit q->valueChanged(item->key(), item->property()); } } } void ConfigPropertyMapPrivate::writeConfig() { if (!config) { return; } - foreach (KConfigSkeletonItem *item, config.data()->items()) { + const auto lstItems = config.data()->items(); + for (KConfigSkeletonItem *item : lstItems) { item->setProperty(q->value(item->key())); } config.data()->blockSignals(true); config.data()->save(); config.data()->blockSignals(false); } void ConfigPropertyMapPrivate::writeConfigValue(const QString &key, const QVariant &value) { KConfigSkeletonItem *item = config.data()->findItem(key); if (item) { item->setProperty(value); config.data()->blockSignals(true); config.data()->save(); //why read? read will update KConfigSkeletonItem::mLoadedValue, //allowing a write operation to be performed next time config.data()->read(); config.data()->blockSignals(false); } } } #include "moc_configpropertymap.cpp" diff --git a/src/kdeclarative/qmlobject.cpp b/src/kdeclarative/qmlobject.cpp index 62a4d55..1f53c01 100644 --- a/src/kdeclarative/qmlobject.cpp +++ b/src/kdeclarative/qmlobject.cpp @@ -1,376 +1,376 @@ /* * Copyright 2013 Marco Martin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "qmlobject.h" #include "private/kdeclarative_p.h" #include #include #include #include #include #include #include #include #include #include //#include "packageaccessmanagerfactory.h" //#include "private/declarative/dataenginebindings_p.h" namespace KDeclarative { class QmlObjectIncubator : public QQmlIncubator { public: QVariantHash m_initialProperties; protected: void setInitialState(QObject *object) override { QHashIterator i(m_initialProperties); while (i.hasNext()) { i.next(); object->setProperty(i.key().toLatin1().data(), i.value()); } } }; class QmlObjectPrivate { public: QmlObjectPrivate(QmlObject *parent) : q(parent), engine(nullptr), component(nullptr), delay(false) { executionEndTimer = new QTimer(q); executionEndTimer->setInterval(0); executionEndTimer->setSingleShot(true); QObject::connect(executionEndTimer, SIGNAL(timeout()), q, SLOT(scheduleExecutionEnd())); } ~QmlObjectPrivate() { delete incubator.object(); } void errorPrint(QQmlComponent *component); void execute(const QUrl &source); void scheduleExecutionEnd(); void minimumWidthChanged(); void minimumHeightChanged(); void maximumWidthChanged(); void maximumHeightChanged(); void preferredWidthChanged(); void preferredHeightChanged(); void checkInitializationCompleted(); QmlObject *q; QUrl source; QQmlEngine *engine; QmlObjectIncubator incubator; QQmlComponent *component; QTimer *executionEndTimer; KDeclarative kdeclarative; KPackage::Package package; QQmlContext *rootContext; bool delay : 1; }; void QmlObjectPrivate::errorPrint(QQmlComponent *component) { QString errorStr = QStringLiteral("Error loading QML file.\n"); if (component->isError()) { - QList errors = component->errors(); - foreach (const QQmlError &error, errors) { + const QList errors = component->errors(); + for (const QQmlError &error : errors) { errorStr += (error.line() > 0 ? QString(QString::number(error.line()) + QLatin1String(": ")) : QLatin1String("")) + error.description() + QLatin1Char('\n'); } } qWarning() << component->url().toString() << '\n' << errorStr; } void QmlObjectPrivate::execute(const QUrl &source) { if (source.isEmpty()) { qWarning() << "File name empty!"; return; } delete component; component = new QQmlComponent(engine, q); QObject::connect(component, &QQmlComponent::statusChanged, q, &QmlObject::statusChanged, Qt::QueuedConnection); delete incubator.object(); component->loadUrl(source); if (delay) { executionEndTimer->start(0); } else { scheduleExecutionEnd(); } } void QmlObjectPrivate::scheduleExecutionEnd() { if (component->isReady() || component->isError()) { q->completeInitialization(); } else { QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)), q, SLOT(completeInitialization())); } } QmlObject::QmlObject(QObject *parent) // cannot do : QmlObject(new QQmlEngine(this), d->engine->rootContext(), parent) : QObject(parent) , d(new QmlObjectPrivate(this)) { d->engine = new QQmlEngine(this); d->rootContext = d->engine->rootContext(); d->kdeclarative.setDeclarativeEngine(d->engine); d->kdeclarative.d->qmlObj = this; d->kdeclarative.setupContext(); KDeclarative::setupEngine(d->engine); } QmlObject::QmlObject(QQmlEngine *engine, QObject *parent) : QmlObject(engine, engine->rootContext(), parent) { } QmlObject::QmlObject(QQmlEngine *engine, QQmlContext *rootContext, QObject *parent) : QmlObject(engine, rootContext, nullptr /*call setupEngine*/, parent) { } QmlObject::QmlObject(QQmlEngine *engine, QQmlContext *rootContext, QmlObject *obj, QObject *parent) : QObject(parent) , d(new QmlObjectPrivate(this)) { if (engine) { d->engine = engine; } else { d->engine = new QQmlEngine(this); } if (rootContext) { d->rootContext = rootContext; } else { d->rootContext = d->engine->rootContext(); } d->kdeclarative.setDeclarativeEngine(d->engine); d->kdeclarative.d->qmlObj = this; d->kdeclarative.setupContext(); if (!obj) { KDeclarative::setupEngine(d->engine); } } QmlObject::~QmlObject() { // QDeclarativeNetworkAccessManagerFactory *factory = d->engine->networkAccessManagerFactory(); // d->engine->setNetworkAccessManagerFactory(0); // delete factory; delete d; } void QmlObject::setTranslationDomain(const QString &translationDomain) { d->kdeclarative.setTranslationDomain(translationDomain); } QString QmlObject::translationDomain() const { return d->kdeclarative.translationDomain(); } void QmlObject::setSource(const QUrl &source) { d->source = source; d->execute(source); } QUrl QmlObject::source() const { return d->source; } void QmlObject::loadPackage(const QString &packageName) { d->package = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("KPackage/GenericQML")); d->package.setPath(packageName); setSource(QUrl::fromLocalFile(d->package.filePath("mainscript"))); } void QmlObject::setPackage(const KPackage::Package &package) { d->package = package; setSource(QUrl::fromLocalFile(package.filePath("mainscript"))); } KPackage::Package QmlObject::package() const { return d->package; } void QmlObject::setInitializationDelayed(const bool delay) { d->delay = delay; } bool QmlObject::isInitializationDelayed() const { return d->delay; } QQmlEngine *QmlObject::engine() { return d->engine; } QObject *QmlObject::rootObject() const { if (d->incubator.status() == QQmlIncubator::Loading) { qWarning() << "Trying to use rootObject before initialization is completed, whilst using setInitializationDelayed. Forcing completion"; d->incubator.forceCompletion(); } return d->incubator.object(); } QQmlComponent *QmlObject::mainComponent() const { return d->component; } QQmlContext *QmlObject::rootContext() const { return d->rootContext; } QQmlComponent::Status QmlObject::status() const { if (!d->engine) { return QQmlComponent::Error; } if (!d->component) { return QQmlComponent::Null; } return QQmlComponent::Status(d->component->status()); } void QmlObjectPrivate::checkInitializationCompleted() { if (!incubator.isReady() && incubator.status() != QQmlIncubator::Error) { QTimer::singleShot(0, q, SLOT(checkInitializationCompleted())); return; } if (!incubator.object()) { errorPrint(component); } emit q->finished(); } void QmlObject::completeInitialization(const QVariantHash &initialProperties) { d->executionEndTimer->stop(); if (d->incubator.object()) { return; } if (!d->component) { qWarning() << "No component for" << source(); return; } if (d->component->status() != QQmlComponent::Ready || d->component->isError()) { d->errorPrint(d->component); return; } d->incubator.m_initialProperties = initialProperties; d->component->create(d->incubator, d->rootContext); if (d->delay) { d->checkInitializationCompleted(); } else { d->incubator.forceCompletion(); if (!d->incubator.object()) { d->errorPrint(d->component); } emit finished(); } } QObject *QmlObject::createObjectFromSource(const QUrl &source, QQmlContext *context, const QVariantHash &initialProperties) { QQmlComponent *component = new QQmlComponent(d->engine, this); component->loadUrl(source); return createObjectFromComponent(component, context, initialProperties); } QObject *QmlObject::createObjectFromComponent(QQmlComponent *component, QQmlContext *context, const QVariantHash &initialProperties) { QmlObjectIncubator incubator; incubator.m_initialProperties = initialProperties; component->create(incubator, context ? context : d->rootContext); incubator.forceCompletion(); QObject *object = incubator.object(); if (!component->isError() && object) { //memory management component->setParent(object); //reparent to root object if wasn't specified otherwise by initialProperties if (!initialProperties.contains(QStringLiteral("parent"))) { if (qobject_cast(rootObject())) { object->setProperty("parent", QVariant::fromValue(rootObject())); } else { object->setParent(rootObject()); } } return object; } else { d->errorPrint(component); delete object; return nullptr; } } } #include "moc_qmlobject.cpp" diff --git a/src/qmlcontrols/draganddrop/DeclarativeDragArea.cpp b/src/qmlcontrols/draganddrop/DeclarativeDragArea.cpp index 8ef5972..384c69b 100644 --- a/src/qmlcontrols/draganddrop/DeclarativeDragArea.cpp +++ b/src/qmlcontrols/draganddrop/DeclarativeDragArea.cpp @@ -1,387 +1,387 @@ /* Copyright (C) 2010 by BetterInbox Original author: Gregory Schlomoff Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "DeclarativeDragArea.h" #include "DeclarativeMimeData.h" #include #include #include #include #include #include #include #include #include #include #include /*! A DragArea is used to make an item draggable. */ DeclarativeDragArea::DeclarativeDragArea(QQuickItem *parent) : QQuickItem(parent), m_delegate(nullptr), m_source(parent), m_target(nullptr), m_enabled(true), m_draggingJustStarted(false), m_dragActive(false), m_supportedActions(Qt::MoveAction), m_defaultAction(Qt::MoveAction), m_data(new DeclarativeMimeData()), // m_data is owned by us, and we shouldn't pass it to Qt directly as it will automatically delete it after the drag and drop. m_pressAndHoldTimerId(0) { m_startDragDistance = QGuiApplication::styleHints()->startDragDistance(); setAcceptedMouseButtons(Qt::LeftButton); // setFiltersChildEvents(true); setFlag(ItemAcceptsDrops, m_enabled); setFiltersChildMouseEvents(true); } DeclarativeDragArea::~DeclarativeDragArea() { if (m_data) { delete m_data; } } /*! The delegate is the item that will be displayed next to the mouse cursor during the drag and drop operation. It usually consists of a large, semi-transparent icon representing the data being dragged. */ QQuickItem* DeclarativeDragArea::delegate() const { return m_delegate; } void DeclarativeDragArea::setDelegate(QQuickItem *delegate) { if (m_delegate != delegate) { //qDebug() << " ______________________________________________ " << delegate; m_delegate = delegate; emit delegateChanged(); } } void DeclarativeDragArea::resetDelegate() { setDelegate(nullptr); } /*! The QML element that is the source of this drag and drop operation. This can be defined to any item, and will be available to the DropArea as event.data.source */ QQuickItem* DeclarativeDragArea::source() const { return m_source; } void DeclarativeDragArea::setSource(QQuickItem* source) { if (m_source != source) { m_source = source; emit sourceChanged(); } } void DeclarativeDragArea::resetSource() { setSource(nullptr); } bool DeclarativeDragArea::dragActive() const { return m_dragActive; } // target QQuickItem* DeclarativeDragArea::target() const { //TODO: implement me return nullptr; } // data DeclarativeMimeData* DeclarativeDragArea::mimeData() const { return m_data; } // startDragDistance int DeclarativeDragArea::startDragDistance() const { return m_startDragDistance; } void DeclarativeDragArea::setStartDragDistance(int distance) { if (distance == m_startDragDistance) { return; } m_startDragDistance = distance; emit startDragDistanceChanged(); } // delegateImage QVariant DeclarativeDragArea::delegateImage() const { return m_delegateImage; } void DeclarativeDragArea::setDelegateImage(const QVariant &image) { if (image.canConvert() && image.value() == m_delegateImage) { return; } if (image.canConvert()) { m_delegateImage = image.value(); } else if (image.canConvert()) { m_delegateImage = QIcon::fromTheme(image.toString()).pixmap(QSize(48, 48)).toImage(); } else { m_delegateImage = image.value().pixmap(QSize(48, 48)).toImage(); } emit delegateImageChanged(); } // enabled bool DeclarativeDragArea::isEnabled() const { return m_enabled; } void DeclarativeDragArea::setEnabled(bool enabled) { if (enabled != m_enabled) { m_enabled = enabled; emit enabledChanged(); } } // supported actions Qt::DropActions DeclarativeDragArea::supportedActions() const { return m_supportedActions; } void DeclarativeDragArea::setSupportedActions(Qt::DropActions actions) { if (actions != m_supportedActions) { m_supportedActions = actions; emit supportedActionsChanged(); } } // default action Qt::DropAction DeclarativeDragArea::defaultAction() const { return m_defaultAction; } void DeclarativeDragArea::setDefaultAction(Qt::DropAction action) { if (action != m_defaultAction) { m_defaultAction = action; emit defaultActionChanged(); } } void DeclarativeDragArea::mousePressEvent(QMouseEvent* event) { m_pressAndHoldTimerId = startTimer(QGuiApplication::styleHints()->mousePressAndHoldInterval()); m_buttonDownPos = event->screenPos(); m_draggingJustStarted = true; setKeepMouseGrab(true); } void DeclarativeDragArea::mouseReleaseEvent(QMouseEvent* event) { Q_UNUSED(event); killTimer(m_pressAndHoldTimerId); m_pressAndHoldTimerId = 0; m_draggingJustStarted = false; setKeepMouseGrab(false); ungrabMouse(); } void DeclarativeDragArea::timerEvent(QTimerEvent *event) { if (event->timerId() == m_pressAndHoldTimerId && m_draggingJustStarted && m_enabled) { // Grab delegate before starting drag if (m_delegate) { // Another grab is already in progress if (m_grabResult) { return; } m_grabResult = m_delegate->grabToImage(); if (m_grabResult) { connect(m_grabResult.data(), &QQuickItemGrabResult::ready, this, [this]() { startDrag(m_grabResult->image()); m_grabResult.reset(); }); return; } } // No delegate or grab failed, start drag immediately startDrag(m_delegateImage); } } void DeclarativeDragArea::mouseMoveEvent(QMouseEvent *event) { if ( !m_enabled || QLineF(event->screenPos(), m_buttonDownPos).length() < m_startDragDistance) { return; } //don't start drags on move for touch events, they'll be handled only by press and hold //reset timer if moved more than m_startDragDistance if (event->source() == Qt::MouseEventSynthesizedByQt) { killTimer(m_pressAndHoldTimerId); m_pressAndHoldTimerId = 0; return; } if (m_draggingJustStarted) { // Grab delegate before starting drag if (m_delegate) { // Another grab is already in progress if (m_grabResult) { return; } m_grabResult = m_delegate->grabToImage(); if (m_grabResult) { connect(m_grabResult.data(), &QQuickItemGrabResult::ready, this, [this]() { startDrag(m_grabResult->image()); m_grabResult.reset(); }); return; } } // No delegate or grab failed, start drag immediately startDrag(m_delegateImage); } } bool DeclarativeDragArea::childMouseEventFilter(QQuickItem *item, QEvent *event) { if (!isEnabled()) { return false; } switch (event->type()) { case QEvent::MouseButtonPress: { QMouseEvent *me = static_cast(event); //qDebug() << "press in dragarea"; mousePressEvent(me); break; } case QEvent::MouseMove: { QMouseEvent *me = static_cast(event); //qDebug() << "move in dragarea"; mouseMoveEvent(me); break; } case QEvent::MouseButtonRelease: { QMouseEvent *me = static_cast(event); //qDebug() << "release in dragarea"; mouseReleaseEvent(me); break; } default: break; } return QQuickItem::childMouseEventFilter(item, event); } void DeclarativeDragArea::startDrag(const QImage &image) { grabMouse(); m_draggingJustStarted = false; QDrag *drag = new QDrag(parent()); DeclarativeMimeData *dataCopy = new DeclarativeMimeData(m_data); //Qt will take ownership of this copy and delete it. drag->setMimeData(dataCopy); const qreal devicePixelRatio = window() ? window()->devicePixelRatio() : 1; const int imageSize = 48 * devicePixelRatio; if (!image.isNull()) { drag->setPixmap(QPixmap::fromImage(image)); } else if (mimeData()->hasImage()) { const QImage im = qvariant_cast(mimeData()->imageData()); drag->setPixmap(QPixmap::fromImage(im)); } else if (mimeData()->hasColor()) { QPixmap px(imageSize, imageSize); px.fill(mimeData()->color()); drag->setPixmap(px); } else { // Icons otherwise QStringList icons; if (mimeData()->hasText()) { icons << QStringLiteral("text-plain"); } if (mimeData()->hasHtml()) { icons << QStringLiteral("text-html"); } if (mimeData()->hasUrls()) { for (int i = 0; i < std::min(4, mimeData()->urls().size()); ++i) { icons << QStringLiteral("text-html"); } } if (!icons.isEmpty()) { QPixmap pm(imageSize * icons.count(), imageSize); pm.fill(Qt::transparent); QPainter p(&pm); int i = 0; - foreach (const QString &ic, icons) { + for (const QString &ic : qAsConst(icons)) { p.drawPixmap(QPoint(i * imageSize, 0), QIcon::fromTheme(ic).pixmap(imageSize)); i++; } p.end(); drag->setPixmap(pm); } } //drag->setHotSpot(QPoint(drag->pixmap().width()/2, drag->pixmap().height()/2)); // TODO: Make a property for that //setCursor(Qt::OpenHandCursor); //TODO? Make a property for the cursor m_dragActive = true; emit dragActiveChanged(); emit dragStarted(); Qt::DropAction action = drag->exec(m_supportedActions, m_defaultAction); setKeepMouseGrab(false); m_dragActive = false; emit dragActiveChanged(); emit drop(action); ungrabMouse(); } diff --git a/src/qmlcontrols/draganddrop/DeclarativeMimeData.cpp b/src/qmlcontrols/draganddrop/DeclarativeMimeData.cpp index 1456dd8..69507ab 100644 --- a/src/qmlcontrols/draganddrop/DeclarativeMimeData.cpp +++ b/src/qmlcontrols/draganddrop/DeclarativeMimeData.cpp @@ -1,166 +1,168 @@ /* Copyright (C) 2010 by BetterInbox Original author: Gregory Schlomoff Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "DeclarativeMimeData.h" /*! \qmlclass MimeData DeclarativeMimeData This is a wrapper class around QMimeData, with a few extensions to provide better support for in-qml drag & drops. */ DeclarativeMimeData::DeclarativeMimeData() : QMimeData(), m_source(nullptr) {} /*! \internal \class DeclarativeMimeData Creates a new DeclarativeMimeData by cloning the QMimeData passed as parameter. This is useful for two reasons : - In DragArea, we want to clone our "working copy" of the DeclarativeMimeData instance, as Qt will automatically delete it after the drag and drop operation. - In the drop events, the QMimeData is const, and we have troubles passing const to QML. So we clone it to remove the "constness" This method will try to cast the QMimeData to DeclarativeMimeData, and will clone our extensions to QMimeData as well */ DeclarativeMimeData::DeclarativeMimeData(const QMimeData* copy) : QMimeData(), m_source(nullptr) { // Copy the standard MIME data - foreach(QString format, copy->formats()) { + const auto formats = copy->formats(); + for (const QString &format : formats) { QMimeData::setData(format, copy->data(format)); } // If the object we are copying actually is a DeclarativeMimeData, copy our extended properties as well const DeclarativeMimeData* declarativeMimeData = qobject_cast(copy); if (declarativeMimeData) { this->setSource(declarativeMimeData->source()); } } /*! \qmlproperty url MimeData::url Returns the first URL from the urls property of QMimeData TODO: We should use QDeclarativeListProperty to return the whole list instead of only the first element. */ QUrl DeclarativeMimeData::url() const { if ( this->hasUrls() && !this->urls().isEmpty()) { return QMimeData::urls().first(); } return QUrl(); } void DeclarativeMimeData::setUrl(const QUrl &url) { if (this->url() == url) return; QList urlList; urlList.append(url); QMimeData::setUrls(urlList); emit urlChanged(); } QJsonArray DeclarativeMimeData::urls() const { QJsonArray varUrls; - foreach (const QUrl &url, QMimeData::urls()) { + const auto lstUrls = QMimeData::urls(); + for (const QUrl &url : lstUrls) { varUrls.append(url.toString()); } return varUrls; } void DeclarativeMimeData::setUrls(const QJsonArray &urls) { QList urlList; urlList.reserve(urls.size()); - foreach (const QVariant &varUrl, urls) { + for (const QVariant &varUrl : urls) { urlList << varUrl.toUrl(); } QMimeData::setUrls(urlList); emit urlsChanged(); } // color QColor DeclarativeMimeData::color() const { if (this->hasColor()) { return qvariant_cast(this->colorData()); } return QColor(); } bool DeclarativeMimeData::hasColor() const { //qDebug() << " hasColor " << (QMimeData::hasColor() ? color().name() : "false"); return QMimeData::hasColor(); } void DeclarativeMimeData::setColor(const QColor &color) { if (this->color() != color) { this->setColorData(color); emit colorChanged(); } } void DeclarativeMimeData::setData(const QString &mimeType, const QVariant &data) { if (data.type() == QVariant::ByteArray) { QMimeData::setData(mimeType, data.toByteArray()); } else if (data.canConvert(QVariant::String)) { QMimeData::setData(mimeType, data.toString().toLatin1()); } } /*! \qmlproperty item MimeData::source Setting source to any existing qml item will enable the receiver of the drag and drop operation to know in which item the operation originated. In the case of inter-application drag and drop operations, the source will not be available, and will be 0. Be sure to test it in your QML code, before using it, or it will generate errors in the console. */ QQuickItem* DeclarativeMimeData::source() const { return m_source; } void DeclarativeMimeData::setSource(QQuickItem* source) { if (m_source != source) { m_source = source; emit sourceChanged(); } } QByteArray DeclarativeMimeData::getDataAsByteArray(const QString& format) { return data(format); } diff --git a/src/qmlcontrols/draganddrop/MimeDataWrapper.cpp b/src/qmlcontrols/draganddrop/MimeDataWrapper.cpp index f2db9d2..350ec6f 100644 --- a/src/qmlcontrols/draganddrop/MimeDataWrapper.cpp +++ b/src/qmlcontrols/draganddrop/MimeDataWrapper.cpp @@ -1,93 +1,94 @@ /* Copyright (C) 2015 by Aleix Pol Gonzalez Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "MimeDataWrapper.h" #include #include #include MimeDataWrapper::MimeDataWrapper(const QMimeData* data, QObject* parent) : QObject(parent) , m_data(data) {} QString MimeDataWrapper::text() const { return m_data->text(); } QString MimeDataWrapper::html() const { return m_data->html(); } QUrl MimeDataWrapper::url() const { if ( m_data->hasUrls() && !m_data->urls().isEmpty()) { return m_data->urls().first(); } return QUrl(); } bool MimeDataWrapper::hasUrls() const { return m_data->hasUrls(); } QJsonArray MimeDataWrapper::urls() const { QJsonArray varUrls; - foreach (const QUrl &url, m_data->urls()) { + const auto urls = m_data->urls(); + for (const QUrl &url : urls) { varUrls.append(url.toString()); } return varUrls; } QVariant MimeDataWrapper::color() const { if (m_data->hasColor()) return m_data->colorData(); else return QVariant(); } QStringList MimeDataWrapper::formats() const { return m_data->formats(); } QByteArray MimeDataWrapper::getDataAsByteArray(const QString& format) { return m_data->data(format); } QVariant MimeDataWrapper::source() const { // In case it comes from a DeclarativeMimeData return m_data->property("source"); } QMimeData* MimeDataWrapper::mimeData() const { return const_cast(m_data); } diff --git a/src/qmlcontrols/kquickcontrolsaddons/clipboard.cpp b/src/qmlcontrols/kquickcontrolsaddons/clipboard.cpp index f906079..9944d66 100644 --- a/src/qmlcontrols/kquickcontrolsaddons/clipboard.cpp +++ b/src/qmlcontrols/kquickcontrolsaddons/clipboard.cpp @@ -1,128 +1,129 @@ /* * Copyright 2014 Aleix Pol Gonzalez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "clipboard.h" #include #include #include #include Clipboard::Clipboard(QObject* parent) : QObject(parent) , m_clipboard(QGuiApplication::clipboard()) , m_mode(QClipboard::Clipboard) { connect(m_clipboard, SIGNAL(changed(QClipboard::Mode)), SLOT(clipboardChanged(QClipboard::Mode))); } void Clipboard::setMode(QClipboard::Mode mode) { m_mode = mode; emit modeChanged(m_mode); } void Clipboard::clipboardChanged(QClipboard::Mode m) { if (m == m_mode) { emit contentChanged(); } } void Clipboard::clear() { m_clipboard->clear(m_mode); } QClipboard::Mode Clipboard::mode() const { return m_mode; } QVariant Clipboard::contentFormat(const QString &format) const { const QMimeData* data = m_clipboard->mimeData(m_mode); QVariant ret; if(format == QStringLiteral("text/uri-list")) { QVariantList retList; - foreach(const QUrl& url, data->urls()) + const auto urls = data->urls(); + for (const QUrl& url : urls) retList += url; ret = retList; } else if(format.startsWith(QStringLiteral("text/"))) { ret = data->text(); } else if(format.startsWith(QStringLiteral("image/"))) { ret = data->imageData(); } else ret = data->data(format.isEmpty() ? data->formats().first(): format); return ret; } QVariant Clipboard::content() const { return contentFormat(m_clipboard->mimeData(m_mode)->formats().first()); } void Clipboard::setContent(const QVariant &content) { QMimeData* mimeData = new QMimeData; switch(content.type()) { case QVariant::String: mimeData->setText(content.toString()); break; case QVariant::Color: mimeData->setColorData(content.toString()); break; case QVariant::Pixmap: case QVariant::Image: mimeData->setImageData(content); break; default: if (content.type() == QVariant::List) { - QVariantList list = content.toList(); + const QVariantList list = content.toList(); QList urls; bool wasUrlList = true; - foreach (const QVariant& url, list) { + for (const QVariant& url : list) { if (url.type() != QVariant::Url) { wasUrlList = false; break; } urls += url.toUrl(); } if(wasUrlList) { mimeData->setUrls(urls); break; } } if (content.canConvert(QVariant::String)) { mimeData->setText(content.toString()); } else { mimeData->setData(QStringLiteral("application/octet-stream"), content.toByteArray()); qWarning() << "Couldn't figure out the content type, storing as application/octet-stream"; } break; } m_clipboard->setMimeData(mimeData, m_mode); } QStringList Clipboard::formats() const { return m_clipboard->mimeData(m_mode)->formats(); } diff --git a/src/qmlcontrols/kquickcontrolsaddons/eventgenerator.cpp b/src/qmlcontrols/kquickcontrolsaddons/eventgenerator.cpp index 29fbdeb..f943fa6 100644 --- a/src/qmlcontrols/kquickcontrolsaddons/eventgenerator.cpp +++ b/src/qmlcontrols/kquickcontrolsaddons/eventgenerator.cpp @@ -1,148 +1,150 @@ /* * Copyright (C) 2015 by Eike Hein * Copyright (C) 2015 Marco Martin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "eventgenerator.h" #include #include #include EventGenerator::EventGenerator(QObject *parent) : QObject(parent) { } EventGenerator::~EventGenerator() { } void EventGenerator::sendMouseEvent(QQuickItem *item, EventGenerator::MouseEvent type, int x, int y, int button, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers) { if (!item) { return; } QEvent::Type eventType; switch (type) { case MouseButtonPress: eventType = QEvent::MouseButtonPress; break; case MouseButtonRelease: eventType = QEvent::MouseButtonRelease; break; case MouseMove: eventType = QEvent::MouseMove; break; default: return; } QMouseEvent ev(eventType, QPointF(x, y), static_cast(button), buttons, modifiers); QGuiApplication::sendEvent(item, &ev); } void EventGenerator::sendMouseEventRecursive(QQuickItem *parentItem, EventGenerator::MouseEvent type, int x, int y, int button, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers) { if (!parentItem) { return; } const QList items = allChildItemsRecursive(parentItem); - foreach(QQuickItem *item, items) { + for (QQuickItem *item : items) { sendMouseEvent(item, type, x, y, button, buttons, modifiers); } } void EventGenerator::sendWheelEvent(QQuickItem *item, int x, int y, const QPoint &pixelDelta, const QPoint &angleDelta, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers) { if (!item || !item->window()) { return; } QPointF pos(x, y); QPointF globalPos(item->window()->mapToGlobal(item->mapToScene(pos).toPoint())); QWheelEvent ev(pos, globalPos, pixelDelta, angleDelta, /* qt4Delta */ 0, /* qt4Orientation */ Qt::Horizontal, buttons, modifiers); QGuiApplication::sendEvent(item, &ev); } void EventGenerator::sendWheelEventRecursive(QQuickItem *parentItem, int x, int y, const QPoint &pixelDelta, const QPoint &angleDelta, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers) { if (!parentItem) { return; } const QList items = allChildItemsRecursive(parentItem); - foreach(QQuickItem *item, items) { + for (QQuickItem *item : items) { sendWheelEvent(item, x, y, pixelDelta, angleDelta, buttons, modifiers); } } void EventGenerator::sendGrabEvent(QQuickItem *item, EventGenerator::GrabEvent type) { if (!item) { return; } QQuickWindow *win = item->window(); if (!win) { return; } switch (type) { case GrabMouse: item->grabMouse(); break; case UngrabMouse: { QEvent ev(QEvent::UngrabMouse); win->sendEvent(item, &ev); return; } default: return; } } void EventGenerator::sendGrabEventRecursive(QQuickItem *parentItem, EventGenerator::GrabEvent type) { if (!parentItem) { return; } const QList items = allChildItemsRecursive(parentItem); - foreach(QQuickItem *item, items) { + for (QQuickItem *item : items) { sendGrabEvent(item, type); } } QList EventGenerator::allChildItemsRecursive(QQuickItem *parentItem) { QList itemList; - itemList.append(parentItem->childItems()); + const auto childsItems = parentItem->childItems(); + itemList.append(childsItems); - foreach(QQuickItem *childItem, parentItem->childItems()) { + + for (QQuickItem *childItem : childsItems) { itemList.append(allChildItemsRecursive(childItem)); } return itemList; } diff --git a/src/qmlcontrols/kquickcontrolsaddons/mouseeventlistener.cpp b/src/qmlcontrols/kquickcontrolsaddons/mouseeventlistener.cpp index 10aa2f7..3e5f65e 100644 --- a/src/qmlcontrols/kquickcontrolsaddons/mouseeventlistener.cpp +++ b/src/qmlcontrols/kquickcontrolsaddons/mouseeventlistener.cpp @@ -1,410 +1,411 @@ /* Copyright 2011 Marco Martin Copyright 2013 Sebastian Kügler This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "mouseeventlistener.h" #include #include #include #include #include #include #include #include MouseEventListener::MouseEventListener(QQuickItem *parent) : QQuickItem(parent), m_pressed(false), m_pressAndHoldEvent(nullptr), m_lastEvent(nullptr), m_containsMouse(false), m_acceptedButtons(Qt::LeftButton) { m_pressAndHoldTimer = new QTimer(this); m_pressAndHoldTimer->setSingleShot(true); connect(m_pressAndHoldTimer, SIGNAL(timeout()), this, SLOT(handlePressAndHold())); qmlRegisterType(); qmlRegisterType(); setFiltersChildMouseEvents(true); setAcceptedMouseButtons(Qt::LeftButton|Qt::RightButton|Qt::MidButton|Qt::XButton1|Qt::XButton2); } MouseEventListener::~MouseEventListener() { } Qt::MouseButtons MouseEventListener::acceptedButtons() const { return m_acceptedButtons; } Qt::CursorShape MouseEventListener::cursorShape() const { return cursor().shape(); } void MouseEventListener::setCursorShape(Qt::CursorShape shape) { if (cursor().shape() == shape) { return; } setCursor(shape); emit cursorShapeChanged(); } void MouseEventListener::setAcceptedButtons(Qt::MouseButtons buttons) { if (buttons == m_acceptedButtons) { return; } m_acceptedButtons = buttons; emit acceptedButtonsChanged(); } void MouseEventListener::setHoverEnabled(bool enable) { if (enable == acceptHoverEvents()) { return; } setAcceptHoverEvents(enable); emit hoverEnabledChanged(enable); } bool MouseEventListener::hoverEnabled() const { return acceptHoverEvents(); } bool MouseEventListener::isPressed() const { return m_pressed; } void MouseEventListener::hoverEnterEvent(QHoverEvent *event) { Q_UNUSED(event); m_containsMouse = true; emit containsMouseChanged(true); } void MouseEventListener::hoverLeaveEvent(QHoverEvent *event) { Q_UNUSED(event); m_containsMouse = false; emit containsMouseChanged(false); } void MouseEventListener::hoverMoveEvent(QHoverEvent * event) { if (m_lastEvent == event) { return; } QQuickWindow *w = window(); QPoint screenPos; if (w) { screenPos = w->mapToGlobal(event->pos()); } KDeclarativeMouseEvent dme(event->pos().x(), event->pos().y(), screenPos.x(), screenPos.y(), Qt::NoButton, Qt::NoButton, event->modifiers(), nullptr); emit positionChanged(&dme); } bool MouseEventListener::containsMouse() const { return m_containsMouse; } void MouseEventListener::mousePressEvent(QMouseEvent *me) { if (m_lastEvent == me || !(me->buttons() & m_acceptedButtons)) { me->setAccepted(false); return; } //FIXME: when a popup window is visible: a click anywhere hides it: but the old qquickitem will continue to think it's under the mouse //doesn't seem to be any good way to properly reset this. //this msolution will still caused a missed click after the popup is gone, but gets the situation unblocked. QPoint viewPosition; if (window()) { viewPosition = window()->position(); } if (!QRectF(mapToScene(QPoint(0, 0)) + viewPosition, QSizeF(width(), height())).contains(me->screenPos())) { me->ignore(); return; } m_buttonDownPos = me->screenPos(); KDeclarativeMouseEvent dme(me->pos().x(), me->pos().y(), me->screenPos().x(), me->screenPos().y(), me->button(), me->buttons(), me->modifiers(), screenForGlobalPos(me->globalPos())); if (!m_pressAndHoldEvent) { m_pressAndHoldEvent = new KDeclarativeMouseEvent(me->pos().x(), me->pos().y(), me->screenPos().x(), me->screenPos().y(), me->button(), me->buttons(), me->modifiers(), screenForGlobalPos(me->globalPos())); } m_pressed = true; emit pressed(&dme); emit pressedChanged(); if (dme.isAccepted()) { me->setAccepted(true); return; } m_pressAndHoldTimer->start(QGuiApplication::styleHints()->mousePressAndHoldInterval()); } void MouseEventListener::mouseMoveEvent(QMouseEvent *me) { if (m_lastEvent == me || !(me->buttons() & m_acceptedButtons)) { me->setAccepted(false); return; } if (QPointF(me->screenPos() - m_buttonDownPos).manhattanLength() > QGuiApplication::styleHints()->startDragDistance() && m_pressAndHoldTimer->isActive()) { m_pressAndHoldTimer->stop(); } KDeclarativeMouseEvent dme(me->pos().x(), me->pos().y(), me->screenPos().x(), me->screenPos().y(), me->button(), me->buttons(), me->modifiers(), screenForGlobalPos(me->globalPos())); emit positionChanged(&dme); if (dme.isAccepted()) { me->setAccepted(true); } } void MouseEventListener::mouseReleaseEvent(QMouseEvent *me) { if (m_lastEvent == me) { me->setAccepted(false); return; } KDeclarativeMouseEvent dme(me->pos().x(), me->pos().y(), me->screenPos().x(), me->screenPos().y(), me->button(), me->buttons(), me->modifiers(), screenForGlobalPos(me->globalPos())); m_pressed = false; emit released(&dme); emit pressedChanged(); if (boundingRect().contains(me->pos()) && m_pressAndHoldTimer->isActive()) { emit clicked(&dme); m_pressAndHoldTimer->stop(); } if (dme.isAccepted()) { me->setAccepted(true); } } void MouseEventListener::wheelEvent(QWheelEvent *we) { if (m_lastEvent == we) { return; } KDeclarativeWheelEvent dwe(we->pos(), we->globalPos(), we->delta(), we->buttons(), we->modifiers(), we->orientation()); emit wheelMoved(&dwe); } void MouseEventListener::handlePressAndHold() { if (m_pressed) { emit pressAndHold(m_pressAndHoldEvent); delete m_pressAndHoldEvent; m_pressAndHoldEvent = nullptr; } } bool MouseEventListener::childMouseEventFilter(QQuickItem *item, QEvent *event) { if (!isEnabled()) { return false; } //don't filter other mouseeventlisteners if (qobject_cast(item)) { return false; } switch (event->type()) { case QEvent::MouseButtonPress: { m_lastEvent = event; QMouseEvent *me = static_cast(event); if (!(me->buttons() & m_acceptedButtons)) { break; } //the parent will receive events in its own coordinates const QPointF myPos = mapFromScene(me->windowPos()); KDeclarativeMouseEvent dme(myPos.x(), myPos.y(), me->screenPos().x(), me->screenPos().y(), me->button(), me->buttons(), me->modifiers(), screenForGlobalPos(me->globalPos())); delete m_pressAndHoldEvent; m_pressAndHoldEvent = new KDeclarativeMouseEvent(myPos.x(), myPos.y(), me->screenPos().x(), me->screenPos().y(), me->button(), me->buttons(), me->modifiers(), screenForGlobalPos(me->globalPos())); //qDebug() << "pressed in sceneEventFilter"; m_buttonDownPos = me->screenPos(); m_pressed = true; emit pressed(&dme); emit pressedChanged(); if (dme.isAccepted()) { return true; } m_pressAndHoldTimer->start(QGuiApplication::styleHints()->mousePressAndHoldInterval()); break; } case QEvent::HoverMove: { if (!acceptHoverEvents()) { break; } m_lastEvent = event; QHoverEvent *he = static_cast(event); const QPointF myPos = item->mapToItem(this, he->pos()); QQuickWindow *w = window(); QPoint screenPos; if (w) { screenPos = w->mapToGlobal(myPos.toPoint()); } KDeclarativeMouseEvent dme(myPos.x(), myPos.y(), screenPos.x(), screenPos.y(), Qt::NoButton, Qt::NoButton, he->modifiers(), nullptr); //qDebug() << "positionChanged..." << dme.x() << dme.y(); emit positionChanged(&dme); if (dme.isAccepted()) { return true; } break; } case QEvent::MouseMove: { m_lastEvent = event; QMouseEvent *me = static_cast(event); if (!(me->buttons() & m_acceptedButtons)) { break; } const QPointF myPos = mapFromScene(me->windowPos()); KDeclarativeMouseEvent dme(myPos.x(), myPos.y(), me->screenPos().x(), me->screenPos().y(), me->button(), me->buttons(), me->modifiers(), screenForGlobalPos(me->globalPos())); //qDebug() << "positionChanged..." << dme.x() << dme.y(); //stop the pressandhold if mouse moved enough if (QPointF(me->screenPos() - m_buttonDownPos).manhattanLength() > QGuiApplication::styleHints()->startDragDistance() && m_pressAndHoldTimer->isActive()) { m_pressAndHoldTimer->stop(); //if the mouse moves and we are waiting to emit a press and hold event, update the co-ordinates //as there is no update function, delete the old event and create a new one } else if (m_pressAndHoldEvent) { delete m_pressAndHoldEvent; m_pressAndHoldEvent = new KDeclarativeMouseEvent(myPos.x(), myPos.y(), me->screenPos().x(), me->screenPos().y(), me->button(), me->buttons(), me->modifiers(), screenForGlobalPos(me->globalPos())); } emit positionChanged(&dme); if (dme.isAccepted()) { return true; } break; } case QEvent::MouseButtonRelease: { m_lastEvent = event; QMouseEvent *me = static_cast(event); const QPointF myPos = mapFromScene(me->windowPos()); KDeclarativeMouseEvent dme(myPos.x(), myPos.y(), me->screenPos().x(), me->screenPos().y(), me->button(), me->buttons(), me->modifiers(), screenForGlobalPos(me->globalPos())); m_pressed = false; emit released(&dme); emit pressedChanged(); if (QPointF(me->screenPos() - m_buttonDownPos).manhattanLength() <= QGuiApplication::styleHints()->startDragDistance() && m_pressAndHoldTimer->isActive()) { emit clicked(&dme); m_pressAndHoldTimer->stop(); } if (dme.isAccepted()) { return true; } break; } case QEvent::UngrabMouse: { m_lastEvent = event; handleUngrab(); break; } case QEvent::Wheel: { m_lastEvent = event; QWheelEvent *we = static_cast(event); KDeclarativeWheelEvent dwe(we->pos(), we->globalPos(), we->delta(), we->buttons(), we->modifiers(), we->orientation()); emit wheelMoved(&dwe); break; } default: break; } return QQuickItem::childMouseEventFilter(item, event); // return false; } QScreen* MouseEventListener::screenForGlobalPos(const QPoint& globalPos) { - foreach(QScreen *screen, QGuiApplication::screens()) { + const auto screens = QGuiApplication::screens(); + for (QScreen *screen : screens) { if (screen->geometry().contains(globalPos)) { return screen; } } return nullptr; } void MouseEventListener::mouseUngrabEvent() { handleUngrab(); QQuickItem::mouseUngrabEvent(); } void MouseEventListener::touchUngrabEvent() { handleUngrab(); QQuickItem::touchUngrabEvent(); } void MouseEventListener::handleUngrab() { if (m_pressed) { m_pressAndHoldTimer->stop(); m_pressed = false; emit pressedChanged(); emit canceled(); } }