Here's a first try:

Use KIO::TransferJob to retrieve the mimetype of dropped remote content

This is a rough proof-of-concept to enable dropping remote urls onto Plasma. 
Currently they're simply added as an icon. The goal is to be able to 
transparantly add remote content to the plasma desktop by dropping urls to 
websites, pictures or references to database such as akonadi or nepomuk.

With this patch, Containment retrieves the mimetype for URLs through KIO, and 
offers a qmenu popup after retrieving the applet's mimedata.

There are a couple of interesting things s mimetype retrieved signal of the 
TransferJob triggers the popupmenu (since only then we can get a list of 
possible applets).

- Applets need to actually support loading content through URLs. That means 
checking the args passed when loading the applet, and loading for example an 
image through KIO. The Picture Frame applet only does the arg part right now, 
the webbrowser does both.


- The akonadi: url is currently hard-coded to the emailmessage applet. I'll 
need to find a more elegant way, since it technically doesn't have emaildata, 
probably a mimetype for an akonadi object.

- The algorithm in there is a bit wacky. In current trunk, containment tries 
to find an applet suitable for the mimetype, if it doesn't it just puts a URL 
there. I guess a change to isLocalFile: handle it sync, else do the 
KIO::TransferJob async popup should make more sense, semantically. And it 
wouldn't stop working when someone registers an applet for application/octet-
stream (which is what you get in the default case).

- Since we don't have the pointer to the event in the slotMimetype() method, I 
had to cache the dropped location. I've put that QRectF into the d-pointer. 
The slot is in Containment. Should that slot also go into the d-pointer? It's 
private.

- This QRectF makes the menu pop up in the wrong location (usually way to much 
top right. I guess the cached location needs to be mapped to the scene here?

- What if the user wants to save the document? KIO will probably do caching 
for us, but I wonder if it makes sense to save the dropped URL to the 
~/Desktop directory.


So as you see there are some rough edges about this patch right now. I'd like 
some conceptual feedback, and a bit of input on the above items.

Thanks,
-- 
sebas

 http://www.kde.org | http://vizZzion.org |  GPG Key ID: 9119 0EF9 

Index: widgets/scrollwidget.cpp
===================================================================
--- widgets/scrollwidget.cpp	(revision 945686)
+++ 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 945686)
+++ private/containment_p.h	(working copy)
@@ -48,7 +48,8 @@
           toolBox(0),
           con(0),
           type(Containment::NoContainmentType),
-          drawWallpaper(true)
+          drawWallpaper(true),
+          dropGeometry(0,0,0,0)
     {
     }
 
@@ -114,6 +115,7 @@
     Containment::Type type;
     static bool s_positioning;
     bool drawWallpaper;
+    QRectF dropGeometry;
 };
 
 } // Plasma namespace
Index: containment.h
===================================================================
--- containment.h	(revision 945686)
+++ containment.h	(working copy)
@@ -32,6 +32,11 @@
 #include <plasma/applet.h>
 #include <plasma/animator.h>
 
+namespace KIO
+{
+    class Job;
+}
+
 namespace Plasma
 {
 
@@ -506,6 +511,12 @@
          */
         const QGraphicsItem *toolBoxItem() const;
 
+    private Q_SLOTS:
+        /**
+        * This slot is called when the 'stat' after a job event has finished.
+        */
+        void slotMimeType(KIO::Job *job, const QString &mimetype);
+
     private:
         Q_PRIVATE_SLOT(d, void appletDestroyed(Plasma::Applet*))
         Q_PRIVATE_SLOT(d, void containmentAppletAnimationComplete(QGraphicsItem *item,
Index: containment.cpp
===================================================================
--- containment.cpp	(revision 945686)
+++ 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"
@@ -526,7 +529,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);
@@ -935,13 +938,13 @@
     }
 
     QString mimetype(static_cast<Corona*>(scene())->appletMimeType());
+    kDebug() << "Something dropped mimetype, -data: " << mimetype << event->mimeData()->text();
 
     if (event->mimeData()->hasFormat(mimetype) && scene()) {
         QString data = event->mimeData()->data(mimetype);
         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);
         }
@@ -960,22 +963,30 @@
     } 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());
+            d->dropGeometry = QRectF(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, d->dropGeometry);
+
+            } 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());
@@ -984,17 +995,25 @@
                     }
 
                     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, d->dropGeometry);
                 }
-            } 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);
+
+                connect(job, SIGNAL(mimetype(KIO::Job *, const QString&)),
+                        this, SLOT(slotMimeType(KIO::Job *, const QString&)));
             }
         }
         event->acceptProposedAction();
@@ -1015,13 +1034,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 {
@@ -1068,6 +1088,55 @@
     }
 }
 
+void Containment::slotMimeType(KIO::Job * job, const QString &mimetype)
+{
+    if (job->error()) {
+        kDebug() << "ERROR" << job->error() << ' ' << job->errorString();
+    } else {
+        KIO::TransferJob* tjob = static_cast<KIO::TransferJob*>(job);
+        if (!tjob) {
+            kDebug() << "job should be a TransferJob, but isn't";
+            return;
+        }
+        // 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  << d->dropGeometry << args;
+        KPluginInfo::List appletList = Applet::listAppletInfoForMimetype(mimetype);
+        if (!appletList.isEmpty()) {
+            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());
+                } 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(d->dropGeometry.topLeft().toPoint());
+            if (choice) {
+                addApplet(actionsToPlugins[choice], args, d->dropGeometry);
+            }
+        } else {
+            addApplet("icon", args, d->dropGeometry);
+        }
+
+        // TODO: The file should be saved in a sensible location (Desktop? Documents?)
+    }
+}
+
 const QGraphicsItem *Containment::toolBoxItem() const
 {
     return d->toolBox;

Attachment: 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

Reply via email to