def rebuild_database(self): from time import time as systime systime1 = systime() #Tempory Database connection for thread conn = sqlite3.connect(self.dblocation) cursor = conn.cursor() trackparser = TrackMetaData() #clear out current database cursor.execute("DELETE FROM Songs") for libraryfolder in self.libraryfolders: libraryfolder = libraryfolder.replace('file://', '').replace( '%20', ' ') #simple but is a bit slow if os.path.isdir(libraryfolder): for root, dirs, files in scandir.walk(libraryfolder): for name in files: metadata = trackparser.getTrackType( os.path.join(root, name)) if metadata != False: #escape single quotes for sql query metadata[2] = metadata[2].replace("'", "''") #Title metadata[3] = metadata[3].replace("'", "''") #Artist metadata[4] = metadata[4].replace("'", "''") #Album metadata[6] = metadata[6].replace("'", "''") #Genre metadata[7] = metadata[7].replace("'", "''") #Url #build query and encode to ascii for python 2 #query = "INSERT INTO Songs(TrackNum,Title,Artist,Album,Length,Genre,Url) VALUES ({},'{}','{}','{}','{}','{}','{}');".format(metadata[1],metadata[2].encode('ascii','ignore'),metadata[3].encode('ascii','ignore'),metadata[4].encode('ascii','ignore'),metadata[5].encode('ascii','ignore'),metadata[6].encode('ascii','ignore'),metadata[7]) #since we truncate anyway, checking for existing entrys is redundant for now """cursor.execute("SELECT * FROM Songs WHERE Url='{}'".format(metadata[7])) if cursor.fetchone() == None: query = "INSERT INTO Songs(TrackNum,Title,Artist,Album,Length,Genre,Url) VALUES ({},'{}','{}','{}','{}','{}','{}');".format(metadata[1],metadata[2],metadata[3],metadata[4],metadata[5],metadata[6],metadata[7]) cursor.execute(query) else: query = "UPDATE Songs SET TrackNum='{}',Title='{}',Artist='{}',Album='{}',Length='{}',Genre='{}' WHERE Url='{}';".format(metadata[1],metadata[2],metadata[3],metadata[4],metadata[5],metadata[6],metadata[7]) cursor.execute(query)""" query = "INSERT INTO Songs(TrackNum,Title,Artist,Album,Length,Genre,Url) VALUES ({},'{}','{}','{}','{}','{}','{}');".format( metadata[1], metadata[2], metadata[3], metadata[4], metadata[5], metadata[6], metadata[7]) cursor.execute(query) conn.commit() print("%s%f" % ("Operation took ", systime() - systime1))
def rebuild_database(self): from time import time as systime systime1 = systime() #Tempory Database connection for thread conn = sqlite3.connect(self.dblocation) cursor = conn.cursor() trackparser = TrackMetaData() #clear out current database cursor.execute("DELETE FROM Songs") for libraryfolder in self.libraryfolders: libraryfolder = libraryfolder.replace('file://','').replace('%20',' ') #simple but is a bit slow if os.path.isdir(libraryfolder): for root, dirs, files in scandir.walk(libraryfolder): for name in files: metadata = trackparser.getTrackType(os.path.join(root, name)) if metadata != False: #escape single quotes for sql query metadata[2] = metadata[2].replace("'","''")#Title metadata[3] = metadata[3].replace("'","''")#Artist metadata[4] = metadata[4].replace("'","''")#Album metadata[6] = metadata[6].replace("'","''")#Genre metadata[7] = metadata[7].replace("'","''")#Url #build query and encode to ascii for python 2 #query = "INSERT INTO Songs(TrackNum,Title,Artist,Album,Length,Genre,Url) VALUES ({},'{}','{}','{}','{}','{}','{}');".format(metadata[1],metadata[2].encode('ascii','ignore'),metadata[3].encode('ascii','ignore'),metadata[4].encode('ascii','ignore'),metadata[5].encode('ascii','ignore'),metadata[6].encode('ascii','ignore'),metadata[7]) #since we truncate anyway, checking for existing entrys is redundant for now """cursor.execute("SELECT * FROM Songs WHERE Url='{}'".format(metadata[7])) if cursor.fetchone() == None: query = "INSERT INTO Songs(TrackNum,Title,Artist,Album,Length,Genre,Url) VALUES ({},'{}','{}','{}','{}','{}','{}');".format(metadata[1],metadata[2],metadata[3],metadata[4],metadata[5],metadata[6],metadata[7]) cursor.execute(query) else: query = "UPDATE Songs SET TrackNum='{}',Title='{}',Artist='{}',Album='{}',Length='{}',Genre='{}' WHERE Url='{}';".format(metadata[1],metadata[2],metadata[3],metadata[4],metadata[5],metadata[6],metadata[7]) cursor.execute(query)""" query = "INSERT INTO Songs(TrackNum,Title,Artist,Album,Length,Genre,Url) VALUES ({},'{}','{}','{}','{}','{}','{}');".format(metadata[1],metadata[2],metadata[3],metadata[4],metadata[5],metadata[6],metadata[7]) cursor.execute(query) conn.commit() print("%s%f" % ("Operation took ",systime() - systime1))
class SopranoApp: def __init__(self): #Global Variables (keep to a minimum) self.settings = settings.IconoSettings(sopranoGlobals.SETTINGS_DATA) self.taglookup = TrackMetaData() self.seekingnow = False #load settings self.currentview, self.winwidth, self.winheight, self.defaultexplorer, self.shuffle, self.repeat, self.showtrayicon, self.closetotray = self.settings.get_settings() libraryFolderlist = settings.IconoPrefs(sopranoGlobals.LIBRARY_DATA) self.SopranoDB = MusicDB(os.path.join(sopranoGlobals.CONFIGDIR, 'sopranoDB.db')) libraryFolderlist.add_radio(('/media/Media/Music','/media/Media/Music')) for key,value in libraryFolderlist.get_radioStations().items(): self.SopranoDB.add_folder(value) #turn on the dbus mainloop for sound menu from dbus.mainloop.glib import DBusGMainLoop DBusGMainLoop(set_as_default=True) #Start Sound Menu Support self.sopranompris = SoundMenuControls("soprano-player") self.sopranompris.signal_next = self.play_next self.sopranompris.signal_prev = self.play_prev self.sopranompris.signal_play_pause = self.play_pause self.sopranompris.signal_raise = self.toggle_window #Enable Notifications Notify.init ("Soprano") self.notification = Notify.Notification.new("","","") #Window Creation self.builder = Gtk.Builder() filename = os.path.join('data', 'MainWindow.glade') self.builder.add_from_file(filename) self.builder.connect_signals(self) self.window = self.builder.get_object('win-main') self.window.set_default_size(self.winwidth,self.winheight) self.window.connect('delete-event', self.pre_exit) #radiowindow self.aRadio = IconoRadio() #Gstreamer sink self.player = MusicPlayer() self.player.on_eos(self.on_message) #media keys setup self.mediakeys = mediakeys(self.play_prev, self.play_pause, self.play_next) timer = GObject.timeout_add(500, self.update_time_items) #trayicon self.tray = IconoTray("soprano-player-tray") self.trayshowhide = self.tray.add_menu_item(self.toggle_window, "Hide/Show") self.tray.add_seperator() self.trayplaypause = self.tray.add_menu_item(self.play_pause, "Play/Pause") self.tray.add_menu_item(self.play_next, "Next") self.tray.add_menu_item(self.play_prev, "Previous") self.tray.add_seperator() self.tray.add_menu_item(self.on_exit, "Quit") self.update_tray_icon(self.showtrayicon) #View Menu# menuvfull = self.builder.get_object('menu-mode-full') menuvfull.connect('activate', self.to_full_mode) menuvmini = self.builder.get_object('menu-mode-mini') menuvmini.connect('activate', self.to_mini_mode) menuvplist = self.builder.get_object('menu-mode-playlist') menuvplist.connect('activate', self.to_playlist_mode) #Quit, About Menus menuaqt = self.builder.get_object('menu-quit') menuaqt.connect('activate',self.on_exit) menuabt = self.builder.get_object('menu-about') menuabt.connect('activate', aboutBoxShow, self.window) #Edit Menu# menuaddfolder = self.builder.get_object('menu-folderadd') #menuaddfolder.connect('activate', lambda x: self.addFolderExplorer(('Video','/media/Media/Videos'))) menuaddfolder.connect('activate', self.show_pref_win) menuaddradio = self.builder.get_object('menu-radioadd') #menuaddradio.connect('activate', lambda x: self.delFolderExplorer(('Video','/media/Media/Videos'))) menuaddradio.connect('activate', self.aRadio.addStationDialog) self.menuautopop = self.builder.get_object('menu-autopop') #playing Toolbar self.toolnext = self.builder.get_object('btn-next') self.toolnext.connect('clicked', self.play_next) self.toolprev = self.builder.get_object('btn-previous') self.toolprev.connect('clicked', self.play_prev) self.toolstop = self.builder.get_object('btn-stop') self.toolstop.connect('clicked', self.stop_play) self.toolplay = self.builder.get_object('btn-play') self.toolplay.connect('clicked', self.play_pause) self.toolSeekBar = self.builder.get_object('scl-position') self.toolSeekBar.connect('button-release-event', self.seek) self.toolSeekBar.connect('button-press-event', self.seekevent) self.toolVolume = self.builder.get_object('btn-volume') self.toolVolume.connect('value-changed', self.change_volume) #Text Displays self.titleText = self.builder.get_object('lbl-trkTitle') self.infoText = self.builder.get_object('lbl-trkMisc') self.lengthLabel = self.builder.get_object('lbl-length') self.elapsedLabel = self.builder.get_object('lbl-elapsed') #bottom toolbar barclr = self.builder.get_object('btn-tracklistClear') barclr.connect('clicked', self.clear_liststore) barshfl = self.builder.get_object('btn-tracklistShuffle') if self.shuffle == True: barshfl.set_active(True) barshfl.connect('clicked', self.shuffleliststore) barrpt = self.builder.get_object('btn-tracklistRepeat') if self.repeat == True: barrpt.set_active(True) barrpt.connect('toggled', self.setrepeat) #listview self.iconoListView = IconoListView() self.iconoListView.get_sw().get_child().connect('row-activated', self.on_activated) #self.iconoListView.get_sw().get_child().connect('button-press-event', self.on_right_click) vbox2 = self.builder.get_object('vbox2') vbox2.add(self.iconoListView.get_sw()) vbox2.reorder_child(self.iconoListView.get_sw(), 1) if os.path.exists(sopranoGlobals.TREE_DATA): GObject.idle_add(self.iconoListView.load_shelf, sopranoGlobals.TREE_DATA) #combobox self.hCombo = HeaderedComboBox() self.hCombo.connect("changed", self.on_name_combo_changed) self.builder.get_object('box-combo-explorer').add(self.hCombo) GObject.idle_add(self.setup_explorer) GObject.idle_add(self.cover_update) self.window.show_all() if self.currentview == 'playlist': menuvplist.set_active(True) self.to_playlist_mode() elif self.currentview == 'mini': menuvmini.set_active(True) self.to_mini_mode() #Notebook self.notebook = self.builder.get_object('notebook-explorer') def update_tray_icon(self, enabled=True): if enabled: try: self.tray.myStatusIcon.set_visible(True) except: self.tray.ind.set_status(AppIndicator3.IndicatorStatus.ACTIVE) elif not enabled: try: self.tray.myStatusIcon.set_visible(False) except: self.tray.ind.set_status(AppIndicator3.IndicatorStatus.PASSIVE) def show_pref_win(self, widget=None): newWin = SopranoPrefWin(self.showtrayicon, self.closetotray, self.window) newWin.win.set_transient_for(self.window) newWin.win.show_all() newWin.win.connect("destroy", self.pref_win_closed) def pref_win_closed(self, widget): currentpage = self.notebook.get_current_page() currentactive = self.hCombo.get_active() self.clear_notebook() self.setup_explorer() self.notebook.set_current_page(currentpage + widget.change) self.hCombo.set_active(currentactive + widget.change) self.showtrayicon = widget.traycheckbox.get_active() if self.showtrayicon: self.closetotray = widget.closecheckbox.get_active() else: self.closetotray = False self.update_tray_icon(self.showtrayicon) def toggle_window(self, justShow=True): if self.window.get_property("visible") and not justShow == True: self.window.hide() #self.trayshowhide.set_label("Show") else: self.window.show() #self.trayshowhide.set_label("Hide") def pre_exit(self, widget, var): if widget == self.window and self.closetotray: self.window.hide() return True else: self.on_exit(widget) def on_exit(self, widget): #hide window and tray icon first to give appearence of instant close self.window.hide() self.tray = None if self.currentview != 'mini': size = self.window.get_size() winheight = size[1]#.height winwidth = size[0]#.width else: winheight = self.winheight winwidth = self.winwidth self.settings.write_settings([self.currentview, winwidth, winheight ,self.notebook.get_current_page()+1, self.shuffle, self.repeat, self.showtrayicon, self.closetotray]) self.iconoListView.save_shelf(sopranoGlobals.TREE_DATA) Gtk.main_quit() def addFolderExplorer(self, station): explorer = IconoTreeFile(station[1], sopranoGlobals.FILE_FORMATS) audioFolderlist = settings.IconoPrefs(sopranoGlobals.EXPLORER_DATA) audioFolderlist.add_radio(station) self.setup_explorer_page(self.notebook, explorer.get_sw(), self.hCombo, [len(audioFolderlist.get_radioStations()), 0, station[0], sopranoGlobals.FOLDERPB], self.notebook.get_n_pages()-2) #Update the audioCD and Radio Indexes model = self.hCombo.get_model() length = len(model) for i in range(1,3): iter = model.get_iter(length-i) model.set_value(iter, 0, length-(1+i)) def clear_notebook(self, widget=None): for i in range(self.notebook.get_n_pages(), 0, -1): self.notebook.remove_page(i-1) self.hCombo.get_model().clear() def delFolderExplorer(self, station): self.clear_notebook() audioFolderlist = settings.IconoPrefs(sopranoGlobals.EXPLORER_DATA) audioFolderlist.delete_radio(station) self.setup_explorer() #explorer and combobox Handlers def setup_explorer(self, widget=None): self.hCombo.add_entry(None, 1, "<b>Folders</b>", None, -1) explorer = IconoTreeFile('/', sopranoGlobals.FILE_FORMATS) self.setup_explorer_page(self.notebook, explorer.get_sw(), self.hCombo, [self.notebook.get_n_pages(), 0, "Root", sopranoGlobals.FOLDERPB]) audioFolderlist = settings.IconoPrefs(sopranoGlobals.EXPLORER_DATA) for key, value in audioFolderlist.get_radioStations().items(): explorer = IconoTreeFile(value, sopranoGlobals.FILE_FORMATS) self.setup_explorer_page(self.notebook, explorer.get_sw(), self.hCombo, [self.notebook.get_n_pages(), 0, key, sopranoGlobals.FOLDERPB]) #aCdTree = IconoAudioCD() #self.setup_explorer_page(self.notebook, aCdTree.get_sw(), self.hCombo, [self.notebook.get_n_pages(), 0, "<b>Audio CD</b>", sopranoGlobals.TRACKPB]) self.setup_explorer_page(self.notebook, self.aRadio.get_sw(), self.hCombo, [self.notebook.get_n_pages(), 0, "<b>Radio</b>", sopranoGlobals.RADIOPB]) self.medialib = IconoMediaLibrary(self.SopranoDB) self.setup_explorer_page(self.notebook, self.medialib.get_sw(), self.hCombo, [self.notebook.get_n_pages(), 0, "<b>Library</b>", sopranoGlobals.USERSPB]) self.notebook.set_current_page(self.defaultexplorer) self.hCombo.set_active(self.defaultexplorer) def setup_explorer_page(self, notebook, widget, combo, arglist, insertHere=-1): combo.add_entry(arglist[0], arglist[1], arglist[2], arglist[3], insertHere) label = Gtk.Label(arglist[2]) notebook.insert_page(widget, label, insertHere) notebook.show_all() def on_name_combo_changed(self, combo): tree_iter = combo.get_active_iter() if tree_iter != None: model = combo.get_model() index, row_id, name = model[tree_iter][:3] if row_id == 1: combo.set_active_iter(model.iter_next(tree_iter)) # if they try and select a header move to the real entry below instead else: self.notebook.set_current_page(index) #ListStore Handlers def on_activated(self, widget, row, col): model = widget.get_model() text = model[row][7] GObject.idle_add(self.playitem, text) self.iconoListView.set_playmark(row) #View Menu Handlers def to_full_mode(self, unused=None): self.window.resize(self.winwidth,self.winheight) self.builder.get_object('pan-main').get_child1().show() self.builder.get_object('statusbar').show() self.builder.get_object('box-btn-tracklist').show() self.iconoListView.get_sw().show() self.currentview = 'full' def to_mini_mode(self, unused=None): self.builder.get_object('pan-main').get_child1().hide() self.builder.get_object('statusbar').hide() self.builder.get_object('box-btn-tracklist').hide() self.iconoListView.get_sw().hide() self.window.resize(600, 150) self.currentview = 'mini' def to_playlist_mode(self, unused=None): self.to_full_mode(None) self.window.resize(self.winwidth, self.winheight) self.builder.get_object('pan-main').get_child1().hide() self.currentview = 'playlist' #Bottom Toolbar Handlers# def clear_liststore(self, action): GObject.idle_add(self.stop_play) self.iconoListView.return_model().clear() def shuffleliststore(self, button): self.shuffle = not(self.shuffle) def setrepeat(self, arg1): self.repeat = not(self.repeat) #Data Display Handlers def update_time_items(self): if (self.player.get_state() == Gst.State.PLAYING): if not(self.seekingnow): self.toolSeekBar.set_value(self.player.track_percent()) self.elapsedLabel.set_text(self.player.get_trackposition()) self.lengthLabel.set_text('/' + self.player.get_tracklength()) return True def update_labels(self, title, artist, album): self.titleText.set_text(title) self.infoText.set_text("By " + artist + " from " + album) def clear_labels(self): self.titleText.set_text("Soprano Audio Player") self.infoText.set_text("...One Goal, Be Epic") self.lengthLabel.set_text("") self.elapsedLabel.set_text("") def cover_update(self): filepath = self.player.get_track() if filepath != None: data = self.taglookup.getTrackType(filepath) try: artist = data[3].replace(' ','%20') except: artist = "" try: album = data[4].replace(' ','%20') except: album = "" coverFetch = getCover(artist, album, filepath) img = coverFetch.run() coverart = self.builder.get_object('img-cover') coverart.set_from_pixbuf(img.scale_simple(100,100,GdkPixbuf.InterpType.BILINEAR)) #Play Handlers def on_message(self, bus, message): self.play_next() def seekevent(self, widget, event): self.seekingnow = True def seek(self, widget, test): self.seekingnow = False self.player.seek(widget.get_value()) def change_volume(self, widget, volume): self.player.change_volume(volume) def play_prev(self, widget=None): for x in range(1,len(self.iconoListView.return_model())): if self.iconoListView.return_model()[x][0] == 'media-playback-start': GObject.idle_add(self.playitem, self.iconoListView.return_model()[x-1][7]) self.iconoListView.set_playmark(x-1) break def play_next(self, widget=None): listlength = len(self.iconoListView.return_model()) if self.shuffle: import random arand = random.randrange(0, listlength) self.iconoListView.set_playmark(arand) self.iconoListView.get_sw().get_child().scroll_to_cell(arand) GObject.idle_add(self.playitem, self.iconoListView.return_model()[arand][7]) return for x in range(0, listlength): #if there on the last track, and they press next without repeat enabled, do nothing if x == listlength-1 and not(self.repeat):# and widget == self.toolnext: if self.menuautopop.get_active() == True: self.SopranoDB.cursor.execute("SELECT Url FROM Songs ORDER BY RANDOM() LIMIT 2;") rows = self.SopranoDB.cursor.fetchall() if len(rows) != 0: for item in rows: self.iconoListView.add_row(item[0],self.iconoListView.return_model(),False) else: break else: break #if the last track finished without repeat enabled, stop playing elif x == listlength-1 and not(self.repeat) and widget != self.toolnext: GObject.idle_add(self.stop_play) break #if there on the last track and repeat is enabled go back to the first track elif x == listlength-1 and self.repeat: self.iconoListView.set_playmark(0) self.iconoListView.get_sw().get_child().scroll_to_cell(0) GObject.idle_add(self.playitem, self.iconoListView.return_model()[0][7]) break #if not the last track, just find the playmark and play the track below if self.iconoListView.return_model()[x][0] == 'media-playback-start': self.iconoListView.set_playmark(x+1) self.iconoListView.get_sw().get_child().scroll_to_cell(x+1) GObject.idle_add(self.playitem, self.iconoListView.return_model()[x+1][7]) break def playitem(self, filepath): self.player.stop_play() self.player.set_track(filepath) self.player.play_item() data = self.taglookup.getTrackType(filepath) #print(data) if data != False: self.update_labels(str(data[2]), str(data[3]), str(data[4])) #Notifications self.notification.update (str(data[2]), str(data[3]), "media-playback-start") self.notification.show() #set Sound Menu Data self.sopranompris.set_metadata(str(data[2]), str(data[3]), str(data[4]), "file://" + sopranoGlobals.CACHEFILE) self.sopranompris.signal_playing() self.toolSeekBar.set_sensitive(True) toolplayimg = self.builder.get_object('image3') toolplayimg.set_from_icon_name('media-playback-pause', Gtk.IconSize.LARGE_TOOLBAR) GObject.idle_add(self.cover_update) else: self.clear_labels() self.play_next() def stop_play(self, *args): self.player.stop_play() self.iconoListView.clear_playmark() self.clear_labels() self.toolSeekBar.set_sensitive(False) self.toolSeekBar.set_value(0) toolplayimg = self.builder.get_object('image3') toolplayimg.set_from_icon_name('media-playback-start', Gtk.IconSize.LARGE_TOOLBAR) GObject.idle_add(self.cover_update) def play_pause(self, filepath=None): #print(self.player.get_state()) toolplayimg = self.builder.get_object('image3') if (self.player.get_state() == Gst.State.PLAYING): if self.player.get_track()[:7] == 'http://' or self.player.get_track()[:6] == 'mms://': self.player.stop_play() print("Radio Stop") else: self.player.pause_item() toolplayimg.set_from_icon_name('media-playback-start', Gtk.IconSize.LARGE_TOOLBAR) #self.trayplaypause.set_label("Play") elif (self.player.get_state() == Gst.State.PAUSED): self.player.play_item() toolplayimg.set_from_icon_name('media-playback-pause', Gtk.IconSize.LARGE_TOOLBAR) #self.trayplaypause.set_label("Pause") else:#if os.path.isfile(filepath): selected = self.iconoListView.get_sw().get_child().get_selection() if selected.get_selected_rows()[1] != []: modeliter = self.iconoListView.return_model().get_iter(selected.get_selected_rows()[1][0]) elif self.player.get_state() == Gst.State.NULL and self.iconoListView.get_playmark() != None: modelrow = self.iconoListView.get_playmark() modeliter = self.iconoListView.return_model().get_iter(modelrow) elif self.iconoListView.return_model().get_iter_first() != None: modeliter = self.iconoListView.return_model().get_iter_first() try: filepath = self.iconoListView.return_model().get_value(modeliter, 7) except: return #self.trayplaypause.set_label("Pause") GObject.idle_add(self.playitem, filepath) self.iconoListView.set_playmark(modeliter) toolplayimg.set_from_icon_name('media-playback-pause', Gtk.IconSize.LARGE_TOOLBAR) GObject.idle_add(self.cover_update)
class IconoListView(): def __init__(self): self.sw = Gtk.ScrolledWindow() self.trackparser = TrackMetaData() builder = Gtk.Builder() filename = os.path.join('data', 'treeview.ui') builder.add_from_file(filename) self.abox = builder.get_object('treeview1') self.abox.set_fixed_height_mode(False) self.abox.set_search_column(1) self.abox.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE) trackCol = builder.get_object('trackCol') titleCol = builder.get_object('titleCol') artistCol = builder.get_object('artistCol') albumCol = builder.get_object('albumCol') lengthCol = builder.get_object('lengthCol') genreCol = builder.get_object('genreCol') pathCol = builder.get_object('pathCol') #need to figure a working sorting function #self.abox.get_model().set_sort_func(1, self.tracknumsortfunc, None) trackCol.set_sort_column_id(1) titleCol.set_sort_column_id(2) artistCol.set_sort_column_id(3) albumCol.set_sort_column_id(4) lengthCol.set_sort_column_id(5) genreCol.set_sort_column_id(6) #anEntry = Gtk.TargetEntry.new("abox",Gtk.TargetFlags.SAME_WIDGET, 10) self.abox.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK, [('TREE_MODEL_ROW', Gtk.TargetFlags.SAME_WIDGET, 0),], Gdk.DragAction.COPY|Gdk.DragAction.MOVE) #self.abox.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, [anEntry], 0) self.abox.enable_model_drag_dest([], Gdk.DragAction.COPY|Gdk.DragAction.DEFAULT) #self.abox.drag_dest_set(0, [], 0) self.abox.connect('drag_motion', self.drag_motion_cb) self.abox.connect('drag_drop', self.drop_cb) self.abox.connect('drag_data_received', self.got_data_cb) self.abox.connect("drag_data_get", self.drag_data_get_data) self.abox.connect('button_press_event', self.on_button_press) self.abox.connect('button_release_event', self.on_button_release) self.defer_select=False self.sw.add(self.abox) def tracknumsortfunc(self,model, row1, row2, user_data): if (model.get_value(row1, 3) == model.get_value(row2, 3)) and (model.get_value(row1, 4) == model.get_value(row2, 4)): #print("Same Band! and Same Album!") #print(model.get_value(row1, 3), model.get_value(row1, 4)) #print cmp(model[row1][3], model[row2][3]) if (model.get_value(row1, 1) <= model.get_value(row2, 1)): print("0") return 0 #print(model.get_value(row1, 1)) #model.swap(row1, row2) else: print("-1") return -1 #model.swap(row2, row1) #else: #print cmp(model[row1][3], model[row2][3]) def drag_data_get_data(self, treeview, context, selection, target_id, etime): treeselection = treeview.get_selection() model, paths = treeselection.get_selected_rows() Gtk.tree_set_row_drag_data(selection, treeview.get_model(), paths[0]) def drag_motion_cb(self, senderID, context, x, y, time): Gdk.drag_status(context, Gdk.DragAction.COPY, time) if self.abox.get_dest_row_at_pos(x, y) == None: return True path, pos = self.abox.get_dest_row_at_pos(x, y) self.abox.set_drag_dest_row(path, pos) return True def got_data_cb(self, windowid, context, x, y, data, info, time): treeselection = windowid.get_selection() model, paths = treeselection.get_selected_rows() refs = [] for path in paths: refs.append(Gtk.TreeRowReference.new(model, path)) #refs = [path.append(Gtk.TreeRowReference.new(model, path)) for path in paths# different way of wording the above destpath = windowid.get_dest_row_at_pos(x, y) if destpath: destpath, position = destpath destiter = model.get_iter(destpath) else: #print "outside the rows" try: destiter = model.get_iter(len(model)) except: destiter = False #handle internal drag/drops here sourceWidget = Gtk.drag_get_source_widget(context) if sourceWidget == windowid: #print "internals" if not destpath in paths: if (position == Gtk.TreeViewDropPosition.BEFORE):# or position == Gtk.TreeViewDropPosition.INTO_OR_BEFORE): print("into or before") for currentref in refs: model.move_before(model.get_iter(currentref.get_path()), destiter) else: print("else") for currentref in reversed(refs): model.move_after(model.get_iter(currentref.get_path()), destiter) else: ##detach model improves performance but causes flicker # MAKES MIKE A SAD PANDA windowid.set_model(None) #f****n file managers handling differently :( nautilus sends plaintext, but pcman sends uris tempArray = [] if data.get_text(): for i in data.get_text().splitlines(): tempArray.append(i) else: for i in data.get_uris(): tempArray.append(i) from time import time as systime systime1 = systime() #got the data now split it up for i in tempArray: i = i.replace('file://','').replace('%20',' ') #simple but is way too slow if os.path.isdir(i): for root, dirs, files in os.walk(i): while Gtk.events_pending(): Gtk.main_iteration() for name in files: #print(name) self.add_row(os.path.join(root, name), model, destiter) else: self.add_row(i, model, destiter) ##reattach model print("%s%f%s%i" % ("Add Operation took ",systime() - systime1," Items:", len(model))) del(systime) windowid.set_model(model) context.finish(True, False, time) def drop_cb(self, windowid, context, x, y, time): # Some data was dropped, get the data windowid.drag_get_data(context, context.list_targets()[-1], time) return True def add_row(self, action, widget, destiter): x = self.trackparser.getTrackType(action) #x = [None, 1,"Title","Artist","Album","400","Genre","/aidscake"] #x.insert(0, None) if destiter == False and x != False: widget.append(x) elif x != False: widget.insert_after(destiter, x) def load_shelf(self, path): model = self.return_model() self.abox.set_model(None) db = pickle.load(open(path, "rb")) for i in range(0, len(db), 8): templist = [] for j in range(0, 8): templist.append(db[i+j]) while Gtk.events_pending(): Gtk.main_iteration() model.append(templist) self.abox.set_model(model) def save_shelf(self, path): count = 0 settings = [] def writeouttree(model, path, iter, data): for i in range(0, 8): settings.append(model.get_value(iter, i)) self.return_model().foreach(writeouttree, None) db = pickle.dump(settings, open(path, "wb" ),2) def on_button_press(self, widget, event): # Here we intercept mouse clicks on selected items so that we can # drag multiple items without the click selecting only one target = widget.get_path_at_pos(int(event.x), int(event.y)) if (target and event.type == Gdk.EventType.BUTTON_PRESS and not (event.get_state() & (Gdk.ModifierType.CONTROL_MASK|Gdk.ModifierType.SHIFT_MASK)) and widget.get_selection().path_is_selected(target[0])): # disable selection widget.get_selection().set_select_function(lambda *ignore: False, None) self.defer_select = target[0] if event.button == 3: self.menu = Gtk.Menu() aMenuitem = Gtk.MenuItem() aMenuitem.set_label("Remove") aMenuitem.connect("activate", self.remove_rows, widget) self.menu.append(aMenuitem) self.menu.show_all() self.menu.popup( None, None, None, None, event.button, event.time) return True def on_button_release(self, widget, event): # re-enable selection widget.get_selection().set_select_function(lambda *ignore: True, None) target = widget.get_path_at_pos(int(event.x), int(event.y)) if (self.defer_select and target and self.defer_select == target[0] and not (event.x==0 and event.y==0)): # certain drag and drop widget.set_cursor(target[0], target[1], False) def clear_playmark(self): for i in range(0, len(self.return_model())): self.return_model().set_value(self.return_model().get_iter(i), 0, '') def set_playmark(self, row): self.clear_playmark() try: self.return_model().set_value(row, 0, 'media-playback-start') except: self.return_model().set_value(self.return_model().get_iter(row), 0, 'media-playback-start') def get_playmark(self): for i in range(0, len(self.return_model())): tempiter = self.return_model().get_iter(i) if self.return_model().get_value(tempiter, 0) == 'media-playback-start': return i break return None def get_sw(self): return self.sw def return_model(self): return self.abox.get_model() def remove_rows(self, widget, treeview): model, selected = self.abox.get_selection().get_selected_rows() treeview.set_model(None) for i in reversed(selected): tempiter = model.get_iter(i) """if model.get_value(tempiter, 0) == 'media-playback-start': GObject.idle_add(self.stop_play)""" model.remove(tempiter) treeview.set_model(model)
class IconoListView(): def __init__(self): self.sw = Gtk.ScrolledWindow() self.trackparser = TrackMetaData() builder = Gtk.Builder() filename = os.path.join('data', 'treeview.ui') builder.add_from_file(filename) self.abox = builder.get_object('treeview1') self.abox.set_fixed_height_mode(False) self.abox.set_search_column(1) self.abox.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE) trackCol = builder.get_object('trackCol') titleCol = builder.get_object('titleCol') artistCol = builder.get_object('artistCol') albumCol = builder.get_object('albumCol') lengthCol = builder.get_object('lengthCol') genreCol = builder.get_object('genreCol') pathCol = builder.get_object('pathCol') #need to figure a working sorting function #self.abox.get_model().set_sort_func(1, self.tracknumsortfunc, None) trackCol.set_sort_column_id(1) titleCol.set_sort_column_id(2) artistCol.set_sort_column_id(3) albumCol.set_sort_column_id(4) lengthCol.set_sort_column_id(5) genreCol.set_sort_column_id(6) #anEntry = Gtk.TargetEntry.new("abox",Gtk.TargetFlags.SAME_WIDGET, 10) self.abox.enable_model_drag_source( Gdk.ModifierType.BUTTON1_MASK, [ ('TREE_MODEL_ROW', Gtk.TargetFlags.SAME_WIDGET, 0), ], Gdk.DragAction.COPY | Gdk.DragAction.MOVE) #self.abox.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, [anEntry], 0) self.abox.enable_model_drag_dest([], Gdk.DragAction.COPY | Gdk.DragAction.DEFAULT) #self.abox.drag_dest_set(0, [], 0) self.abox.connect('drag_motion', self.drag_motion_cb) self.abox.connect('drag_drop', self.drop_cb) self.abox.connect('drag_data_received', self.got_data_cb) self.abox.connect("drag_data_get", self.drag_data_get_data) self.abox.connect('button_press_event', self.on_button_press) self.abox.connect('button_release_event', self.on_button_release) self.defer_select = False self.sw.add(self.abox) def tracknumsortfunc(self, model, row1, row2, user_data): if (model.get_value(row1, 3) == model.get_value( row2, 3)) and (model.get_value(row1, 4) == model.get_value( row2, 4)): #print("Same Band! and Same Album!") #print(model.get_value(row1, 3), model.get_value(row1, 4)) #print cmp(model[row1][3], model[row2][3]) if (model.get_value(row1, 1) <= model.get_value(row2, 1)): print("0") return 0 #print(model.get_value(row1, 1)) #model.swap(row1, row2) else: print("-1") return -1 #model.swap(row2, row1) #else: #print cmp(model[row1][3], model[row2][3]) def drag_data_get_data(self, treeview, context, selection, target_id, etime): treeselection = treeview.get_selection() model, paths = treeselection.get_selected_rows() Gtk.tree_set_row_drag_data(selection, treeview.get_model(), paths[0]) def drag_motion_cb(self, senderID, context, x, y, time): Gdk.drag_status(context, Gdk.DragAction.COPY, time) if self.abox.get_dest_row_at_pos(x, y) == None: return True path, pos = self.abox.get_dest_row_at_pos(x, y) self.abox.set_drag_dest_row(path, pos) return True def got_data_cb(self, windowid, context, x, y, data, info, time): treeselection = windowid.get_selection() model, paths = treeselection.get_selected_rows() refs = [] for path in paths: refs.append(Gtk.TreeRowReference.new(model, path)) #refs = [path.append(Gtk.TreeRowReference.new(model, path)) for path in paths# different way of wording the above destpath = windowid.get_dest_row_at_pos(x, y) if destpath: destpath, position = destpath destiter = model.get_iter(destpath) else: #print "outside the rows" try: destiter = model.get_iter(len(model)) except: destiter = False #handle internal drag/drops here sourceWidget = Gtk.drag_get_source_widget(context) if sourceWidget == windowid: #print "internals" if not destpath in paths: if ( position == Gtk.TreeViewDropPosition.BEFORE ): # or position == Gtk.TreeViewDropPosition.INTO_OR_BEFORE): print("into or before") for currentref in refs: model.move_before( model.get_iter(currentref.get_path()), destiter) else: print("else") for currentref in reversed(refs): model.move_after(model.get_iter(currentref.get_path()), destiter) else: ##detach model improves performance but causes flicker # MAKES MIKE A SAD PANDA windowid.set_model(None) #f****n file managers handling differently :( nautilus sends plaintext, but pcman sends uris tempArray = [] if data.get_text(): for i in data.get_text().splitlines(): tempArray.append(i) else: for i in data.get_uris(): tempArray.append(i) from time import time as systime systime1 = systime() #got the data now split it up for i in tempArray: i = i.replace('file://', '').replace('%20', ' ') #simple but is way too slow if os.path.isdir(i): for root, dirs, files in os.walk(i): while Gtk.events_pending(): Gtk.main_iteration() for name in files: #print(name) self.add_row(os.path.join(root, name), model, destiter) else: self.add_row(i, model, destiter) ##reattach model print("%s%f%s%i" % ("Add Operation took ", systime() - systime1, " Items:", len(model))) del (systime) windowid.set_model(model) context.finish(True, False, time) def drop_cb(self, windowid, context, x, y, time): # Some data was dropped, get the data windowid.drag_get_data(context, context.list_targets()[-1], time) return True def add_row(self, action, widget, destiter): x = self.trackparser.getTrackType(action) #x = [None, 1,"Title","Artist","Album","400","Genre","/aidscake"] #x.insert(0, None) if destiter == False and x != False: widget.append(x) elif x != False: widget.insert_after(destiter, x) def load_shelf(self, path): model = self.return_model() self.abox.set_model(None) db = pickle.load(open(path, "rb")) for i in range(0, len(db), 8): templist = [] for j in range(0, 8): templist.append(db[i + j]) while Gtk.events_pending(): Gtk.main_iteration() model.append(templist) self.abox.set_model(model) def save_shelf(self, path): count = 0 settings = [] def writeouttree(model, path, iter, data): for i in range(0, 8): settings.append(model.get_value(iter, i)) self.return_model().foreach(writeouttree, None) db = pickle.dump(settings, open(path, "wb"), 2) def on_button_press(self, widget, event): # Here we intercept mouse clicks on selected items so that we can # drag multiple items without the click selecting only one target = widget.get_path_at_pos(int(event.x), int(event.y)) if (target and event.type == Gdk.EventType.BUTTON_PRESS and not ( event.get_state() & (Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.SHIFT_MASK)) and widget.get_selection().path_is_selected(target[0])): # disable selection widget.get_selection().set_select_function(lambda *ignore: False, None) self.defer_select = target[0] if event.button == 3: self.menu = Gtk.Menu() aMenuitem = Gtk.MenuItem() aMenuitem.set_label("Remove") aMenuitem.connect("activate", self.remove_rows, widget) self.menu.append(aMenuitem) self.menu.show_all() self.menu.popup(None, None, None, None, event.button, event.time) return True def on_button_release(self, widget, event): # re-enable selection widget.get_selection().set_select_function(lambda *ignore: True, None) target = widget.get_path_at_pos(int(event.x), int(event.y)) if (self.defer_select and target and self.defer_select == target[0] and not (event.x == 0 and event.y == 0)): # certain drag and drop widget.set_cursor(target[0], target[1], False) def clear_playmark(self): for i in range(0, len(self.return_model())): self.return_model().set_value(self.return_model().get_iter(i), 0, '') def set_playmark(self, row): self.clear_playmark() try: self.return_model().set_value(row, 0, 'media-playback-start') except: self.return_model().set_value(self.return_model().get_iter(row), 0, 'media-playback-start') def get_playmark(self): for i in range(0, len(self.return_model())): tempiter = self.return_model().get_iter(i) if self.return_model().get_value(tempiter, 0) == 'media-playback-start': return i break return None def get_sw(self): return self.sw def return_model(self): return self.abox.get_model() def remove_rows(self, widget, treeview): model, selected = self.abox.get_selection().get_selected_rows() treeview.set_model(None) for i in reversed(selected): tempiter = model.get_iter(i) """if model.get_value(tempiter, 0) == 'media-playback-start': GObject.idle_add(self.stop_play)""" model.remove(tempiter) treeview.set_model(model)