diff --git a/qubes_rpc/qvm-copy-to-vm.gnome b/qubes_rpc/qvm-copy-to-vm.gnome index cb2b86e..e6c6c70 100755 --- a/qubes_rpc/qvm-copy-to-vm.gnome +++ b/qubes_rpc/qvm-copy-to-vm.gnome @@ -20,7 +20,7 @@ # # -VM=$(zenity --entry --title="File Copy" --text="Enter the destination domain name:") +VM=$(qvm-mru-entry --title="File Copy" --text="Enter the destination domain name:" --mrufile "qvm-mru-filecopy") if [ X$VM = X ] ; then exit 0 ; fi SIZE=$(du --apparent-size -c "$@" | tail -1 | cut -f 1) diff --git a/qubes_rpc/qvm-mru-entry b/qubes_rpc/qvm-mru-entry new file mode 100755 index 0000000..b516753 --- /dev/null +++ b/qubes_rpc/qvm-mru-entry @@ -0,0 +1,165 @@ +#!/usr/bin/python +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2012 Bruce Downs +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# +import os +from optparse import OptionParser +import gtk + +class QubesMruDialog(gtk.Dialog): + entry = None + mrufile = None + + def __init__(self, title, text, mrufile): + self.mrufile = mrufile + + gtk.Dialog.__init__( + self, + title, + None, + 0, + (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, + gtk.STOCK_OK, gtk.RESPONSE_OK)) + + # setting the default response to 'ok' + # does not work as advertised + # using key-press-event instead + #self.set_default_response(gtk.RESPONSE_OK) + + self.connect("destroy", lambda *w: gtk.main_quit()) + self.connect("response", self.response_callback) + self.connect("key-press-event", self.key_press_callback) + + self.set_position(gtk.WIN_POS_CENTER) + self.set_resizable(True) + + vbox = gtk.VBox(True, 5) + self.vbox.pack_start(vbox, True, True, 0) + vbox.set_border_width(5) + + label = gtk.Label() + label.set_markup(text) + vbox.pack_start(label, False, False, 0) + + # Create our entry + self.entry = gtk.Entry() + vbox.pack_start(self.entry, False, False, 0) + + # Create the completion object + completion = gtk.EntryCompletion() + + # Assign the completion to the entry + self.entry.set_completion(completion) + + # Create a tree model and use it as the completion model + completion_model, firstline = self.create_completion_model() + completion.set_model(completion_model) + + # Use model column 0 as the text column + completion.set_text_column(0) + + if firstline: + self.entry.set_text(firstline) + + self.show_all() + + def create_completion_model(self): + store = gtk.ListStore(str) + firstline = None + + if self.mrufile and os.access(self.mrufile, os.R_OK): + # read lines from mru file + lines = [line.strip() for line in open(self.mrufile)] + for line in lines: + if not firstline: + firstline = line + + iter = store.append() + store.set(iter, 0, line) + + return store, firstline + + def handle_ok(self): + my_entry = self.entry.get_text() + + if len(my_entry) > 0: + linesorg = [] + linesorg.insert(0, my_entry) + + # calc mru lines + if os.access(self.mrufile, os.R_OK): + # read lines from existing mru file + fMru = open(self.mrufile, "r") + linesorg += [line.strip() for line in fMru] + fMru.close() + + #uniqify + linesuniq = [] + for lineuniq in linesorg: + if (len(lineuniq) > 0 and lineuniq not in linesuniq): + linesuniq.append(lineuniq) + + # write to mru + # up to 50 unique + fMru = file(self.mrufile, "w") + fMru.writelines( "%s\n" % line for line in linesuniq[:50] ) + fMru.close() + + # print entry to stdout + print my_entry + + def response_callback(self, button, response_id): + if response_id == gtk.RESPONSE_OK: + self.handle_ok() + self.destroy() + + def key_press_callback(self, button, event): + if event.keyval == gtk.keysyms.Return: + self.handle_ok() + self.destroy() + +def main(): + usage = "usage: %prog [--title 'Qubes Title'] [--text 'Qubes Text'] [--mrufile 'mru file name']" + parser = OptionParser (usage) + parser.add_option ("-l", "--title", + action="store", + dest="title", + default="Qubes MRU Dialog Entry", + help="Set the dialog title [%default]") + parser.add_option ("-x", "--text", + action="store", + dest="text", + default="Enter Qubes text:", + help="Set the dialog text [%default]") + parser.add_option ("-f", "--mrufile", + action="store", + dest="mrufile", + default='qvm-mru', + help="MRU file name [%default]") + (options, args) = parser.parse_args () + + mrudir = os.path.expanduser('~') + os.sep + '.config' + if not os.path.exists(mrudir): + os.makedirs(mrudir) + QubesMruDialog(options.title, options.text, mrudir + os.sep + options.mrufile) + gtk.main() + +main() + diff --git a/rpm_spec/core-vm.spec b/rpm_spec/core-vm.spec index f1a5e5d..72bf87a 100644 --- a/rpm_spec/core-vm.spec +++ b/rpm_spec/core-vm.spec @@ -153,7 +153,7 @@ install network/qubes_netwatcher $RPM_BUILD_ROOT/usr/sbin/ install -d $RPM_BUILD_ROOT/usr/bin -install qubes_rpc/{qvm-open-in-dvm,qvm-open-in-vm,qvm-copy-to-vm,qvm-run} $RPM_BUILD_ROOT/usr/bin +install qubes_rpc/{qvm-open-in-dvm,qvm-open-in-vm,qvm-copy-to-vm,qvm-run,qvm-mru-entry} $RPM_BUILD_ROOT/usr/bin install qubes_rpc/wrap_in_html_if_url.sh $RPM_BUILD_ROOT/usr/lib/qubes install qubes_rpc/qvm-copy-to-vm.kde $RPM_BUILD_ROOT/usr/lib/qubes install qubes_rpc/qvm-copy-to-vm.gnome $RPM_BUILD_ROOT/usr/lib/qubes @@ -393,6 +393,7 @@ rm -rf $RPM_BUILD_ROOT /usr/bin/qvm-open-in-dvm /usr/bin/qvm-open-in-vm /usr/bin/qvm-run +/usr/bin/qvm-mru-entry /usr/bin/xenstore-watch-qubes %dir /usr/lib/qubes /usr/lib/qubes/block_add_change