1 # Copyright (C) 2006, 2007 Ulrik Sverdrup
3 # dragbox -- Commandline drag-and-drop tool for GNOME
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
20 from sys
import exit
, argv
21 from os
import path
, fork
23 from utils
import print_error
, print_debug
25 class dragbox(object):
27 Dragbox application object
31 This class runs one instance of dragbox
38 # Read commandline switches
39 (files
, texts
, cli_flags
) = self
.read_opts(argv
[1:])
43 if not stdin
.isatty():
44 pipe_text
= stdin
.read()
48 self
.cli_flags
= cli_flags
50 get
= self
.cli_flags
.get("get")
51 list_names
= self
.cli_flags
.get("list-names")
52 nofork
= self
.cli_flags
.get("no-fork")
53 self
.identifier
= self
.cli_flags
.get("identifier")
56 self
.dbus_connection
= None
61 self
.dbus_connection
= self
.get_dbus_connection()
63 success
= self
.try_get_data()
64 raise SystemExit(not success
)
65 elif not nofork
and self
.dbus_connection
:
66 self
.dbus_send(files
, texts
)
67 # Done, sent to other running instance
70 self
.start_dbus_service()
76 (self
.data_controller
, self
.writer
) = self
.init_data()
77 self
.add_files(None, files
)
78 self
.add_texts(None, texts
)
82 from data
import DataController
83 data_controller
= DataController()
85 quiet
= self
.cli_flags
.get("quiet", True)
86 onexit
= self
.cli_flags
.get("write-on-exit", False)
87 if onexit
or not quiet
:
88 writer
= self
.make_writer()
90 data_controller
.connect("item-added", writer
.print_item
)
93 return (data_controller
, writer
)
95 def make_writer(self
):
97 Return a plugins.Writer object
99 Initialized with current null termination and
102 from plugins
import Writer
103 null_term
= self
.cli_flags
.get("null", False)
104 paths
= self
.cli_flags
.get("paths", True)
105 writer
= Writer(paths
, null_term
)
108 def run_window(self
):
109 from window
import WindowController
111 window_title
= self
.cli_flags
.get("window-title", "Dragbox")
113 window_title
+= (" (%s)" % self
.identifier
)
114 self
.wc
= WindowController(self
.data_controller
, window_title
)
115 self
.wc
.ready_window()
120 except KeyboardInterrupt:
121 # catch ctrl-c and exit nicely
126 def prepare_quit(self
):
127 exit
= self
.cli_flags
.get("write-on-exit")
128 if self
.writer
and exit
:
129 self
.writer
.print_all(self
.data_controller
)
131 def read_opts(self
, argv
):
133 Uses gnu getopt to read command line arguments
135 returns a tuple of (files, texts, options)
137 from getopt
import gnu_getopt
, GetoptError
138 short_opts
= "hf:t:nvpu0ax"
156 (options
, arguments
) = gnu_getopt(argv
, short_opts
, long_opts
)
157 except GetoptError
, exception
:
158 print_error("Sorry, %s" % exception
)
159 self
.print_usage(usage_error
=True)
161 # store command line flags in `prefs`
162 # quiet: if True, output async
163 # list-names: if True, list running instances
164 for (o
,a
) in options
:
165 if o
in ("-h", "--help"):
167 elif o
in ("-v", "--version"):
169 elif o
in ("-n", "--no-fork"):
170 prefs
["no-fork"] = True
171 prefs
["quiet"] = True
172 prefs
["write-on-exit"] = True
173 elif o
in ("-p", "--paths"):
174 prefs
["paths"] = True
175 elif o
in ("-u", "--uris"):
176 prefs
["paths"] = False
177 elif o
in ("-0", "--null-terminate"):
179 elif o
in ("--window-title"):
180 prefs
["window-title"] = a
181 elif o
in ("-x", "--write-on-exit"):
182 # don't write _asyncronously_
183 prefs
["quiet"] = True
184 prefs
["write-on-exit"] = True
185 elif o
in ("-a", "--write-async"):
186 # don't write _asyncronously_
187 prefs
["quiet"] = False
188 prefs
["write-on-exit"] = False
191 elif o
in ("--name"):
192 prefs
["identifier"] = a
193 elif o
in ("--list"):
194 prefs
["list-names"] = True
196 # Handle strongly typed items
199 for (o
, a
) in options
:
200 if o
in ("-f", "--file"):
201 path
= self
.check_file_exists(a
, warn
=True)
202 if path
: files
.append(path
)
203 elif o
in ("-t", "--text"):
206 # Try if they are files
208 for item
in arguments
:
209 path
= self
.check_file_exists(item
, warn
=False)
213 text
= text
+ " " + item
215 # Take rest as one text block
216 if text
: texts
.append(text
)
217 return (files
, texts
, prefs
)
219 def check_file_exists(self
, f
, warn
=True):
221 Check if a file exists
224 warn: If True, print an error message and exit if nonexistant
231 print_error("The file %s does not exist" % f
)
234 def get_dbus_connection(self
):
236 Tries to connect ot already running instance
238 from version
import dbus_enabled
239 if dbus_enabled
!= "yes":
240 return None #return with no success
244 except ImportError, info
:
249 dclient
= dbuscontrol
.Connection(self
.identifier
)
250 except dbuscontrol
.ServiceUnavailable
, info
:
254 def dbus_send(self
, files
, texts
):
256 Sends files, texts and activates
258 # Send data to running Service
259 iface
= self
.dbus_connection
.get_interface()
260 if files
: iface
.send_files(files
)
261 if texts
: iface
.send_texts(texts
)
264 print_debug("Sent data to %s" % iface
)
266 def try_get_data(self
):
268 Send get_data method to another instance and try to get its data
270 from shelfitem
import make_item
271 if not self
.dbus_connection
:
272 name
= self
.identifier
and self
.identifier
or "Default"
273 print_error("Shelf %s not found" % name
)
275 datas
, types
= self
.dbus_connection
.get_interface().get_data()
276 writer
= self
.make_writer()
277 for data
, type in zip(datas
, types
):
278 writer
.print_item(None, make_item(data
, type))
281 def data_requested(self
, service
, send_callback
, error_callback
):
282 print_debug("Data requested from %s" % service
)
283 items
= self
.data_controller
.get_items()
284 datas
, types
= [], []
286 datas
.append(item
.get_object())
287 types
.append(item
.get_type())
288 send_callback(datas
, types
)
289 #error_callback(Exception())
291 def start_dbus_service(self
):
293 Create a dbus Service object
295 Set up signals for the service
299 dserver
= dbuscontrol
.make_service(self
.identifier
)
300 except Exception, info
:
301 from utils
import print_debug
, print_error
303 print_error("Failed to use dbus, might not be available")
305 self
.dbus_service
= dserver
306 self
.dbus_service
.connect("files-received", self
.add_files
)
307 self
.dbus_service
.connect("texts-received", self
.add_texts
)
308 self
.dbus_service
.connect("activate", self
.activate_application
)
309 self
.dbus_service
.connect("data-requested", self
.data_requested
)
311 def get_dbus_names(self
):
312 from dbuscontrol
import list_names
313 names
= list(list_names())
314 print "%d shelves available" % len(names
)
317 print u
"\n ".join(names
)
319 def add_files(self
, service
, flist
):
321 Adds a list of files to the dragbox
323 flist: a list of absolute paths
325 from shelfitem
import FILE_TYPE
328 fileloc
= path
.abspath(f
)
329 self
.data_controller
.add_item(fileloc
, FILE_TYPE
)
331 def add_texts(self
, service
, tlist
):
333 Adds a list of text to the dragbox
335 tlist: a list of strings
337 from shelfitem
import TEXT_TYPE
340 self
.data_controller
.add_item(text
, TEXT_TYPE
)
342 def activate_application(self
, service
):
344 Activate and bring to front
346 self
.wc
.show_window()
348 def print_usage(self
, usage_error
=False):
350 Usage: %s [-nq] item [...]
352 item add item to dragbox
353 added as file if it is a valid path
355 -t, --text "text" add text
356 -f, --file file add file
358 --window-title name set window title to name
360 -n, --no-fork don't fork (also disables use of dbus)
362 The options below only apply with --no-fork:
363 -q, --quiet don't print dragged-in items
364 -p, --paths print paths of dragged-in files (default)
365 -u, --uris print uris of dragged-in files
366 -0, --null-terminate separate items' output with \\0, not \\n
367 -x, --write-on-exit only write contents on exit
370 -h, --help display this help
371 -v, --version display version information
373 raise SystemExit(usage_error
)
375 def print_version(self
):
377 print "%s %s\n\n%s" % (version
.package_name
, version
.version
, version
.copyright_info
)