1 # Copyright (C) 2006 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 nofork
= self
.cli_flags
.get("no-fork") # there is a cli flag
53 self
.dbus_connection
= None
55 self
.dbus_connection
= self
.get_dbus_connection()
57 success
= self
.try_get_data()
58 raise SystemExit(not success
)
59 elif not nofork
and self
.dbus_connection
:
60 self
.dbus_send(files
, texts
)
61 # Done, sent to other running instance
64 self
.start_dbus_service()
70 (self
.data_controller
, self
.writer
) = self
.init_data()
71 self
.add_files(None, files
)
72 self
.add_texts(None, texts
)
76 from data
import DataController
77 data_controller
= DataController()
79 quiet
= self
.cli_flags
.get("quiet", True)
80 onexit
= self
.cli_flags
.get("write-on-exit", False)
81 if onexit
or not quiet
:
82 writer
= self
.make_writer()
84 data_controller
.connect("item-added", writer
.print_item
)
87 return (data_controller
, writer
)
89 def make_writer(self
):
91 Return a plugins.Writer object
93 Initialized with current null termination and
96 from plugins
import Writer
97 null_term
= self
.cli_flags
.get("null", False)
98 paths
= self
.cli_flags
.get("paths", True)
99 writer
= Writer(paths
, null_term
)
102 def run_window(self
):
103 from window
import WindowController
105 window_title
= self
.cli_flags
.get("window-title", "Dragbox")
106 self
.wc
= WindowController(self
.data_controller
, window_title
)
107 self
.wc
.ready_window()
112 except KeyboardInterrupt:
113 # catch ctrl-c and exit nicely
118 def prepare_quit(self
):
119 exit
= self
.cli_flags
.get("write-on-exit")
120 if self
.writer
and exit
:
121 self
.writer
.print_all(self
.data_controller
)
123 def read_opts(self
, argv
):
125 Uses gnu getopt to read command line arguments
127 returns a tuple of (files, texts, options)
129 from getopt
import gnu_getopt
, GetoptError
130 short_opts
= "nhf:t:vqpu0x"
132 'help', 'file=', 'text=', 'no-fork',
133 'version', 'quiet' , 'paths', 'uris',
134 'null-terminate', 'window-title=',
135 'write-on-exit', 'no-quiet', 'get'
138 (options
, arguments
) = gnu_getopt(argv
, short_opts
, long_opts
)
139 except GetoptError
, exception
:
140 print_error("Sorry, %s" % exception
)
141 self
.print_usage(usage_error
=True)
143 # Search for preferences
144 for (o
,a
) in options
:
145 if o
in ("-h", "--help"):
147 elif o
in ("-v", "--version"):
149 elif o
in ("-n", "--no-fork"):
150 prefs
["no-fork"] = True
151 if not prefs
.get("quiet"): # make sure we don't ow
152 prefs
["quiet"] = False
153 elif o
in ("-q", "--quiet"):
154 prefs
["quiet"] = True
155 elif o
in ("--no-quiet"):
156 prefs
["quiet"] = False
157 elif o
in ("-p", "--paths"):
158 prefs
["paths"] = True
159 elif o
in ("-u", "--uris"):
160 prefs
["paths"] = False
161 elif o
in ("-0", "--null-terminate"):
163 elif o
in ("--window-title"):
164 prefs
["window-title"] = a
165 elif o
in ("-x", "--write-on-exit"):
166 # don't write _asyncronously_
167 prefs
["quiet"] = True
168 prefs
["write-on-exit"] = True
172 # Handle strongly typed items
175 for (o
, a
) in options
:
176 if o
in ("-f", "--file"):
177 path
= self
.check_file_exists(a
, warn
=True)
178 if path
: files
.append(path
)
179 elif o
in ("-t", "--text"):
182 # Try if they are files
184 for item
in arguments
:
185 path
= self
.check_file_exists(item
, warn
=False)
189 text
= text
+ " " + item
191 # Take rest as one text block
192 if text
: texts
.append(text
)
193 return (files
, texts
, prefs
)
195 def get_dbus_connection(self
):
197 Tries to connect ot already running instance
199 from version
import dbus_enabled
200 if dbus_enabled
!= "yes":
201 return None #return with no success
205 except ImportError, info
:
210 dclient
= dbuscontrol
.Connection()
211 except dbuscontrol
.ServiceUnavailable
, info
:
215 def dbus_send(self
, files
, texts
):
217 Sends files, texts and activates
219 # Send data to running Service
220 iface
= self
.dbus_connection
.get_interface()
221 if files
: iface
.send_files(files
)
222 if texts
: iface
.send_texts(texts
)
225 print_debug("Sent data to %s" % iface
)
227 def try_get_data(self
):
229 Send get_data method to another instance and try to get its data
231 from shelfitem
import make_item
232 if not self
.dbus_connection
:
233 print_error("No running instance found")
235 datas
, types
= self
.dbus_connection
.get_interface().get_data()
236 writer
= self
.make_writer()
237 for data
, type in zip(datas
, types
):
238 writer
.print_item(None, make_item(data
, type))
241 def data_requested(self
, service
, send_callback
, error_callback
):
242 print_debug("Data requested from %s" % service
)
243 items
= self
.data_controller
.get_items()
244 datas
, types
= [], []
246 datas
.append(item
.get_object())
247 types
.append(item
.get_type())
248 send_callback(datas
, types
)
249 #error_callback(Exception())
251 def start_dbus_service(self
):
253 Create a dbus Service object
255 Set up signals for the service
259 dserver
= dbuscontrol
.make_service()
260 except Exception, info
:
261 from utils
import print_debug
, print_error
263 print_error("Failed to use dbus, might not be available")
265 self
.dbus_service
= dserver
266 self
.dbus_service
.connect("files-received", self
.add_files
)
267 self
.dbus_service
.connect("texts-received", self
.add_texts
)
268 self
.dbus_service
.connect("activate", self
.activate_application
)
269 self
.dbus_service
.connect("data-requested", self
.data_requested
)
271 def check_file_exists(self
, f
, warn
=True):
273 Check if a file exists
276 warn: If True, print an error message and exit if nonexistant
283 print_error("The file %s does not exist" % f
)
286 def add_files(self
, service
, flist
):
288 Adds a list of files to the dragbox
290 flist: a list of absolute paths
292 from shelfitem
import FILE_TYPE
295 fileloc
= path
.abspath(f
)
296 self
.data_controller
.add_item(fileloc
, FILE_TYPE
)
298 def add_texts(self
, service
, tlist
):
300 Adds a list of text to the dragbox
302 tlist: a list of strings
304 from shelfitem
import TEXT_TYPE
307 self
.data_controller
.add_item(text
, TEXT_TYPE
)
309 def activate_application(self
, service
):
311 Activate and bring to front
313 self
.wc
.show_window()
315 def print_usage(self
, usage_error
=False):
317 Usage: %s [-nq] item [...]
319 item add item to dragbox
320 added as file if it is a valid path
322 -t, --text "text" add text
323 -f, --file file add file
325 --window-title name set window title to name
327 -n, --no-fork don't fork (also disables use of dbus)
329 The options below only apply with --no-fork:
330 -q, --quiet don't print dragged-in items
331 -p, --paths print paths of dragged-in files (default)
332 -u, --uris print uris of dragged-in files
333 -0, --null-terminate separate items' output with \\0, not \\n
334 -x, --write-on-exit only write contents on exit
337 -h, --help display this help
338 -v, --version display version information
340 raise SystemExit(usage_error
)
342 def print_version(self
):
344 print "%s %s\n\n%s" % (version
.package_name
, version
.version
, version
.copyright_info
)