immsview
branchimmsview
changeset 33 ad808d18c693
parent 31 13f56bb29b96
child 35 ab72cbd172b8
equal deleted inserted replaced
32:85c8f5280d48 33:ad808d18c693
    18 # You should have received a copy of the GNU General Public License
    18 # You should have received a copy of the GNU General Public License
    19 # along with GNU Emacs; see the file COPYING.  If not, write to the
    19 # along with GNU Emacs; see the file COPYING.  If not, write to the
    20 # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    20 # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    21 # Boston, MA 02111-1307, USA.
    21 # Boston, MA 02111-1307, USA.
    22 
    22 
    23 _version_ = "$Id: immsview 1713 2004-02-08 21:55:24Z fabien $"
    23 _version_ = "$Id: immsview 1715 2004-02-10 04:29:08Z fabien $"
    24 
    24 
    25 # $Log$
    25 # $Log$
       
    26 # Revision 1.30  2004/02/10 04:29:08  fabien
       
    27 # Many cleanup, both architecture (division of interface), encoding
       
    28 # behavior and also many bugs corrected.
       
    29 #
    26 # Revision 1.29  2004/02/08 21:55:24  fabien
    30 # Revision 1.29  2004/02/08 21:55:24  fabien
    27 # New bestofimms, cleanimms, imms.py and utils.py.
    31 # New bestofimms, cleanimms, imms.py and utils.py.
    28 #
    32 #
    29 # Revision 1.28  2004/02/07 15:58:54  fabien
    33 # Revision 1.28  2004/02/07 15:58:54  fabien
    30 # Use Python-Gnuplot instead of immsplot.
    34 # Use Python-Gnuplot instead of immsplot.
   147 import gtk.glade
   151 import gtk.glade
   148 import gettext
   152 import gettext
   149 import xmms.control
   153 import xmms.control
   150 import time
   154 import time
   151 import Gnuplot
   155 import Gnuplot
   152 from imms import IMMSDb
   156 from imms import IMMSDb, rating_to_color
       
   157 from utils import strdelay
   153 
   158 
   154 gtk.glade.bindtextdomain('immsview', '/usr/share/immsview/LANG')
   159 gtk.glade.bindtextdomain('immsview', '/usr/share/immsview/LANG')
   155 gtk.glade.textdomain('immsview')
   160 gtk.glade.textdomain('immsview')
   156 _ = gettext.gettext
   161 _ = gettext.gettext
   157 
   162 stderr = sys.stderr
   158 def strtime(seconds):
       
   159     secs = abs(round(seconds))
       
   160     minutes = secs / 60;
       
   161     hours = minutes / 60;
       
   162     days = hours / 24;
       
   163     secs = secs % 60;
       
   164     minutes %= 60;
       
   165     hours %= 24;
       
   166 
       
   167     if seconds < 0:
       
   168             s = "-"
       
   169     else:
       
   170             s = ""
       
   171     if days >= 1:
       
   172             s += "%dd %dh" % (days, hours)
       
   173     elif hours >= 1:
       
   174             s += "%dh%02d" % (hours, minutes)
       
   175     elif minutes >= 1:
       
   176             s += "%d'%02d\"" % (minutes, secs)
       
   177     else:
       
   178             s += "%d\"" % (secs)
       
   179     return s
       
   180 
   163 
   181 class XMMSControl:
   164 class XMMSControl:
   182     def __getattr__(self, name):
   165     def __getattr__(self, name):
   183         return xmms.control.__dict__[name]
   166         return xmms.control.__dict__[name]
   184     def get_current_file(self):
   167     def get_current_file(self):
   194         if idx == -1:
   177         if idx == -1:
   195             self.enqueue_and_play((filename,))
   178             self.enqueue_and_play((filename,))
   196         else:
   179         else:
   197             self.set_playlist_pos(idx)
   180             self.set_playlist_pos(idx)
   198 
   181 
   199 
       
   200 _gdk_colors = []
   182 _gdk_colors = []
   201 for i in range(76):
   183 for i in range(75,150+1):
   202     if i <= 25:
   184     _gdk_colors.append(rating_to_color(i))
   203         red = 255
   185 
   204         green = i * 255 / 25
   186 def gdk_rating_to_color(rate):
   205         blue = 0
       
   206     elif i <= 50:
       
   207         red = (50-i) * 255 / 25
       
   208         green = 255
       
   209         blue = 0
       
   210     else:
       
   211         red = 0
       
   212         green = 255
       
   213         blue = (i-50) * 255 / 25    
       
   214     _gdk_colors.append("#%02X%02X%02X" % (red, green, blue))
       
   215 
       
   216 def rating_to_color(rate):
       
   217     rate = min(max(rate,75),150)
   187     rate = min(max(rate,75),150)
   218     return _gdk_colors[rate-75]
   188     return _gdk_colors[rate-75]
   219 
   189 
   220 # This class must be derived from a GtkTreeModel
   190 # This class must be derived from a GtkTreeModel
   221 # with persistent GtkTreeIter !!!
   191 # with persistent GtkTreeIter !!!
   225     COL_LAST_STR = 2
   195     COL_LAST_STR = 2
   226     COL_LAST = 3
   196     COL_LAST = 3
   227     COL_SELECT = 4
   197     COL_SELECT = 4
   228     COL_UID = 5
   198     COL_UID = 5
   229     COL_RATING_COLOR = 6
   199     COL_RATING_COLOR = 6
   230     COL_PATHS_NUMBER = 7
   200     COL_PATHS = 7
   231     def __init__(self, db):
   201     def __init__(self, db):
   232         gtk.ListStore.__init__(self,
   202         gtk.ListStore.__init__(self,
   233                                gobject.TYPE_INT,
   203                                gobject.TYPE_INT,
   234                                gobject.TYPE_STRING,
   204                                gobject.TYPE_STRING,
   235                                gobject.TYPE_STRING,
   205                                gobject.TYPE_STRING,
   236                                gobject.TYPE_INT,
   206                                gobject.TYPE_INT,
   237                                gobject.TYPE_BOOLEAN,
   207                                gobject.TYPE_BOOLEAN,
   238                                gobject.TYPE_INT,
   208                                gobject.TYPE_INT,
   239                                gobject.TYPE_STRING,
   209                                gobject.TYPE_STRING,
   240                                gobject.TYPE_INT,
   210                                gobject.TYPE_PYOBJECT,
   241                                )
   211                                )
   242         self.db = db
   212         self.db = db
   243         self.set_default_sort_func(self.default_sort)
   213         self.set_default_sort_func(self.default_sort)
   244         self.set_sort_column_id(IMMSStore.COL_RATING, gtk.SORT_DESCENDING)
   214         self.set_sort_column_id(IMMSStore.COL_RATING, gtk.SORT_DESCENDING)
   245         self.curtime = time.time()
   215         self.curtime = time.time()
   263         if not giter:
   233         if not giter:
   264             giter = self.append(None)
   234             giter = self.append(None)
   265         self.set(giter,
   235         self.set(giter,
   266                  IMMSStore.COL_UID, uid,
   236                  IMMSStore.COL_UID, uid,
   267                  IMMSStore.COL_RATING, tune['rating'],
   237                  IMMSStore.COL_RATING, tune['rating'],
   268                  IMMSStore.COL_PATH, fn,
   238                  IMMSStore.COL_PATH, fn.decode('utf-8','replace'),
   269                  IMMSStore.COL_LAST, tune['last'],
   239                  IMMSStore.COL_LAST, tune['last'],
   270                  IMMSStore.COL_LAST_STR, strtime(self.curtime-tune['last']),
   240                  IMMSStore.COL_LAST_STR, strdelay(self.curtime-tune['last']),
   271                  IMMSStore.COL_RATING_COLOR, rating_to_color(tune['rating']),
   241                  IMMSStore.COL_RATING_COLOR, gdk_rating_to_color(tune['rating']),
   272                  IMMSStore.COL_PATHS_NUMBER, len(tune['path']),
   242                  IMMSStore.COL_PATHS, tune['path'],
   273                  IMMSStore.COL_SELECT, gtk.FALSE)
   243                  IMMSStore.COL_SELECT, gtk.FALSE)
   274         return giter
   244         return giter
   275     def update(self):
   245     def update(self):
   276         self.curtime = time
   246         self.curtime = time
   277         self.curtime = time.time()
   247         self.curtime = time.time()
   278         col, order = self.get_sort_column_id()
   248         col, order = self.get_sort_column_id()
   279 	if col:
   249 	if col:
   280         	self.set_sort_column_id(-1, gtk.SORT_ASCENDING)
   250         	self.set_sort_column_id(-1, gtk.SORT_ASCENDING)
   281         tunes = self.db.get_ratings_and_info()
   251         tunes = self.db.get_ratings_and_paths()
   282 	print time.ctime(time.time()) + ": inserting"
   252 	print >> stderr, time.ctime(time.time()) + ": inserting"
   283         self._update_me(tunes)
   253         self._update_me(tunes)
   284 	print time.ctime(time.time()) + ": end insert"
   254 	print time.ctime(time.time()) + ": end insert"
   285 	if col:
   255 	if col:
   286         	self.set_sort_column_id(col, order)
   256         	self.set_sort_column_id(col, order)
   287     def replace(self, tunes):
   257     def replace(self, tunes):
   298                 giter = self.iter_next(giter)
   268                 giter = self.iter_next(giter)
   299         while giter:
   269         while giter:
   300             next = self.iter_next(giter)
   270             next = self.iter_next(giter)
   301             self.remove(giter)
   271             self.remove(giter)
   302             giter = next
   272             giter = next
   303     def refresh(self, tunes):
       
   304         "refresh only get new data and update last time and rating."
       
   305         freed_giters = []
       
   306         # first, try to recycle current giter.
       
   307         giter = self.get_iter_first()
       
   308         while giter:
       
   309             # check if giter exist in DB.
       
   310             guid = self.get_value(giter, IMMSStore.COL_UID)
       
   311             if tunes.has_key(guid):
       
   312                 tune = tunes[guid]
       
   313                 self.set(giter,
       
   314                          IMMSStore.COL_RATING, tune['rating'],
       
   315                          IMMSStore.COL_LAST, tune['last'],
       
   316                          IMMSStore.COL_LAST_STR,
       
   317                          strtime(self.curtime-tune['last']),
       
   318                          IMMSStore.COL_RATING_COLOR,
       
   319                          rating_to_color(tune['rating']))
       
   320             else:
       
   321                 # Elsewhere, collect them for further use...
       
   322                 # Hopefully, ListStore have persistent giter!
       
   323                 freed_giters.append(giter)
       
   324             giter = self.iter_next(giter)
       
   325         # populate the remeaning tunes into the collected giters
       
   326         for uid, tune in tunes.iteritems():
       
   327             if len(freed_giters) > 0:
       
   328                 giter = freed_giters.pop()
       
   329             else:
       
   330                 giter = None
       
   331             self.tune_to_giter(uid, tune, None, giter)
       
   332         # then erase the remeaning giter.
       
   333         for giter in freed_giters:
       
   334             self.remove(giter)
       
   335     def find_selected_giter(self):
   273     def find_selected_giter(self):
   336         giter = self.get_iter_first()
   274         giter = self.get_iter_first()
   337         while giter:
   275         while giter:
   338             if self.get_value(giter, IMMSStore.COL_SELECT):
   276             if self.get_value(giter, IMMSStore.COL_SELECT):
   339                 break
   277                 break
   351         if len(uids) == 0:
   289         if len(uids) == 0:
   352             return None
   290             return None
   353         uid = uids[0]
   291         uid = uids[0]
   354         giter = self.find_giter_from_uid(uid)
   292         giter = self.find_giter_from_uid(uid)
   355         if not giter:
   293         if not giter:
   356             tunes = self.db.get_ratings_and_info([uid])
   294             tunes = self.db.get_ratings_and_paths([uid])
   357             if tunes > 0:
   295             if tunes > 0:
   358                 giter = self.tune_to_giter(uid, tunes[uid], song)
   296                 giter = self.tune_to_giter(uid, tunes[uid], song)
   359 	else:
   297 	else:
   360             giter = self.update_giter(giter, song)
   298             giter = self.update_giter(giter, song)
   361         return giter
   299         return giter
   368             res.append((uid, rating))
   306             res.append((uid, rating))
   369             giter = self.iter_next(giter)
   307             giter = self.iter_next(giter)
   370         return res
   308         return res
   371     def update_giter(self, giter, path = None):
   309     def update_giter(self, giter, path = None):
   372         uid = self.get_value(giter, IMMSStore.COL_UID)
   310         uid = self.get_value(giter, IMMSStore.COL_UID)
   373         tunes = self.db.get_ratings_and_info([uid,])
   311         tunes = self.db.get_ratings_and_paths([uid,])
   374         if len(tunes) > 0:
   312         if len(tunes) > 0:
   375             return self.tune_to_giter(uid, tunes[uid], path, giter)
   313             return self.tune_to_giter(uid, tunes[uid], path, giter)
   376         return giter
   314         return giter
   377 ##     def get_value(self, giter, col):
   315 ##     def get_value(self, giter, col):
   378 ##         # sniff!  Can't override built-ins
   316 ##         # sniff!  Can't override built-ins
   379 ##         if col == IMMSStore.COL_LAST_STR:
   317 ##         if col == IMMSStore.COL_LAST_STR:
   380 ##             return strtime(time.time() -
   318 ##             return strdelay(time.time() -
   381 ##                            self.get_value(giter, IMMSStore.COL_LAST))
   319 ##                            self.get_value(giter, IMMSStore.COL_LAST))
   382 ##         else:
   320 ##         else:
   383 ##             return gtk.ListStore.get_value(self, giter, col)
   321 ##             return gtk.ListStore.get_value(self, giter, col)
   384 
   322 
   385 class IMMSPlot(Gnuplot.Gnuplot):
   323 class IMMSPlot(Gnuplot.Gnuplot):
   419             column = gtk.TreeViewColumn(_("Last"), renderer,
   357             column = gtk.TreeViewColumn(_("Last"), renderer,
   420                                         weight_set = IMMSStore.COL_SELECT,
   358                                         weight_set = IMMSStore.COL_SELECT,
   421                                         text = IMMSStore.COL_LAST_STR)
   359                                         text = IMMSStore.COL_LAST_STR)
   422             column.set_sort_column_id(IMMSStore.COL_LAST)
   360             column.set_sort_column_id(IMMSStore.COL_LAST)
   423             self.append_column(column)
   361             self.append_column(column)
   424             column = gtk.TreeViewColumn(_("#"), renderer,
       
   425                                         weight_set = IMMSStore.COL_SELECT,
       
   426                                         text = IMMSStore.COL_PATHS_NUMBER)
       
   427             self.append_column(column)
       
   428             column = gtk.TreeViewColumn(_("File"), renderer,
   362             column = gtk.TreeViewColumn(_("File"), renderer,
   429                                         weight_set = IMMSStore.COL_SELECT,
   363                                         weight_set = IMMSStore.COL_SELECT,
   430                                         text = IMMSStore.COL_PATH)
   364                                         text = IMMSStore.COL_PATH)
   431             column.set_resizable(gtk.TRUE)
   365             column.set_resizable(gtk.TRUE)
   432             column.set_sort_column_id(IMMSStore.COL_PATH)
   366             column.set_sort_column_id(IMMSStore.COL_PATH)
   444             if giter:
   378             if giter:
   445                 model.set_value(giter, IMMSStore.COL_SELECT, gtk.TRUE)
   379                 model.set_value(giter, IMMSStore.COL_SELECT, gtk.TRUE)
   446                 self.set_cursor(model.get_path(giter))
   380                 self.set_cursor(model.get_path(giter))
   447         def get_filename(self, giter):
   381         def get_filename(self, giter):
   448             model = self.get_model()
   382             model = self.get_model()
   449             fn = model.get_value(model.update_giter(giter), IMMSStore.COL_PATH)
   383             model.update_giter(giter)
   450             try:
   384             paths = model.get_value(giter, IMMSStore.COL_PATHS)
   451                 os.stat(fn)
   385             enc_path = model.get_value(giter, IMMSStore.COL_PATH)
   452             except OSError:
   386             paths = filter(os.path.isfile, paths)
       
   387             # No valid file in list
       
   388             if len(paths) == 0:
   453                 return None
   389                 return None
   454             return fn
   390             # Try to find the currently display file
       
   391             for fn in paths:
       
   392                 if enc_path == fn.decode('utf8', 'replace'):
       
   393                     return fn
       
   394             # Else, return the first find
       
   395             return paths[0]
   455         def get_file_selected(self):
   396         def get_file_selected(self):
   456             model, giter = self.get_selection().get_selected()
   397             model, giter = self.get_selection().get_selected()
   457             if giter:
   398             if giter:
   458                 return self.get_filename(giter)
   399                 return self.get_filename(giter)
   459             return None
   400             return None
   492             self.iview.get_model().update()
   433             self.iview.get_model().update()
   493     def do_get_current(self, dummy):
   434     def do_get_current(self, dummy):
   494         song = self.xmms.get_current_file()
   435         song = self.xmms.get_current_file()
   495         try:
   436         try:
   496             self.iview.set_current_song(song)
   437             self.iview.set_current_song(song)
   497         except:
   438         except Exception, e:
   498             pass
   439             print >> stderr, e
   499     def do_play(self, dummy):
   440     def do_play(self, dummy):
   500         fn = self.iview.get_file_selected()
   441         fn = self.iview.get_file_selected()
   501         if fn:
   442         if fn:
   502             self.xmms.play_file(fn)
   443             self.xmms.play_file(fn)
   503         self.sleep(self._SLEEP_TIME)
   444         self.sleep(self._SLEEP_TIME)