Drag-and-drop Loading

This tutorial shows how to handle files being dropped onto your application from the filer or from another application. We will make an application that counts the number of words in a file.


You should have already read the first tutorial, as this one assumes you already have the application directory and other files set up.

Simple drag-and-drop

The easiest way to handle drag-and-drop is to let the filer deal with it. The user drops data onto your application icon in a filer window, panel, etc. When this happens, the filer will run your application with a list of files dropped (sys.argv is the list of arguments passed to your program; argv[0] is the name of the program itself):

#!/usr/bin/env python
import findrox; findrox.version(1, 9, 8)
import rox
import sys, os
files = sys.argv[1:]
if not files:
        rox.croak('Drag a file onto the WordCount application to count it')
rox.info('The following files were dropped on me:\n' + '\n'.join(files))

If you drag some files onto this program, it will list their names. Try dragging from Edit's savebox onto the WordCount application. You should see the file is named '-', meaning that you should read the data from the standard input stream (it doesn't exist as a file).

Replace the last line with some code to actually count the files:

message = 'WordCount results:\n'
for filename in files:
        if filename == '-': stream = sys.stdin
        else: stream = file(filename)
        words = 0
        for line in stream:
                words += len(line.split())
        message += '\n%s: %d' % (os.path.basename(filename), words)

And that's it! Coupled with the next tutorial (drag-and-drop saving), you can write lots of useful 'filter' type applications, such as Archive.

Drag-and-drop loading within an application

You can make any widget in your application sensitive to data being dropped on it by using the rox.loading module's XDSLoader mix-in class:

#!/usr/bin/env python
import findrox; findrox.version(1, 9, 8)
import rox
from rox import g, loading
class DropBox(rox.Window, loading.XDSLoader):
        def __init__(self):
                loading.XDSLoader.__init__(self, ['text/plain'])
                label = g.Label('Drop some data here')
window = DropBox()

Notice how our new DropBox class is both a Window and an XDSLoader, so we have to initialise both base classes in the __init__ constructor. XDSLoader is passed a list of MIME types that we're interested in.

If you try running the code above, you'll get a window which you can drop files onto, although doing so just shows an error message because we haven't set a handler yet. Try dragging in a file from ROX-Filer, and some text from Edit's savebox.

There are various methods in XDSLoader we can override to handle the data, but the most useful is xds_load_from_stream():

        def xds_load_from_stream(self, name, type, stream):
                if not name: name = 'Untitled data'
                words = 0
                for line in stream:
                        words += len(line.split())
                rox.info('%s contains %d words' % (name, words))