def __connect_device(self): dev = MTPDevice() self.__device_engine = DeviceEngine(dev) if not self.__device_engine.connect_device(): # TODO: notify connection failed self.__device_engine = None return tv = self.__getWidget("treeview_transfer_manager") notebook = self.__getWidget("notebook_device_info") self.__transferManager = TransferManager(self.__device_engine, tv, notebook) # update model model = self.__device_engine.get_track_listing_model() self.__treeview_track.set_model(model) # change menu and toobar label and stock #TODO: use gtk.Action and gtk.ActionGroup for menu and toolbutton # ou uimanager http://python.developpez.com/cours/pygtktutorial/php/pygtkfr/sec-UIManager.php text="Disconnect device" stock=gtk.STOCK_DISCONNECT #TODO self.__getWidget("button_connect").set_label(text) self.__getWidget("button_connect").set_stock_id(stock) #TODO self.__getWidget("menuitem_connect").set_label(text) img = gtk.image_new_from_stock(stock, gtk.ICON_SIZE_LARGE_TOOLBAR) #TODO self.__getWidget("menuitem_connect").set_image(img) self.__getWidget("label_device_name").set_markup("<b>" + self.__device_engine.get_device().get_name() + "</b>") self.__getWidget("label_device_name2").set_markup("<b>" + self.__device_engine.get_device().get_name() + "</b>") # disk usage used = self.__device_engine.get_device().get_diskusage()[0] total = self.__device_engine.get_device().get_diskusage()[1] prog_bar = self.__getWidget("progressbar_disk_usage") prog_bar.set_fraction(float(used)/float(total)) prog_bar.set_text("%s of %s" % (util.format_filesize(used), util.format_filesize(total))) # batterie level max = self.__device_engine.get_device().get_batterylevel()[0] current = self.__device_engine.get_device().get_batterylevel()[1] prog_bar = self.__getWidget("progressbar_batterie_level") fraction = float(current)/float(max) prog_bar.set_fraction(fraction) prog_bar.set_text("%i%%" % (fraction * 100)) infos = self.__device_engine.get_device().get_information() text="" for info in infos: text += "<b>" + info[0] + ":</b> " + info[1] + "\n" self.__getWidget("label_information").set_markup(text)
return localCommand, command, mouse_x, mouse_y ##### START OF THE GAME ### Main Menu # get user's nick nickname = input('Enter nickname: ') ip = input('Enter server\'s ip adress: ') if ip == '': ip = '127.0.0.1' # init connection with the server transfer_manager = TransferManager(nickname, ip) if transfer_manager.initConnection() == -1: sys.exit() done = False while (not done): # ask user if he is ready to start the game input('Ready?: ') transfer_manager.ready_to_play = True # wait for init pack to be sent while (transfer_manager.init_pack_recived == False): continue
class MTPnavigator: #--- INITIALISATION ---------------------------------- def __init__(self): self.__device_engine = None self.transfer_manager = None self.__current_mode = None self.__current_folder = 0 self.__file_chooser_current_folder = None # bind to glade self.gtkbuilder = gtk.Builder() self.gtkbuilder.add_from_file(XML_GUI_FILE) self.gtkbuilder.connect_signals(self) self.window = self.__getWidget("window_mtpnav") uimanager = self.__create_uimanager() self.__treeview_files = TreeViewFiles(self) self.__treeview_navigator = TreeViewNavigator(self) self.__getWidget("scrolledwindow_navigator").add( self.__treeview_navigator) self.__treeview_navigator.set_property("visible", True) self.__getWidget("scrolledwindow_files").add(self.__treeview_files) self.__treeview_files.set_property("visible", True) TEXT_COLOR_DEFAULT = self.__getWidget( "entry_add_object").get_style().text[gtk.STATE_NORMAL] wwidth = 800 #TODO: save size wheight = 600 self.window.set_default_size(wwidth, wheight) self.window.set_size_request(500, 350) #self.__getWidget("vpaned_main").set_position(wheight-250) #TODO: save position self.__create_combo_change_mode() self.window.show() self.on_connect_device() def __getWidget(self, widget_id): return self.gtkbuilder.get_object(widget_id) def __create_uimanager(self): ui = ''' <menubar name="MenuBar"> <menu action="File"> <menuitem action="Connect"/> <menuitem action="Disconnect"/> <separator/> <menuitem action="Quit"/> </menu> <menu action="Device"> <menuitem action="SendFiles"/> <menuitem action="Delete"/> <menuitem action="CreateFolder"/> <menuitem action="CreatePlaylist"/> </menu> <menu action="Help"> <menuitem action="About"/> </menu> </menubar> <toolbar action="Toolbar"> <toolitem action="Connect"/> <toolitem action="Disconnect"/> <separator/> <toolitem action="SendFiles"/> <toolitem action="Delete"/> </toolbar> ''' self.__actiongroup = gtk.ActionGroup('MainActions') #TRANSLATE: see http://www.moeraki.com/pygtktutorial/pygtk2reference/class-gtkactiongroup.html#method-gtkactiongroup--set-translation-domain self.__actiongroup.add_actions([ ('File', None, '_File'), ('Device', None, '_Device'), ('Connect', gtk.STOCK_CONNECT, '_Connect', None, 'Connect the device', self.on_connect_device), ('Disconnect', gtk.STOCK_DISCONNECT, '_Disconnect', None, 'Disconnect the device', self.on_disconnect_device), ('Quit', gtk.STOCK_QUIT, '_Quit', None, 'Quit the Program', self.on_quit), ('Help', None, '_Help'), ('About', gtk.STOCK_ABOUT, '_About', None, 'About ' + APPLICATION_NAME, self.on_about) ]) self.__actiongroup_connected = gtk.ActionGroup('ActionConnected') self.__actiongroup_connected.add_actions([ ('SendFiles', gtk.STOCK_OPEN, '_Send files to device...', '<Control>S', 'Pickup files to transfer into the device', self.on_send_files), ('Delete', gtk.STOCK_DELETE, '_Delete', None, 'Delete the selected objects from device', self.on_delete_item_activate), ('CreateFolder', None, 'Create _folder', None, 'Add a new folder into the currently selected folder', self.on_create_folder_item_activate), ('CreatePlaylist', None, 'Create _playlist', None, 'Create a new playlist', self.on_create_playlist_item_activate) ]) self.__actiongroup_connected.get_action('SendFiles').set_property( 'short-label', '_Send...') self.__actiongroup_connected.set_sensitive(False) self.__actiongroup.get_action("Disconnect").set_visible(False) uimanager = gtk.UIManager() uimanager.insert_action_group(self.__actiongroup, 0) uimanager.insert_action_group(self.__actiongroup_connected, 0) uimanager.add_ui_from_string(ui) self.window.add_accel_group(uimanager.get_accel_group()) self.__getWidget("vbox_Menu_And_ToolBar").pack_start( uimanager.get_widget('/MenuBar'), expand=False) self.__getWidget("vbox_Menu_And_ToolBar").pack_start( uimanager.get_widget('/Toolbar'), expand=False) def __create_combo_change_mode(self): liststore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_UINT) liststore.append(["audio-x-generic", "Playlists", MODE_PLAYLIST_VIEW]) #TRANSLATE liststore.append(["folder", "Folders", MODE_FOLDER_VIEW]) #TRANSLATE combobox = self.__getWidget("combo_change_mode") combobox.set_model(liststore) cell = gtk.CellRendererPixbuf() combobox.pack_start(cell, False) combobox.set_attributes(cell, icon_name=0) cell = gtk.CellRendererText() combobox.pack_start(cell, True) combobox.add_attribute(cell, 'text', 1) combobox.connect('changed', self.on_combo_change_mode_changed) #--- EVENTS ---------------------------------- def on_connect_device(self, widget=None): self.connect_device() def on_disconnect_device(self, widget=None): self.disconnect_device() def on_delete_item_activate(self, emiter): treeview = None if self.__treeview_navigator.is_focus(): if DEBUG: debug_trace( "Delete action activated. __treeview_navigator has focus", sender=self) treeview = self.__treeview_navigator if self.__treeview_files.is_focus(): if DEBUG: debug_trace( "Delete action activated. __treeview_files has focus", sender=self) treeview = self.__treeview_files if not treeview: if DEBUG: debug_trace("Delete action activated. No treeview has focus", sender=self) return selection = treeview.get_selected_rows_metadata() self.delete_objects(selection) def on_create_folder_item_activate(self, emiter): dialog = GetTextDialog(self.window, "Enter the new folder name") #TRANSLATE if dialog.run() == gtk.RESPONSE_OK: self.__create_folder(dialog.get_text()) dialog.destroy() def on_create_playlist_item_activate(self, emiter): dialog = GetTextDialog(self.window, "Enter the new playlist name") #TRANSLATE if dialog.run() == gtk.RESPONSE_OK: self.__create_playlist(dialog.get_text()) dialog.destroy() def on_button_cancel_job_clicked(self, emiter): (model, paths) = self.transfer_manager.get_selection().get_selected_rows() to_cancel = [ ] #store the files id to delete before stating deleted, else, path may change if more line are selecetd for path in paths: job = model.get_job(path) to_cancel.append(job) for job in to_cancel: self.transfer_manager.cancel_job(job) def on_quit(self, emiter): self.exit() def on_about(self, emiter): dlg = self.__getWidget("aboutdialog") dlg.set_program_name(APPLICATION_NAME) dlg.set_version(VERSION) dlg.set_copyright(COPYRIGHT) dlg.set_authors(AUTHORS) dlg.run() dlg.hide() def on_window_mtpnav_destroy(self, widget): self.exit() def on_send_files(self, widget): parent_id = self.get_current_folder() # create and open the file chooser title = "Select files to transfer to the device" buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK) fs = gtk.FileChooserDialog(title, self.window, gtk.FILE_CHOOSER_ACTION_OPEN, buttons) fs.set_select_multiple(True) fs.set_default_response(gtk.RESPONSE_OK) if self.__file_chooser_current_folder: fs.set_current_folder(self.__file_chooser_current_folder) response = fs.run() if response == gtk.RESPONSE_OK: uris = fs.get_uris() self.__file_chooser_current_folder = fs.get_current_folder() fs.destroy() for uri in uris: self.transfer_manager.send_file(uri, parent_id) else: fs.destroy() def on_combo_change_mode_changed(self, combo): iter = combo.get_active_iter() mode = combo.get_model().get(iter, 2)[0] self.activate_mode(mode) def on_btn_add_object_clicked(self, button): new_object = self.__getWidget("entry_add_object").get_text() self.__empty_new_object_entry() if new_object == "" or new_object == self.__add_object_empty_text: msg = "Please, enter a name for the new element" #TRANSLATE notify_information(msg, sender=self.window) return if self.__current_mode == MODE_FOLDER_VIEW: self.__create_folder(new_object) elif self.__current_mode == MODE_PLAYLIST_VIEW: self.__create_playlist(new_object) else: if DEBUG: debug_trace("Unknow mode %i" % self.__current_mode, sender=self) assert False def on_entry_add_object_focus_in_event(self, widget, event): #widget.modify_text(gtk.STATE_NORMAL, self.default_entry_text_color) if widget.get_text() == self.__add_object_empty_text: widget.modify_text(gtk.STATE_NORMAL, TEXT_COLOR_DEFAULT) widget.set_text('') def on_entry_add_object_focus_out_event(self, widget, event): if widget.get_text() == '': widget.set_text(self.__add_object_empty_text) widget.modify_text(gtk.STATE_NORMAL, TEXT_COLOR_GRAY) #--- CONTROL METHODS ----------------------- def get_current_folder(self): return self.__current_folder def get_selected_rows_metadata(self, treeview): metadata = [] (model, paths) = treeview.get_selection().get_selected_rows() for path in paths: if type(model) is type(gtk.TreeModelFilter()): row = model.get_model().get_metadata( model.convert_path_to_child_path(path)) else: row = model.get_metadata(path) metadata.append(row) return metadata def __create_folder(self, new_folder_name): parent_id = self.get_current_folder() self.transfer_manager.create_folder(new_folder_name, parent_id) def __create_playlist(self, new_playlist_name): self.transfer_manager.create_playlist(new_playlist_name) def __show_connected_state(self, is_connected): self.__actiongroup_connected.set_sensitive(is_connected) self.__actiongroup.get_action("Connect").set_visible(not is_connected) self.__actiongroup.get_action("Disconnect").set_visible(is_connected) #self.__getWidget("hbox_device_information").set_sensitive(is_connected) self.__getWidget("scrolledwindow_files").set_sensitive(is_connected) self.__getWidget("vbox1").set_sensitive(is_connected) if is_connected: connected_device = self.__device_engine.get_device().get_name() else: connected_device = "No device connected" #TRANSLATE self.__getWidget("label_device_name").set_markup("<b>" + connected_device + "</b>") self.__getWidget("label_device_name2").set_markup("<b>" + connected_device + "</b>") if not is_connected: self.window.set_title(APPLICATION_NAME) prog_bar = self.__getWidget("progressbar_disk_usage") prog_bar.set_fraction(0) prog_bar.set_text("") prog_bar = self.__getWidget("progressbar_batterie_level") prog_bar.set_fraction(0) prog_bar.set_text("") self.__getWidget("label_information").set_text( "No device connected") else: self.window.set_title(connected_device + " - " + APPLICATION_NAME) # disk usage used = self.__device_engine.get_device().get_diskusage()[0] total = self.__device_engine.get_device().get_diskusage()[1] prog_bar = self.__getWidget("progressbar_disk_usage") prog_bar.set_fraction(float(used) / float(total)) prog_bar.set_text( "%s of %s" % (util.format_filesize(used), util.format_filesize(total))) # batterie level max = self.__device_engine.get_device().get_batterylevel()[0] current = self.__device_engine.get_device().get_batterylevel()[1] prog_bar = self.__getWidget("progressbar_batterie_level") fraction = float(current) / float(max) prog_bar.set_fraction(fraction) prog_bar.set_text("%i%%" % (fraction * 100)) def __empty_new_object_entry(self, ): if self.__current_mode == MODE_PLAYLIST_VIEW: empty_text = "New playlist name..." #TRANSLATE elif self.__current_mode == MODE_FOLDER_VIEW: empty_text = "new folder name..." #TRANSLATE else: if DEBUG: debug_trace("Unknow mode %i" % self.__current_mode, sender=self) assert False self.__add_object_empty_text = empty_text entry = self.__getWidget("entry_add_object") entry.set_text(empty_text) entry.modify_text(gtk.STATE_NORMAL, TEXT_COLOR_GRAY) button = self.__getWidget("btn_add_object") def connect_device(self): self.__device_engine = None if "--dummy-device" in sys.argv: debug_trace("USE DUMMY DEVICE") import dummyDevice dev = dummyDevice.DummyDevice() else: if not pymtp_available: msg = "pymtp is not or incorrectly installed on your system.\nThis is needed to access you device.\nGoto http://nick125.com/projects/pymtp to grab it and get installation instruction " notify_error(msg, title="pymtp not available", sender=self.window) self.__show_connected_state(False) return dev = MTPDevice() self.__device_engine = DeviceEngine(dev) try: self.__device_engine.connect_device() except Exception, exc: msg = "No device was found.\nPlease verify it was correctly plugged" notify_error(msg, title="No device found", exception=exc, sender=self.window) self.__device_engine = None self.__show_connected_state(False) return self.__show_connected_state(True) # FIXME: Do not pass gui elements. use observer/observable instead tv = self.__getWidget("treeview_transfer_manager") notebook = self.__getWidget("notebook_device_info") prog_bar = self.__getWidget("progressbar_disk_usage") self.transfer_manager = TransferManager(self.__device_engine, tv, notebook, prog_bar) self.activate_mode(MODE_FOLDER_VIEW) self.__getWidget("combo_change_mode").set_active(MODE_PLAYLIST_VIEW)
class MTPnavigator: def __init__(self): self.__treeview_track = None self.__device_engine = None self.__transferManager = None # bind to glade self.gtkbuilder = gtk.Builder() self.gtkbuilder.add_from_file("./mtpnavigator/MTPnavigator.xml") self.gtkbuilder.connect_signals(self) self.window = self.__getWidget("window_mtpnav") wwidth=800 #TODO save size wheight=600 self.window.set_default_size(wwidth, wheight) self.window.set_size_request(500,350) self.window.set_title("MTP navigatore " + VERSION) self.__getWidget("vpaned_main").set_position(wheight-250) #TODO: save position # create the track view self.__treeview_track = self.gtkbuilder.get_object("treeview_track_list") self.__treeview_track.get_selection().set_mode( gtk.SELECTION_MULTIPLE) t = TrackListingModel if DEBUG: col = gtk.TreeViewColumn("object ID", gtk.CellRendererText(), text=t.OBJECT_ID) self.__treeview_track.append_column(col) col = gtk.TreeViewColumn("title", gtk.CellRendererText(), text=t.TITLE) col.set_sort_column_id(t.TITLE) self.__treeview_track.append_column(col) col = gtk.TreeViewColumn("artist", gtk.CellRendererText(), text=t.ARTIST) col.set_sort_column_id(t.ARTIST) self.__treeview_track.append_column(col) col = gtk.TreeViewColumn("album", gtk.CellRendererText(), text=t.ALBUM) col.set_sort_column_id(t.ALBUM) self.__treeview_track.append_column(col) col = gtk.TreeViewColumn("genre", gtk.CellRendererText(), text=t.GENRE) col.set_sort_column_id(t.GENRE) self.__treeview_track.append_column(col) col = gtk.TreeViewColumn("length", gtk.CellRendererText(), text=t.LENGTH_STR) col.set_sort_column_id(t.LENGTH_INT) self.__treeview_track.append_column(col) col = gtk.TreeViewColumn("date", gtk.CellRendererText(), text=t.DATE) col.set_sort_column_id(t.DATE) self.__treeview_track.append_column(col) # add drag and drop support # @TODO: deactivate if not connected self.__treeview_track.drag_dest_set(gtk.DEST_DEFAULT_ALL, [('text/uri-list', 0, 0)], gtk.gdk.ACTION_COPY) self.__treeview_track.connect('drag_data_received', self.on_drag_data_received) self.connect_or_disconnect_device() self.window.show() def __getWidget(self, widget_id): return self.gtkbuilder.get_object(widget_id) #------ EVENTS ---------------------------------- def on_delete_files_activate(self, emiter): (model, paths) = self.__treeview_track.get_selection().get_selected_rows() to_del = [] #store the files id to delete before stating deleted, else, path may change if more line are selecetd for path in paths: metadata = model.get_row(path) to_del.append(metadata) for metadata in to_del: if DEBUG: debug_trace("deleting file with ID %s (%s)" % (metadata.id, metadata.filename), sender=self) self.__transferManager.del_file(metadata) def on_connect_activate(self, emiter): self.connect_or_disconnect_device() def on_quit_activate(self, emiter): self.exit() def on_window_mtpnav_destroy(self, widget): self.exit() def on_send_files_activate(self, widget): title = "Select files to transfer to the device" buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK) fs = gtk.FileChooserDialog(title, self.window, gtk.FILE_CHOOSER_ACTION_OPEN, buttons) fs.set_select_multiple(True) fs.set_default_response(gtk.RESPONSE_OK) #fs.set_current_folder("") #TODO: remember previous path response = fs.run() if response == gtk.RESPONSE_OK: for uri in fs.get_uris(): self.send_file(uri) fs.destroy() def on_drag_data_received(self, w, context, x, y, data, info, time): if data and data.format == 8: for uri in data.data.split('\r\n')[:-1]: self.send_file(uri) context.finish(True, False, time) def exit(self): self.window.destroy() gtk.main_quit() def connect_or_disconnect_device(self): widgets = ["menuitem_send_files", "menuitem_delete_files", "button_add_file", "button_del_file", "hbox_device_information"] if self.__device_engine: self.__disconnect_device() else: self.__connect_device() sensible = (self.__device_engine is not None) for w in widgets: self.__getWidget(w).set_sensitive(sensible) def __connect_device(self): dev = MTPDevice() self.__device_engine = DeviceEngine(dev) if not self.__device_engine.connect_device(): # TODO: notify connection failed self.__device_engine = None return tv = self.__getWidget("treeview_transfer_manager") notebook = self.__getWidget("notebook_device_info") self.__transferManager = TransferManager(self.__device_engine, tv, notebook) # update model model = self.__device_engine.get_track_listing_model() self.__treeview_track.set_model(model) # change menu and toobar label and stock #TODO: use gtk.Action and gtk.ActionGroup for menu and toolbutton # ou uimanager http://python.developpez.com/cours/pygtktutorial/php/pygtkfr/sec-UIManager.php text="Disconnect device" stock=gtk.STOCK_DISCONNECT #TODO self.__getWidget("button_connect").set_label(text) self.__getWidget("button_connect").set_stock_id(stock) #TODO self.__getWidget("menuitem_connect").set_label(text) img = gtk.image_new_from_stock(stock, gtk.ICON_SIZE_LARGE_TOOLBAR) #TODO self.__getWidget("menuitem_connect").set_image(img) self.__getWidget("label_device_name").set_markup("<b>" + self.__device_engine.get_device().get_name() + "</b>") self.__getWidget("label_device_name2").set_markup("<b>" + self.__device_engine.get_device().get_name() + "</b>") # disk usage used = self.__device_engine.get_device().get_diskusage()[0] total = self.__device_engine.get_device().get_diskusage()[1] prog_bar = self.__getWidget("progressbar_disk_usage") prog_bar.set_fraction(float(used)/float(total)) prog_bar.set_text("%s of %s" % (util.format_filesize(used), util.format_filesize(total))) # batterie level max = self.__device_engine.get_device().get_batterylevel()[0] current = self.__device_engine.get_device().get_batterylevel()[1] prog_bar = self.__getWidget("progressbar_batterie_level") fraction = float(current)/float(max) prog_bar.set_fraction(fraction) prog_bar.set_text("%i%%" % (fraction * 100)) infos = self.__device_engine.get_device().get_information() text="" for info in infos: text += "<b>" + info[0] + ":</b> " + info[1] + "\n" self.__getWidget("label_information").set_markup(text) def __disconnect_device(self): self.__device_engine.disconnect_device() self.__device_engine = None self.__treeview_track.set_model(None) # change menu and toobar label and stock text="Connect device" stock=gtk.STOCK_CONNECT self.__getWidget("button_connect").set_label(text) self.__getWidget("button_connect").set_stock_id(stock) self.__getWidget("menuitem_connect").set_label(text) img = gtk.image_new_from_stock(stock, gtk.ICON_SIZE_LARGE_TOOLBAR) self.__getWidget("menuitem_connect").set_image(img) self.__getWidget("label_device_name").set_markup("<b>No device connected</b>") self.__getWidget("label_device_name2").set_markup("<b>No device connected</b>") # device info prog_bar.set_fraction(0) prog_bar.set_text("") prog_bar.set_fraction(0) prog_bar.set_text("") self.__getWidget("label_information").set_text("No device connected") def send_file(self, uri): #TODO copy whole directory self.__transferManager.send_file(uri)
class MTPnavigator: def __init__(self): self.__treeview_track = None self.__treeview_file = None self.__device_engine = None self.__transferManager = None # bind to glade self.gtkbuilder = gtk.Builder() self.gtkbuilder.add_from_file(XML_GUI_FILE) self.gtkbuilder.connect_signals(self) self.window = self.__getWidget("window_mtpnav") uimanager = self.__create_uimanager() wwidth = 800 #TODO save size wheight = 600 self.window.set_default_size(wwidth, wheight) self.window.set_size_request(500, 350) self.window.set_title("MTP navigatore " + VERSION) self.__getWidget("vpaned_main").set_position(wheight - 250) #TODO: save position # create the track view self.__treeview_track = self.gtkbuilder.get_object( "treeview_track_list") self.__treeview_track.get_selection().set_mode(gtk.SELECTION_MULTIPLE) t = TrackListingModel # columns to create: (visible, title, model_col, sort_col, sizing, width, resizable) cols = [(DEBUG_ID, "object ID", t.OBJECT_ID, t.OBJECT_ID, gtk.TREE_VIEW_COLUMN_AUTOSIZE, -1, False), (DEBUG_ID, "parent ID", t.PARENT_ID, t.OBJECT_ID, gtk.TREE_VIEW_COLUMN_AUTOSIZE, -1, False), (True, "title", t.TITLE, t.TITLE, gtk.TREE_VIEW_COLUMN_FIXED, COL_DEFAULT_WIDTH, True), (True, "artist", t.ARTIST, t.ARTIST, gtk.TREE_VIEW_COLUMN_FIXED, COL_DEFAULT_WIDTH, True), (True, "album", t.ALBUM, t.ALBUM, gtk.TREE_VIEW_COLUMN_FIXED, COL_DEFAULT_WIDTH, True), (True, "genre", t.GENRE, t.GENRE, gtk.TREE_VIEW_COLUMN_FIXED, COL_DEFAULT_WIDTH, True), (True, "length", t.LENGTH_STR, t.LENGTH_INT, gtk.TREE_VIEW_COLUMN_AUTOSIZE, -1, True), (True, "date", t.DATE_STR, t.DATE, gtk.TREE_VIEW_COLUMN_AUTOSIZE, -1, True)] for c in cols: if not c[0]: continue col = gtk.TreeViewColumn(c[1]) cell = gtk.CellRendererText() cell.set_property('ellipsize', pango.ELLIPSIZE_END) col.pack_start(cell, True) col.set_attributes(cell, text=c[2]) col.set_sort_column_id(c[3]) col.set_sizing(c[4]) if c[5] > 0: col.set_fixed_width(c[5]) col.set_resizable(c[6]) self.__treeview_track.append_column(col) # add drag and drop support # @TODO: deactivate if not connected self.__treeview_track.drag_dest_set( gtk.DEST_DEFAULT_ALL, [('text/uri-list', 0, 0)], gtk.gdk.ACTION_COPY | gtk.gdk.ACTION_MOVE) self.__treeview_track.connect('drag_data_received', self.on_drag_data_received) # create the file view self.__treeview_file = self.gtkbuilder.get_object("treeview_file_list") self.__treeview_file.get_selection().set_mode(gtk.SELECTION_MULTIPLE) f = FileTreeModel if DEBUG_ID: col = gtk.TreeViewColumn("object ID", gtk.CellRendererText(), text=f.OBJECT_ID) self.__treeview_file.append_column(col) col = gtk.TreeViewColumn("parent ID", gtk.CellRendererText(), text=f.PARENT_ID) self.__treeview_file.append_column(col) col = gtk.TreeViewColumn("filename") cell = gtk.CellRendererPixbuf() col.pack_start(cell, False) col.set_attributes(cell, icon_name=f.ICON) cell = gtk.CellRendererText() col.pack_start(cell, True) col.set_attributes(cell, text=f.FILENAME) col.set_sort_column_id(f.FILENAME) col.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) col.set_fixed_width(400) col.set_resizable(True) self.__treeview_file.append_column(col) col = gtk.TreeViewColumn("length", gtk.CellRendererText(), text=f.LENGTH_STR) col.set_sort_column_id(f.LENGTH_INT) col.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE) self.__treeview_file.append_column(col) self.__treeview_file.expand_all() # add drag and drop support # @TODO: deactivate if not connected self.__treeview_file.drag_dest_set( gtk.DEST_DEFAULT_ALL, [('text/uri-list', 0, 0)], gtk.gdk.ACTION_COPY | gtk.gdk.ACTION_MOVE) self.__treeview_file.connect('drag_motion', self.on_drag_motion) self.__treeview_file.connect('drag_drop', self.on_drag_drop) self.__treeview_file.connect('drag_data_received', self.on_drag_data_received) self.window.show() self.on_connect_device() def __create_uimanager(self): ui = ''' <menubar name="MenuBar"> <menu action="File"> <menuitem action="Connect"/> <menuitem action="Disconnect"/> <separator/> <menuitem action="Quit"/> </menu> <menu action="Device"> <menuitem action="CreateFolder"/> <menuitem action="SendFiles"/> <menuitem action="Delete"/> </menu> </menubar> <toolbar action="Toolbar"> <toolitem action="Connect"/> <toolitem action="Disconnect"/> <separator/> <toolitem action="SendFiles"/> <toolitem action="Delete"/> </toolbar> ''' self.__actiongroup = gtk.ActionGroup('MainActions') #TRANSLATE: see http://www.moeraki.com/pygtktutorial/pygtk2reference/class-gtkactiongroup.html#method-gtkactiongroup--set-translation-domain self.__actiongroup.add_actions([ ('File', None, '_File'), ('Device', None, '_Device'), ('Connect', gtk.STOCK_CONNECT, '_Connect', None, 'Connect the device', self.on_connect_device), ('Disconnect', gtk.STOCK_DISCONNECT, '_Disconnect', None, 'Disconnect the device', self.on_disconnect_device), ('Quit', gtk.STOCK_QUIT, '_Quit', None, 'Quit the Program', self.on_quit), ]) self.__actiongroup_connected = gtk.ActionGroup('ActionConnected') self.__actiongroup_connected.add_actions([ ('CreateFolder', None, '_Create folder...', None, 'Create a folder into the selected folder', self.on_create_folder), ('SendFiles', gtk.STOCK_OPEN, '_Send files to device...', '<Control>S', 'Pickup files to transfer into the device', self.on_send_files), ('Delete', gtk.STOCK_DELETE, '_Delete', 'Delete', 'Delete the selected objects from device', self.on_delete_files) ]) self.__actiongroup_connected.get_action('SendFiles').set_property( 'short-label', '_Send...') self.__actiongroup_connected.set_sensitive(False) self.__actiongroup.get_action("Disconnect").set_visible(False) uimanager = gtk.UIManager() uimanager.insert_action_group(self.__actiongroup, 0) uimanager.insert_action_group(self.__actiongroup_connected, 0) uimanager.add_ui_from_string(ui) self.window.add_accel_group(uimanager.get_accel_group()) self.__getWidget("vbox_Menu_And_ToolBar").pack_start( uimanager.get_widget('/MenuBar'), expand=False) self.__getWidget("vbox_Menu_And_ToolBar").pack_start( uimanager.get_widget('/Toolbar'), expand=False) def __getWidget(self, widget_id): return self.gtkbuilder.get_object(widget_id) #------ EVENTS ---------------------------------- def on_create_folder(self, emiter): # find the last selected row ? FIXME: what to do there if more rows are selected? selrow_metadata = None selected = self.__get_currently_selected_rows_metadata() if selected: selrow_metadata = selected[-1] parent_id = 0 if selrow_metadata: parent_id = selrow_metadata.id debug_trace("create folder on item %s" % parent_id, sender=self) # if the row is not a folder, take the parent which should be one if selrow_metadata.type <> Metadata.TYPE_FOLDER: parent_id = selrow_metadata.parent_id debug_trace( "It was not a folder. Its parent %s is taken instead." % parent_id, sender=self) if parent_id == 0: # not allow to create folder on root msg = "You can't add a folder to the root.\nSelect which folder to create a new one into" notify_error(msg, title="Add folder", exception=None, sender=self.window) return dlg = GetTextDialog(self.window, "Enter the new folder name:") new_folder_name = dlg.get_text() if new_folder_name and new_folder_name <> "": self.__transferManager.create_folder(new_folder_name, parent_id) def on_delete_files(self, emiter): #store the files id to delete before stating deleted, else, path may change if more line are selecetd to_del = [] folder_count = 0 for row in self.__get_currently_selected_rows_metadata(): to_del.append(row) if row.type == Metadata.TYPE_FOLDER: folder_count += 1 if len(to_del) == 0: return # show confirmation msg = "You are about to delete %i files" % (len(to_del) - folder_count) if folder_count > 0: msg += " and %i folders\nAll the files contained within the folders will be destroyed as well" % folder_count confirm_dlg = gtk.MessageDialog(self.window, gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION, gtk.BUTTONS_OK_CANCEL, msg) confirm_dlg.set_title("Confirm delete") response = confirm_dlg.run() confirm_dlg.destroy() if response <> gtk.RESPONSE_OK: return # send order to transfer manager for metadata in to_del: if DEBUG: debug_trace("deleting file with ID %s (%s)" % (metadata.id, metadata.filename), sender=self) self.__transferManager.del_file(metadata) def on_button_cancel_job_clicked(self, emiter): (model, paths) = self.__transferManager.get_selection().get_selected_rows() to_cancel = [ ] #store the files id to delete before stating deleted, else, path may change if more line are selecetd for path in paths: job = model.get_job(path) to_cancel.append(job) for job in to_cancel: self.__transferManager.cancel_job(job) def on_quit(self, emiter): self.exit() def on_window_mtpnav_destroy(self, widget): self.exit() def on_send_files(self, widget): # find the last selected row ? FIXME: what to do there if more rows are selected? selrow_metadata = None selected = self.__get_currently_selected_rows_metadata() if selected: selrow_metadata = selected[-1] # create and open the file chooser title = "Select files to transfer to the device" buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK) fs = gtk.FileChooserDialog(title, self.window, gtk.FILE_CHOOSER_ACTION_OPEN, buttons) fs.set_select_multiple(True) fs.set_default_response(gtk.RESPONSE_OK) #fs.set_current_folder("") #TODO: remember previous path response = fs.run() if response == gtk.RESPONSE_OK: for uri in fs.get_uris(): self.send_file(uri, selrow_metadata) fs.destroy() def on_drag_motion(self, treeview, drag_context, x, y, time): return #FIXME treeview.get_selection().set_mode(gtk.SELECTION_SINGLE) treeview.set_hover_selection(True) treeview.set_hover_expand(True) def on_drag_drop(self, treeview, drag_context, x, y, time, data): return #FIXME treeview.get_selection().set_mode(gtk.SELECTION_MULTIPLE) treeview.set_hover_selection(False) treeview.set_hover_expand(False) def on_drag_data_received(self, treeview, context, x, y, data, info, time): if data and data.format == 8: # find the row where data was dropped selrow_metadata = None drop_info = treeview.get_dest_row_at_pos(x, y) if drop_info: selrow_metadata = treeview.get_model().get_metadata( drop_info[0]) # process the list containing dropped objects for uri in data.data.split('\r\n')[:-1]: self.send_file(uri, selrow_metadata) context.finish(True, False, time) #FIXME: reject if not a file? def send_file(self, uri, selrow_metadata): """ selected_row: the metadata of the selected row """ assert not selrow_metadata or type(selrow_metadata) is type( Metadata.Metadata()) parent_id = 0 if selrow_metadata: parent_id = selrow_metadata.id debug_trace("files where dropped on %s" % parent_id, sender=self) # if the row is not a folder, take the parent which should be one if selrow_metadata.type <> Metadata.TYPE_FOLDER: parent_id = selrow_metadata.parent_id debug_trace( "It was not a folder. Its parent %s is taken instead." % parent_id, sender=self) return self.__transferManager.send_file(uri, parent_id) def exit(self): self.window.destroy() gtk.main_quit() def __get_currently_selected_rows_metadata(self): tv = None selrow_metadata = None #get the current treeview if self.__treeview_file.is_focus(): tv = self.__treeview_file elif self.__treeview_track.is_focus(): tv = self.__treeview_track else: return None # find which (last) row was selected on which treeview selrow_metadata = [] (model, paths) = tv.get_selection().get_selected_rows() if tv: for path in paths: selrow_metadata.append(model.get_metadata(path)) return selrow_metadata def on_connect_device(self, widget=None): self.__device_engine = None if not pymtp_available: msg = "pymtp is not or incorrectly installed on your system.\nThis is needed to access you device.\nGoto http://nick125.com/projects/pymtp to grab it and get installation instruction " notify_error(msg, title="pymtp not available", sender=self.window) self.__show_connected_state(False) return dev = MTPDevice() self.__device_engine = DeviceEngine(dev) try: self.__device_engine.connect_device() except Exception, exc: msg = "No device was found.\nPlease verify it was correctly plugged" notify_error(msg, title="No device found", exception=exc, sender=self.window) self.__device_engine = None self.__show_connected_state(False) return self.__show_connected_state(True) # FIXME Do not pass gui elements. use observer/observable instead tv = self.__getWidget("treeview_transfer_manager") notebook = self.__getWidget("notebook_device_info") prog_bar = self.__getWidget("progressbar_disk_usage") self.__transferManager = TransferManager(self.__device_engine, tv, notebook, prog_bar) # update models model = self.__device_engine.get_track_listing_model() self.__treeview_track.set_model(model) model = self.__device_engine.get_file_tree_model() self.__treeview_file.set_model(model)