diff options
author | Jefry Lagrange <jefry.reyes@gmail.com> | 2012-10-28 22:45:00 +0400 |
---|---|---|
committer | Jefry Lagrange <jefry.reyes@gmail.com> | 2012-10-28 22:45:00 +0400 |
commit | f9271e98092880a04dc3ecb87554e391c498e0be (patch) | |
tree | a867e92718b9c592bd90afc7ae4ea2d6bd53b817 /file_sharing/fileshare_window.py | |
parent | 511b37dd911cc3fb30047a024db6f3f45b6da312 (diff) |
initial commit for file_share plugin
Diffstat (limited to 'file_sharing/fileshare_window.py')
-rw-r--r-- | file_sharing/fileshare_window.py | 411 |
1 files changed, 411 insertions, 0 deletions
diff --git a/file_sharing/fileshare_window.py b/file_sharing/fileshare_window.py new file mode 100644 index 0000000..a53491f --- /dev/null +++ b/file_sharing/fileshare_window.py @@ -0,0 +1,411 @@ +import database +import gtk +import gobject +from common import gajim +from common import helpers +from common.file_props import FilesProp +import fshare +import os +import fshare_protocol +import config + +class FileShareWindow(gtk.Window): + + def __init__(self): + gtk.Window.__init__(self) + self.set_title('File Share') + self.connect('delete_event', self.delete_event) + self.set_position(gtk.WIN_POS_CENTER) + self.set_default_size(400, 400) + # Children + self.notebook = gtk.Notebook() + # Browse page + self.bt_search = gtk.Button('Search') + self.bt_search.connect('clicked', self.on_bt_search_clicked) + self.entry_search = gtk.Entry(max=0) + self.entry_search.set_size_request(300, -1) + self.exp_advance = gtk.Expander('Advance') + self.ts_search = gtk.TreeStore(gobject.TYPE_STRING) + self.tv_search = gtk.TreeView(self.ts_search) + self.tv_search.connect('row-expanded', self.row_expanded) + self.tv_search.connect('button-press-event', + self.on_treeview_button_press_event) + self.browse_popup = gtk.Menu() + mi_download = gtk.MenuItem('Download') + mi_property = gtk.MenuItem('Property') + mi_download.show() + mi_property.show() + mi_download.connect('activate', self.on_download_clicked) + self.browse_popup.append(mi_download) + self.browse_popup.append(mi_property) + self.browse_sw = gtk.ScrolledWindow() + self.browse_sw.add(self.tv_search) + self.tvcolumn_browse = gtk.TreeViewColumn('') + self.tv_search.append_column(self.tvcolumn_browse) + self.cell_browse = gtk.CellRendererText() + self.tvcolumn_browse.pack_start(self.cell_browse, True) + self.tvcolumn_browse.add_attribute(self.cell_browse, 'text', 0) + self.lbl_browse = gtk.Label('Browse') + self.browse_hbox = gtk.HBox() + self.browse_hbox2 = gtk.HBox() + self.browse_vbox = gtk.VBox() + self.browse_hbox.pack_start(self.entry_search, True, True, 10) + self.browse_hbox.pack_start(self.bt_search, False, False, 10) + self.browse_vbox.pack_start(self.browse_hbox, False, False, 10) + self.browse_vbox.pack_start(self.exp_advance, False, False, 10) + self.browse_vbox.pack_start(self.browse_sw, True, True, 10) + self.notebook.append_page(self.browse_vbox, self.lbl_browse) + # file references for tv_search + self.browse_fref = {} + # contact references for tv_search + self.browse_jid = {} + # Information of the files inserted in the treeview: name, size, etc + self.brw_file_info = {} + # dummy row children so that we can get expanders + self.empty_row_child = {} + # Manage page + self.bt_add_file = gtk.Button('Add file') + self.bt_add_file.connect('clicked', self.add_file) + self.bt_add_dir = gtk.Button('Add directory') + self.bt_add_dir.connect('clicked', self.add_directory) + self.bt_remove = gtk.Button('Remove') + self.bt_remove.connect('clicked', self.remove_file_clicked) + self.bt_remove_all = gtk.Button('Remove all') + self.bt_remove_all.connect('clicked', self.remove_all_clicked) + self.ts_contacts = gtk.TreeStore(gobject.TYPE_STRING) + self.cbb_contacts = gtk.ComboBoxEntry(self.ts_contacts) + self.cbb_contacts.connect('changed', self.__check_combo_edit) + cbb_entry = self.cbb_contacts.child + self.cbb_completion = gtk.EntryCompletion() + cbb_entry.set_completion(self.cbb_completion) + self.cbb_completion.set_model(self.ts_contacts) + self.cbb_completion.set_text_column(0) + self.bt_stophash = gtk.Button('Calculating hash') + self.lbl_manage = gtk.Label('Manage Shared Files') + self.ts_files = gtk.TreeStore(gobject.TYPE_STRING) + self.tv_files = gtk.TreeView(self.ts_files) + self.treeSelection_files = self.tv_files.get_selection() + self.treeSelection_files.connect('changed', self.row_selected) + self.manage_sw = gtk.ScrolledWindow() + self.manage_sw.add(self.tv_files) + self.tvcolumn = gtk.TreeViewColumn('') + self.tv_files.append_column(self.tvcolumn) + self.cell = gtk.CellRendererText() + self.tvcolumn.pack_start(self.cell, True) + self.tvcolumn.add_attribute(self.cell, 'text', 0) + self.pb_filehash = gtk.ProgressBar() + self.manage_hbox = gtk.HBox() + self.manage_hbox2 = gtk.HBox() + self.manage_vbox = gtk.VBox() + self.manage_vbox2 = gtk.VBox() + self.manage_hbox.pack_start(self.bt_stophash , False, False, 10) + self.manage_hbox.pack_start(self.pb_filehash, True, True, 10) + self.manage_hbox.set_sensitive(False) + self.manage_vbox.pack_start(self.cbb_contacts, False, False, 10) + self.manage_vbox.pack_start(self.manage_hbox, False, False, 10) + self.manage_hbox2.pack_start(self.manage_sw, True, True, 10) + self.manage_hbox2.pack_start(self.manage_vbox2, False, False, 10) + self.manage_vbox2.pack_start(self.bt_add_file, False, False, 10) + self.manage_vbox2.pack_start(self.bt_add_dir, False, False, 10) + self.manage_vbox2.pack_start(self.bt_remove, False, False, 10) + self.manage_vbox2.pack_start(self.bt_remove_all, False, False, 10) + self.manage_vbox2.set_sensitive(False) + self.manage_vbox.pack_start(self.manage_hbox2, True, True, 10) + self.notebook.append_page(self.manage_vbox, self.lbl_manage) + # Preferences page + self.lbl_pref = gtk.Label('Preferences') + self.entry_dir_pref = gtk.Entry(max=0) + self.entry_dir_pref.set_text(config.INCOMING_DIR) + self.bt_sel_dir_pref = gtk.Button('Select dir', gtk.STOCK_OPEN) + self.bt_sel_dir_pref.connect('clicked', self.on_bt_sel_dir_pref_clicked) + self.frm_dir_pref = gtk.Frame('Incoming files directory') + self.frm_dir_pref.set_shadow_type(gtk.SHADOW_IN) + self.pref_hbox = gtk.HBox() + self.pref_vbox = gtk.VBox() + self.pref_hbox.pack_start(self.entry_dir_pref, True, True, 10) + self.pref_hbox.pack_start(self.bt_sel_dir_pref, False, False, 10) + self.frm_dir_pref.add(self.pref_hbox) + self.pref_vbox.pack_start(self.frm_dir_pref, False, False, 10) + self.notebook.append_page(self.pref_vbox , self.lbl_pref) + self.add(self.notebook) + self.show_all() + + def set_account(self, account): + self.account = account + # connect window to protocol + pro = fshare.FileSharePlugin.prohandler[self.account] + pro.set_window(self) + + def add_file(self, widget): + dialog = gtk.FileChooserDialog('Add file to be shared', self, + gtk.FILE_CHOOSER_ACTION_OPEN, + (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, + gtk.STOCK_OPEN, gtk.RESPONSE_OK) + ) + dialog.set_select_multiple(True) + response = dialog.run() + if response == gtk.RESPONSE_OK: + file_list = dialog.get_filenames() + self.add_items_tvcontacts(file_list) + dialog.destroy() + + def add_directory(self, widget): + dialog = gtk.FileChooserDialog('Add directory to be shared', self, + gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, + (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, + gtk.STOCK_OPEN, gtk.RESPONSE_ACCEPT) + ) + response = dialog.run() + if response == gtk.RESPONSE_ACCEPT: + file_list = [] + file_list.append(dialog.get_filename()) + self.add_items_tvcontacts(file_list) + dialog.destroy() + + def add_file_list(self, flist, treestore, fref = {}, root = None): + # file references to their in the treeStore + for f in flist: + # keeps track of the relative dir path + tail = '' + # keeps track of the parent row + parent = None + dirpath = f.split('/') + if len(dirpath) == 1: + # Top level file, it doesnt have parent, add it right away + fref[dirpath[0]] = treestore.insert(root, + 0, + (dirpath[0],) + ) + else: + for dir_ in dirpath: + if tail + dir_ not in fref: + fref[tail + dir_] = treestore.append( + parent, + (dir_,) + ) + parent = fref[tail + dir_] + tail = tail + dir_ + '/' + return fref + + def __convert_date(self, epoch): + # Converts date-time from seconds from epoch to iso 8601 + import time, datetime + ts = time.gmtime(epoch) + dt = datetime.datetime(ts.tm_year, ts.tm_mon, ts.tm_mday, ts.tm_hour, + ts.tm_min, ts.tm_sec) + return dt.isoformat() + + def add_items_tvcontacts(self, file_list, parentdir = None, parent = None): + # TODO: execute this method inside of a thread + for f in file_list: + # Relative name to be used internally in the shared folders + relative_name = f.split('/')[-1] + if parentdir: + relative_name = parentdir + '/' + relative_name + short_name = relative_name.split('/')[-1] + if short_name[0] == '.': + # Return if it is a hidden file + return + if parent: + row = self.ts_files.append(parent, (short_name,)) + else: + row = self.ts_files.insert(None, 0, (short_name,)) + # File info + size = os.path.getsize(f) + is_dir = os.path.isdir(f) + mod_date = os.path.getmtime(f) + mod_date = self.__convert_date(mod_date) + # TODO: add hash + file_ = (f, relative_name, '', size, '', mod_date, is_dir) + requester = self.cbb_contacts.get_active_text() + try: + fid = database.add_file(self.account, requester, file_) + except Exception, e: + if e == 'Duplicated entry': + print 'Error: ' + e + continue + else: + raise Exception(e) + if is_dir: + tmpfl = os.listdir(f) + fl = [] + for item in tmpfl: + fl.append(f + '/' + item) + self.add_items_tvcontacts(fl, relative_name, row) + + def add_contact_browse(self, contact): + fjid = contact.get_full_jid() + jid = gajim.get_jid_without_resource(fjid) + contacts = gajim.contacts.get_contacts(self.account, jid) + for con in contacts: + if con.show in ('offline', 'error') and not \ + con.supports(fshare_protocol.NS_FILE_SHARING): + break + cjid = con.get_full_jid() + r = self.ts_search.insert(None, 0, + (cjid, )) + self.browse_jid[cjid] = r + pro = fshare.FileSharePlugin.prohandler[self.account] + # Request list of files from peer + stanza = pro.request(cjid) + if pro.conn.connection: + pro.conn.connection.send(stanza) + + def add_contact_manage(self, contact): + self.contacts_rows = [] + self.cbb_contacts.grab_focus() + for c in gajim.contacts.iter_contacts(self.account): + jid = gajim.get_jid_without_resource(c.get_full_jid()) + r = self.ts_contacts.insert(None, len(self.ts_contacts), + (jid, )) + if c.get_full_jid() == contact.get_full_jid(): + self.cbb_contacts.set_active_iter(r) + self.contacts_rows.append(r) + self.manage_vbox2.set_sensitive(True) + self.bt_remove.set_sensitive(False) + self.add_file_list(database.get_files_name(self.account, + gajim.get_jid_without_resource(contact.get_full_jid())), + self.ts_files + ) + + def delete_event(self, widget, data=None): + fshare.FileSharePlugin.filesharewindow = {} + return False + + def __check_combo_edit(self, widget, data=None): + self.ts_files.clear() + entry = self.cbb_contacts.child + contact = entry.get_text() + self.manage_vbox2.set_sensitive(False) + for i in self.contacts_rows: + # If the contact in the comboboxentry is include inside of the + # combobox + if contact == self.ts_contacts.get_value(i, 0): + self.add_file_list(database.get_files_name(self.account, + contact), + self.ts_files + ) + self.manage_vbox2.set_sensitive(True) + self.bt_remove.set_sensitive(False) + break + + def remove_file_clicked(self, widget, data=None): + entry = self.cbb_contacts.child + contact = entry.get_text() + sel = self.treeSelection_files.get_selected() + relative_name = self.ts_files.get_value(sel[1], 0) + self.ts_files.remove(sel[1]) + database.delete(self.account, contact, relative_name) + widget.set_sensitive(False) + + def remove_all_clicked(self, widget, data=None): + entry = self.cbb_contacts.child + contact = entry.get_text() + database.delete_all(self.account, contact) + self.ts_files.clear() + + def row_selected(self, widget, data=None): + # When row is selected in tv_files + sel = self.treeSelection_files.get_selected() + if not sel[1]: + return + depth = self.ts_files.iter_depth(sel[1]) + # Don't remove file and dirs that aren't at the root level + if depth == 0: + self.bt_remove.set_sensitive(True) + else: + self.bt_remove.set_sensitive(False) + + def row_expanded(self, widget, iter_, path, data=None): + name = None + for key in self.empty_row_child: + parent = self.ts_search.iter_parent(self.empty_row_child[key]) + p = self.ts_search.get_path(parent) + if p == path: + name = key + break + if name: + # if we found that the expanded row is the parent of the empty row + # remove it from the treestore and empty_row dictionary. Then ask + # peer for list of files of that directory + i = self.empty_row_child[name] + pro = fshare.FileSharePlugin.prohandler[self.account] + contact = self.get_contact_from_iter(self.ts_search, i) + contact = gajim.contacts.get_contact_with_highest_priority( + self.account, + contact ) + stanza = pro.request(contact.get_full_jid(), name, isFile=False) + if pro.conn.connection: + pro.conn.connection.send(stanza) + self.ts_search.remove(i) + del self.empty_row_child[name] + + def get_contact_from_iter(self, treestore, iter_): + toplevel = treestore.get_iter_root() + while toplevel: + if treestore.is_ancestor(toplevel, iter_): + return treestore.get_value(toplevel, 0) + toplevel = treestore.iter_next(toplevel) + + def on_treeview_button_press_event(self, treeview, event): + if event.button == 3: + x = int(event.x) + y = int(event.y) + time = event.time + pthinfo = treeview.get_path_at_pos(x, y) + if pthinfo is not None: + path, col, cellx, celly = pthinfo + treeview.grab_focus() + treeview.set_cursor( path, col, 0) + treestore = treeview.get_model() + it = treestore.get_iter(path) + if treestore.iter_depth(it) != 0: + self.browse_popup.popup(None, None, None, event.button, time) + return True + + def on_bt_search_clicked(self, widget, data=None): + pass + + def on_download_clicked(self, widget, data=None): + tree, row = self.tv_search.get_selection().get_selected() + path = tree.get_path(row) + file_info = self.brw_file_info[path] + fjid = self.get_contact_from_iter(tree, row) + # Request the file + file_path = config.INCOMING_DIR + '/%s' % file_info[0] + sid = helpers.get_random_string_16() + new_file_props = FilesProp.getNewFileProp(self.account, sid) + new_file_props.file_name = file_path + print file_path + new_file_props.name = file_info[0] + new_file_props.desc = file_info[4] + new_file_props.size = file_info[2] + new_file_props.date = file_info[1] + new_file_props.hash_ = None if file_info[3] == '' else file_info[3] + new_file_props.type_ = 'r' + tsid = gajim.connections[self.account].start_file_transfer(fjid, + new_file_props, + True) + new_file_props.transport_sid = tsid + ft_window = gajim.interface.instances['file_transfers'] + contact = gajim.contacts.get_contact_from_full_jid(self.account, fjid) + ft_window .add_transfer(self.account, contact, new_file_props) + + def on_bt_sel_dir_pref_clicked(self, widget, data=None): + chooser = gtk.FileChooserDialog(title='Incoming files directory', + action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, + buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL, + gtk.STOCK_OPEN,gtk.RESPONSE_OK)) + response = chooser.run() + if response == gtk.RESPONSE_OK: + file_name = chooser.get_filename() + self.entry_dir_pref.set_text(file_name) + config.set('incoming_dir', file_name) + chooser.destroy() + + +if __name__ == "__main__": + f = FileShareWindow() + f.show() + gtk.main() + |