I've been hacking on dropping URLs onto Plasma again, and although I got a bit further, I'm running into problems still. Let me first explain the concept:
- Something is dropped onto Plasma - we don't understand its mimetype since it's remote content - we open a QMenu stating "fetching mimetype" or similar - the dropEvent and the QMenu are stored in a QHash, indexed by a TransferJob that's started to retrieve the mimetype - We catch the signal mimeType(KJob*, QString) - We get the dropEvent associated with this "drop" using dropEvent[job] (We need this for the coordinates to create the applet at) - We get the QMenu associated using dropMenu[job] (We want to recycle this QMenu, clear it and insert our choices so the user can pick an applet to load) - Profit. Wait, no profit yet. :/ While the mechanism works fine for the dropEvent, it looks like the QMenu vanishes somehow, dropMenu[job] returns a null-pointer. I assume the QMenu is taking a break and going on a long vacation there somewhere. I'm a bit puzzled by this, can anyone enlighten me? Dirty, dirty patch attached. Feedback is of course welcome. -- sebas http://www.kde.org | http://vizZzion.org | GPG Key ID: 9119 0EF9
Index: widgets/scrollbar.cpp =================================================================== --- widgets/scrollbar.cpp (revision 961916) +++ widgets/scrollbar.cpp (working copy) @@ -43,6 +43,9 @@ scrollbar->resize(scrollbar->sizeHint()); connect(scrollbar, SIGNAL(valueChanged(int)), this, SIGNAL(valueChanged(int))); + setFlag(QGraphicsItem::ItemClipsChildrenToShape, true); + setFlag(QGraphicsItem::ItemClipsToShape, true); + } ScrollBar::~ScrollBar() Index: widgets/scrollwidget.cpp =================================================================== --- widgets/scrollwidget.cpp (revision 961916) +++ widgets/scrollwidget.cpp (working copy) @@ -41,6 +41,7 @@ ScrollWidgetPrivate(ScrollWidget *parent) : q(parent), widget(0), + layout(0), dragging(false) { } @@ -51,6 +52,9 @@ void adjustScrollbars() { + if (!layout) { + return; + } verticalScrollBar->nativeWidget()->setMaximum(qMax(0, int((widget->size().height() - scrollingWidget->size().height())/10))); if (verticalScrollBarPolicy == Qt::ScrollBarAlwaysOff || Index: private/containment_p.h =================================================================== --- private/containment_p.h (revision 961916) +++ private/containment_p.h (working copy) @@ -80,6 +80,7 @@ void containmentAppletAnimationComplete(QGraphicsItem *item, Plasma::Animator::Animation anim); void zoomIn(); void zoomOut(); + void mimeTypeRetrieved(KIO::Job *job, const QString &mimetype); void containmentActions(KMenu &desktopMenu); void appletActions(KMenu &desktopMenu, Applet *applet, bool includeApplet); bool showContextMenu(const QPointF &point, const QPoint &screenPos, bool includeApplet); @@ -115,6 +116,17 @@ Containment::Type type; static bool s_positioning; bool drawWallpaper; + QRectF dropGeometry; + QHash<KIO::Job*, QGraphicsSceneDragDropEvent*> dropEvents; + QHash<KIO::Job*, QMenu*> dropMenus; + + //public Q_SLOTS: + /** + * This slot is called when the 'stat' after a job event has finished. + */ + //void mimeTypeRetrieved(KIO::Job *job, const QString &mimetype); + + }; } // Plasma namespace Index: containment.h =================================================================== --- containment.h (revision 961916) +++ containment.h (working copy) @@ -32,6 +32,11 @@ #include <plasma/applet.h> #include <plasma/animator.h> +namespace KIO +{ + class Job; +} + namespace Plasma { @@ -542,7 +547,7 @@ private: Q_PRIVATE_SLOT(d, void appletDestroyed(Plasma::Applet*)) - Q_PRIVATE_SLOT(d, void containmentAppletAnimationComplete(QGraphicsItem *item, + Q_PRIVATE_SLOT(d, void containmentAppletAnimationComplete(QGraphicsItem *, Plasma::Animator::Animation anim)) Q_PRIVATE_SLOT(d, void triggerShowAddWidgets()) Q_PRIVATE_SLOT(d, void handleDisappeared(AppletHandle *handle)) @@ -550,6 +555,7 @@ Q_PRIVATE_SLOT(d, void zoomIn()) Q_PRIVATE_SLOT(d, void zoomOut()) Q_PRIVATE_SLOT(d, void requestConfiguration()) + Q_PRIVATE_SLOT(d, void mimeTypeRetrieved(KIO::Job *, const QString &)) Q_PRIVATE_SLOT(d, void updateToolBoxVisibility()) friend class Applet; Index: containment.cpp =================================================================== --- containment.cpp (revision 961916) +++ containment.cpp (working copy) @@ -42,6 +42,9 @@ #include <kstandarddirs.h> #include <ktemporaryfile.h> #include <kwindowsystem.h> +#include "kio/jobclasses.h" // for KIO::JobFlags +#include "kio/job.h" +#include "kio/scheduler.h" #include "animator.h" #include "context.h" @@ -546,7 +549,7 @@ //if there is only one, don't create a submenu if(enabled < 2) { foreach(QAction *action, containmentMenu->actions()) { - desktopMenu.addAction(action); + desktopMenu.addAction(action); } } else { desktopMenu.addMenu(containmentMenu); @@ -972,13 +975,13 @@ } QString appletMimetype(corona() ? corona()->appletMimeType() : QString()); + kDebug() << "Something dropped mimetype, -data: " << appletMimetype << event->mimeData()->text(); if (!appletMimetype.isEmpty() && event->mimeData()->hasFormat(appletMimetype)) { QString data = event->mimeData()->data(appletMimetype); QStringList appletNames = data.split('\n', QString::SkipEmptyParts); - foreach (const QString &appletName, appletNames) { - //kDebug() << "doing" << appletName; + kDebug() << "doing" << appletName; QRectF geom(mapFromScene(event->scenePos()), QSize(0, 0)); addApplet(appletName, QVariantList(), geom); } @@ -997,22 +1000,29 @@ } else if (KUrl::List::canDecode(event->mimeData())) { //TODO: collect the mimetypes of available script engines and offer // to create widgets out of the matching URLs, if any + // this is not a TODO anymore? KUrl::List urls = KUrl::List::fromMimeData(event->mimeData()); foreach (const KUrl &url, urls) { KMimeType::Ptr mime = KMimeType::findByUrl(url); QString mimeName = mime->name(); - QRectF geom(event->pos(), QSize()); QVariantList args; args << url.url(); - // kDebug() << mimeName; + kDebug() << "can decode" << mimeName << args; + kDebug() << "protocol:" << url.protocol(); KPluginInfo::List appletList = Applet::listAppletInfoForMimetype(mimeName); - if (!appletList.isEmpty()) { - //TODO: should we show a dialog here to choose which plasmoid load if - //!appletList.isEmpty() + // FIXME: This is a shortcut until I find a good solution to choose an applet for + // akonadi: urls, for now hardcode it to emailmessage + if (url.protocol() == "akonadi") { + addApplet("emailmessage", args, QRectF(event->pos(), QSize())); + + } else if (!appletList.isEmpty()) { + // The mimetype is know, i.e. there are applet that can load this mimetype + // Offer the applets in a popupmenu QMenu choices; QHash<QAction *, QString> actionsToPlugins; foreach (const KPluginInfo &info, appletList) { + kDebug() << info.name(); QAction *action; if (!info.icon().isEmpty()) { action = choices.addAction(KIcon(info.icon()), info.name()); @@ -1021,17 +1031,33 @@ } actionsToPlugins.insert(action, info.pluginName()); + kDebug() << info.pluginName(); } + actionsToPlugins.insert(choices.addAction(i18n("Icon")), "icon"); - actionsToPlugins.insert(choices.addAction(i18n("Icon")), "icon"); QAction *choice = choices.exec(event->screenPos()); if (choice) { - addApplet(actionsToPlugins[choice], args, geom); + addApplet(actionsToPlugins[choice], args, QRectF(event->pos(), QSize())); } - } else if (url.protocol() != "data") { - // We don't try to do anything with data: URIs - // no special applet associated with this mimetype, let's - addApplet("icon", args, geom); + + } else if (url.protocol() != "data") { // Why not data:? + kDebug() << "Not handling" << mimeName << url.url(); + kDebug() << "Let's start a KIO::TransferJob to retrieve the mimetype" << KMimeType::findByUrl(url)->name(); + + + // It may be a directory or a file, let's stat + KIO::JobFlags flags = KIO::HideProgressInfo; + KIO::TransferJob *job = KIO::get(url, KIO::NoReload, flags); + + d->dropEvents[job] = event; + connect(job, SIGNAL(mimetype(KIO::Job *, const QString&)), + this, SLOT(mimeTypeRetrieved(KIO::Job *, const QString&))); + + QMenu *choices = new QMenu("Content dropped"); + choices->addAction(KIcon("process-working"), i18n("Fetching file type...")); + QAction *choice = choices->exec(event->screenPos()); + kDebug() << "Inserting our menu ..."; + d->dropMenus[job] = choices; } } event->acceptProposedAction(); @@ -1052,13 +1078,14 @@ pluginFormats.insert(plugin.pluginName(), format); } } + kDebug() << "Mimetype ..." << formats << seenPlugins.keys() << pluginFormats.values(); QString selectedPlugin; if (seenPlugins.isEmpty()) { // do nothing, we have no matches =/ } - + kDebug() << "else" << seenPlugins.keys() << pluginFormats.keys(); if (seenPlugins.count() == 1) { selectedPlugin = seenPlugins.constBegin().key(); } else { @@ -1105,6 +1132,82 @@ } } +void ContainmentPrivate::mimeTypeRetrieved(KIO::Job * job, const QString &mimetype) +{ + if (job->error()) { + kDebug() << "ERROR" << job->error() << ' ' << job->errorString(); + } else { + KIO::TransferJob* tjob = dynamic_cast<KIO::TransferJob*>(job); + if (!tjob) { + kDebug() << "job should be a TransferJob, but isn't"; + return; + } + if (!dropEvents.keys().contains(tjob)) { + kDebug() << "------> Cannot find associated dropEvent"; + kDebug() << dropEvents.keys() << tjob; + return; + } else { + kDebug() << "------> Got a suitable dropEvent"; + kDebug() << dropEvents.keys() << tjob; + } + QMenu *choices = dropMenus[tjob]; + if (choices) { + kDebug() << "Found the QMenu ..."; + kDebug() << dropMenus.keys() << tjob; + } else { + kDebug() << "Apparently no QMenu, looks like it has been deleted ..."; + kDebug() << dropMenus.keys() << tjob; + return; + } + + QGraphicsSceneDragDropEvent* dropEvent = dropEvents[tjob]; + kDebug() << "Screenpos:" << dropEvent->screenPos(); + kDebug() << "scenePos:" << dropEvent->scenePos(); + kDebug() << "pos:" << dropEvent->pos(); + + // Put the job on hold so it can be reused to fetch the actual content, + // which is to be expected when something's dropped onto the desktop. + tjob->putOnHold(); + KIO::Scheduler::publishSlaveOnHold(); + + QVariantList args; + args << tjob->url().url(); + + kDebug() << tjob->url() << " has ====> MimeType:" << mimetype << QRectF(dropEvent->pos(), QSize()) << dropEvent->screenPos() << args; + KPluginInfo::List appletList = Applet::listAppletInfoForMimetype(mimetype); + if (!appletList.isEmpty()) { + choices->clear(); + QHash<QAction *, QString> actionsToPlugins; + foreach (const KPluginInfo &info, appletList) { + kDebug() << info.name(); + QAction *action; + if (!info.icon().isEmpty()) { + action = choices->addAction(KIcon(info.icon()), info.name()); + } else { + action = choices->addAction(info.name()); + } + + actionsToPlugins.insert(action, info.pluginName()); + kDebug() << info.pluginName(); + } + actionsToPlugins.insert(choices->addAction(i18n("Icon")), "icon"); + + QAction *choice = choices->exec(dropEvent->screenPos()); + if (choice) { + addApplet(actionsToPlugins[choice], args, QRectF(dropEvent->pos(), QSize())); + } + } else { + if (dropEvent) { + addApplet("icon", args, QRectF(dropEvent->pos(), QSize())); + } else { + kDebug() << "============> The Job is not existing, hence no dropEvent!"; + } + } + + // TODO: The file should be saved in a sensible location (Desktop? Documents?) + } +} + const QGraphicsItem *Containment::toolBoxItem() const { return d->toolBox;
signature.asc
Description: This is a digitally signed message part.
_______________________________________________ Plasma-devel mailing list Plasma-devel@kde.org https://mail.kde.org/mailman/listinfo/plasma-devel