def new_db(self, parent): #{{{ """initializes a new griffith database file""" response = gutils.question(self, \ _("Are you sure you want to create a new database?\nYou will lose ALL your current data!"), \ 1, parent.main_window) if response == gtk.RESPONSE_YES: response_sec = gutils.question(self, \ _("Last chance!\nDo you confirm that you want\nto lose your current data?"), \ 1, parent.main_window) if response_sec == gtk.RESPONSE_YES: # delete images for root, dirs, files in os.walk(os.path.join(self.griffith_dir,"posters"), topdown=False): for name in files: os.remove(os.path.join(root, name)) # delete db parent.db.con.close() os.unlink(os.path.join(self.griffith_dir,self.config.get('default_db'))) # create/connect db parent.db = GriffithSQL(self.config, self.debug, self.griffith_dir) parent.clear_details() parent.total = 0 parent.count_statusbar() parent.treemodel.clear() from initialize import dictionaries dictionaries(parent) else: pass else: pass
def add_movie_db(self, close): session = self.db.Session() details = get_details(self) if not details['o_title'] and not details['title']: gutils.error( _("You should fill the original title\nor the movie title."), parent=self.widgets['add']['window']) return False asked = False if details['o_title']: if session.query( db.Movie).filter_by(o_title=details['o_title']).count() > 0: asked = True if not gutils.question( _('Movie with that title already exists, are you sure you want to add?' ), self.widgets['add']['window']): return False if not asked and details['title']: if session.query( db.Movie).filter_by(title=details['title']).count() > 0: if not gutils.question( _('Movie with that title already exists, are you sure you want to add?' ), self.widgets['add']['window']): return False new_poster_md5 = None if details['image']: tmp_image_path = details['image'] if not os.path.isfile(tmp_image_path): tmp_image_path = os.path.join(self.locations['temp'], "poster_%s.jpg" % details['image']) if os.path.isfile(tmp_image_path): new_poster_md5 = gutils.md5sum(file(tmp_image_path, 'rb')) if session.query( db.Poster).filter_by(md5sum=new_poster_md5).count() == 0: try: data = file(tmp_image_path, 'rb').read() except Exception, e: log.warning("cannot read poster data") else: poster = db.Poster(md5sum=new_poster_md5, data=data) del details["image"] details["poster_md5"] = new_poster_md5 session.add(poster) else: details["poster_md5"] = new_poster_md5 try: if not tmp_image_path == details['image']: os.remove(tmp_image_path) except Exception, e: log.warn("cannot remove temporary file %s", tmp_image_path)
def delete_poster(self): session = self.db.Session() movie = session.query(db.Movie).filter_by(movie_id=self._movie_id).first() if not movie: log.error("Cannot delete unknown movie's poster!") return False response = gutils.question(_("Are you sure you want to delete this poster?"), True, self.widgets["window"]) if response == -8: image_path = os.path.join(self.locations["images"], "default.png") handler = self.widgets["movie"]["picture"].set_from_pixbuf(gtk.gdk.pixbuf_new_from_file(image_path)) gutils.garbage(handler) update_tree_thumbnail(self, os.path.join(self.locations["images"], "default_thumbnail.png")) # update in database delete.delete_poster(self, movie.poster_md5) movie.poster_md5 = None session.add(movie) try: session.commit() except Exception, e: session.rollback() log.error("cannot delete poster: %s" % e) return False self.update_statusbar(_("Image has been updated")) self.widgets["add"]["delete_poster"].set_sensitive(False) self.widgets["menu"]["delete_poster"].set_sensitive(False) self.widgets["movie"]["picture_button"].set_sensitive(False)
def delete_person(self): has_history = False has_history_msg = "" try: treeselection = self.widgets["people"]["treeview"].get_selection() (tmp_model, tmp_iter) = treeselection.get_selected() person = tmp_model.get_value(tmp_iter, 0).decode("utf-8") except: return person = self.db.session.query(db.Person).filter_by(name=person).first() if not person: return False if person.loaned_movies_count > 0: gutils.info(_("This person has loaned films from you. Return them first."), self.widgets["people"]["window"]) return False if person.returned_movies_count > 0: has_history = True has_history_msg = _("This person has data in the loan history. This data will be erased if you continue.") if gutils.question( _("%s\nAre you sure you want to delete this person?" % has_history_msg), self.widgets["people"]["window"] ): treeselection = self.widgets["people"]["treeview"].get_selection() (tmp_model, tmp_iter) = treeselection.get_selected() self.db.session.delete(person) try: self.db.session.commit() except Exception, e: log.info(str(e)) else: self.p_treemodel.remove(tmp_iter) self.treeview_clicked()
def delete_person(self): response = None has_history = False has_history_msg = '' try: treeselection = self.widgets['people']['treeview'].get_selection() (tmp_model, tmp_iter) = treeselection.get_selected() person = tmp_model.get_value(tmp_iter,0).decode('utf-8') except: return person = self.db.session.query(db.Person).filter_by(name=person).first() if not person: return False data = self.db.session.query(db.Loan).filter_by(person_id=person.person_id, return_date=None).all() if len(data)>0: gutils.info(_("This person has loaned films from you. Return them first."), self.widgets['people']['window']) return False data = self.db.session.query(db.Loan).filter_by(person_id=person.person_id).all() if len(data)>0: has_history = True has_history_msg = _("This person has data in the loan history. This data will be erased if you continue.") response = gutils.question(_("%s\nAre you sure you want to delete this person?" % has_history_msg), \ True, self.widgets['people']['window']) if response == -8: treeselection = self.widgets['people']['treeview'].get_selection() (tmp_model, tmp_iter) = treeselection.get_selected() self.db.session.delete(person) try: self.db.session.commit() except Exception, e: log.info(str(e)) else: self.p_treemodel.remove(tmp_iter) self.treeview_clicked()
def delete_poster(self, movie_id=None): if movie_id is None: movie_id = self._movie_id session = self.db.Session() movie = session.query(db.Movie).filter_by(movie_id=movie_id).first() if not movie: log.error("Cannot delete unknown movie's poster!") return False if gutils.question(_("Are you sure you want to delete this poster?"), self.widgets["window"]): # update in database delete.delete_poster(self, movie.poster_md5) movie.poster_md5 = None session.add(movie) try: session.commit() except Exception, e: session.rollback() log.error("cannot delete poster: %s" % e) return False if self._movie_id == movie_id: # only if the current selected movie is the same like that one for removing poster image_path = gutils.get_defaultimage_fname(self) handler = self.widgets["movie"]["picture"].set_from_pixbuf(gtk.gdk.pixbuf_new_from_file(image_path)) gutils.garbage(handler) self.widgets["add"]["delete_poster"].set_sensitive(False) self.widgets["movie"]["picture_button"].set_sensitive(False) # always refresh the treeview entry update_tree_thumbnail(self, gutils.get_defaultthumbnail_fname(self)) self.update_statusbar(_("Image has been updated")) return True
def delete_person(self): has_history = False has_history_msg = '' try: treeselection = self.widgets['people']['treeview'].get_selection() (tmp_model, tmp_iter) = treeselection.get_selected() person = tmp_model.get_value(tmp_iter,0).decode('utf-8') except: return person = self.db.session.query(db.Person).filter_by(name=person).first() if not person: return False if person.loaned_movies_count > 0: gutils.info(_("This person has loaned films from you. Return them first."), self.widgets['people']['window']) return False if person.returned_movies_count > 0: has_history = True has_history_msg = _("This person has data in the loan history. This data will be erased if you continue.") if gutils.question(_("%s\nAre you sure you want to delete this person?" % has_history_msg), self.widgets['people']['window']): treeselection = self.widgets['people']['treeview'].get_selection() (tmp_model, tmp_iter) = treeselection.get_selected() self.db.session.delete(person) try: self.db.session.commit() except Exception, e: log.info(str(e)) else: self.p_treemodel.remove(tmp_iter) self.treeview_clicked()
def delete_person(self): response = None has_history = False has_history_msg = '' try: treeselection = self.widgets['people']['treeview'].get_selection() (tmp_model, tmp_iter) = treeselection.get_selected() person = tmp_model.get_value(tmp_iter,0) except: return person = self.db.Person.get_by(name=person) if not person: return False data = self.db.Loan.select_by(person_id=person.person_id, return_date=None) if len(data)>0: gutils.info(self, _("This person has loaned films from you. Return them first."), self.widgets['people']['window']) return False data = self.db.Loan.select_by(person_id=person.person_id) if len(data)>0: has_history = True has_history_msg = _("This person has data in the loan history. This data will be erased if you continue.") response = gutils.question(self,_("%s\nAre you sure you want to delete this person?" % has_history_msg), \ 1, self.widgets['people']['window']) if response == -8: treeselection = self.widgets['people']['treeview'].get_selection() (tmp_model, tmp_iter) = treeselection.get_selected() if person.remove_from_db(): self.p_treemodel.remove(tmp_iter) self.treeview_clicked() self.widgets['people']['window'].present()
def run(self): basedir = None if self.config is not None: basedir = self.config.get('export_dir', None, section='export-csv') if not basedir: filename = gutils.file_chooser(_("Export a %s document")%"CSV", action=gtk.FILE_CHOOSER_ACTION_SAVE, \ buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK), name='griffith_list.csv') else: filename = gutils.file_chooser(_("Export a %s document")%"CSV", action=gtk.FILE_CHOOSER_ACTION_SAVE, \ buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE,gtk.RESPONSE_OK), name='griffith_list.csv', folder=basedir) if filename and filename[0]: if self.config is not None and filename[1]: self.config.set('export_dir', filename[1], section='export-csv') self.config.save() overwrite = None if os.path.isfile(filename[0]): if gutils.question(_("File exists. Do you want to overwrite it?"), self.parent_window): overwrite = True else: overwrite = False if overwrite or overwrite is None: movies = self.get_query().execute() writer = csv.writer(file(filename[0], 'w'), dialect=csv.excel) # write column header row writer.writerow(self.fields_to_export) # write data rows for movie in movies: t = [] for s in self.exported_columns: t.append(movie[s]) writer.writerow(t) gutils.info(_("%s file has been created.") % "CSV", self.parent_window)
def export_csv(self): basedir = None if not self.persistent_config is None: basedir = self.persistent_config.get('export_dir', None, section='export-csv') if basedir is None: filename = gutils.file_chooser(_("Export a %s document")%"CSV", action=gtk.FILE_CHOOSER_ACTION_SAVE, \ buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_SAVE,gtk.RESPONSE_OK),name='griffith_list.csv') else: filename = gutils.file_chooser(_("Export a %s document")%"CSV", action=gtk.FILE_CHOOSER_ACTION_SAVE, \ buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_SAVE,gtk.RESPONSE_OK),name='griffith_list.csv',folder=basedir) if filename[0]: if not self.persistent_config is None and filename[1]: self.persistent_config.set('export_dir', filename[1], section='export-csv') self.persistent_config.save() overwrite = None if os.path.isfile(filename[0]): response = gutils.question(self, _("File exists. Do you want to overwrite it?"), 1, self.parent) if response==-8: overwrite = True else: overwrite = False if overwrite == True or overwrite is None: writer = csv.writer(file(filename[0], 'w'), dialect=csv.excel) for movie in self.db.Movie.select(): t = [] for s in ('number', 'o_title', 'title', 'director', 'year', 'classification', 'country', 'genre', 'rating', 'runtime', 'studio', 'seen', 'loaned', 'o_site', 'site', 'trailer', 'plot', 'cast', 'notes','image'): t.append(movie[s]) writer.writerow(t) gutils.info(self, _("%s file has been created.")%"CSV", self.parent)
def toolbar_icon_clicked(self, widget, movie): if question(_('Are you sure you want to remove %d movies?') % self.app.total): session = self.db.Session() # first: remove all dependend data (associated tags, languages, ...) query = select([movies_table.c.movie_id]) # FIXME: self.app._search_conditions contains advfilter conditions only (no other filters) query = update_whereclause(query, self.app._search_conditions) query = query.where(movies_table.c.loaned==False) # don't delete loaned movies for movie_entry in session.execute(query): # tags query_movie_tags = delete(movie_tag_table) query_movie_tags = query_movie_tags.where(movie_tag_table.c.movie_id==movie_entry.movie_id) session.execute(query_movie_tags) # languages query_movie_lang = delete(movie_lang_table) query_movie_lang = query_movie_lang.where(movie_lang_table.c.movie_id==movie_entry.movie_id) session.execute(query_movie_lang) # TODO: removing posters if no longer used by another movie? # second: remove the movie entries query = delete(movies_table) # FIXME: self.app._search_conditions contains advfilter conditions only (no other filters) query = update_whereclause(query, self.app._search_conditions) query = query.where(movies_table.c.loaned==False) # don't delete loaned movies session.execute(query) session.commit() self.app.populate_treeview()
def export_xml(self): filename = gutils.file_chooser(_("Export a %s document")%"XML", action=gtk.FILE_CHOOSER_ACTION_SAVE, \ buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_SAVE,gtk.RESPONSE_OK),name='griffith_list.xml') if filename[0]: overwrite = None if os.path.isfile(filename[0]): response = gutils.question(self, _("File exists. Do you want to overwrite it?"), 1, self.parent) if response==-8: overwrite = True else: overwrite = False if overwrite == True or overwrite == None: # create document impl = xml.dom.minidom.getDOMImplementation() doc = impl.createDocument(None, "root", None) root = doc.documentElement # create object data = self.db.get_all_data(order_by="number ASC") for row in data: e = doc.createElement('movie') root.appendChild(e) for key,value in row.items(): e2 = doc.createElement(key) t = doc.createTextNode(str(value)) e2.appendChild(t) e.appendChild(e2) # write XML to file fp = open(filename[0], "w") xml.dom.ext.PrettyPrint(doc, fp) fp.close() gutils.info(self, _("%s file has been created.")%"XML", self.parent)
def delete_movie(self): if len(self.selected) == 0: gutils.error(_("You have no movies in your database"), self.widgets['window']) return False else: if gutils.question(_('Are you sure you want to delete?'), self.widgets['window']): for each in self.selected: movie = self.db.session.query(db.Movie).filter_by(number=int(each)).first() if movie.loaned: gutils.warning(msg=_("You can't delete movie while it is loaned.")) return False delete_poster(self, movie.poster_md5) self.db.session.delete(movie) try: self.db.session.commit() except: log.info("Unexpected problem: %s", e) return False # update main treelist self.total -= 1 self.clear_details() self.populate_treeview() #self.initialized = False #self.go_prev() #self.go_next() self.count_statusbar()
def delete_movie(self): m_id = None number, m_iter = self.get_maintree_selection() movie = self.db.Movie.get_by(number=number) if movie is None: gutils.error(self,_("You have no movies in your database"), self.widgets['window']) return False if int(movie.loaned)==1: gutils.warning(self, msg=_("You can't delete movie while it is loaned.")) return False response = gutils.question(self, _("Are you sure you want to delete this movie?"), \ 1, self.widgets['window']) if response == -8: # gtk.RESPONSE_YES == -8 # try to delete poster image as well if movie.image is not None: delete_poster(self, movie.image) if movie.remove_from_db(): # update main treelist self.total -= 1 self.treemodel.remove(m_iter) self.go_prev() self.clear_details() self.count_statusbar() else: return False
def delete_poster(self): session = self.db.Session() movie = session.query(db.Movie).filter_by(movie_id=self._movie_id).first() if not movie: log.error("Cannot delete unknown movie's poster!") return False if gutils.question(_("Are you sure you want to delete this poster?"), self.widgets['window']): image_path = gutils.get_defaultimage_fname(self) handler = self.widgets['movie']['picture'].set_from_pixbuf(gtk.gdk.pixbuf_new_from_file(image_path)) gutils.garbage(handler) update_tree_thumbnail(self, gutils.get_defaultthumbnail_fname(self)) # update in database delete.delete_poster(self, movie.poster_md5) movie.poster_md5 = None session.add(movie) try: session.commit() except Exception, e: session.rollback() log.error("cannot delete poster: %s" % e) return False self.update_statusbar(_("Image has been updated")) self.widgets['add']['delete_poster'].set_sensitive(False) self.widgets['movie']['picture_button'].set_sensitive(False)
def delete_movie(self): if len(self.selected) == 0: gutils.error(_("You have no movies in your database"), self.widgets['window']) return False else: if gutils.question(_('Are you sure you want to delete?'), self.widgets['window']): for each in self.selected: movie = self.db.session.query( db.Movie).filter_by(number=int(each)).first() if movie.loaned: gutils.warning( msg=_("You can't delete movie while it is loaned.")) return False delete_poster(self, movie.poster_md5) self.db.session.delete(movie) try: self.db.session.commit() except: log.info("Unexpected problem: %s", e) return False # update main treelist self.total -= 1 self.clear_details() self.populate_treeview() #self.initialized = False #self.go_prev() #self.go_next() self.count_statusbar()
def delete_movie(self): m_id = None number, m_iter = self.get_maintree_selection() movie = self.db.session.query(db.Movie).filter_by(number=number).first() if movie is None: gutils.error(self,_("You have no movies in your database"), self.widgets['window']) return False if movie.loaned: gutils.warning(self, msg=_("You can't delete movie while it is loaned.")) return False response = gutils.question(_("Are you sure you want to delete this movie?"), True, self.widgets['window']) if response == -8: # gtk.RESPONSE_YES == -8 delete_poster(self, movie.poster_md5) self.db.session.delete(movie) try: self.db.session.commit() except: log.info("Unexpected problem: %s", e) return False # update main treelist self.total -= 1 self.clear_details() self.initialized = False self.go_prev() self.treemodel.remove(m_iter) self.initialized = True self.go_next() self.count_statusbar() else: return False
def delete_poster(self, movie_id=None): if movie_id is None: movie_id = self._movie_id session = self.db.Session() movie = session.query(db.Movie).filter_by(movie_id=movie_id).first() if not movie: log.error("Cannot delete unknown movie's poster!") return False if gutils.question(_("Are you sure you want to delete this poster?"), self.widgets['window']): # update in database delete.delete_poster(self, movie.poster_md5) movie.poster_md5 = None session.add(movie) try: session.commit() except Exception, e: session.rollback() log.error("cannot delete poster: %s" % e) return False if self._movie_id == movie_id: # only if the current selected movie is the same like that one for removing poster image_path = gutils.get_defaultimage_fname(self) handler = self.widgets['movie']['picture'].set_from_pixbuf( gtk.gdk.pixbuf_new_from_file(image_path)) gutils.garbage(handler) self.widgets['add']['delete_poster'].set_sensitive(False) self.widgets['movie']['picture_button'].set_sensitive(False) # always refresh the treeview entry update_tree_thumbnail(self, gutils.get_defaultthumbnail_fname(self)) self.update_statusbar(_("Image has been updated")) return True
def delete_poster(self): movie = self.db.Movie.get_by(movie_id=self._movie_id) if not movie: self.debug.show("Can't delete unknown movie's poster!") return False response = gutils.question(self, _("Are you sure you want to delete this poster?"), 1, self.widgets['window']) if response==-8: image_path = os.path.join(self.locations['images'], 'default.png') handler = self.widgets['movie']['picture'].set_from_pixbuf(gtk.gdk.pixbuf_new_from_file(image_path)) gutils.garbage(handler) update_tree_thumbnail(self, os.path.join(self.locations['images'], 'default_thumbnail.png')) # update in database old_image = movie.image movie.image = None movie.update() movie.flush() self.update_statusbar(_("Image has been updated")) self.widgets['add']['delete_poster'].set_sensitive(False) self.widgets['menu']['delete_poster'].set_sensitive(False) self.widgets['movie']['picture_button'].set_sensitive(False) if old_image: delete.delete_poster(self, old_image) else: pass
def commit(self): person_name = gutils.on_combo_box_entry_changed(self.widgets['movie']['loan_to']) if not person_name: return False self.widgets['w_loan_to'].hide() person = self.db.session.query(db.Person.person_id).filter_by(name=person_name).first() if not person: log.info("loan_commit: person doesn't exist") return False if self._movie_id: movie = self.db.session.query(db.Movie.movie_id, db.Movie.collection_id).filter_by(movie_id=self._movie_id).first() if not movie: log.info("loan_commit: wrong movie_id") return False else: log.info("loan_commit: movie not selected") return False # ask if user wants to loan whole collection loan_whole_collection = False if movie.collection_id > 0: response = gutils.question(_("Do you want to loan whole collection?"), window=self.widgets['window']) if response == gtk.RESPONSE_YES: loan_whole_collection = True elif response == gtk.RESPONSE_CANCEL: return False resp = sql.loan_movie(self.db, movie.movie_id, person.person_id, loan_whole_collection) if resp == -1: gutils.warning(_("Collection contains loaned movie.\nLoan aborted!")) return False elif resp: self.update_statusbar(_("Movie loaned")) self.treeview_clicked()
def show_dialog(self): # shows a file dialog and sets self.filepath # derived classes which overwrite this method have also to set self.filepath basedir = None if not self.config is None and not self.config_section is None: basedir = self.config.get('export_dir', None, section=self.config_section) if basedir is None: filenames = gutils.file_chooser(_('Export a %s document') % self.export_name, action=gtk.FILE_CHOOSER_ACTION_SAVE, \ buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK), name=self.filename) else: filenames = gutils.file_chooser(_('Export a %s document') % self.export_name, action=gtk.FILE_CHOOSER_ACTION_SAVE, \ buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK), name=self.filename, folder=basedir) if filenames[0]: self.filepath = filenames[0] if len(filenames) > 1: self.dirpath = filenames[1] else: self.dirpath = os.path.dirname(self.filepath) self.filename = os.path.basename(self.filepath) if not self.config is None and self.dirpath and not self.config_section is None: self.config.set('export_dir', self.dirpath, section=self.config_section) self.config.save() overwrite = None if os.path.isfile(self.filepath): response = gutils.question(_('File exists. Do you want to overwrite it?'), 1, self.parent_window) if response==-8: overwrite = True else: overwrite = False if overwrite == True or overwrite is None: return True return False
def commit_loan(self): person = gutils.on_combo_box_entry_changed(self.loan_to) if person == '' or person == None: return self.w_loan_to.hide() # movie is now loaned. change db movie_id = self.e_number.get_text() self.db.cursor.execute("SELECT volume_id, collection_id FROM movies WHERE number='%s'"%movie_id) volume_id, collection_id = self.db.cursor.fetchall()[0] data_person = self.db.select_person_by_name(person) # ask if user wants to loan whole collection if collection_id>0: loan_whole_collection = False response = gutils.question(self, msg=_("Do you want to loan whole collection?"), parent=self.main_window) if response == gtk.RESPONSE_YES: loan_whole_collection = True elif response == gtk.RESPONSE_CANCEL: return False if volume_id>0 and collection_id>0: if loan_whole_collection: self.db.update_collection(id=collection_id, volume_id=volume_id, loaned=1) else: self.db.update_volume(id=volume_id, loaned=1) elif collection_id>0: if loan_whole_collection: self.db.update_collection(id=collection_id, loaned=1) else: self.db.cursor.execute("UPDATE movies SET loaned='1' WHERE number='%s';" % movie_id) elif volume_id>0: self.db.update_volume(id=volume_id, loaned=1) else: self.db.cursor.execute("UPDATE movies SET loaned='1' WHERE number='%s';" % movie_id) self.update_statusbar(_("Movie loaned")) # next, we insert a new row on the loans table data_movie=self.db.select_movie_by_num(movie_id) query = "INSERT INTO 'loans'('id', 'person_id','" if collection_id > 0 and loan_whole_collection: query +="collection_id" elif volume_id > 0: query +="volume_id" else: query +="movie_id" query += "', 'date', 'return_date') VALUES (Null, '" + str(data_person[0]['id']) + "', '" if collection_id > 0 and loan_whole_collection: query += str(collection_id) elif volume_id>0: query += str(volume_id) else: query += str(movie_id) query += "', '" + str(datetime.date.today()) + "', '');" self.db.cursor.execute(query) self.db.con.commit() # finally, force a refresh self.treeview_clicked()
def run(self): tmp_dir = mkdtemp() griffith_list = open(os.path.join(tmp_dir, "movies"), "w") t = [] movies = self.get_query().execute().fetchall() for movie in movies: t.append( "%s | %s | %s | %s" % ( movie["number"], movie["o_title"].encode("utf-8"), movie["title"].encode("utf-8"), movie["director"].encode("utf-8"), ) ) griffith_list.write("<title>%s</title><br><br>" % _("My Movies List")) for movie in t: griffith_list.write(movie) griffith_list.write("<br>") griffith_list.close() # this is a mac, lets export to iPod's notes folder # TODO: windows and linux iPod autodetection if platform.system() == "Darwin": thisPod = Path2iPod() thisPath = thisPod.returnPath() if thisPath: commands.getoutput( "mv " + os.path.join(tmp_dir, "movies") + ' "' + thisPath + '/Notes/"' ) # FIXME: WTF? gutils.info(_("List was successful exported to iPod."), self.parent_window) else: gutils.info(_("iPod is not connected."), self.parent_window) # this is not a mac, lets save the file else: filename = gutils.file_chooser( _("Export a %s document") % "CSV", action=gtk.FILE_CHOOSER_ACTION_SAVE, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK), name="ipod_griffith_list", ) if filename and filename[0]: overwrite = None if os.path.isfile(filename[0]): if gutils.question(_("File exists. Do you want to overwrite it?"), self.parent_window): overwrite = True else: overwrite = False if overwrite == True or overwrite is None: shutil.copyfile(os.path.join(tmp_dir, "movies"), filename[0]) gutils.info( _("List was successful exported. Now you should move it to the 'Notes' folder on your iPod."), self.parent_window, )
def export_simple_pdf(self): """exports a simple movie list to a pdf file""" myconfig = config.Config() if myconfig.get('font', '')!='': self.fontName = "custom_font" pdfmetrics.registerFont(TTFont(self.fontName, myconfig.get('font', ''))) else: self.fontName = "Helvetica" filename = gutils.file_chooser(_("Export a PDF"), action=gtk.FILE_CHOOSER_ACTION_SAVE, buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_SAVE,gtk.RESPONSE_OK),name="griffith_simple_list.pdf") if filename[0]: overwrite = None if os.path.isfile(filename[0]): response = gutils.question(self,_("File exists. Do you want to overwrite it?"),1,self.parent) if response==-8: overwrite = True else: overwrite = False if overwrite == True or overwrite == None: c = SimpleDocTemplate(filename[0]) style = self.styles["Normal"] Story = [Spacer(1,2*inch)] # define some custom stylesheetfont total = self.db.count_records('movies') p = Paragraph("<font name='" + self.fontName +"' size=\"18\">" + saxutils.escape((_("List of films")).encode('utf-8')) + '</font>', self.styles["Heading1"] ) Story.append(p) Story.append(Paragraph(" ",style)) p = Paragraph("<font name='" + self.fontName +"' size=\"10\">" + saxutils.escape((_("Total Movies: %s") % str(total)).encode('utf-8')) + '</font>', self.styles["Heading3"]) Story.append(p) Story.append(Paragraph(" ",style)) data = self.db.get_all_data(order_by="number ASC") for row in data: number = str(row['number']) number = number.encode('utf-8') original_title = str(row['original_title']) original_title = original_title.encode('utf-8') title = str(row['title']) title = title.encode('utf-8') if row['year']: year = ' - ' + str(row['year']) else: year = "" year = year.encode('utf-8') if row['director']: director = ' - ' + str(row['director']) else: director = "" director = director.encode('utf-8') p = Paragraph("<font name=" + self.fontName + " size=\"7\">" + \ saxutils.escape(number + " | " + original_title) + \ "</font><font name=" + self.fontName + " size=\"7\">" + \ saxutils.escape(" (" + title + ")" + year + director) + \ "</font>", self.styles["Normal"]) Story.append(p) c.build(Story, onFirstPage=self.page_template, onLaterPages=self.page_template) gutils.info(self, _("PDF has been created."), self.parent)
def add_movie_db(self, close): session = self.db.Session() details = get_details(self) if not details['o_title'] and not details['title']: gutils.error(_("You should fill the original title\nor the movie title."), parent=self.widgets['add']['window']) return False asked = False if details['o_title']: if session.query(db.Movie).filter_by(o_title=details['o_title']).count() > 0: asked = True if not gutils.question(_('Movie with that title already exists, are you sure you want to add?'), self.widgets['add']['window']): return False if not asked and details['title']: if session.query(db.Movie).filter_by(title=details['title']).count() > 0: if not gutils.question(_('Movie with that title already exists, are you sure you want to add?'), self.widgets['add']['window']): return False new_poster_md5 = None if details['image']: tmp_image_path = details['image'] if not os.path.isfile(tmp_image_path): tmp_image_path = os.path.join(self.locations['temp'], "poster_%s.jpg" % details['image']) if os.path.isfile(tmp_image_path): new_poster_md5 = gutils.md5sum(file(tmp_image_path, 'rb')) if session.query(db.Poster).filter_by(md5sum=new_poster_md5).count() == 0: try: data = file(tmp_image_path, 'rb').read() except Exception, e: log.warning("cannot read poster data") else: poster = db.Poster(md5sum=new_poster_md5, data=data) del details["image"] details["poster_md5"] = new_poster_md5 session.add(poster) else: details["poster_md5"] = new_poster_md5 try: if not tmp_image_path == details['image']: os.remove(tmp_image_path) except Exception, e: log.warn("cannot remove temporary file %s", tmp_image_path)
def _show_preview(self, data): loader = gtk.gdk.PixbufLoader() loader.write(data, len(data)) loader.close() handler = self.widgets['big_poster'].set_from_pixbuf(loader.get_pixbuf()) self.widgets['poster_window'].show() result = gutils.question(_("Do you want to use this poster instead?"), self.widgets['window']) self.widgets['poster_window'].hide() return result
def run(self): tmp_dir = mkdtemp() griffith_list = open(os.path.join(tmp_dir, "movies"), "w") t = [] def checkForNoneAndEncode(val): if val is None: return '' return val.encode('utf-8') movies = self.get_query().execute().fetchall() for movie in movies: t.append("%s | %s | %s | %s" % (movie['number'], \ checkForNoneAndEncode(movie['o_title']), checkForNoneAndEncode(movie['title']), checkForNoneAndEncode(movie['director']))) griffith_list.write("<title>%s</title><br><br>" % _("My Movies List")) for movie in t: griffith_list.write(movie) griffith_list.write("<br>") griffith_list.close() # this is a mac, lets export to iPod's notes folder # TODO: windows and linux iPod autodetection if platform.system() == 'Darwin': thisPod = Path2iPod() thisPath = thisPod.returnPath() if thisPath: commands.getoutput('mv ' + os.path.join(tmp_dir, "movies") + ' "' + thisPath + '/Notes/"') # FIXME: WTF? gutils.info(_("List successfully exported to iPod."), self.parent_window) else: gutils.info(_("iPod is not connected."), self.parent_window) # this is not a mac, lets save the file else: filename = gutils.file_chooser(_("Export a %s document")%"iPod", action=gtk.FILE_CHOOSER_ACTION_SAVE, \ buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_SAVE,gtk.RESPONSE_OK),name='ipod_griffith_list') if filename and filename[0]: overwrite = None if os.path.isfile(filename[0]): if gutils.question( _("File exists. Do you want to overwrite it?"), self.parent_window): overwrite = True else: overwrite = False if overwrite == True or overwrite is None: shutil.copyfile(os.path.join(tmp_dir, "movies"), filename[0]) gutils.info( _("The list was successfully exported. Now you should move it to the 'Notes' folder on your iPod." ), self.parent_window)
def _show_preview(self, data): loader = gtk.gdk.PixbufLoader() loader.write(data, len(data)) loader.close() # show before set_from_pixbuf because it doesn't resize otherwise self.widgets["poster_window"].show() handler = self.widgets["big_poster"].set_from_pixbuf(loader.get_pixbuf()) result = gutils.question(_("Do you want to use this poster instead?"), self.widgets["window"]) self.widgets["poster_window"].hide() return result
def add_movie_db(self, close): details = get_details(self) if not details['o_title'] and not details['title']: gutils.error(self.widgets['results']['window'], _("You should fill the original title\nor the movie title."), parent=self.widgets['add']['window']) return False if details['o_title']: tmp_movie = self.db.session.query(db.Movie).filter_by(o_title=details['o_title']).first() if tmp_movie is not None: response = gutils.question(_('Movie with that title already exists, are you sure you want to add?'), \ False, self.widgets['add']['window']) if response == gtk.RESPONSE_NO: return False if details['title']: tmp_movie = self.db.session.query(db.Movie).filter_by(title=details['title']).first() if tmp_movie is not None: response = gutils.question(_('Movie with that title already exists, are you sure you want to add?'), \ False, self.widgets['add']['window']) if response == gtk.RESPONSE_NO: return False if details['image']: tmp_image_path = os.path.join(self.locations['temp'], "poster_%s.jpg" % details['image']) if os.path.isfile(tmp_image_path): new_poster_md5 = gutils.md5sum(file(tmp_image_path, 'rb')) poster = self.db.session.query(db.Poster).filter_by(md5sum=new_poster_md5).first() if not poster: try: data = file(tmp_image_path, 'rb').read() except Exception, e: log.warning("cannot read poster data") else: poster = db.Poster(md5sum=new_poster_md5, data=data) del details["image"] details["poster_md5"] = new_poster_md5 self.db.session.add(poster) try: os.remove(tmp_image_path) except Exception, e: log.warn("cannot remove temporary file %s", tmp_image_path)
def _show_preview(self, data): loader = gtk.gdk.PixbufLoader() loader.write(data, len(data)) loader.close() # show before set_from_pixbuf because it doesn't resize otherwise self.widgets['poster_window'].show() handler = self.widgets['big_poster'].set_from_pixbuf(loader.get_pixbuf()) result = gutils.question(_("Do you want to use this poster instead?"), self.widgets['window']) self.widgets['poster_window'].hide() return result
def run(self): basedir = None if self.config is not None: basedir = self.config.get('export_dir', None, section='export-xml') if basedir is None: filename = gutils.file_chooser(_("Export a %s document")%"XML", action=gtk.FILE_CHOOSER_ACTION_SAVE, \ buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_SAVE,gtk.RESPONSE_OK),name='griffith_list.xml') else: filename = gutils.file_chooser(_("Export a %s document")%"XML", action=gtk.FILE_CHOOSER_ACTION_SAVE, \ buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_SAVE,gtk.RESPONSE_OK),name='griffith_list.xml',folder=basedir) if filename and filename[0]: if self.config is not None and filename[1]: self.config.set('export_dir', filename[1], section='export-xml') self.config.save() overwrite = None if os.path.isfile(filename[0]): response = gutils.question(_("File exists. Do you want to overwrite it?"), True, self.parent_window) if response==-8: overwrite = True else: overwrite = False if overwrite or overwrite is None: # create document impl = xml.dom.minidom.getDOMImplementation() doc = impl.createDocument(None, "root", None) root = doc.documentElement movies = self.get_query().execute().fetchall() # create object for movie in movies: e = doc.createElement('movie') root.appendChild(e) for key in self.exported_columns: e2 = doc.createElement(str(key).replace('movies_', '')) if movie[key] is None: value = '' elif movie[key] in (True, False): value = str(int(movie[key])) else: if movie[key] is unicode: value = movie[key].encode('utf-8') else: value = str(movie[key]) t = doc.createTextNode(value) e2.appendChild(t) e.appendChild(e2) # write XML to file fp = open(filename[0], "w") xml.dom.ext.PrettyPrint(doc, fp) fp.close() gutils.info( _("%s file has been created.")%"XML", self.parent_window)
def export_simple_pdf(self): """exports a simple movie list to a pdf file""" myconfig = config.Config(os.path.join(self.locations['home'], 'griffith.conf')) if myconfig.get('font', '')!='': self.fontName = "custom_font" pdfmetrics.registerFont(TTFont(self.fontName, myconfig.get('font', ''))) else: self.fontName = "Helvetica" filename = gutils.file_chooser(_("Export a PDF"), action=gtk.FILE_CHOOSER_ACTION_SAVE, buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_SAVE,gtk.RESPONSE_OK),name="griffith_simple_list.pdf") if filename[0]: overwrite = None if os.path.isfile(filename[0]): response = gutils.question(self,_("File exists. Do you want to overwrite it?"),1,self.parent) if response==-8: overwrite = True else: overwrite = False if overwrite == True or overwrite is None: c = SimpleDocTemplate(filename[0]) style = self.styles["Normal"] Story = [Spacer(1,2*inch)] # define some custom stylesheetfont total = self.db.Movie.count() p = Paragraph("<font name='" + self.fontName +"' size=\"18\">" + saxutils.escape((_("List of films")).encode('utf-8')) + '</font>', self.styles["Heading1"] ) Story.append(p) Story.append(Paragraph(" ",style)) p = Paragraph("<font name='" + self.fontName +"' size=\"10\">" + saxutils.escape((_("Total Movies: %s") % str(total)).encode('utf-8')) + '</font>', self.styles["Heading3"]) Story.append(p) Story.append(Paragraph(" ",style)) movies = self.db.Movie.select() for movie in movies: number = movie.number original_title = str(movie.o_title) title = str(movie.title) if movie.year: year = ' - ' + str(movie.year) else: year = "" if movie.director: director = ' - ' + str(movie.director) else: director = "" p = Paragraph("<font name=" + self.fontName + " size=\"7\">" + \ saxutils.escape(str(number) + " | " + original_title) + \ "</font><font name=" + self.fontName + " size=\"7\">" + \ saxutils.escape(" (" + title + ")" + year + director) + \ "</font>", self.styles["Normal"]) Story.append(p) c.build(Story, onFirstPage=self.page_template, onLaterPages=self.page_template) gutils.info(self, _("PDF has been created."), self.parent)
def toolbar_icon_clicked(self, widget, movie): if question(_('Are you sure you want to update %d movies?') % self.app.total): session = self.db.Session() update_query = update(movies_table, values={'seen': True}) # FIXME: self.app._search_conditions contains advfilter conditions only (no other filters) update_query = update_whereclause(update_query, self.app._search_conditions) session.execute(update_query) session.commit() self.app.populate_treeview() # update seen widget in the list
def export_xml(self): basedir = None if not self.persistent_config is None: basedir = self.persistent_config.get('export_dir', None, section='export-xml') if basedir is None: filename = gutils.file_chooser(_("Export a %s document")%"XML", action=gtk.FILE_CHOOSER_ACTION_SAVE, \ buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_SAVE,gtk.RESPONSE_OK),name='griffith_list.xml') else: filename = gutils.file_chooser(_("Export a %s document")%"XML", action=gtk.FILE_CHOOSER_ACTION_SAVE, \ buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_SAVE,gtk.RESPONSE_OK),name='griffith_list.xml',folder=basedir) if filename[0]: if not self.persistent_config is None and filename[1]: self.persistent_config.set('export_dir', filename[1], section='export-xml') self.persistent_config.save() overwrite = None if os.path.isfile(filename[0]): response = gutils.question(self, _("File exists. Do you want to overwrite it?"), 1, self.parent) if response==-8: overwrite = True else: overwrite = False if overwrite == True or overwrite is None: # create document impl = xml.dom.minidom.getDOMImplementation() doc = impl.createDocument(None, "root", None) root = doc.documentElement # create object for movie in self.db.Movie.select(): e = doc.createElement('movie') root.appendChild(e) for key in movie.c.keys(): e2 = doc.createElement(key) if movie[key] is None: value = '' elif movie[key] in (True, False): value = str(int(movie[key])) else: value = str(movie[key]) t = doc.createTextNode(value) e2.appendChild(t) e.appendChild(e2) # write XML to file fp = open(filename[0], "w") xml.dom.ext.PrettyPrint(doc, fp) fp.close() gutils.info(self, _("%s file has been created.")%"XML", self.parent)
def toolbar_icon_clicked(self, widget, movie): if question( _('Are you sure you want to update %d movies?') % self.app.total): session = self.db.Session() update_query = update(movies_table, values={'seen': True}) # FIXME: self.app._search_conditions contains advfilter conditions only (no other filters) update_query = update_whereclause(update_query, self.app._search_conditions) session.execute(update_query) session.commit() self.app.populate_treeview() # update seen widget in the list
def delete_poster(self): m_id, m_iter = self.get_maintree_selection() poster = self.db.select_movie_by_num(m_id)[0]['image'] response = gutils.question(self, _("Are you sure you want to delete this poster?"), 1, self.main_window) if response==-8: image_path = self.locations['images'] + "/default.png" handler = self.e_picture.set_from_pixbuf(gtk.gdk.pixbuf_new_from_file(image_path)) gutils.garbage(handler) update_tree_thumbnail(self, self.locations['images'] + "/default_thumbnail.png") m_id = self.get_maintree_selection() update.clear_image(self, m_id[0]) self.delete_poster.set_sensitive(False) self.zoom_poster.set_sensitive(False) delete.delete_poster(self, poster) else: pass
def delete_movie(self): m_id = None m_id, m_iter = self.get_maintree_selection() if self.db.is_movie_loaned(movie_number=m_id): gutils.warning(self, msg=_("You can't delete movie while it is loaned.")) return False response = gutils.question(self,_("Are you sure you want to delete this movie?"), \ 1, self.main_window) if response == -8: # gtk.RESPONSE_YES == -8 # try to delete poster image as well poster = self.db.get_value('image', table="movies", where="number='%s'"%m_id) if poster != None: delete_poster(self, poster) delete_movie_from_db(self, m_id, m_iter) self.main_treeview.set_cursor_on_cell(self.total_filter-1) else: return False
def toolbar_icon_clicked(self, widget, movie): if question( _('Are you sure you want to remove %d movies?') % self.app.total): session = self.db.Session() # first: remove all dependend data (associated tags, languages, ...) query = select([movies_table.c.movie_id]) # add conditions from simple filter change_filter_update_whereclause(self.app, query) # add conditions from adv filter query = update_whereclause(query, self.app._search_conditions) query = query.where( movies_table.c.loaned == False) # don't delete loaned movies log.debug(query) movie_ids = [] for movie_entry in session.execute(query): movie_ids.append(movie_entry.movie_id) # tags query_movie_tags = delete(movie_tag_table) query_movie_tags = query_movie_tags.where( movie_tag_table.c.movie_id == movie_entry.movie_id) log.debug(query_movie_tags) session.execute(query_movie_tags) # languages query_movie_lang = delete(movie_lang_table) query_movie_lang = query_movie_lang.where( movie_lang_table.c.movie_id == movie_entry.movie_id) log.debug(query_movie_lang) session.execute(query_movie_lang) # TODO: removing posters if no longer used by another movie? # second: remove the movie entries if len(movie_ids): query = delete(movies_table) # use the collected movie ids because other conditions are not true anymore # (f.e. tags are already deleted) query = query.where(movies_table.c.movie_id.in_(movie_ids)) log.debug(query) session.execute(query) session.commit() self.app.populate_treeview()
def commit(self): person_name = gutils.on_combo_box_entry_changed( self.widgets['movie']['loan_to']) if not person_name: return False self.widgets['w_loan_to'].hide() session = self.db.Session() person = session.query( db.Person.person_id).filter_by(name=person_name).first() if not person: log.warn("loan_commit: person doesn't exist") return False if self._movie_id: movie = session.query( db.Movie).filter_by(movie_id=self._movie_id).first() if not movie: log.warn("loan_commit: movie doesn't exist") return False else: log.warn("loan_commit: movie not selected") return False # ask if user wants to loan whole collection loan_whole_collection = False if movie.collection_id > 0: if gutils.question(_('Do you want to loan the whole collection?'), window=self.widgets['window']): loan_whole_collection = True try: if movie.loan_to(person, whole_collection=loan_whole_collection): session.commit() except Exception, e: session.rollback() if e.message == 'loaned movies in the collection already': gutils.warning( _("Collection contains loaned movie.\nLoan aborted!")) return False else: raise e
def run(self): basedir = None if self.config is not None: basedir = self.config.get('export_dir', None, section='export-csv') if not basedir: filename = gutils.file_chooser(_("Export a %s document")%"CSV", action=gtk.FILE_CHOOSER_ACTION_SAVE, \ buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK), name='griffith_list.csv') else: filename = gutils.file_chooser(_("Export a %s document")%"CSV", action=gtk.FILE_CHOOSER_ACTION_SAVE, \ buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE,gtk.RESPONSE_OK), name='griffith_list.csv', folder=basedir) if filename and filename[0]: if self.config is not None and filename[1]: self.config.set('export_dir', filename[1], section='export-csv') self.config.save() overwrite = None if os.path.isfile(filename[0]): if gutils.question( _("File exists. Do you want to overwrite it?"), self.parent_window): overwrite = True else: overwrite = False if overwrite or overwrite is None: movies = self.get_query().execute() writer = csv.writer(file(filename[0], 'w'), dialect=csv.excel) # write column header row writer.writerow(self.fields_to_export) # write data rows for movie in movies: t = [] for s in self.exported_columns: t.append(movie[s]) writer.writerow(t) gutils.info( _("%s file has been created.") % "CSV", self.parent_window)
def show_dialog(self): # shows a file dialog and sets self.filepath # derived classes which overwrite this method have also to set self.filepath basedir = None if not self.config is None and not self.config_section is None: basedir = self.config.get('export_dir', None, section=self.config_section) if basedir is None: filenames = gutils.file_chooser(_('Export a %s document') % self.export_name, action=gtk.FILE_CHOOSER_ACTION_SAVE, \ buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK), name=self.filename) else: filenames = gutils.file_chooser(_('Export a %s document') % self.export_name, action=gtk.FILE_CHOOSER_ACTION_SAVE, \ buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK), name=self.filename, folder=basedir) if filenames[0]: self.filepath = filenames[0] if len(filenames) > 1: self.dirpath = filenames[1] else: self.dirpath = os.path.dirname(self.filepath) self.filename = os.path.basename(self.filepath) if not self.config is None and self.dirpath and not self.config_section is None: self.config.set('export_dir', self.dirpath, section=self.config_section) self.config.save() overwrite = None if os.path.isfile(self.filepath): if gutils.question( _('File exists. Do you want to overwrite it?'), self.parent_window): overwrite = True else: overwrite = False if overwrite == True or overwrite is None: return True return False
def run(self): basedir = None if self.config is not None: basedir = self.config.get('export_dir', None, section='export-xml') if basedir is None: filename = gutils.file_chooser(_("Export a %s document")%"XML", action=gtk.FILE_CHOOSER_ACTION_SAVE, \ buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_SAVE,gtk.RESPONSE_OK),name='griffith_list.xml') else: filename = gutils.file_chooser(_("Export a %s document")%"XML", action=gtk.FILE_CHOOSER_ACTION_SAVE, \ buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_SAVE,gtk.RESPONSE_OK),name='griffith_list.xml',folder=basedir) if filename and filename[0]: if self.config is not None and filename[1]: self.config.set('export_dir', filename[1], section='export-xml') self.config.save() overwrite = None if os.path.isfile(filename[0]): if gutils.question( _("File exists. Do you want to overwrite it?"), self.parent_window): overwrite = True else: overwrite = False posterdir = os.path.join(os.path.dirname(filename[0]), 'posters') if not os.path.exists(posterdir): os.mkdir(posterdir) if overwrite or overwrite is None: # create document impl = xml.dom.minidom.getDOMImplementation() doc = impl.createDocument(None, "root", None) root = doc.documentElement movies = self.get_query().execute().fetchall() # create object for movie in movies: e = doc.createElement('movie') root.appendChild(e) for key in self.exported_columns: e2 = doc.createElement(str(key).replace('movies_', '')) if movie[key] is None: value = '' elif movie[key] in (True, False): value = str(int(movie[key])) else: if movie[key] is unicode: value = movie[key].encode('utf-8') else: value = str(movie[key]) t = doc.createTextNode(value) e2.appendChild(t) e.appendChild(e2) # create image file in ./posters/... md5sum = None posterfilepath = '' if 'poster_md5' in self.exported_columns and movie[ 'poster_md5']: md5sum = movie['poster_md5'] if 'movies_poster_md5' in self.exported_columns and movie[ 'movies_poster_md5']: md5sum = movie['movies_poster_md5'] if md5sum: if gutils.create_imagefile(posterdir, md5sum, self.db): posterfilepath = os.path.join( '.', 'posters', md5sum + '.jpg') e2 = doc.createElement('image') # relative path to image related to xml file t = doc.createTextNode(posterfilepath) e2.appendChild(t) e.appendChild(e2) # write XML to file xmldata = doc.toprettyxml(encoding='utf-8') fp = open(filename[0], "w") try: fp.write(xmldata) finally: fp.close() gutils.info( _("%s file has been created.") % "XML", self.parent_window)
def get_poster(self, item): """Returns file path to the new poster""" from movie import Progress, Retriever file_to_copy = tempfile.mktemp(suffix=self.widgets['movie']['number'].get_text(), \ dir=self.locations['temp']) file_to_copy += ".jpg" canceled = False try: progress = Progress(self.widgets['window'], _("Fetching poster"), _("Wait a moment")) retriever = Retriever(item.LargeImage.URL, self.widgets['window'], progress, file_to_copy) retriever.start() while retriever.isAlive(): progress.pulse() if progress.status: canceled = True while gtk.events_pending(): gtk.main_iteration() progress.close() urlcleanup() except: canceled = True gutils.warning(_("Sorry. A connection error has occurred.")) try: os.remove(file_to_copy) except: log.error("no permission for %s" % file_to_copy) if not canceled: if os.path.isfile(file_to_copy): im = None try: im = Image.open(file_to_copy) except IOError: log.warn("failed to identify %s" % file_to_copy) if im and im.size == (1, 1): url = FancyURLopener().open("http://www.amazon.com/gp/product/images/%s" % item.ASIN).read() if url.find('no-img-sm._V47056216_.gif') > 0: log.warn('No image available') gutils.warning(_("Sorry. This movie is listed but has no poster available at Amazon.com.")) return False url = gutils.after(url, 'id="imageViewerDiv"><img src="') url = gutils.before(url, '" id="prodImage"') urlretrieve(url, file_to_copy) try: im = Image.open(file_to_copy) except IOError: log.warn("failed to identify %s", file_to_copy) if not im: # something wrong with the image, give some feedback to the user log.warn('No image available') gutils.warning(_("Sorry. This movie is listed but has no poster available at Amazon.com.")) return False if im.mode != 'RGB': # convert GIFs im = im.convert('RGB') im.save(file_to_copy, 'JPEG') # set to None because the file is locked otherwise (os.remove throws an exception) im = None handler = self.widgets['big_poster'].set_from_file(file_to_copy) self.widgets['poster_window'].show() self.widgets['poster_window'].move(0, 0) if gutils.question(_("Do you want to use this poster instead?"), self.widgets['window']): return file_to_copy else: log.info("Reverting to previous poster and deleting new one from disk.") try: os.remove(file_to_copy) except: log.error('cannot remove %s', file_to_copy) self.widgets['poster_window'].hide() else: gutils.warning(_("Sorry. This movie is listed but has no poster available at Amazon.com.")) else: # cleanup temporary files after canceling the download if os.path.isfile(file_to_copy): try: os.remove(file_to_copy) except: log.error('cannot remove %s', file_to_copy)
def create(self): """perform a compressed griffith database/posters/preferences backup""" #if self.db.session.bind.engine.name != 'sqlite': # gutils.error(_("Backup function is available only for SQLite engine for now"), self.widgets['window']) # return False default_name = "%s_backup_%s.zip" % (self.config.get('name', 'griffith', section='database'),\ datetime.date.isoformat(datetime.datetime.now())) filename = gutils.file_chooser(_("Save Griffith backup"), \ action=gtk.FILE_CHOOSER_ACTION_SAVE, name=default_name, \ buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK)) if filename and filename[0]: proceed = True zipfilename = filename[0].decode('utf-8') log.debug('Backup filename: %s', zipfilename) if os.path.isfile(zipfilename): if not gutils.question(_("File exists. Do you want to overwrite it?"), window=self.widgets['window']): proceed = False if proceed: try: if zipfile.zlib is not None: log.debug('Creating zip file with compression') mzip = zipfile.ZipFile(zipfilename, 'w', zipfile.ZIP_DEFLATED) else: log.debug('Creating zip file without compression') mzip = zipfile.ZipFile(zipfilename, 'w') except: gutils.error(_("Error creating backup"), self.widgets['window']) return False log.debug('Preparing data and saving it to the zip archive') if self.db.session.bind.engine.name == 'sqlite': mzip.write(os.path.join(self.locations['home'], 'griffith.cfg').encode('utf-8'), arcname='griffith.cfg') db_file_name = "%s.db" % self.config.get('name', 'griffith', section='database') file_path = os.path.join(self.locations['home'], db_file_name).encode('utf-8') mzip.write(file_path, arcname=db_file_name) else: tmp_engine = None try: tmp_dir = mkdtemp() tmp_config_file = os.path.join(tmp_dir, 'griffith.cfg') self.config.save(tmp_config_file) tmp_config = config.Config(file=tmp_config_file) tmp_config.set('type', 'sqlite', section='database') tmp_config.set('file', 'griffith.db', section='database') tmp_config.set('name', 'griffith', section='database') tmp_config.save() mzip.write(tmp_config._file, arcname='griffith.cfg') tmp_file = os.path.join(tmp_dir, 'griffith.db') tmp_engine = create_engine("sqlite:///%s" % tmp_file) db.metadata.create_all(bind=tmp_engine) # SQLite doesn't care about foreign keys much so we can just copy the data for table in db.metadata.sorted_tables: if table.name in ('posters', 'filters'): continue # see below data = table.select(bind=self.db.session.bind).execute().fetchall() if data: table.insert(bind=tmp_engine).execute(data) # posters for poster in db.metadata.tables['posters'].select(bind=self.db.session.bind).execute(): db.metadata.tables['posters'].insert(bind=tmp_engine).execute(md5sum=poster.md5sum, data=StringIO(poster.data).read()) mzip.write(tmp_file, arcname='griffith.db') finally: # disposing the temporary db connection before rmtree and in finally block to avoid locked db file if tmp_engine: tmp_engine.dispose() rmtree(tmp_dir) gutils.info(_("Backup has been created"), self.widgets['window'])
class ExportPlugin(Base): name = 'HTML' description = _('Plugin exports data using templates') author = 'Piotr Ożarowski' email = '*****@*****.**' version = '4.0' #==[ configuration - default values ]==========={{{ settings = { 'sorting': 'movies_title', 'sorting2': 'ASC', 'export_dir': '', 'template': 2, 'title': _("Griffith's movies list"), 'style': 0, 'custom_style': False, 'custom_style_file': None, 'split_num': 50, # split into x files/pages 'split_by': 1, # 0==files, 1==movies 'poster_convert': False, # dont convert 'poster_height': 200, 'poster_width': 150, 'poster_mode': 'RGB', # RGB == color, L == black and white 'poster_format': 'jpeg' } fields = { 'movies_cast': False, 'movies_classification': False, 'movies_country': True, 'movies_genre': True, 'movies_director': True, 'movies_image': True, 'movies_o_site': True, 'movies_site': True, 'movies_trailer': True, 'movies_loaned': False, 'movies_media_num': True, 'movies_number': True, 'movies_o_title': True, 'movies_plot': False, 'movies_rating': True, 'movies_runtime': True, 'movies_studio': False, 'movies_seen': True, 'movies_title': True, 'movies_year': True, 'movies_notes': False, 'movies_screenplay': False, 'movies_cameraman': False, 'movies_width': False, 'movies_height': False, 'movies_barcode': False, # 'movies_region' : False, # 'movies_layers' : False, # 'movies_condition' : False, # 'movies_color' : False, # 'movies_volume_id' : False, # 'movies_collection_id' : False, 'media_name': True, 'collections_name': True, 'volumes_name': True, # 'acodecs_name' : True, 'vcodecs_name': True, } fields_as_columns = { 'movies_cast': 'cast', 'movies_classification': 'classification', 'movies_country': 'country', 'movies_genre': 'genre', 'movies_director': 'director', 'movies_image': 'poster_md5', 'movies_o_site': 'o_site', 'movies_site': 'site', 'movies_trailer': 'trailer', 'movies_loaned': 'loaned', 'movies_media_num': 'media_num', 'movies_number': 'number', 'movies_o_title': 'o_title', 'movies_plot': 'plot', 'movies_rating': 'rating', 'movies_runtime': 'runtime', 'movies_studio': 'studio', 'movies_seen': 'seen', 'movies_title': 'title', 'movies_year': 'year', 'movies_notes': 'notes', 'movies_screenplay': 'screenplay', 'movies_cameraman': 'cameraman', 'movies_width': 'width', 'movies_height': 'height', 'movies_barcode': 'barcode', # 'movies_region' : 'region', # 'movies_layers' : 'layers', # 'movies_condition' : 'condition', # 'movies_color' : 'color', # 'movies_volume_id' : 'volume_id', # 'movies_collection_id' : 'collection_id', 'media_name': 'name', 'collections_name': 'name', 'volumes_name': 'name', # 'acodecs_name' : 'name', 'vcodecs_name': 'name', } names = { _('Cast'): 'movies_cast', _('Classification'): 'movies_classification', _('Country'): 'movies_country', _('Director'): 'movies_director', _('Genre'): 'movies_genre', _('Image'): 'movies_image', _('Official site'): 'movies_o_site', _('Site'): 'movies_site', _('Trailer'): 'movies_trailer', _('Loaned'): 'movies_loaned', _('Discs'): 'movies_media_num', _('Number'): 'movies_number', _('Original Title'): 'movies_o_title', _('Plot'): 'movies_plot', _('Rating'): 'movies_rating', _('Runtime'): 'movies_runtime', _('Studio'): 'movies_studio', _('Seen it'): 'movies_seen', _('Title'): 'movies_title', _('Year'): 'movies_year', _('Notes'): 'movies_notes', _('Screenplay'): 'movies_screenplay', _('Cameraman'): 'movies_cameraman', _('Width'): 'movies_width', _('Height'): 'movies_height', _('Barcode'): 'movies_barcode', # _('Region') : 'movies_region', # _('Layers') : 'movies_layers', # _('Condition') : 'movies_condition', # _('Color') : 'movies_color', # _('Volume') : 'movies_volume_id', # _('Collection') : 'movies_collection_id', _('Media'): 'media_name', _('Collection'): 'collections_name', _('Volume'): 'volumes_name', # _('Audio codecs') : 'acodecs_name', _('Video codec'): 'vcodecs_name', } #}}} def initialize(self): #{{{ self.fields_to_export = [] for field in ExportPlugin.fields: if field == 'movies_image': self.fields_to_export.append('movies.poster_md5') else: pos = field.find('_') self.fields_to_export.append("%s.%s" % (field[:pos], field[pos + 1:])) self.widgets = {} self.style_list = {} self.templates = self.make_template_list() # glade gf = os.path.join(self.locations['glade'], 'exporthtml.glade') self.load_configuration() self.define_widgets(gtk.glade.XML(gf)) self.fill_widgets() return True #}}} def load_configuration(self): #{{{ # persist config if self.config is not None: config = self.settings for name, value in config.items(): try: tmp = self.config.get(name, value, section='export-html') if isinstance(value, bool): config[name] = bool(int(tmp)) elif isinstance(value, int): config[name] = int(tmp) else: config[name] = tmp except: pass selected_fields = self.config.get('selected_fields', '', section='export-html') if selected_fields: for name in self.fields: self.fields[name] = False selected_fields = selected_fields.split(',') for selected_field in selected_fields: if selected_field in self.fields: self.fields[selected_field] = True #}}} def run(self): pass def get_node_value_by_language(self, parent, name, language='en'): #{{{ nodes = parent.getElementsByTagName(name) for node in nodes: if node.parentNode != parent: continue elif node.attributes.get('xml:lang') is not None: if node.attributes.get('xml:lang').value == language: return node.firstChild.nodeValue else: # set default value in case node has no xml:lang attribute value = node.firstChild.nodeValue return value #}}} def make_template_list(self): #{{{ language = 'en' if os.environ.has_key('LANG'): language = os.environ['LANG'][:2] templates = {} j = 0 # number of templates dirName = os.path.join(self.locations['share'], 'export_templates') items = os.listdir(dirName) items.sort() for i in items: fileName = os.path.join(dirName, i) if not os.path.islink(fileName) and os.path.isdir(fileName): # clear previous data doc = None styles = {} tpl_name = None tpl_author = None tpl_email = None tpl_version = None tpl_ext = None tpl_desc = None try: doc = minidom.parse(os.path.join(fileName, 'config.xml')) except: log.info( "Can't parse configuration file for template: %s" % fileName) continue for template in doc.getElementsByTagName('template'): tpl_name = self.get_node_value_by_language( template, 'name', language) tpl_author = template.getElementsByTagName( 'author')[0].firstChild.nodeValue tpl_email = template.getElementsByTagName( 'email')[0].firstChild.nodeValue tpl_version = template.getElementsByTagName( 'version')[0].firstChild.nodeValue tpl_ext = template.getElementsByTagName( 'extension')[0].firstChild.nodeValue tpl_desc = self.get_node_value_by_language( template, 'description', language) k = 0 # number of styles try: styles_list = template.getElementsByTagName( 'styles')[0].getElementsByTagName('style') for style in styles_list: tpl_style_name = self.get_node_value_by_language( style, 'name', language) tpl_style_file = style.getElementsByTagName( 'file')[0].firstChild.nodeValue # get preview if available try: tpl_style_preview = style.getElementsByTagName( 'preview')[0].firstChild.nodeValue except: tpl_style_preview = None styles[k] = { 'name': tpl_style_name, 'file': tpl_style_file, 'preview': tpl_style_preview } k = k + 1 except: styles = None if tpl_name == '': continue templates[j] = { 'dir': i, 'name': tpl_name, 'author': tpl_author, 'email': tpl_email, 'version': tpl_version, 'ext': tpl_ext, 'desc': tpl_desc, 'styles': styles } j = j + 1 return templates #}}} #==[ widgets ]=================================={{{ def define_widgets(self, glade_file): get = lambda x: glade_file.get_widget(x) self.widgets = { 'window': get('w_eh'), 'fcw': get('fcw'), 'box_include_1': get('box_include_1'), 'box_include_2': get('box_include_2'), 'box_include_3': get('box_include_3'), 'sb_split_num': get('sb_split_num'), 'rb_split_files': get('rb_split_files'), 'rb_split_movies': get('rb_split_movies'), 'entry_header': get('entry_header'), 'cb_custom_style': get('cb_custom_style'), 'cb_reverse': get('cb_reverse'), 'combo_style': get('combo_style'), 'combo_sortby': get('combo_sortby'), 'combo_theme': get('combo_theme'), 'fcb_custom_style_file': get('fcb_custom_style_file'), 'l_tpl_author': get('l_tpl_author'), 'l_tpl_email': get('l_tpl_email'), 'l_tpl_version': get('l_tpl_version'), 'l_tpl_desc': get('l_tpl_desc'), 'image_preview': get('image_preview'), 'vb_posters': get('vb_posters'), 'sb_height': get('sb_height'), 'sb_width': get('sb_width'), 'cb_black': get('cb_black'), 'combo_format': get('combo_format'), 'cb_convert': get('cb_convert'), } # define handlers for general events glade_file.signal_autoconnect({ 'on_export_button_clicked': self.export_data, 'on_rb_split_files_toggled': self.on_rb_split_files_toggled, 'on_rb_split_movies_toggled': self.on_rb_split_movies_toggled, 'on_cancel_button_clicked': self.on_quit, 'on_cb_data_toggled': self.on_cb_data_toggled, 'on_cb_custom_style_toggled': self.on_cb_custom_style_toggled, 'on_fcb_custom_style_file_activated': self.on_fcb_custom_style_file_activated, 'on_combo_style_changed': self.on_combo_style_changed, 'on_combo_theme_changed': self.on_combo_theme_changed, 'on_cb_convert_toggled': self.on_cb_convert_toggled, }) def fill_widgets(self): # themes for i in self.templates: self.widgets['combo_theme'].insert_text(i, self.templates[i]['name']) # sortby combo keys = self.names.keys() keys.sort() j = 0 pos_o_title = 0 for i in keys: self.widgets['combo_sortby'].append_text(i) if self.names[i] == self.settings['sorting']: pos_o_title = j j = j + 1 self.widgets['combo_sortby'].set_wrap_width(3) # include data j = 0 k = math.ceil(len(self.names) / float(3)) for i in keys: j = j + 1 field = self.names[i] self.widgets['cb_' + field] = gtk.CheckButton(i) self.widgets['cb_' + field].set_name("cb_%s" % field) self.widgets['cb_' + field].connect('toggled', self.on_cb_data_toggled) self.widgets['cb_' + field].set_active(self.fields[field]) if j <= k: self.widgets['box_include_1'].add(self.widgets["cb_%s" % field]) elif j <= 2 * k: self.widgets['box_include_2'].add(self.widgets["cb_%s" % field]) else: self.widgets['box_include_3'].add(self.widgets["cb_%s" % field]) self.widgets['box_include_1'].show_all() self.widgets['box_include_2'].show_all() self.widgets['box_include_3'].show_all() # set defaults -------------------------------- self.widgets['entry_header'].set_text(self.settings['title']) self.widgets['combo_sortby'].set_active(pos_o_title) if self.settings['sorting2'] == 'DESC': self.widgets['cb_reverse'].set_active(True) else: self.widgets['cb_reverse'].set_active(False) # template and theme style = self.settings[ 'style'] # save it temporary because change of the template set it 0 self.widgets['combo_theme'].set_active(self.settings['template']) self.widgets['combo_style'].set_active(style) self.widgets['cb_custom_style'].set_active( self.settings['custom_style']) if self.settings['custom_style_file']: self.widgets['fcb_custom_style_file'].set_filename( self.settings['custom_style_file']) # spliting self.widgets['sb_split_num'].set_value(self.settings['split_num']) if self.settings['split_by'] == 0: self.widgets['rb_split_files'].set_active(True) else: self.widgets['rb_split_movies'].set_active(True) # posters self.widgets['combo_format'].set_active(0) if self.settings['poster_format'] == 'PNG': self.widgets['combo_format'].set_active(1) elif self.settings['poster_format'] == 'GIF': self.widgets['combo_format'].set_active(2) if self.settings['poster_convert'] and self.settings[ 'poster_convert'] == True: self.widgets['cb_convert'].set_active(True) self.widgets['vb_posters'].set_sensitive(True) else: self.widgets['cb_convert'].set_active(False) self.widgets['vb_posters'].set_sensitive(False) self.widgets['sb_height'].set_value(self.settings['poster_height']) self.widgets['sb_width'].set_value(self.settings['poster_width']) if self.settings['poster_mode'] == 'L': self.widgets['cb_black'].set_active(True) # destination dir if self.settings['export_dir']: self.widgets['fcw'].set_current_folder(self.settings['export_dir']) #}}} #==[ callbacks ]================================{{{ # buttons: def on_quit(self, widget=None): self.widgets['window'].destroy() # data tab -------------------------------------#{{{ def on_rb_split_files_toggled(self, widget): self.settings['split_by'] = 0 # files def on_rb_split_movies_toggled(self, widget): self.settings['split_by'] = 1 # movies # export frame def on_cb_data_toggled(self, widget): self.fields[gutils.after(widget.get_name(), 'cb_')] = widget.get_active() # posters frame def on_cb_convert_toggled(self, widget): active = widget.get_active() self.settings['poster_convert'] = active if not active: self.widgets['vb_posters'].set_sensitive(False) else: self.widgets['vb_posters'].set_sensitive(True) #}}} # template tab ---------------------------------#{{{ def on_combo_theme_changed(self, widget): old_id = self.settings['template'] tpl_id = widget.get_active() self.settings['template'] = tpl_id # fill authors data self.widgets['l_tpl_author'].set_markup( "<i>%s</i>" % self.templates[tpl_id]['author']) self.widgets['l_tpl_email'].set_markup("<i>%s</i>" % self.templates[tpl_id]['email']) self.widgets['l_tpl_email'].set_selectable(True) self.widgets['l_tpl_version'].set_markup( "<i>%s</i>" % self.templates[tpl_id]['version']) self.widgets['l_tpl_desc'].set_markup("<i>%s</i>" % self.templates[tpl_id]['desc']) # remove old style list self.widgets['combo_style'].get_model().clear() # ... and add new if self.templates[tpl_id]['styles'] is not None: for i in self.templates[tpl_id]['styles']: self.widgets['combo_style'].insert_text( i, self.templates[tpl_id]['styles'][i] ['name']) # template name self.widgets['combo_style'].set_active(0) else: self.settings['style'] = None self.widgets['image_preview'].set_from_stock( gtk.STOCK_MISSING_IMAGE, gtk.ICON_SIZE_LARGE_TOOLBAR) def on_combo_style_changed(self, widget): self.settings['style'] = widget.get_active() self.widgets['cb_custom_style'].set_active(False) preview_file = None tpl_id = self.settings['template'] template_dir = os.path.join(self.locations['share'], 'export_templates', self.templates[tpl_id]['dir']) if self.settings['style'] > -1: preview_file = self.templates[self.settings['template']]['styles'][ self.settings['style']]['preview'] if preview_file is not None: preview_file = os.path.join(template_dir, preview_file) if preview_file is not None and not os.path.isfile(preview_file): preview_file = os.path.join( template_dir, 'preview.jpg') # try default preview image if not os.path.isfile(preview_file): preview_file = None if preview_file is not None: self.widgets['image_preview'].set_from_file(preview_file) else: self.widgets['image_preview'].set_from_stock( gtk.STOCK_MISSING_IMAGE, gtk.ICON_SIZE_LARGE_TOOLBAR) self.widgets['image_preview'].show() def on_cb_custom_style_toggled(self, widget): if widget.get_active(): self.settings['custom_style'] = True self.widgets['image_preview'].hide() else: self.settings['custom_style'] = False self.widgets['image_preview'].show() def on_fcb_custom_style_file_activated(self, widget): self.settings['custom_style_file'] = widget.get_filename() self.widgets['cb_custom_style'].set_active(True) #}}} }}} def make_navigation(self, pages, current): #{{{ if pages > 1: # navigation needed tpl_id = self.settings['template'] t = '<div class="navi">\n\t<p id="prev">' if current > 1: t += '<a href="./page_%s.%s">%s</a>' % \ (str(current-1), self.templates[tpl_id]['ext'], _('previous')) else: # first page t += _('previous') t += "</p>\n" for i in range(1, pages + 1): if i == current: t += '\t<p id="current">%s</p>\n' % str(i) else: t +='\t<p><a href="./page_%s.%s">%s</a></p>\n' % \ (str(i), self.templates[tpl_id]['ext'], str(i)) t += '\t<p id="next">' if pages > current: t +='<a href="./page_%s.%s">%s</a>' % \ (str(current+1), self.templates[tpl_id]['ext'], _('next')) else: # last page t += _('next') t += "</p>\n</div>" return t else: return '' #}}} def fill_template(self, template, field, data='', title='', remove=False): #{{{ start = template.find('<@' + field + '>') end = template.find('</@' + field + '>', start + 1) if start > -1 and end > -1: if remove == True: return template[:start] + template[end + 4 + len(field):] else: tmp = gutils.trim(template, '<@' + field + '>', '</@' + field + '>') tmp = tmp.replace("@DATA@", data) tmp = tmp.replace("@TITLE@", title) tmp = template[:start] + tmp + template[end + 4 + len(field):] if tmp.find('<@' + field + '>') != -1: tmp = self.fill_template(tmp, field, data, title, remove) return tmp else: return template #}}} def select(self): #{{{ config = self.settings # sort order TODO: update self.search_conditions["sort_by"] tmp = config['sorting'].split('_') sort_column = "%s.%s" % (tmp[0], '_'.join(tmp[1:])) if config['sorting2'] == 'ASC': sort_column += ' ASC' else: sort_column += ' DESC' self.search_conditions["sort_by"] = (sort_column, ) query = self.get_query() return query.execute() #}}} #==[ main function ]============================{{{ def export_data(self, widget): """Main exporting function""" config = self.settings fields = self.fields tid = config['template'] # get data from widgets self.settings['export_dir'] = self.widgets['fcw'].get_filename() self.settings['title'] = self.widgets['entry_header'].get_text( ).decode('utf-8') self.settings['sorting'] = self.names[ self.widgets['combo_sortby'].get_active_text().decode('utf-8')] if self.widgets['cb_reverse'].get_active(): self.settings['sorting2'] = 'DESC' else: self.settings['sorting2'] = 'ASC' self.settings['split_num'] = self.widgets[ 'sb_split_num'].get_value_as_int() self.settings['poster_height'] = self.widgets[ 'sb_height'].get_value_as_int() self.settings['poster_width'] = self.widgets[ 'sb_width'].get_value_as_int() if self.widgets['cb_black'].get_active(): self.settings['poster_mode'] = 'L' else: self.settings['poster_mode'] = 'RGB' self.settings['poster_format'] = self.widgets[ 'combo_format'].get_active_text() # persist config if self.config is not None: for name, value in config.items(): self.config.set(name, value, section='export-html') selected_fields = '' for name, value in self.fields.items(): if value: selected_fields = selected_fields + name + ',' self.config.set('selected_fields', selected_fields, section='export-html') self.config.save() # create directories if not config['export_dir']: log.info("Error: Folder name not set!") return 1 if not os.path.isdir(config['export_dir']): try: os.mkdir(config['export_dir']) except: gutils.error(_("Can't create %s!") % config['export_dir']) return 2 data_path = os.path.join(self.locations['share'], 'export_templates', self.templates[tid]['dir'], 'data') if os.path.isdir(data_path): try: gutils.copytree(data_path, config['export_dir']) except Exception, err: gutils.warning(str(err)) if fields['movies_image']: # import modules needed later # modules are needed at least to convert griffith.png to nopic.(gif|jpeg|png) from PIL import Image # py2exe problem workaround: if os.name == 'nt' or os.name.startswith('win'): # win32, win64 from PIL import PngImagePlugin from PIL import GifImagePlugin from PIL import JpegImagePlugin Image._initialized = 2 if not config['poster_convert']: config['poster_format'] = 'jpeg' # replace 'jpeg' posters_dir = os.path.join(config['export_dir'], 'posters') if os.path.isdir(posters_dir): if gutils.question( _("Directory %s already exists.\nDo you want to overwrite it?" ) % posters_dir, self.widgets['window']): try: shutil.rmtree(posters_dir) except: gutils.error( _("Can't remove %s!") % config['export_dir']) return 3 else: return 4 try: os.mkdir(posters_dir) except: gutils.error(_("Can't create %s!") % posters_dir) return 5 if config['custom_style']: if config['custom_style_file'] is not None and os.path.isfile( config['custom_style_file']): try: shutil.copy(config['custom_style_file'], config['export_dir']) except: gutils.warning(_("Can't copy %s!") % style_file) config['custom_style'] = False style = os.path.split(self.settings['custom_style_file'])[1] else: config['custom_style'] = False if config['style'] is not None and config['custom_style'] == False: style = self.templates[tid]['styles'][config['style']]['file'] style_path = os.path.join(self.locations['share'], 'export_templates', self.templates[tid]['dir'], style) try: shutil.copy(style_path, config['export_dir']) except: gutils.warning(_("Can't copy %s!") % style_path) # select exported movies exported_movies = self.select().fetchall() if self.settings['sorting'] in ('movies_title', 'movies_o_title'): # re-sorting movies case-insensitive and respect the current locale setting # if sorting by title or original title is selected import locale locale.setlocale(locale.LC_ALL, "") exported_movies.sort(cmp = locale.strcoll, \ key = lambda k: k[self.settings['sorting']] and k[self.settings['sorting']].lower() or '', \ reverse = self.settings['sorting2']=='DESC') number_of_exported_movies = len(exported_movies) if config['split_by'] == 1: # split by number of movies per page self.entries_per_page = config['split_num'] else: # split by number of pagess if number_of_exported_movies < config['split_num']: self.entries_per_page = 1 else: self.entries_per_page = int(number_of_exported_movies / config['split_num']) # calculate number of files to be created (pages) self.pages = int( math.ceil( float(number_of_exported_movies) / self.entries_per_page)) template_dir = os.path.join(self.locations['share'], 'export_templates', self.templates[tid]['dir']) try: filename = 'page.tpl' tpl_header = file(os.path.join(template_dir, filename), "r").read() except: gutils.error(_("Can't open %s!") % filename) return False tpl_header = self.fill_template(tpl_header, 'header', config['title']) try: tpl_header = self.fill_template(tpl_header, 'style', style) except: pass tmp = _('Document generated by Griffith v') + version.pversion + \ ' - Copyright (C) ' + version.pyear + ' ' + version.pauthor + ' - ' + \ _('Released Under the GNU/GPL License') tmp = gutils.html_encode(tmp) tmp = tmp.replace('@', ' at ') # prevent spam tpl_header = self.fill_template(tpl_header, 'copyright', tmp) tmp = None tpl_header = self.fill_template(tpl_header, 'pages', self.pages) # count exported fields rowspan = 0 for i in fields: if fields[i] == True: rowspan = rowspan + 1 rowspan = str(rowspan) tpl_header = self.fill_template(tpl_header, 'rowspan', rowspan) # split template tpl_tail = gutils.after(tpl_header, '<!-- /ITEMS -->') tpl_item = gutils.trim(tpl_header, '<!-- ITEMS -->', '<!-- /ITEMS -->') tpl_header = gutils.before(tpl_header, '<!-- ITEMS -->') # fill header for j in self.names: if self.fields[self.names[j]] == True: tpl_header = self.fill_template(tpl_header, self.names[j], '', j) else: tpl_header = self.fill_template(tpl_header, self.names[j], remove=True) # check if line break needs conversion if tpl_header.upper().find('XHTML 1.0') > -1: linebreak_replacement = '<br />' else: linebreak_replacement = None item = 1 # item's position on page (1 - first, ...) i = 1 page = 1 # page number for row in exported_movies: # fill items {{{ # check if new file has to be created if item == 1: filename = os.path.join( config['export_dir'], 'page_%s.' % page + self.templates[tid]['ext']) try: exported_file = file(filename, 'w') except: gutils.error(_("Can't create %s!") % filename) return False tmp2 = tpl_header + '' exported_file.write(self.fill_template(tmp2, 'page', str(page))) tmp2 = None # --------------------------------------------- tmp = tpl_item + '' # a copy (not a reference!) tmp = self.fill_template(tmp, 'id', str(item)) tmp = self.fill_template(tmp, 'item', str(i)) for j in self.names: if self.fields[self.names[j]] == True: if self.names[j] == 'movies_image': if row['movies_poster_md5']: #image = row['movies_poster_md5'] + '.' + config['poster_format'].lower() image = "%d.%s" % (row['movies_number'], config['poster_format'].lower()) tmp = self.fill_template(tmp, self.names[j], image, j) else: tmp = self.fill_template( tmp, self.names[j], 'nopic.' + config['poster_format'].lower(), j) elif row[self.names[j]] is None: tmp = self.fill_template(tmp, self.names[j], '', j) elif row[self.names[j]] is True: tmp = self.fill_template(tmp, self.names[j], _('Yes'), j) elif row[self.names[j]] is False: tmp = self.fill_template(tmp, self.names[j], _('No'), j) else: try: data = str(row[self.names[j]]).encode('utf-8') if linebreak_replacement is not None: data = data.replace('\r\n', linebreak_replacement) data = data.replace('\n', linebreak_replacement) tmp = self.fill_template(tmp, self.names[j], data, j) except UnicodeDecodeError: log.info( "Unicode Decode Error occurred while decoding %s (movie number: %s)" % (self.names[j], row['movies_number'])) data = str(row[self.names[j]]) if linebreak_replacement is not None: data = data.replace('\r\n', linebreak_replacement) data = data.replace('\n', linebreak_replacement) tmp = self.fill_template(tmp, self.names[j], data, j) except Exception, ex: log.info( "Error occurred while decoding %s (movie number: %s)" % (self.names[j], row['movies_number'])) else: tmp = self.fill_template(tmp, self.names[j], remove=True) tmp = gutils.convert_entities(tmp) exported_file.write(tmp) tmp = None # --------------------------------------------- # copy poster if fields['movies_image']: if row['movies_poster_md5']: image_file_src = gutils.get_image_fname( row['movies_poster_md5'], self.db) image_file_dst = os.path.join( posters_dir, "%d.%s" % (row['movies_number'], config['poster_format'].lower())) if not config['poster_convert']: # copy file try: shutil.copy(image_file_src, image_file_dst) except: log.info("Can't copy %s", image_file_src) else: # convert posters try: im = Image.open(image_file_src, 'r').convert(config['poster_mode']) im.thumbnail((config['poster_width'], config['poster_height']), Image.ANTIALIAS) im.save(image_file_dst, config['poster_format']) except: log.info("Can't convert %s", image_file_src) # close file if last item if ((page - 1) * self.entries_per_page) + item == number_of_exported_movies: tmp2 = tpl_tail + '' exported_file.write( self.fill_template(tmp2, 'navigation', self.make_navigation(self.pages, page))) exported_file.close() tmp2 = None # close file if last item in page elif item == self.entries_per_page: tmp2 = tpl_tail + '' exported_file.write( self.fill_template(tmp2, 'navigation', self.make_navigation(self.pages, page))) exported_file.close() page = page + 1 item = 1 tmp2 = None else: item = item + 1 i = i + 1
def run(self): """exports a simple movie list to a pdf file""" basedir = None if not self.config is None: basedir = self.config.get('export_dir', None, section='export-pdf') if basedir is None: filename = gutils.file_chooser( _("Export a PDF"), action=gtk.FILE_CHOOSER_ACTION_SAVE, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK), name="griffith_simple_list.pdf") else: filename = gutils.file_chooser( _("Export a PDF"), action=gtk.FILE_CHOOSER_ACTION_SAVE, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK), name="griffith_simple_list.pdf", folder=basedir) if filename is not False and filename[0]: if not self.config is None and filename[1]: self.config.set('export_dir', filename[1], section='export-pdf') self.config.save() overwrite = None pdffilename = filename[0].decode('utf-8') if os.path.isfile(pdffilename): if gutils.question( _("File exists. Do you want to overwrite it?"), self.parent_window): overwrite = True else: overwrite = False if overwrite == True or overwrite is None: try: # filename encoding defaultLang, defaultEnc = getdefaultlocale() if defaultEnc is None: defaultEnc = 'UTF-8' c = SimpleDocTemplate(pdffilename.encode(defaultEnc), \ author = 'Griffith', \ title = _('List of films').encode('utf-8'), \ subject = _('List of films').encode('utf-8'), \ allowSplitting = False) # data encoding #if defaultEncoding == 'WinAnsiEncoding': # defaultEnc = 'cp1252' #else: defaultEnc = 'utf-8' pdf_elements = self.config.get( 'pdf_elements', 'image,director,genre,cast').split(',') self.create_styles() style = self.styles["Normal"] Story = [Spacer(1, 2 * inch)] # select sort column - FIXME sort_column_name = self.config.get('sortby', 'number', section='mainlist') sort_reverse = self.config.get('sortby_reverse', False, section='mainlist') do_grouping = True for i in sort_column_name.split(','): if i != 'title' and i != 'o_title': do_grouping = False # build the query query = self.get_query() movies = query.execute().fetchall() # define some custom stylesheetfont total = len(movies) p = Paragraph( saxutils.escape((_("List of films")).encode('utf-8')), self.styles["Heading1"]) Story.append(p) Story.append(Paragraph(" ", style)) p = Paragraph( saxutils.escape((_("Total Movies: %s") % str(total)).encode('utf-8')), self.styles["Heading3"]) Story.append(p) Story.append(Paragraph(" ", style)) # output movies first_letter = '' for movie in movies: number = movie.movies_number if movie.movies_o_title: original_title = movie.movies_o_title.encode( defaultEnc) else: original_title = '' if movie.movies_title: title = movie.movies_title.encode(defaultEnc) else: title = '' grouping_title = movie.movies_title if grouping_title is None: grouping_title = u'None' if movie.movies_director: director = ' - ' + movie.movies_director.encode( defaultEnc) else: director = "" # group by first letter # use movie.title/grouping_title for grouping because of encoding problems !!! if do_grouping and grouping_title[0] != first_letter: if grouping_title[0] in '0123456789': # Group Numbers if first_letter != '0-9': first_letter = '0-9' paragraph_text = saxutils.escape( first_letter) p = Paragraph( paragraph_text.decode(defaultEnc), self.styles['Heading2']) Story.append(p) else: first_letter = grouping_title[0] paragraph_text = saxutils.escape(first_letter) p = Paragraph( paragraph_text.decode(defaultEnc), self.styles['Heading2']) Story.append(p) # add movie title paragraph_text = '<b>'+ saxutils.escape(title) + '</b>' + \ saxutils.escape(' (' + original_title + ') | ' + str(number)) p = Paragraph(paragraph_text.decode(defaultEnc), self.styles['Heading3']) if 'image' in pdf_elements: image_filename = None if movie.movies_poster_md5: image_filename = gutils.get_image_fname( movie.movies_poster_md5, self.db, 'm') if image_filename: p = ParagraphAndImage(p, Image(image_filename, width=30, height=40), side='left') # wrap call needed because of a bug in reportlab flowables.py - ParagraphAndImage::split(self,availWidth, availHeight) # AttributeError: ParagraphAndImage instance has no attribute 'wI' p.wrap(30, 40) Story.append(p) if 'year' in pdf_elements and movie.movies_year: paragraph_text = '<b>' + _( 'Year') + ': </b>' + saxutils.escape( str(movie.movies_year)) p = Paragraph(paragraph_text.decode(defaultEnc), self.styles['Normal']) Story.append(p) if 'runtime' in pdf_elements and movie.movies_runtime: paragraph_text = '<b>' + _( 'Runtime') + ': </b>' + saxutils.escape( str(movie.movies_runtime)) p = Paragraph(paragraph_text.decode(defaultEnc), self.styles['Normal']) Story.append(p) if 'genre' in pdf_elements and movie.movies_genre: paragraph_text = '<b>' + _( 'Genre') + ': </b>' + saxutils.escape( movie.movies_genre.encode(defaultEnc)) p = Paragraph(paragraph_text.decode(defaultEnc), self.styles['Normal']) Story.append(p) if 'director' in pdf_elements and movie.movies_director: paragraph_text = '<i><b>' + _( 'Director') + ': </b>' + saxutils.escape( movie.movies_director.encode( defaultEnc)) + '</i>' p = Paragraph(paragraph_text.decode(defaultEnc), self.styles['Normal']) Story.append(p) if 'cast' in pdf_elements and movie.movies_cast: paragraph_text = '<i><b>' + _( 'Cast') + ': </b>' + saxutils.escape('; '.join( movie.movies_cast.encode(defaultEnc).split( "\n")[0:2])) + '</i>' p = Paragraph(paragraph_text.decode(defaultEnc), self.styles['Normal']) Story.append(p) if 'plot' in pdf_elements and movie.movies_plot: paragraph_text = '<i><b>' + _( 'Plot') + ': </b>' + saxutils.escape( movie.movies_plot.encode( defaultEnc)) + '</i>' p = Paragraph(paragraph_text.decode(defaultEnc), self.styles['Normal']) Story.append(p) if 'notes' in pdf_elements and movie.movies_notes: paragraph_text = '<i><b>' + _( 'Notes') + ': </b>' + saxutils.escape( movie.movies_notes.encode( defaultEnc)) + '</i>' p = Paragraph(paragraph_text.decode(defaultEnc), self.styles['Normal']) Story.append(p) resolution = self._get_resolution(movie) if resolution: paragraph_text = '<i><b>' + _( 'Resolution') + ': </b>' + saxutils.escape( resolution.encode(defaultEnc)) + '</i>' p = Paragraph(paragraph_text.decode(defaultEnc), self.styles['Normal']) Story.append(p) if movie.volumes_name: paragraph_text = '<i><b>' + _( 'Volume') + ': </b>' + saxutils.escape( movie.volumes_name.encode( defaultEnc)) + '</i>' p = Paragraph(paragraph_text.decode(defaultEnc), self.styles['Normal']) Story.append(p) if movie.collections_name: paragraph_text = '<i><b>' + _( 'Collection') + ': </b>' + saxutils.escape( movie.collections_name.encode( defaultEnc)) + '</i>' p = Paragraph(paragraph_text.decode(defaultEnc), self.styles['Normal']) Story.append(p) c.build(Story, onFirstPage=self.page_template, onLaterPages=self.page_template) gutils.info(_('PDF has been created.'), self.parent_window) except Exception, e: log.exception('') gutils.error(str(e))