diff --git a/src/blackgui/dropbase.cpp b/src/blackgui/dropbase.cpp new file mode 100644 index 000000000..2980f67f9 --- /dev/null +++ b/src/blackgui/dropbase.cpp @@ -0,0 +1,56 @@ +/* Copyright (C) 2015 + * swift project Community / Contributors + * + * This file is part of swift Project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "dropbase.h" +#include "guiutility.h" + +using namespace BlackMisc; + +namespace BlackGui +{ + CDropBase::CDropBase() + { } + + void CDropBase::setAcceptedMetaTypeIds(const QList &ids) + { + m_acceptedMetaTypes = ids; + } + + void CDropBase::addAcceptedMetaTypeId(int id) + { + m_acceptedMetaTypes.append(id); + } + + bool CDropBase::isDropAllowed() const + { + return m_allowDrop; + } + + void CDropBase::allowDrop(bool allowed) + { + this->m_allowDrop = allowed; + } + + bool CDropBase::acceptDrop(const QMimeData *mime) const + { + Q_ASSERT_X(!this->m_acceptedMetaTypes.isEmpty(), Q_FUNC_INFO, "no accepted meta type ids"); + if (m_acceptedMetaTypes.isEmpty()) { return false; } + if (!m_allowDrop || !CGuiUtility::hasSwiftVariantMimeType(mime)) { return false; } + int metaTypeId = CGuiUtility::metaTypeIdFromSwiftDragAndDropData(mime); + if (metaTypeId == QMetaType::UnknownType) { return false; } + bool accept = m_acceptedMetaTypes.contains(metaTypeId); + return accept; + } + + CVariant CDropBase::toCVariant(const QMimeData *mime) const + { + return CGuiUtility::fromSwiftDragAndDropData(mime); + } + +} // ns diff --git a/src/blackgui/dropbase.h b/src/blackgui/dropbase.h new file mode 100644 index 000000000..986c67fca --- /dev/null +++ b/src/blackgui/dropbase.h @@ -0,0 +1,56 @@ +/* Copyright (C) 2015 + * swift project Community / Contributors + * + * This file is part of swift Project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#ifndef BLACKGUI_DROPBASE_H +#define BLACKGUI_DROPBASE_H + +#include "blackmisc/variant.h" +#include +#include + +namespace BlackGui +{ + /*! + * Utilities for dropping swift value objects + */ + class CDropBase + { + public: + //! Set text for drop site + void setInfoText(const QString &dropSiteText); + + //! Accepted ids + void setAcceptedMetaTypeIds(const QList &ids); + + //! Accepted ids + void addAcceptedMetaTypeId(int id); + + //! Drop allowed + bool isDropAllowed() const; + + //! Drop allowed + void allowDrop(bool allowed); + + //! Mime data to CVariant (normally encapsulating a value object) + BlackMisc::CVariant toCVariant(const QMimeData *mime) const; + + protected: + CDropBase(); + + //! Accept drop + bool acceptDrop(const QMimeData *mime) const; + + private: + bool m_allowDrop = true; //!< dropping allowed? + QList m_acceptedMetaTypes; //!< accepted meta types + }; + +} // ns + +#endif // guard diff --git a/src/blackgui/dropsite.cpp b/src/blackgui/dropsite.cpp new file mode 100644 index 000000000..e69f0a4a9 --- /dev/null +++ b/src/blackgui/dropsite.cpp @@ -0,0 +1,75 @@ +/* Copyright (C) 2015 + * swift project Community / Contributors + * + * This file is part of swift Project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "dropsite.h" +#include + +using namespace BlackMisc; + +namespace BlackGui +{ + CDropSite::CDropSite(QWidget *parent) : QLabel(parent) + { + setFrameStyle(QFrame::Sunken | QFrame::StyledPanel); + setAlignment(Qt::AlignCenter); + setAcceptDrops(true); + this->setInfoText(tr("")); + } + + void CDropSite::setInfoText(const QString &dropSiteText) + { + this->m_infoText = dropSiteText; + this->resetText(); + } + + void CDropSite::allowDrop(bool allowed) + { + CDropBase::allowDrop(allowed); + this->setEnabled(allowed); + this->setVisible(allowed); + } + + void CDropSite::resetText() + { + setText(this->m_infoText); + } + + void CDropSite::dragEnterEvent(QDragEnterEvent *event) + { + if (!event || !acceptDrop(event->mimeData())) { return; } + setBackgroundRole(QPalette::Highlight); + event->acceptProposedAction(); + } + + void CDropSite::dragMoveEvent(QDragMoveEvent *event) + { + if (!event || !acceptDrop(event->mimeData())) { return; } + setBackgroundRole(QPalette::Highlight); + event->acceptProposedAction(); + } + + void CDropSite::dragLeaveEvent(QDragLeaveEvent *event) + { + if (!event || !m_allowDrop) { return; } + resetText(); + event->accept(); + } + + void CDropSite::dropEvent(QDropEvent *event) + { + if (!event || !acceptDrop(event->mimeData())) { return; } + CVariant valueVariant(toCVariant(event->mimeData())); + if (valueVariant.isValid()) + { + emit droppedValueObject(valueVariant); + } + this->resetText(); + } + +} // ns diff --git a/src/blackgui/dropsite.h b/src/blackgui/dropsite.h new file mode 100644 index 000000000..76db0af1d --- /dev/null +++ b/src/blackgui/dropsite.h @@ -0,0 +1,68 @@ +/* Copyright (C) 2015 + * swift project Community / Contributors + * + * This file is part of swift Project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#ifndef BLACKGUI_DROPSITE_H +#define BLACKGUI_DROPSITE_H + +#include "blackmisc/variant.h" +#include "blackgui/dropbase.h" +#include +#include + +namespace BlackGui +{ + /*! + * Area where items can be dropped + * \remark inspired by Qt example: http://doc.qt.io/qt-4.8/qt-draganddrop-dropsite-example.html + */ + class CDropSite : + public QLabel, + public CDropBase + { + Q_OBJECT + + public: + //! Constructor + CDropSite(QWidget *parent = nullptr); + + //! Set text for drop site + void setInfoText(const QString &dropSiteText); + + //! Drop allowed + void allowDrop(bool allowed); + + signals: + //! Dropped value object + void droppedValueObject(const BlackMisc::CVariant &droppedObject); + + protected: + //! \copydoc QWidget::dragEnterEvent + virtual void dragEnterEvent(QDragEnterEvent *event) override; + + //! \copydoc QWidget::dragMoveEvent + virtual void dragMoveEvent(QDragMoveEvent *event) override; + + //! \copydoc QWidget::dragLeaveEvent + virtual void dragLeaveEvent(QDragLeaveEvent *event) override; + + //! \copydoc QWidget::dropEvent + virtual void dropEvent(QDropEvent *event) override; + + private: + //! Clear + void resetText(); + + QString m_infoText; //!< text displayed for drop site + bool m_allowDrop = true; //!< dropping allowed? + QList m_acceptedMetaTypes; //!< accepted meta types + }; + +} // ns + +#endif // guard diff --git a/src/blackgui/guiutility.cpp b/src/blackgui/guiutility.cpp index 25ff8eb5a..33aa91fe0 100644 --- a/src/blackgui/guiutility.cpp +++ b/src/blackgui/guiutility.cpp @@ -16,6 +16,11 @@ #include #include #include +#include +#include +#include +#include +#include using namespace BlackCore; using namespace BlackMisc; @@ -111,6 +116,86 @@ namespace BlackGui return t == c; } + bool CGuiUtility::setComboBoxValueByStartingString(QComboBox *box, const QString &candidate, const QString &unspecified) + { + if (!box) { return false; } + if (!candidate.isEmpty()) + { + for (int i = 0; i < box->count(); i++) + { + QString t(box->itemText(i)); + if (t.startsWith(candidate, Qt::CaseInsensitive)) + { + box->setCurrentIndex(i); + return true; + } + } + } + + // not found + if (unspecified.isEmpty()) { return false; } + for (int i = 0; i < box->count(); i++) + { + QString t(box->itemText(i)); + if (t.startsWith(unspecified, Qt::CaseInsensitive)) + { + box->setCurrentIndex(i); + return true; + } + } + return false; + } + + bool CGuiUtility::hasSwiftVariantMimeType(const QMimeData *mime) + { + return mime && mime->hasFormat(swiftJsonDragAndDropMimeType()); + } + + CVariant CGuiUtility::fromSwiftDragAndDropData(const QMimeData *mime) + { + if (hasSwiftVariantMimeType(mime)) + { + return fromSwiftDragAndDropData(mime->data(swiftJsonDragAndDropMimeType())); + } + return CVariant(); + } + + CVariant CGuiUtility::fromSwiftDragAndDropData(const QByteArray &utf8Data) + { + if (utf8Data.isEmpty()) { return CVariant(); } + QJsonDocument jsonDoc(QJsonDocument::fromJson(utf8Data)); + QJsonObject jsonObj(jsonDoc.object()); + QString typeName(jsonObj.value("type").toString()); + int typeId = QMetaType::type(qPrintable(typeName)); + + // check if a potential valid value object + if (typeName.isEmpty() || typeId == QMetaType::UnknownType) { return CVariant(); } + + CVariant valueVariant; + valueVariant.convertFromJson(jsonObj); + return valueVariant; + } + + int CGuiUtility::metaTypeIdFromSwiftDragAndDropData(const QMimeData *mime) + { + static const int Unknown = static_cast(QMetaType::UnknownType); + + if (!hasSwiftVariantMimeType(mime)) { return Unknown; } + QJsonDocument jsonDoc(QJsonDocument::fromJson(mime->data(swiftJsonDragAndDropMimeType()))); + QJsonObject jsonObj(jsonDoc.object()); + if (jsonObj.isEmpty()) { return Unknown; } + QString typeName(jsonObj.value("type").toString()); + if (typeName.isEmpty()) { return Unknown; } + int typeId = QMetaType::type(qPrintable(typeName)); + return typeId; + } + + const QString &CGuiUtility::swiftJsonDragAndDropMimeType() + { + static const QString m("text/json/swift"); + return m; + } + QWidgetList CGuiUtility::topLevelApplicationWidgetsWithName() { QWidgetList tlw = QApplication::topLevelWidgets(); diff --git a/src/blackgui/guiutility.h b/src/blackgui/guiutility.h index 2235b6c87..db25ea778 100644 --- a/src/blackgui/guiutility.h +++ b/src/blackgui/guiutility.h @@ -16,6 +16,7 @@ #include "blackmisc/icon.h" #include "enableforframelesswindow.h" #include +#include #include namespace BlackGui @@ -67,6 +68,24 @@ namespace BlackGui //! Leninet / relaxed static bool lenientTitleComparison(const QString &title, const QString &comparison); + //! Find best match in comboBox + static bool setComboBoxValueByStartingString(QComboBox *box, const QString &candidate, const QString &unspecified = QString()); + + //! Mime data with swift type + static bool hasSwiftVariantMimeType(const QMimeData *mime); + + //! From text dropped + static BlackMisc::CVariant fromSwiftDragAndDropData(const QMimeData *mime); + + //! From text dropped + static BlackMisc::CVariant fromSwiftDragAndDropData(const QByteArray &utf8Data); + + //! Meta type id from dropped data + static int metaTypeIdFromSwiftDragAndDropData(const QMimeData *mime); + + //! Metatype + static const QString &swiftJsonDragAndDropMimeType(); + private: //! Constructor, use static methods only CGuiUtility() {}