From 9c5cf74dab0c8ba263cf7ca3a8c074129b532180 Mon Sep 17 00:00:00 2001 From: "beville@gmail.com" Date: Sat, 3 Nov 2012 03:56:01 +0000 Subject: [PATCH] Reworked the credit writing in CIX Added credit editing UI git-svn-id: http://comictagger.googlecode.com/svn/trunk@4 6c5673fe-1810-88d6-992b-cd32ca31540c --- comicinfoxml.py | 122 ++++++++++++++++++-------------------- crediteditorwindow.py | 55 +++++++++++++++++ crediteditorwindow.ui | 107 +++++++++++++++++++++++++++++++++ filenameparser.py | 5 +- taggerwindow.py | 135 ++++++++++++++++++++++++++++++++++-------- todo.txt | 12 +--- 6 files changed, 337 insertions(+), 99 deletions(-) create mode 100644 crediteditorwindow.py create mode 100644 crediteditorwindow.ui diff --git a/comicinfoxml.py b/comicinfoxml.py index ceeeb6e..5f2e5dd 100644 --- a/comicinfoxml.py +++ b/comicinfoxml.py @@ -7,7 +7,7 @@ import zipfile from pprint import pprint import xml.etree.ElementTree as ET from genericmetadata import GenericMetadata - +import utils class ComicInfoXml: @@ -83,71 +83,67 @@ class ComicInfoXml: ET.SubElement(root, 'BlackAndWhite').text = "Yes" # need to specially process the credits, since they are structured differently than CIX - credit_writer = None - credit_penciller = None - credit_inker = None - credit_colorist = None - credit_letterer = None - credit_cover = None - credit_editor = None - + credit_writer_list = list() + credit_penciller_list = list() + credit_inker_list = list() + credit_colorist_list = list() + credit_letterer_list = list() + credit_cover_list = list() + credit_editor_list = list() + + # first, loop thru credits, and build a list for each role that CIX supports for credit in metadata.credits: - if credit['role'].title() in set( ['Writer', 'Plotter'] ): - if credit_writer == None: - credit_writer = ET.SubElement(root, 'Writer') - credit_writer.text = "" - if len(credit_writer.text) > 0: - credit_writer.text += ", " - credit_writer.text += credit['person'] + + if credit['role'].lower() in set( ['writer', 'plotter', 'scripter'] ): + credit_writer_list.append(credit['person']) + + if credit['role'].lower() in set( [ 'artist', 'penciller', 'penciler', 'breakdowns' ] ): + credit_penciller_list.append(credit['person']) - if credit['role'].title() in set( [ 'Inker', 'Artist', 'Finishes' ] ): - if credit_inker == None: - credit_inker = ET.SubElement(root, 'Inker') - credit_inker.text = "" - if len(credit_inker.text) > 0: - credit_inker.text += ", " - credit_inker.text += credit['person'] - - if credit['role'].title() in set( [ 'Artist', 'Penciller', 'Penciler', 'Breakdowns' ] ): - if credit_penciller == None: - credit_penciller = ET.SubElement(root, 'Penciller') - credit_penciller.text = "" - if len(credit_penciller.text) > 0: - credit_penciller.text += ", " - credit_penciller.text += credit['person'] - - if credit['role'].title() in set( [ 'Colorist', 'Colourist' ]): - if credit_colorist == None: - credit_colorist = ET.SubElement(root, 'Colorist') - credit_colorist.text = "" - if len(credit_colorist.text) > 0: - credit_colorist.text += ", " - credit_colorist.text += credit['person'] - - if credit['role'].title() == 'Letterer': - if credit_letterer == None: - credit_letterer = ET.SubElement(root, 'Letterer') - credit_letterer.text = "" - if len(credit_letterer.text) > 0: - credit_letterer.text += ", " - credit_letterer.text += credit['person'] - - if credit['role'].title() in set( [ 'Cover', 'Covers', 'CoverArtist', 'Cover Artist' ] ): - if credit_cover == None: - credit_cover = ET.SubElement(root, 'CoverArtist') - credit_cover.text = "" - if len(credit_cover.text) > 0: - credit_cover.text += ", " - credit_cover.text += credit['person'] - - if credit['role'].title() in set( [ 'Editor'] ): - if credit_editor == None: - credit_editor = ET.SubElement(root, 'Editor') - credit_editor.text = "" - if len(credit_editor.text) > 0: - credit_editor.text += ", " - credit_editor.text += credit['person'] + if credit['role'].lower() in set( [ 'inker', 'artist', 'finishes' ] ): + credit_inker_list.append(credit['person']) + if credit['role'].lower() in set( [ 'colorist', 'colourist', 'colorer', 'colourer' ]): + credit_colorist_list.append(credit['person']) + + if credit['role'].lower() in set( [ 'letterer'] ): + credit_letterer_list.append(credit['person']) + + if credit['role'].lower() in set( [ 'cover', 'covers', 'coverartist', 'cover artist' ] ): + credit_cover_list.append(credit['person']) + + if credit['role'].lower() in set( [ 'editor'] ): + credit_editor_list.append(credit['person']) + + # second, convert each list to string, and add to XML struct + if len( credit_writer_list ) > 0: + node = ET.SubElement(root, 'Writer') + node.text = utils.listToString( credit_writer_list ) + + if len( credit_penciller_list ) > 0: + node = ET.SubElement(root, 'Penciller') + node.text = utils.listToString( credit_penciller_list ) + + if len( credit_inker_list ) > 0: + node = ET.SubElement(root, 'Inker') + node.text = utils.listToString( credit_inker_list ) + + if len( credit_colorist_list ) > 0: + node = ET.SubElement(root, 'Colorist') + node.text = utils.listToString( credit_colorist_list ) + + if len( credit_letterer_list ) > 0: + node = ET.SubElement(root, 'Letterer') + node.text = utils.listToString( credit_letterer_list ) + + if len( credit_cover_list ) > 0: + node = ET.SubElement(root, 'CoverArtist') + node.text = utils.listToString( credit_cover_list ) + + if len( credit_editor_list ) > 0: + node = ET.SubElement(root, 'Editor') + node.text = utils.listToString( credit_editor_list ) + # !!!ATB todo: loop and add the page entries under pages node #pages = ET.SubElement(root, 'Pages') diff --git a/crediteditorwindow.py b/crediteditorwindow.py new file mode 100644 index 0000000..4cb5a8b --- /dev/null +++ b/crediteditorwindow.py @@ -0,0 +1,55 @@ + +from PyQt4 import QtCore, QtGui, uic + + +class CreditEditorWindow(QtGui.QDialog): + + + ModeEdit = 0 + ModeNew = 1 + + + def __init__(self, parent, mode, role, name ): + super(CreditEditorWindow, self).__init__(parent) + + uic.loadUi('crediteditorwindow.ui', self) + + self.mode = mode + + if self.mode == self.ModeEdit: + self.setWindowTitle("Edit Credit") + else: + self.setWindowTitle("New Credit") + + # Add the entries to the role combobox + self.cbRole.addItem( "" ) + self.cbRole.addItem( "Writer" ) + self.cbRole.addItem( "Artist" ) + self.cbRole.addItem( "Penciller" ) + self.cbRole.addItem( "Inker" ) + self.cbRole.addItem( "Colorist" ) + self.cbRole.addItem( "Letterer" ) + self.cbRole.addItem( "Cover Artist" ) + self.cbRole.addItem( "Editor" ) + self.cbRole.addItem( "Other" ) + self.cbRole.addItem( "Plotter" ) + self.cbRole.addItem( "Scripter" ) + + self.leName.setText( name ) + + if role is not None and role != "": + i = self.cbRole.findText( role ) + if i == -1: + self.cbRole.setEditText( role ) + else: + self.cbRole.setCurrentIndex( i ) + + def getCredits( self ): + return self.cbRole.currentText(), self.leName.text() + + + def accept( self ): + if self.cbRole.currentText() == "" or self.leName.text() == "": + QtGui.QMessageBox.warning(self, self.tr("Whoops"), self.tr("You need to enter both role and name for a credit.")) + else: + QtGui.QDialog.accept(self) \ No newline at end of file diff --git a/crediteditorwindow.ui b/crediteditorwindow.ui new file mode 100644 index 0000000..5b5a0e1 --- /dev/null +++ b/crediteditorwindow.ui @@ -0,0 +1,107 @@ + + + dialogCreditEditor + + + + 0 + 0 + 400 + 196 + + + + Modify Credit + + + false + + + + + 180 + 140 + 191 + 30 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + 30 + 30 + 341 + 91 + + + + + + + Role + + + + + + + true + + + + + + + + + + Name + + + + + + + + + + buttonBox + accepted() + dialogCreditEditor + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + dialogCreditEditor + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/filenameparser.py b/filenameparser.py index 2687767..dbc684f 100644 --- a/filenameparser.py +++ b/filenameparser.py @@ -1,6 +1,9 @@ #!/usr/bin/python -# This is horrible, and needs to be re-written, but, well, it mostly works! +# This should probably be re-written, but, well, it mostly works! + +# Some portions of this code were modified from pyComicMetaThis project +# http://code.google.com/p/pycomicmetathis/ import re import os diff --git a/taggerwindow.py b/taggerwindow.py index 1dc5ccc..95f021e 100644 --- a/taggerwindow.py +++ b/taggerwindow.py @@ -1,13 +1,15 @@ from PyQt4 import QtCore, QtGui, uic +import locale from volumeselectionwindow import VolumeSelectionWindow from options import Options, MetaDataStyle from genericmetadata import GenericMetadata from comicvinetalker import ComicVineTalker from comicarchive import ComicArchive +from crediteditorwindow import CreditEditorWindow import utils -import locale + # this reads the environment and inits the right locale locale.setlocale(locale.LC_ALL, "") @@ -43,7 +45,11 @@ class TaggerWindow( QtGui.QMainWindow): # hook up the callbacks self.cbDataStyle.currentIndexChanged.connect(self.setDataStyle) - + self.btnEditCredit.clicked.connect(self.editCredit) + self.btnAddCredit.clicked.connect(self.addCredit) + self.btnRemoveCredit.clicked.connect(self.removeCredit) + self.twCredits.cellDoubleClicked.connect(self.editCredit) + self.updateStyleTweaks() @@ -232,36 +238,40 @@ class TaggerWindow( QtGui.QMainWindow): row = 0 for credit in md.credits: - - # before we add the credit, see if the role-person pair already exists: - r = 0 - while r < self.twCredits.rowCount(): - if ( self.twCredits.item(r, 0).text() == credit['role'].title() and - self.twCredits.item(r, 1).text() == credit['person'] ): - break - r = r + 1 - - # if we didn't make it through the table, it's there alread, so continue without adding - if ( r != self.twCredits.rowCount() ): + # if the role-person pair already exists, just skip adding it to the list + if self.isDupeCredit( credit['role'].title(), credit['person']): continue - self.twCredits.insertRow(row) - - item_text = credit['role'].title() - item = QtGui.QTableWidgetItem(item_text) - #item.setData( QtCore.Qt.UserRole ,record['id']) - item.setFlags(QtCore.Qt.ItemIsSelectable| QtCore.Qt.ItemIsEnabled) - self.twCredits.setItem(row, 0, item) - - item_text = credit['person'] - item = QtGui.QTableWidgetItem(item_text) - item.setFlags(QtCore.Qt.ItemIsSelectable| QtCore.Qt.ItemIsEnabled) - self.twCredits.setItem(row, 1, item) - + self.addNewCreditEntry( row, credit['role'].title(), credit['person'] ) + row += 1 self.twCredits.setSortingEnabled( True ) + + def addNewCreditEntry( self, row, role, name ): + self.twCredits.insertRow(row) + item_text = role + item = QtGui.QTableWidgetItem(item_text) + item.setFlags(QtCore.Qt.ItemIsSelectable| QtCore.Qt.ItemIsEnabled) + self.twCredits.setItem(row, 0, item) + + item_text = name + item = QtGui.QTableWidgetItem(item_text) + item.setFlags(QtCore.Qt.ItemIsSelectable| QtCore.Qt.ItemIsEnabled) + self.twCredits.setItem(row, 1, item) + + + def isDupeCredit( self, role, name ): + r = 0 + while r < self.twCredits.rowCount(): + if ( self.twCredits.item(r, 0).text() == role and + self.twCredits.item(r, 1).text() == name ): + return True + r = r + 1 + + return False + def formToMetadata( self ): @@ -326,6 +336,16 @@ class TaggerWindow( QtGui.QMainWindow): else: md.blackAndWhite = False + # get the credits from the table + md.credits = list() + row = 0 + while row < self.twCredits.rowCount(): + role = str(self.twCredits.item(row, 0).text()) + name = str(self.twCredits.item(row, 1).text()) + md.addCredit( name, role, False ) + print name, role, row + row += 1 + def useFilename( self ): self.metadata = self.comic_archive.metadataFromFilename( ) @@ -443,6 +463,69 @@ class TaggerWindow( QtGui.QMainWindow): for item in cix_only: enableWidget(item, False ) + def cellDoubleClicked( self, r, c ): + self.editCredit() + + def addCredit( self ): + self.modifyCredits( "add" ) + + def editCredit( self ): + if ( self.twCredits.currentRow() > -1 ): + self.modifyCredits( "edit" ) + + def modifyCredits( self , action ): + + if action == "edit": + row = self.twCredits.currentRow() + role = self.twCredits.item( row, 0 ).text() + name = self.twCredits.item( row, 1 ).text() + else: + role = "" + name = "" + + editor = CreditEditorWindow( self, CreditEditorWindow.ModeEdit, role, name ) + editor.setModal(True) + editor.exec_() + if editor.result(): + new_role, new_name = editor.getCredits() + + if new_name == name and new_role == role: + #nothing has changed, just quit + return + + # check for dupes + ok_to_mod = True + if self.isDupeCredit( new_role, new_name): + # delete the dupe credit from list + #TODO warn user!! + reply = QtGui.QMessageBox.question(self, + self.tr("Duplicate Credit!"), + self.tr("This will create a duplicate credit entry. Would you like to merge the entries, or create a duplicate?"), + self.tr("Merge"), self.tr("Duplicate" )) + + if reply == 0: + # merge + if action == "edit": + # just remove the row that would be same + self.twCredits.removeRow( row ) + + ok_to_mod = False + + + if ok_to_mod: + #modify it + if action == "edit": + self.twCredits.item(row, 0).setText( new_role ) + self.twCredits.item(row, 1).setText( new_name ) + else: + # add new entry + row = self.twCredits.rowCount() + self.addNewCreditEntry( row, new_role, new_name) + + def removeCredit( self ): + row = self.twCredits.currentRow() + if row != -1 : + self.twCredits.removeRow( row ) def center(self): diff --git a/todo.txt b/todo.txt index 569a357..ee07291 100644 --- a/todo.txt +++ b/todo.txt @@ -1,4 +1,3 @@ -Add more CIX tags: ComicArchive support for folders @@ -8,20 +7,15 @@ API Key config Toolbar icons -Consolidate Credit Roles for english variants : Penciler vs Penciller +Consolidate Credit Roles for english variants? : Penciler vs Penciller TaggerWindow entry fields General layout Special Dialogs needed for: - Credits Pages Info - Some entry fields should/could be combobox: - Format - Language - Country - Manga?? CIX: "Yes", "No", "YesAndRightToLeft" + CR has editable dropdowns/comboboxes for Format, Publisher, Imprint ----------- Form type validation Ints vs strings for month, year. etc @@ -72,4 +66,4 @@ Some that seem library only: Tags Proposed Values - Community Rating \ No newline at end of file + Community Rating