diff --git a/src/calibre/customize/profiles.py b/src/calibre/customize/profiles.py index 7141fe05b2..f253b17c6e 100644 --- a/src/calibre/customize/profiles.py +++ b/src/calibre/customize/profiles.py @@ -4,6 +4,7 @@ __copyright__ = '2009, Kovid Goyal ' __docformat__ = 'restructuredtext en' from itertools import izip +from xml.sax.saxutils import escape from calibre.customize import Plugin as _Plugin @@ -238,7 +239,7 @@ class OutputProfile(Plugin): @classmethod def tags_to_string(cls, tags): - return ', '.join(tags) + return escape(', '.join(tags)) class iPadOutput(OutputProfile): @@ -383,7 +384,8 @@ class KindleOutput(OutputProfile): @classmethod def tags_to_string(cls, tags): - return 'ttt '.join(tags)+'ttt ' + return u'%s
%s' % (', '.join(tags), + 'ttt '.join(tags)+'ttt ') class KindleDXOutput(OutputProfile): @@ -399,7 +401,8 @@ class KindleDXOutput(OutputProfile): @classmethod def tags_to_string(cls, tags): - return 'ttt '.join(tags)+'ttt ' + return u'%s
%s' % (', '.join(tags), + 'ttt '.join(tags)+'ttt ') class IlliadOutput(OutputProfile): diff --git a/src/calibre/devices/manager.py b/src/calibre/devices/manager.py index bc493d9f1a..b00e944d05 100644 --- a/src/calibre/devices/manager.py +++ b/src/calibre/devices/manager.py @@ -10,7 +10,7 @@ import threading, Queue class DeviceManager(object): - + def __init__(self): self.devices = [] self.device_jobs = Queue(0) @@ -21,19 +21,19 @@ class Job(object): def __init__(self, func, args): self.completed = False self.exception = None - + class Worker(threading.Thread): - - def __init__(self, jobs): + + def __init__(self, jobs): self.jobs = jobs self.results = [] threading.Thread.__init__(self) self.setDaemon(True) - + def run(self): '''Thread loops taking jobs from the queue as they become available''' while True: - job = self.jobs.get(True, None) + self.jobs.get(True, None) # Do job - self.jobs.task_done() \ No newline at end of file + self.jobs.task_done() diff --git a/src/calibre/ebooks/oeb/transforms/jacket.py b/src/calibre/ebooks/oeb/transforms/jacket.py index 2991e28d02..fec4d230c3 100644 --- a/src/calibre/ebooks/oeb/transforms/jacket.py +++ b/src/calibre/ebooks/oeb/transforms/jacket.py @@ -99,7 +99,7 @@ class Jacket(object): except: tags = [] if tags: - tags = 'Tags: ' + escape(self.opts.dest.tags_to_string(tags)) + tags = 'Tags: ' + self.opts.dest.tags_to_string(tags) else: tags = '' try: diff --git a/src/calibre/ebooks/rtf2xml/paragraph_def.py b/src/calibre/ebooks/rtf2xml/paragraph_def.py index 6635024273..aa13f9e4e2 100755 --- a/src/calibre/ebooks/rtf2xml/paragraph_def.py +++ b/src/calibre/ebooks/rtf2xml/paragraph_def.py @@ -354,7 +354,6 @@ if another paragraph_def is found, the state changes to collect_tokens. def __tab_stop_func(self, line): """ """ - type = 'tabs-%s' % self.__tab_type self.__att_val_dict['tabs'] += '%s:' % self.__tab_type self.__att_val_dict['tabs'] += '%s;' % line[20:-1] self.__tab_type = 'left' @@ -373,7 +372,6 @@ if another paragraph_def is found, the state changes to collect_tokens. """ leader = self.__tab_type_dict.get(self.__token_info) if leader != None: - type = 'tabs-%s' % self.__tab_type self.__att_val_dict['tabs'] += '%s^' % leader else: if self.__run_level > 3: diff --git a/src/calibre/ebooks/rtf2xml/styles.py b/src/calibre/ebooks/rtf2xml/styles.py index c551b7ad3c..815a64e4f4 100755 --- a/src/calibre/ebooks/rtf2xml/styles.py +++ b/src/calibre/ebooks/rtf2xml/styles.py @@ -318,7 +318,6 @@ class Styles: Try to add the number to dictionary entry tabs-left, or tabs-right, etc. If the dictionary entry doesn't exist, create one. """ - type = 'tabs-%s' % self.__tab_type try: if self.__leader_found: self.__styles_dict['par'][self.__styles_num]['tabs']\ @@ -362,7 +361,6 @@ class Styles: leader = self.__tab_type_dict.get(self.__token_info) if leader != None: leader += '^' - type = 'tabs-%s' % self.__tab_type try: self.__styles_dict['par'][self.__styles_num]['tabs'] += ':%s;' % leader except KeyError: diff --git a/src/calibre/gui2/dialogs/comments_dialog.py b/src/calibre/gui2/dialogs/comments_dialog.py index e3b256f7f9..f9806b44d1 100644 --- a/src/calibre/gui2/dialogs/comments_dialog.py +++ b/src/calibre/gui2/dialogs/comments_dialog.py @@ -1,17 +1,16 @@ -#!/usr/bin/env python -__license__ = 'GPL v3' -__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net' -__docformat__ = 'restructuredtext en' - -from PyQt4.Qt import QDialog -from calibre.gui2 import ResizableDialog -from calibre.gui2.dialogs.comments_dialog_ui import Ui_CommentsDialog - -class CommentsDialog(QDialog, Ui_CommentsDialog): - def __init__(self, parent, text): - QDialog.__init__(self, parent) - Ui_CommentsDialog.__init__(self) - self.setupUi(self) - if text is not None: - self.textbox.setPlainText(text) - self.textbox.setTabChangesFocus(True) \ No newline at end of file +#!/usr/bin/env python +__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net' +__docformat__ = 'restructuredtext en' +__license__ = 'GPL v3' + +from PyQt4.Qt import QDialog +from calibre.gui2.dialogs.comments_dialog_ui import Ui_CommentsDialog + +class CommentsDialog(QDialog, Ui_CommentsDialog): + def __init__(self, parent, text): + QDialog.__init__(self, parent) + Ui_CommentsDialog.__init__(self) + self.setupUi(self) + if text is not None: + self.textbox.setPlainText(text) + self.textbox.setTabChangesFocus(True) diff --git a/src/calibre/gui2/dialogs/comments_dialog.ui b/src/calibre/gui2/dialogs/comments_dialog.ui index b05069f1f6..c008ee0573 100644 --- a/src/calibre/gui2/dialogs/comments_dialog.ui +++ b/src/calibre/gui2/dialogs/comments_dialog.ui @@ -1,83 +1,83 @@ - - - CommentsDialog - - - - 0 - 0 - 336 - 235 - - - - - 0 - 0 - - - - Edit Comments - - - - - 10 - 10 - 311 - 211 - - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - - buttonBox - accepted() - CommentsDialog - accept() - - - 229 - 211 - - - 157 - 234 - - - - - buttonBox - rejected() - CommentsDialog - reject() - - - 297 - 217 - - - 286 - 234 - - - - - + + + CommentsDialog + + + + 0 + 0 + 336 + 235 + + + + + 0 + 0 + + + + Edit Comments + + + + + 10 + 10 + 311 + 211 + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + buttonBox + accepted() + CommentsDialog + accept() + + + 229 + 211 + + + 157 + 234 + + + + + buttonBox + rejected() + CommentsDialog + reject() + + + 297 + 217 + + + 286 + 234 + + + + + diff --git a/src/calibre/gui2/dialogs/config/__init__.py b/src/calibre/gui2/dialogs/config/__init__.py index 26d99b4ff2..72a5680bc8 100644 --- a/src/calibre/gui2/dialogs/config/__init__.py +++ b/src/calibre/gui2/dialogs/config/__init__.py @@ -1,6 +1,6 @@ __license__ = 'GPL v3' __copyright__ = '2008, Kovid Goyal ' -import os, re, time, textwrap, sys, copy +import os, re, time, textwrap, copy from PyQt4.Qt import QDialog, QListWidgetItem, QIcon, \ QDesktopServices, QVBoxLayout, QLabel, QPlainTextEdit, \ @@ -17,7 +17,6 @@ from calibre.gui2 import qstring_to_unicode, choose_dir, error_dialog, config, \ ALL_COLUMNS, NONE, info_dialog, choose_files, \ warning_dialog, ResizableDialog from calibre.utils.config import prefs -from calibre.gui2.library import BooksModel from calibre.ebooks import BOOK_EXTENSIONS from calibre.ebooks.oeb.iterator import is_supported from calibre.library import server_config @@ -666,10 +665,10 @@ class ConfigDialog(ResizableDialog, Ui_Dialog): return def add_custcol(self): - d = CreateCustomColumn(self, False, self.model.orig_headers, ALL_COLUMNS) + CreateCustomColumn(self, False, self.model.orig_headers, ALL_COLUMNS) def edit_custcol(self): - d = CreateCustomColumn(self, True, self.model.orig_headers, ALL_COLUMNS) + CreateCustomColumn(self, True, self.model.orig_headers, ALL_COLUMNS) def view_server_logs(self): from calibre.library.server import log_access_file, log_error_file diff --git a/src/calibre/gui2/dialogs/config/create_custom_column.py b/src/calibre/gui2/dialogs/config/create_custom_column.py index b0f0fbcaac..89b31c41fa 100644 --- a/src/calibre/gui2/dialogs/config/create_custom_column.py +++ b/src/calibre/gui2/dialogs/config/create_custom_column.py @@ -1,123 +1,121 @@ -__license__ = 'GPL v3' -__copyright__ = '2010, Kovid Goyal ' - -'''Dialog to create a new custom column''' - -from PyQt4.QtCore import SIGNAL, QObject -from PyQt4.Qt import QDialog, Qt, QMessageBox, QListWidgetItem, QVariant -from calibre.gui2.dialogs.config.create_custom_column_ui import Ui_QCreateCustomColumn -from calibre.gui2 import ALL_COLUMNS, qstring_to_unicode - -class CreateCustomColumn(QDialog, Ui_QCreateCustomColumn): - column_types = { - 0:{'datatype':'text', 'text':_('Text, column shown in tags browser'), 'is_multiple':False}, - 1:{'datatype':'*text', 'text':_('Comma separated text, shown in tags browser'), 'is_multiple':True}, - 2:{'datatype':'comments', 'text':_('Text, column not shown in tags browser'), 'is_multiple':False}, - 3:{'datatype':'datetime', 'text':_('Date'), 'is_multiple':False}, - 4:{'datatype':'float', 'text':_('Float'), 'is_multiple':False}, - 5:{'datatype':'int', 'text':_('Integer'), 'is_multiple':False}, - 6:{'datatype':'rating', 'text':_('Rating (stars)'), 'is_multiple':False}, - 7:{'datatype':'bool', 'text':_('Yes/No'), 'is_multiple':False}, - } - def __init__(self, parent, editing, standard_colheads, standard_colnames): - QDialog.__init__(self, parent) - Ui_QCreateCustomColumn.__init__(self) - self.setupUi(self) - self.connect(self.button_box, SIGNAL("accepted()"), self.accept) - self.connect(self.button_box, SIGNAL("rejected()"), self.reject) - self.parent = parent - self.editing_col = editing - self.standard_colheads = standard_colheads - self.standard_colnames = standard_colnames - if not self.editing_col: - for t in self.column_types: - self.column_type_box.addItem(self.column_types[t]['text']) - self.exec_() - return - idx = parent.columns.currentRow() - if idx < 0: - self.parent.messagebox(_('No column has been selected')) - return - col = qstring_to_unicode(parent.columns.item(idx).data(Qt.UserRole).toString()) - if col not in parent.custcols: - self.parent.messagebox(_('Selected column is not a user-defined column')) - return - - c = parent.custcols[col] - self.column_name_box.setText(c['label']) - self.column_heading_box.setText(c['name']) - ct = c['datatype'] if not c['is_multiple'] else '*text' - self.orig_column_number = c['num'] - self.orig_column_name = col - column_numbers = dict(map(lambda x:(self.column_types[x]['datatype'], x), self.column_types)) - self.column_type_box.addItem(self.column_types[column_numbers[ct]]['text']) - self.exec_() - - def accept(self): - col = qstring_to_unicode(self.column_name_box.text()) - col_heading = qstring_to_unicode(self.column_heading_box.text()) - col_type = self.column_types[self.column_type_box.currentIndex()]['datatype'] - if col_type == '*text': - col_type='text' - is_multiple = True - else: - is_multiple = False - if not col: - self.parent.messagebox(_('No lookup name was provided')) - return - if not col_heading: - self.parent.messagebox(_('No column heading was provided')) - return - bad_col = False - if col in self.parent.custcols: - if not self.editing_col or self.parent.custcols[col]['num'] != self.orig_column_number: - bad_col = True - if col in self.standard_colnames: - bad_col = True - if bad_col: - self.parent.messagebox(_('The lookup name %s is already used')%col) - return - bad_head = False - for t in self.parent.custcols: - if self.parent.custcols[t]['name'] == col_heading: - if not self.editing_col or self.parent.custcols[t]['num'] != self.orig_column_number: - bad_head = True - for t in self.standard_colheads: - if self.standard_colheads[t] == col_heading: - bad_head = True - if bad_head: - self.parent.messagebox(_('The heading %s is already used')%col_heading) - return - if col.find(':') >= 0 or col.find(' ') >= 0 and \ - (not is_alpha(col) or is_lower(col)): - self.parent.messagebox(_('The lookup name must be lower case and cannot contain ":"s or spaces')) - return - - if not self.editing_col: - self.parent.custcols[col] = { - 'label':col, - 'name':col_heading, - 'datatype':col_type, - 'editable':True, - 'display':None, - 'normalized':None, - 'num':None, - 'is_multiple':is_multiple, - } - item = QListWidgetItem(col_heading, self.parent.columns) - item.setData(Qt.UserRole, QVariant(col)) - item.setFlags(Qt.ItemIsEnabled|Qt.ItemIsUserCheckable|Qt.ItemIsSelectable) - item.setCheckState(Qt.Checked) - else: - idx = self.parent.columns.currentRow() - item = self.parent.columns.item(idx) - item.setData(Qt.UserRole, QVariant(col)) - item.setText(col_heading) - self.parent.custcols[self.orig_column_name]['label'] = col - self.parent.custcols[self.orig_column_name]['name'] = col_heading - self.parent.custcols[self.orig_column_name]['*edited'] = True - self.parent.custcols[self.orig_column_name]['*must_restart'] = True - QDialog.accept(self) - - def reject(self): - QDialog.reject(self) \ No newline at end of file +__license__ = 'GPL v3' +__copyright__ = '2010, Kovid Goyal ' + +'''Dialog to create a new custom column''' + +from PyQt4.QtCore import SIGNAL +from PyQt4.Qt import QDialog, Qt, QListWidgetItem, QVariant +from calibre.gui2.dialogs.config.create_custom_column_ui import Ui_QCreateCustomColumn + +class CreateCustomColumn(QDialog, Ui_QCreateCustomColumn): + column_types = { + 0:{'datatype':'text', 'text':_('Text, column shown in tags browser'), 'is_multiple':False}, + 1:{'datatype':'*text', 'text':_('Comma separated text, shown in tags browser'), 'is_multiple':True}, + 2:{'datatype':'comments', 'text':_('Text, column not shown in tags browser'), 'is_multiple':False}, + 3:{'datatype':'datetime', 'text':_('Date'), 'is_multiple':False}, + 4:{'datatype':'float', 'text':_('Float'), 'is_multiple':False}, + 5:{'datatype':'int', 'text':_('Integer'), 'is_multiple':False}, + 6:{'datatype':'rating', 'text':_('Rating (stars)'), 'is_multiple':False}, + 7:{'datatype':'bool', 'text':_('Yes/No'), 'is_multiple':False}, + } + def __init__(self, parent, editing, standard_colheads, standard_colnames): + QDialog.__init__(self, parent) + Ui_QCreateCustomColumn.__init__(self) + self.setupUi(self) + self.connect(self.button_box, SIGNAL("accepted()"), self.accept) + self.connect(self.button_box, SIGNAL("rejected()"), self.reject) + self.parent = parent + self.editing_col = editing + self.standard_colheads = standard_colheads + self.standard_colnames = standard_colnames + if not self.editing_col: + for t in self.column_types: + self.column_type_box.addItem(self.column_types[t]['text']) + self.exec_() + return + idx = parent.columns.currentRow() + if idx < 0: + self.parent.messagebox(_('No column has been selected')) + return + col = unicode(parent.columns.item(idx).data(Qt.UserRole).toString()) + if col not in parent.custcols: + self.parent.messagebox(_('Selected column is not a user-defined column')) + return + + c = parent.custcols[col] + self.column_name_box.setText(c['label']) + self.column_heading_box.setText(c['name']) + ct = c['datatype'] if not c['is_multiple'] else '*text' + self.orig_column_number = c['num'] + self.orig_column_name = col + column_numbers = dict(map(lambda x:(self.column_types[x]['datatype'], x), self.column_types)) + self.column_type_box.addItem(self.column_types[column_numbers[ct]]['text']) + self.exec_() + + def accept(self): + col = unicode(self.column_name_box.text()) + col_heading = unicode(self.column_heading_box.text()) + col_type = self.column_types[self.column_type_box.currentIndex()]['datatype'] + if col_type == '*text': + col_type='text' + is_multiple = True + else: + is_multiple = False + if not col: + self.parent.messagebox(_('No lookup name was provided')) + return + if not col_heading: + self.parent.messagebox(_('No column heading was provided')) + return + bad_col = False + if col in self.parent.custcols: + if not self.editing_col or self.parent.custcols[col]['num'] != self.orig_column_number: + bad_col = True + if col in self.standard_colnames: + bad_col = True + if bad_col: + self.parent.messagebox(_('The lookup name %s is already used')%col) + return + bad_head = False + for t in self.parent.custcols: + if self.parent.custcols[t]['name'] == col_heading: + if not self.editing_col or self.parent.custcols[t]['num'] != self.orig_column_number: + bad_head = True + for t in self.standard_colheads: + if self.standard_colheads[t] == col_heading: + bad_head = True + if bad_head: + self.parent.messagebox(_('The heading %s is already used')%col_heading) + return + if ':' in col or ' ' in col or col.lower() != col: + self.parent.messagebox(_('The lookup name must be lower case and cannot contain ":"s or spaces')) + return + + if not self.editing_col: + self.parent.custcols[col] = { + 'label':col, + 'name':col_heading, + 'datatype':col_type, + 'editable':True, + 'display':None, + 'normalized':None, + 'num':None, + 'is_multiple':is_multiple, + } + item = QListWidgetItem(col_heading, self.parent.columns) + item.setData(Qt.UserRole, QVariant(col)) + item.setFlags(Qt.ItemIsEnabled|Qt.ItemIsUserCheckable|Qt.ItemIsSelectable) + item.setCheckState(Qt.Checked) + else: + idx = self.parent.columns.currentRow() + item = self.parent.columns.item(idx) + item.setData(Qt.UserRole, QVariant(col)) + item.setText(col_heading) + self.parent.custcols[self.orig_column_name]['label'] = col + self.parent.custcols[self.orig_column_name]['name'] = col_heading + self.parent.custcols[self.orig_column_name]['*edited'] = True + self.parent.custcols[self.orig_column_name]['*must_restart'] = True + QDialog.accept(self) + + def reject(self): + QDialog.reject(self) diff --git a/src/calibre/gui2/dialogs/config/create_custom_column.ui b/src/calibre/gui2/dialogs/config/create_custom_column.ui index 17291c020d..9ba9c1d547 100644 --- a/src/calibre/gui2/dialogs/config/create_custom_column.ui +++ b/src/calibre/gui2/dialogs/config/create_custom_column.ui @@ -1,142 +1,142 @@ - - - QCreateCustomColumn - - - Qt::ApplicationModal - - - - 0 - 0 - 391 - 157 - - - - - 0 - 0 - - - - Create Tag-based Column - - - - - 10 - 0 - 371 - 141 - - - - - QLayout::SetDefaultConstraint - - - 5 - - - - - - - Lookup name - - - - - - - Column heading - - - - - - - - 20 - 0 - - - - Used for searching the column. Must be lower case and not contain spaces or colons. - - - - - - - Column heading in the library view and category name in tags browser - - - - - - - Column type - - - - - - - - 0 - 0 - - - - - 70 - 0 - - - - What kind of information will be kept in the column. - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - true - - - - - - - - 75 - true - - - - Create and edit custom columns - - - - - - - - column_name_box - column_heading_box - column_type_box - button_box - - - - + + + QCreateCustomColumn + + + Qt::ApplicationModal + + + + 0 + 0 + 391 + 157 + + + + + 0 + 0 + + + + Create Tag-based Column + + + + + 10 + 0 + 371 + 141 + + + + + QLayout::SetDefaultConstraint + + + 5 + + + + + + + Lookup name + + + + + + + Column heading + + + + + + + + 20 + 0 + + + + Used for searching the column. Must be lower case and not contain spaces or colons. + + + + + + + Column heading in the library view and category name in tags browser + + + + + + + Column type + + + + + + + + 0 + 0 + + + + + 70 + 0 + + + + What kind of information will be kept in the column. + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + true + + + + + + + + 75 + true + + + + Create and edit custom columns + + + + + + + + column_name_box + column_heading_box + column_type_box + button_box + + + + diff --git a/src/calibre/gui2/dialogs/tag_categories.py b/src/calibre/gui2/dialogs/tag_categories.py index dbba827cbe..9f55738000 100644 --- a/src/calibre/gui2/dialogs/tag_categories.py +++ b/src/calibre/gui2/dialogs/tag_categories.py @@ -1,186 +1,182 @@ -__license__ = 'GPL v3' - -__copyright__ = '2008, Kovid Goyal ' - -from copy import copy - -from PyQt4.QtCore import SIGNAL, Qt, QVariant -from PyQt4.QtGui import QDialog, QDialogButtonBox, QLineEdit, QComboBox, \ - QIcon, QListWidgetItem -from PyQt4.Qt import QString - -from calibre.gui2.dialogs.tag_categories_ui import Ui_TagCategories -from calibre.gui2 import qstring_to_unicode, config -from calibre.gui2 import question_dialog, error_dialog -from calibre.gui2.dialogs.confirm_delete import confirm -from calibre.constants import islinux - -class Item: - def __init__(self, name, label, index, icon, exists): - self.name = name - self.label = label - self.index = index - self.icon = icon - self.exists = exists - def __str__(self): - return 'name=%s, label=%s, index=%s, exists='%(self.name, self.label, self.index, self.exists) - -class TagCategories(QDialog, Ui_TagCategories): - category_labels = ['', 'author', 'series', 'publisher', 'tag'] - - def __init__(self, window, db, index=None): - QDialog.__init__(self, window) - Ui_TagCategories.__init__(self) - self.setupUi(self) - - self.db = db - self.index = index - self.applied_items = [] - - category_icons = [None, QIcon(I('user_profile.svg')), QIcon(I('series.svg')), - QIcon(I('publisher.png')), QIcon(I('tags.svg'))] - category_values = [None, - lambda: [n for (id, n) in self.db.all_authors()], - lambda: [n for (id, n) in self.db.all_series()], - lambda: [n for (id, n) in self.db.all_publishers()], - lambda: self.db.all_tags() - ] - category_names = ['', _('Authors'), _('Series'), _('Publishers'), _('Tags')] - - self.all_items = [] - self.all_items_dict = {} - for idx,label in enumerate(self.category_labels): - if idx == 0: - continue - for n in category_values[idx](): - t = Item(name=n, label=label, index=len(self.all_items),icon=category_icons[idx], exists=True) - self.all_items.append(t) - self.all_items_dict[label+':'+n] = t - - self.categories = dict.copy(config['user_categories']) - if self.categories is None: - self.categories = {} - for cat in self.categories: - for item,l in enumerate(self.categories[cat]): - key = ':'.join([l[1], l[0]]) - t = self.all_items_dict.get(key, None) - if t is None: - t = Item(name=l[0], label=l[1], index=len(self.all_items), - icon=category_icons[self.category_labels.index(l[1])], exists=False) - self.all_items.append(t) - self.all_items_dict[key] = t - l[2] = t.index - - self.all_items_sorted = sorted(self.all_items, cmp=lambda x,y: cmp(x.name.lower(), y.name.lower())) - self.display_filtered_categories(0) - - for v in category_names: - self.category_filter_box.addItem(v) - self.current_cat_name = None - - self.connect(self.apply_button, SIGNAL('clicked()'), self.apply_tags) - self.connect(self.unapply_button, SIGNAL('clicked()'), self.unapply_tags) - self.connect(self.add_category_button, SIGNAL('clicked()'), self.add_category) - self.connect(self.category_box, SIGNAL('currentIndexChanged(int)'), self.select_category) - self.connect(self.category_filter_box, SIGNAL('currentIndexChanged(int)'), self.display_filtered_categories) - self.connect(self.delete_category_button, SIGNAL('clicked()'), self.del_category) - if islinux: - self.available_items_box.itemDoubleClicked.connect(self.apply_tags) - else: - self.connect(self.available_items_box, SIGNAL('itemActivated(QListWidgetItem*)'), self.apply_tags) - self.connect(self.applied_items_box, SIGNAL('itemActivated(QListWidgetItem*)'), self.unapply_tags) - - self.populate_category_list() - return - self.select_category(0) - - def make_list_widget(self, item): - n = item.name if item.exists else item.name + _(' (not on any book)') - w = QListWidgetItem(item.icon, n) - w.setData(Qt.UserRole, item.index) - return w - - def display_filtered_categories(self, idx): - idx = idx if idx is not None else self.category_filter_box.currentIndex() - self.available_items_box.clear() - self.applied_items_box.clear() - for item in self.all_items_sorted: - if idx == 0 or item.label == self.category_labels[idx]: - if item.index not in self.applied_items and item.exists: - self.available_items_box.addItem(self.make_list_widget(item)) - for index in self.applied_items: - self.applied_items_box.addItem(self.make_list_widget(self.all_items[index])) - - def apply_tags(self, node=None): - if self.current_cat_name is None: - return - nodes = self.available_items_box.selectedItems() if node is None else [node] - for node in nodes: - index = self.all_items[node.data(Qt.UserRole).toPyObject()].index - if index not in self.applied_items: - self.applied_items.append(index) - self.applied_items.sort(cmp=lambda x, y:cmp(self.all_items[x].name.lower(), self.all_items[y].name.lower())) - self.display_filtered_categories(None) - - def unapply_tags(self, node=None): - nodes = self.applied_items_box.selectedItems() if node is None else [node] - for node in nodes: - index = self.all_items[node.data(Qt.UserRole).toPyObject()].index - self.applied_items.remove(index) - self.display_filtered_categories(None) - - def add_category(self): - self.save_category() - cat_name = qstring_to_unicode(self.input_box.text()).strip() - if cat_name == '': - return False - if cat_name not in self.categories: - self.category_box.clear() - self.current_cat_name = cat_name - self.categories[cat_name] = [] - self.applied_items = [] - self.populate_category_list() - self.category_box.setCurrentIndex(self.category_box.findText(cat_name)) - else: - self.select_category(self.category_box.findText(cat_name)) - return True - - def del_category(self): - if self.current_cat_name is not None: - if not confirm('

'+_('The current tag category will be ' - 'permanently deleted. Are you sure?') - +'

', 'tag_category_delete', self): - return - del self.categories[self.current_cat_name] - self.current_cat_name = None - self.category_box.removeItem(self.category_box.currentIndex()) - - def select_category(self, idx): - self.save_category() - s = self.category_box.itemText(idx) - if s: - self.current_cat_name = unicode(s) - else: - self.current_cat_name = None - if self.current_cat_name: - self.applied_items = [cat[2] for cat in self.categories.get(self.current_cat_name, [])] - else: - self.applied_items = [] - self.display_filtered_categories(None) - - def accept(self): - self.save_category() - config['user_categories'] = self.categories - QDialog.accept(self) - - def save_category(self): - if self.current_cat_name is not None: - l = [] - for index in self.applied_items: - item = self.all_items[index] - l.append([item.name, item.label, item.index]) - self.categories[self.current_cat_name] = l - - def populate_category_list(self): - for n in sorted(self.categories.keys(), cmp=lambda x,y: cmp(x.lower(), y.lower())): - self.category_box.addItem(n) \ No newline at end of file +__license__ = 'GPL v3' + +__copyright__ = '2008, Kovid Goyal ' + + +from PyQt4.QtCore import SIGNAL, Qt +from PyQt4.QtGui import QDialog, QIcon, QListWidgetItem + +from calibre.gui2.dialogs.tag_categories_ui import Ui_TagCategories +from calibre.gui2 import qstring_to_unicode, config +from calibre.gui2.dialogs.confirm_delete import confirm +from calibre.constants import islinux + +class Item: + def __init__(self, name, label, index, icon, exists): + self.name = name + self.label = label + self.index = index + self.icon = icon + self.exists = exists + def __str__(self): + return 'name=%s, label=%s, index=%s, exists='%(self.name, self.label, self.index, self.exists) + +class TagCategories(QDialog, Ui_TagCategories): + category_labels = ['', 'author', 'series', 'publisher', 'tag'] + + def __init__(self, window, db, index=None): + QDialog.__init__(self, window) + Ui_TagCategories.__init__(self) + self.setupUi(self) + + self.db = db + self.index = index + self.applied_items = [] + + category_icons = [None, QIcon(I('user_profile.svg')), QIcon(I('series.svg')), + QIcon(I('publisher.png')), QIcon(I('tags.svg'))] + category_values = [None, + lambda: [n for (id, n) in self.db.all_authors()], + lambda: [n for (id, n) in self.db.all_series()], + lambda: [n for (id, n) in self.db.all_publishers()], + lambda: self.db.all_tags() + ] + category_names = ['', _('Authors'), _('Series'), _('Publishers'), _('Tags')] + + self.all_items = [] + self.all_items_dict = {} + for idx,label in enumerate(self.category_labels): + if idx == 0: + continue + for n in category_values[idx](): + t = Item(name=n, label=label, index=len(self.all_items),icon=category_icons[idx], exists=True) + self.all_items.append(t) + self.all_items_dict[label+':'+n] = t + + self.categories = dict.copy(config['user_categories']) + if self.categories is None: + self.categories = {} + for cat in self.categories: + for item,l in enumerate(self.categories[cat]): + key = ':'.join([l[1], l[0]]) + t = self.all_items_dict.get(key, None) + if t is None: + t = Item(name=l[0], label=l[1], index=len(self.all_items), + icon=category_icons[self.category_labels.index(l[1])], exists=False) + self.all_items.append(t) + self.all_items_dict[key] = t + l[2] = t.index + + self.all_items_sorted = sorted(self.all_items, cmp=lambda x,y: cmp(x.name.lower(), y.name.lower())) + self.display_filtered_categories(0) + + for v in category_names: + self.category_filter_box.addItem(v) + self.current_cat_name = None + + self.connect(self.apply_button, SIGNAL('clicked()'), self.apply_tags) + self.connect(self.unapply_button, SIGNAL('clicked()'), self.unapply_tags) + self.connect(self.add_category_button, SIGNAL('clicked()'), self.add_category) + self.connect(self.category_box, SIGNAL('currentIndexChanged(int)'), self.select_category) + self.connect(self.category_filter_box, SIGNAL('currentIndexChanged(int)'), self.display_filtered_categories) + self.connect(self.delete_category_button, SIGNAL('clicked()'), self.del_category) + if islinux: + self.available_items_box.itemDoubleClicked.connect(self.apply_tags) + else: + self.connect(self.available_items_box, SIGNAL('itemActivated(QListWidgetItem*)'), self.apply_tags) + self.connect(self.applied_items_box, SIGNAL('itemActivated(QListWidgetItem*)'), self.unapply_tags) + + self.populate_category_list() + return + self.select_category(0) + + def make_list_widget(self, item): + n = item.name if item.exists else item.name + _(' (not on any book)') + w = QListWidgetItem(item.icon, n) + w.setData(Qt.UserRole, item.index) + return w + + def display_filtered_categories(self, idx): + idx = idx if idx is not None else self.category_filter_box.currentIndex() + self.available_items_box.clear() + self.applied_items_box.clear() + for item in self.all_items_sorted: + if idx == 0 or item.label == self.category_labels[idx]: + if item.index not in self.applied_items and item.exists: + self.available_items_box.addItem(self.make_list_widget(item)) + for index in self.applied_items: + self.applied_items_box.addItem(self.make_list_widget(self.all_items[index])) + + def apply_tags(self, node=None): + if self.current_cat_name is None: + return + nodes = self.available_items_box.selectedItems() if node is None else [node] + for node in nodes: + index = self.all_items[node.data(Qt.UserRole).toPyObject()].index + if index not in self.applied_items: + self.applied_items.append(index) + self.applied_items.sort(cmp=lambda x, y:cmp(self.all_items[x].name.lower(), self.all_items[y].name.lower())) + self.display_filtered_categories(None) + + def unapply_tags(self, node=None): + nodes = self.applied_items_box.selectedItems() if node is None else [node] + for node in nodes: + index = self.all_items[node.data(Qt.UserRole).toPyObject()].index + self.applied_items.remove(index) + self.display_filtered_categories(None) + + def add_category(self): + self.save_category() + cat_name = qstring_to_unicode(self.input_box.text()).strip() + if cat_name == '': + return False + if cat_name not in self.categories: + self.category_box.clear() + self.current_cat_name = cat_name + self.categories[cat_name] = [] + self.applied_items = [] + self.populate_category_list() + self.category_box.setCurrentIndex(self.category_box.findText(cat_name)) + else: + self.select_category(self.category_box.findText(cat_name)) + return True + + def del_category(self): + if self.current_cat_name is not None: + if not confirm('

'+_('The current tag category will be ' + 'permanently deleted. Are you sure?') + +'

', 'tag_category_delete', self): + return + del self.categories[self.current_cat_name] + self.current_cat_name = None + self.category_box.removeItem(self.category_box.currentIndex()) + + def select_category(self, idx): + self.save_category() + s = self.category_box.itemText(idx) + if s: + self.current_cat_name = unicode(s) + else: + self.current_cat_name = None + if self.current_cat_name: + self.applied_items = [cat[2] for cat in self.categories.get(self.current_cat_name, [])] + else: + self.applied_items = [] + self.display_filtered_categories(None) + + def accept(self): + self.save_category() + config['user_categories'] = self.categories + QDialog.accept(self) + + def save_category(self): + if self.current_cat_name is not None: + l = [] + for index in self.applied_items: + item = self.all_items[index] + l.append([item.name, item.label, item.index]) + self.categories[self.current_cat_name] = l + + def populate_category_list(self): + for n in sorted(self.categories.keys(), cmp=lambda x,y: cmp(x.lower(), y.lower())): + self.category_box.addItem(n) diff --git a/src/calibre/gui2/library.py b/src/calibre/gui2/library.py index 7cc264344c..f499c95e14 100644 --- a/src/calibre/gui2/library.py +++ b/src/calibre/gui2/library.py @@ -6,16 +6,15 @@ import os, textwrap, traceback, re, shutil, functools from operator import attrgetter from math import cos, sin, pi from contextlib import closing -from datetime import date from PyQt4.QtGui import QTableView, QAbstractItemView, QColor, \ QPainterPath, QLinearGradient, QBrush, \ QPen, QStyle, QPainter, QStyleOptionViewItemV4, \ QIcon, QImage, QMenu, \ QStyledItemDelegate, QCompleter, QIntValidator, \ - QPlainTextEdit, QDoubleValidator, QCheckBox, QMessageBox + QDoubleValidator, QCheckBox from PyQt4.QtCore import QAbstractTableModel, QVariant, Qt, pyqtSignal, \ - SIGNAL, QObject, QSize, QModelIndex, QDate, QRect + SIGNAL, QObject, QSize, QModelIndex, QDate from calibre import strftime from calibre.ebooks.metadata import string_to_authors, fmt_sidx, authors_to_string @@ -25,7 +24,7 @@ from calibre.gui2.dialogs.comments_dialog import CommentsDialog from calibre.gui2.widgets import EnLineEdit, TagsLineEdit from calibre.library.caches import _match, CONTAINS_MATCH, EQUALS_MATCH, REGEXP_MATCH from calibre.ptempfile import PersistentTemporaryFile -from calibre.utils.config import tweaks, prefs +from calibre.utils.config import tweaks from calibre.utils.date import dt_factory, qt_to_dt, isoformat from calibre.utils.pyparsing import ParseException from calibre.utils.search_query_parser import SearchQueryParser @@ -222,10 +221,7 @@ class CcBoolDelegate(QStyledItemDelegate): QStyledItemDelegate.__init__(self, parent) def createEditor(self, parent, option, index): - m = index.model() - col = m.column_map[index.column()] editor = QCheckBox(parent) - val = m.db.data[index.row()][m.db.FIELD_MAP[m.custom_columns[col]['num']]] if tweaks['bool_custom_columns_are_tristate'] == 'no': pass else: diff --git a/src/calibre/gui2/tag_view.py b/src/calibre/gui2/tag_view.py index 7d79fedb72..89e3c37e25 100644 --- a/src/calibre/gui2/tag_view.py +++ b/src/calibre/gui2/tag_view.py @@ -8,7 +8,6 @@ Browsing book collection by tags. ''' from itertools import izip -from copy import copy from PyQt4.Qt import Qt, QTreeView, QApplication, pyqtSignal, \ QFont, SIGNAL, QSize, QIcon, QPoint, \ @@ -435,4 +434,4 @@ class TagsModel(QAbstractItemModel): continue tags_seen.append(tag.name) ans.append('%s%s:"=%s"'%(prefix, category, tag.name)) - return ans \ No newline at end of file + return ans diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index 754bc6d7da..d5f50b92b8 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -62,8 +62,6 @@ from calibre.library.caches import CoverCache from calibre.gui2.dialogs.confirm_delete import confirm from calibre.gui2.dialogs.tag_categories import TagCategories -from datetime import datetime - class SaveMenu(QMenu): def __init__(self, parent): @@ -129,7 +127,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): pixmap_to_data(pixmap)) def __init__(self, listener, opts, actions, parent=None): - self.last_time = datetime.now() + self.last_time = datetime.datetime.now() self.preferences_action, self.quit_action = actions self.spare_servers = [] self.must_restart_before_config = False @@ -2167,7 +2165,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): return for row in rows: path = self.library_view.model().db.abspath(row.row()) - QDesktopServices.openUrl(QUrl('file:'+path)) + QDesktopServices.openUrl(QUrl.fromLocalFile(path)) def view_book(self, triggered): diff --git a/src/calibre/library/caches.py b/src/calibre/library/caches.py index eb456241ce..a31a8a846c 100644 --- a/src/calibre/library/caches.py +++ b/src/calibre/library/caches.py @@ -13,7 +13,7 @@ from datetime import timedelta from PyQt4.QtCore import QThread, QReadWriteLock from PyQt4.QtGui import QImage -from calibre.utils.config import tweaks, prefs +from calibre.utils.config import tweaks from calibre.utils.date import parse_date, now from calibre.utils.search_query_parser import SearchQueryParser from calibre.utils.pyparsing import ParseException @@ -541,4 +541,4 @@ class ResultCache(SearchQueryParser): return [] def set_search_restriction(self, s): - self.search_restriction = '' if not s else 'search:"%s"' % (s.strip()) \ No newline at end of file + self.search_restriction = '' if not s else 'search:"%s"' % (s.strip()) diff --git a/src/calibre/utils/pdftk.py b/src/calibre/utils/pdftk.py index fdc60edb2c..1263b60306 100644 --- a/src/calibre/utils/pdftk.py +++ b/src/calibre/utils/pdftk.py @@ -54,7 +54,7 @@ def set_metadata(stream, mi): while True: try: - ret = p.wait() + p.wait() break except OSError, e: if e.errno == errno.EINTR: