diff --git a/src/scriptengines/qml/plasmoid/containmentinterface.h b/src/scriptengines/qml/plasmoid/containmentinterface.h --- a/src/scriptengines/qml/plasmoid/containmentinterface.h +++ b/src/scriptengines/qml/plasmoid/containmentinterface.h @@ -215,13 +215,17 @@ private: void clearDataForMimeJob(KIO::Job *job); void setAppletArgs(Plasma::Applet *applet, const QString &mimetype, const QString &data); + void showDropjobMenu(KIO::DropJob *dropJob, QPoint dropPoint); WallpaperInterface *m_wallpaperInterface; QList m_appletInterfaces; QHash m_dropPoints; QHash m_dropMenus; QHash m_dropCallbacks; QHash m_dropJobs; + QList m_dropActions; + QList m_urlsHaveSameMimename; + bool m_multipleMimenames; KActivities::Info *m_activityInfo; QPointer m_containment; QPointer m_contextMenu; diff --git a/src/scriptengines/qml/plasmoid/containmentinterface.cpp b/src/scriptengines/qml/plasmoid/containmentinterface.cpp --- a/src/scriptengines/qml/plasmoid/containmentinterface.cpp +++ b/src/scriptengines/qml/plasmoid/containmentinterface.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -433,6 +434,10 @@ return; } + m_multipleMimenames = false; + m_urlsHaveSameMimename.clear(); + m_dropActions.clear(); + //const QMimeData *mimeData = data; qDebug() << "Arrived mimeData" << mimeData->urls() << mimeData->formats() << "at" << x << ", " << y; @@ -455,36 +460,47 @@ //TODO: collect the mimetypes of available script engines and offer // to create widgets out of the matching URLs, if any const QList urls = KUrlMimeData::urlsFromMimeData(mimeData); + QMenu *choices = nullptr; + + if (!urls.at(0).isLocalFile()) { + QApplication::setOverrideCursor(Qt::WaitCursor); + } + + if (!dropJob) { + choices = new QMenu(i18n("Content dropped")); + + if (choices->winId()) { + choices->windowHandle()->setTransientParent(window()); + } + } + + QMimeDatabase db; + QSet mimenames; + foreach (const QUrl &url, urls) { - QMimeDatabase db; const QMimeType &mime = db.mimeTypeForUrl(url); QString mimeName = mime.name(); - QVariantList args; - args << url.url(); - qDebug() << "can decode" << mimeName << args; - - // It may be a directory or a file, let's stat - KIO::JobFlags flags = KIO::HideProgressInfo; - KIO::MimetypeJob *job = KIO::mimetype(url, flags); - m_dropPoints[job] = QPoint(x, y); - - QObject::connect(job, &KJob::result, this, &ContainmentInterface::dropJobResult); - QObject::connect(job, SIGNAL(mimetype(KIO::Job*,QString)), - this, SLOT(mimeTypeRetrieved(KIO::Job*,QString))); + m_urlsHaveSameMimename << url; + mimenames << mimeName; + qDebug() << "can decode" << mimeName; // << args; + } - if (dropJob) { - m_dropJobs[job] = dropJob; - } else { - QMenu *choices = new QMenu(i18n("Content dropped")); - if (choices->winId()) { - choices->windowHandle()->setTransientParent(window()); - } - choices->addAction(QIcon::fromTheme(QStringLiteral("process-working")), i18n("Fetching file type...")); - choices->popup(window() ? window()->mapToGlobal(QPoint(x, y)) : QPoint(x, y)); + if (mimenames.size() > 1) { + m_multipleMimenames = true; + } + // It may be a directory or a file, let's stat + KIO::JobFlags flags = KIO::HideProgressInfo; + KIO::MimetypeJob *job = KIO::mimetype(m_urlsHaveSameMimename.at(0), flags); + m_dropPoints[job] = QPoint(x, y); - m_dropMenus[job] = choices; - } + if (dropJob) { + m_dropJobs[job] = dropJob; + } else { + m_dropMenus[job] = choices; } + QObject::connect(job, &KJob::result, this, &ContainmentInterface::dropJobResult); + QObject::connect(job, SIGNAL(mimetype(KIO::Job*, QString)), + this, SLOT(mimeTypeRetrieved(KIO::Job*,QString))); } else { QStringList formats = mimeData->formats(); @@ -508,7 +524,7 @@ QString selectedPlugin; if (seenPlugins.isEmpty()) { - // do nothing + //do nothing //directly create if only one offer only if the containment didn't pass an existing plugin } else if (seenPlugins.count() == 1) { selectedPlugin = seenPlugins.constBegin().key(); @@ -548,7 +564,6 @@ //if the menu was created by ourselves, delete it if (choices) { QAction *choice = choices->exec(window() ? window()->mapToGlobal(QPoint(x, y)) : QPoint(x, y)); - delete choices; } else { Q_ASSERT(dropJob); @@ -561,16 +576,30 @@ void ContainmentInterface::clearDataForMimeJob(KIO::Job *job) { QObject::disconnect(job, nullptr, this, nullptr); + auto dropJob = m_dropJobs.value(job); + auto dropPoint = m_dropPoints.value(job); + m_dropPoints.remove(job); QMenu *choices = m_dropMenus.take(job); m_dropJobs.remove(job); job->kill(); + + if (choices) { + choices->popup(dropPoint); + } else { + showDropjobMenu(dropJob, dropPoint); + } + + if (!m_urlsHaveSameMimename.at(0).isLocalFile()) { + QApplication::restoreOverrideCursor(); + } } void ContainmentInterface::dropJobResult(KJob *job) { if (job->error()) { qDebug() << "ERROR" << job->error() << ' ' << job->errorString(); + clearDataForMimeJob(dynamic_cast(job)); } } @@ -584,6 +613,7 @@ clearDataForMimeJob(job); return; } + QList appletList = Plasma::PluginLoader::self()->listAppletMetaDataForUrl(tjob->url()); if (mimetype.isEmpty() && appletList.isEmpty()) { clearDataForMimeJob(job); @@ -602,8 +632,8 @@ } QMenu *choices = m_dropMenus.value(tjob); - QList dropActions; KIO::DropJob *dropJob = m_dropJobs.value(tjob); + auto dropPoint = m_dropPoints.value(job); if (!choices && !dropJob) { qDebug() << "Bailing out. No QMenu or drop job found for this job."; @@ -629,22 +659,22 @@ const bool isPlasmaPackage = (mimetype == QLatin1String("application/x-plasma")); - if (!appletList.isEmpty() || !wallpaperList.isEmpty() || isPlasmaPackage) { + if ((!appletList.isEmpty() || !wallpaperList.isEmpty() || isPlasmaPackage) && !m_multipleMimenames) { QAction *installPlasmaPackageAction = nullptr; if (isPlasmaPackage) { if (choices) { choices->addSection(i18n("Plasma Package")); installPlasmaPackageAction = choices->addAction(QIcon::fromTheme(QStringLiteral("application-x-plasma")), i18n("Install")); } else { QAction *action = new QAction(i18n("Plasma Package"), nullptr); action->setSeparator(true); - dropActions << action; + m_dropActions << action; installPlasmaPackageAction = new QAction(QIcon::fromTheme(QStringLiteral("application-x-plasma")), i18n("Install"), nullptr); Q_ASSERT(dropJob); - dropActions << installPlasmaPackageAction; - dropJob->setApplicationActions(dropActions); + m_dropActions << installPlasmaPackageAction; } + const QString &packagePath = tjob->url().toLocalFile(); connect(installPlasmaPackageAction, &QAction::triggered, this, [this, posi, packagePath]() { using namespace KPackage; @@ -688,7 +718,7 @@ } else { QAction *action = new QAction(i18n("Widgets"), nullptr); action->setSeparator(true); - dropActions << action; + m_dropActions << action; } foreach (const auto &info, appletList) { const QString actionText = i18nc("Add widget", "Add %1", info.name()); @@ -699,7 +729,7 @@ if (choices) { choices->addAction(action); } - dropActions << action; + m_dropActions << action; action->setData(info.pluginId()); const QUrl url = tjob->url(); connect(action, &QAction::triggered, this, [this, action, posi, mimetype, url]() { @@ -712,7 +742,7 @@ if (choices) { choices->addAction(action); } - dropActions << action; + m_dropActions << action; action->setData(QStringLiteral("org.kde.plasma.icon")); const QUrl url = tjob->url(); connect(action, &QAction::triggered, this, [this, action, posi, mimetype, url](){ @@ -728,7 +758,7 @@ } else { QAction *action = new QAction(i18n("Wallpaper"), nullptr); action->setSeparator(true); - dropActions << action; + m_dropActions << action; } QMap sorted; @@ -746,7 +776,7 @@ if (choices) { choices->addAction(action); } - dropActions << action; + m_dropActions << action; actionsToWallpapers.insert(action, info.pluginId()); const QUrl url = tjob->url(); connect(action, &QAction::triggered, this, [this, url]() { @@ -757,7 +787,6 @@ }); } } - } else { //case in which we created the menu ourselves, just the "fetching type entry, directly create the icon applet if (choices) { @@ -771,10 +800,10 @@ } else { QAction *sep = new QAction(i18n("Widgets"), nullptr); sep->setSeparator(true); - dropActions << sep; + m_dropActions << sep; // we can at least create an icon as a link to the URL action = new QAction(i18nc("Add icon widget", "Add Icon"), nullptr); - dropActions << action; + m_dropActions << action; } const QUrl url = tjob->url(); @@ -785,16 +814,6 @@ } } - if (choices) { - // HACK If the QMenu becomes empty at any point after the "determining mimetype" - // popup was shown, it self-destructs, does not matter if we call clear() or remove - // the action manually, hence we remove the aforementioned item after we populated the menu - choices->removeAction(choices->actions().at(0)); - choices->exec(); - } else { - dropJob->setApplicationActions(dropActions); - } - clearDataForMimeJob(tjob); } } @@ -1123,8 +1142,8 @@ desktopMenu->addAction(appletAlternatives); } } - desktopMenu->addSeparator(); + if (m_containment->containmentType() == Plasma::Types::DesktopContainment) { auto action = m_containment->corona()->actions()->action(QStringLiteral("edit mode")); if (action) { @@ -1201,5 +1220,9 @@ return loading; } +void ContainmentInterface::showDropjobMenu(KIO::DropJob *dropJob, QPoint dropPos) { + dropJob->setApplicationActions(m_dropActions); + dropJob->showMenu(dropPos); +} #include "moc_containmentinterface.cpp"