diff --git a/installer/windows/calibre/calibre.mpi b/installer/windows/calibre/calibre.mpi index 6ad18ddaf1..a5fc37d883 100644 --- a/installer/windows/calibre/calibre.mpi +++ b/installer/windows/calibre/calibre.mpi @@ -534,8 +534,6 @@ File ::8B8655B8-3823-AA02-1CDA-02F5AD4677C0 -name fetch-ebook-metadata.exe -pare File ::8FC3D58A-F3FA-A2D1-711F-F4C3128620CE -name podofo.dll -parent 8E5D85A4-7608-47A1-CF7C-309060D5FF40 File ::88034147-A376-B759-D48C-5F17A47E8CC3 -name ebook-meta.exe.local -parent 8E5D85A4-7608-47A1-CF7C-309060D5FF40 File ::6E6F2A97-6614-F2A6-1751-95C099B909FD -name pdfmanipulate.exe.local -parent 8E5D85A4-7608-47A1-CF7C-309060D5FF40 -File ::AC456A9A-6653-5852-D1F7-B04E2C1AA481 -name isbndb.exe -parent 8E5D85A4-7608-47A1-CF7C-309060D5FF40 -File ::94580010-4CE4-8EC0-3834-9A2BCCB28C70 -name isbndb.exe.local -parent 8E5D85A4-7608-47A1-CF7C-309060D5FF40 File ::BA087530-7CF4-5460-C9AA-DE4A796C9AEB -name pdfmanipulate.exe -parent 8E5D85A4-7608-47A1-CF7C-309060D5FF40 File ::6AF80BFC-A813-074D-897A-856744A91949 -name ebook-convert.exe.local -parent 8E5D85A4-7608-47A1-CF7C-309060D5FF40 File ::F8C59A30-9E90-0861-5604-95E7C69C3C80 -name ebook-convert.exe -parent 8E5D85A4-7608-47A1-CF7C-309060D5FF40 diff --git a/src/calibre/constants.py b/src/calibre/constants.py index 319b01f887..75912b276d 100644 --- a/src/calibre/constants.py +++ b/src/calibre/constants.py @@ -2,7 +2,7 @@ __license__ = 'GPL v3' __copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net' __docformat__ = 'restructuredtext en' __appname__ = 'calibre' -__version__ = '0.6.0b3' +__version__ = '0.6.0b5' __author__ = "Kovid Goyal " import re diff --git a/src/calibre/devices/prs505/books.py b/src/calibre/devices/prs505/books.py index 6e268e734a..c10263c6e0 100644 --- a/src/calibre/devices/prs505/books.py +++ b/src/calibre/devices/prs505/books.py @@ -403,8 +403,9 @@ def fix_ids(main, carda, cardb): for child in db.root_element.childNodes: if child.nodeType == child.ELEMENT_NODE and child.hasAttribute('id'): id_map[child.getAttribute('id')] = str(cid) - child.setAttribute("sourceid", - '0' if getattr(child, 'tagName', '').endswith('playlist') else '1') + child.setAttribute('sourceid', '1') + #child.setAttribute("sourceid", + # '0' if getattr(child, 'tagName', '').endswith('playlist') else '1') child.setAttribute('id', str(cid)) cid += 1 diff --git a/src/calibre/ebooks/__init__.py b/src/calibre/ebooks/__init__.py index d2d6fc94e1..a084cdd0f8 100644 --- a/src/calibre/ebooks/__init__.py +++ b/src/calibre/ebooks/__init__.py @@ -25,7 +25,7 @@ class DRMError(ValueError): BOOK_EXTENSIONS = ['lrf', 'rar', 'zip', 'rtf', 'lit', 'txt', 'htm', 'xhtm', 'html', 'xhtml', 'pdf', 'pdb', 'prc', 'mobi', 'azw', 'doc', 'epub', 'fb2', 'djvu', 'lrx', 'cbr', 'cbz', 'oebzip', - 'rb', 'imp', 'odt'] + 'rb', 'imp', 'odt', 'chm'] class HTMLRenderer(object): diff --git a/src/calibre/ebooks/metadata/__init__.py b/src/calibre/ebooks/metadata/__init__.py index 4c2c6c744a..81275b4ff6 100644 --- a/src/calibre/ebooks/metadata/__init__.py +++ b/src/calibre/ebooks/metadata/__init__.py @@ -63,14 +63,13 @@ def roman(num): def fmt_sidx(i, fmt='%.2f', use_roman=False): if i is None or i == '': i = 1 - i = float(i) + try: + i = float(i) + except TypeError: + return str(i) if int(i) == float(i): return roman(int(i)) if use_roman else '%d'%int(i) - try: - return fmt%i - except TypeError: - return fmt%float(i) - + return fmt%i class Resource(object): ''' diff --git a/src/calibre/ebooks/mobi/writer.py b/src/calibre/ebooks/mobi/writer.py index d3b494af1d..8e9fc25ebf 100644 --- a/src/calibre/ebooks/mobi/writer.py +++ b/src/calibre/ebooks/mobi/writer.py @@ -491,12 +491,12 @@ class MobiWriter(object): else : tbsType = 6 - tbSequence = decint(tbsType, DECINT_BACKWARD) - tbSequence += decint(0x00, DECINT_BACKWARD) + tbSequence = decint(tbsType, DECINT_FORWARD) + tbSequence += decint(0x00, DECINT_FORWARD) # Don't write a nodecount for opening type 2 record if tbsType != 2 : tbSequence += chr(self._HTMLRecords[nrecords].currentSectionNodeCount) - tbSequence += decint(len(tbSequence) + 1, DECINT_BACKWARD) + tbSequence += decint(len(tbSequence) + 1, DECINT_FORWARD) else : # Determine tbsType for HTMLRecords > 0 @@ -520,12 +520,12 @@ class MobiWriter(object): shiftedNCXEntry |= tbsType # Assemble the TBS - tbSequence = decint(shiftedNCXEntry, DECINT_BACKWARD) - tbSequence += decint(0x00, DECINT_BACKWARD) + tbSequence = decint(shiftedNCXEntry, DECINT_FORWARD) + tbSequence += decint(0x00, DECINT_FORWARD) # Don't write a nodecount for terminating type 2 record if tbsType != 2 : tbSequence += chr(self._HTMLRecords[nrecords].currentSectionNodeCount) - tbSequence += decint(len(tbSequence) + 1, DECINT_BACKWARD) + tbSequence += decint(len(tbSequence) + 1, DECINT_FORWARD) # print "record %d: tbsType %d" % (nrecords, tbsType) self._tbSequence = tbSequence diff --git a/src/calibre/ebooks/oeb/base.py b/src/calibre/ebooks/oeb/base.py index e2a4875399..3e16e73ab9 100644 --- a/src/calibre/ebooks/oeb/base.py +++ b/src/calibre/ebooks/oeb/base.py @@ -810,6 +810,12 @@ class Manifest(object): r = [x for x in data.iterdescendants(etree.Element) if 'microsoft-com' in x.tag] for x in r: x.tag = XHTML('span') + + # Remove lang redefinition inserted by the amazing Microsoft Word! + body = xpath(data, '/h:html/h:body')[0] + for key in list(body.attrib.keys()): + if key == 'lang' or key.endswith('}lang'): + body.attrib.pop(key) return data def _parse_css(self, data): @@ -1327,7 +1333,9 @@ class TOC(object): return len(list(self.iter())) - 1 def next_play_order(self): - return max([x.play_order for x in self.iter()])+1 + entries = [x.play_order for x in self.iter()] + base = max(entries) if entries else 0 + return base+1 def has_href(self, href): for x in self.iter(): diff --git a/src/calibre/gui2/dialogs/config.py b/src/calibre/gui2/dialogs/config.py index 59e148046d..70237548d5 100644 --- a/src/calibre/gui2/dialogs/config.py +++ b/src/calibre/gui2/dialogs/config.py @@ -112,19 +112,19 @@ class PluginModel(QAbstractItemModel): return QModelIndex() if parent.isValid(): - return self.createIndex(row, column, parent.row()) + return self.createIndex(row, column, 1+parent.row()) else: - return self.createIndex(row, column, -1) + return self.createIndex(row, column, 0) def parent(self, index): - if not index.isValid() or index.internalId() == -1: + if not index.isValid() or index.internalId() == 0: return QModelIndex() - return self.createIndex(index.internalId(), 0, -1) + return self.createIndex(index.internalId()-1, 0, 0) def rowCount(self, parent): if not parent.isValid(): return len(self.categories) - if parent.internalId() == -1: + if parent.internalId() == 0: category = self.categories[parent.row()] return len(self._data[category]) return 0 diff --git a/src/calibre/gui2/dialogs/scheduler.py b/src/calibre/gui2/dialogs/scheduler.py index 47f5a63db0..3b45e9a759 100644 --- a/src/calibre/gui2/dialogs/scheduler.py +++ b/src/calibre/gui2/dialogs/scheduler.py @@ -182,12 +182,12 @@ class RecipeModel(QAbstractItemModel, SearchQueryParser): self.reset() def index(self, row, column, parent): - return self.createIndex(row, column, parent.row() if parent.isValid() else -1) + return self.createIndex(row, column, parent.row()+1 if parent.isValid() else 0) def parent(self, index): - if index.internalId() == -1: + if index.internalId() == 0: return QModelIndex() - return self.createIndex(index.internalId(), 0, -1) + return self.createIndex(index.internalId()-1, 0, 0) def columnCount(self, parent): if not parent.isValid() or not parent.parent().isValid(): diff --git a/src/calibre/gui2/library.py b/src/calibre/gui2/library.py index 21583e8f98..e27ccba82f 100644 --- a/src/calibre/gui2/library.py +++ b/src/calibre/gui2/library.py @@ -726,7 +726,7 @@ class BooksView(TableView): paths = self.paths_from_event(event) event.setDropAction(Qt.CopyAction) event.accept() - self.emit(SIGNAL('files_dropped(PyQt_PyObject)'), paths, Qt.QueuedConnection) + self.emit(SIGNAL('files_dropped(PyQt_PyObject)'), paths) def set_database(self, db): diff --git a/src/calibre/gui2/main.ui b/src/calibre/gui2/main.ui index 5d564b5f0c..9ad7dbcc49 100644 --- a/src/calibre/gui2/main.ui +++ b/src/calibre/gui2/main.ui @@ -696,7 +696,7 @@ TagsView QTreeView -
tags.h
+
calibre/gui2/tag_view.h
diff --git a/src/calibre/gui2/tag_view.py b/src/calibre/gui2/tag_view.py new file mode 100644 index 0000000000..7d9f435fa9 --- /dev/null +++ b/src/calibre/gui2/tag_view.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python +__license__ = 'GPL v3' +__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net' +__docformat__ = 'restructuredtext en' + +''' +Browsing book collection by tags. +''' +from PyQt4.Qt import QStandardItemModel, Qt, QTreeView, QStandardItem, \ + QFont, SIGNAL, QSize, QIcon, QPoint, QPixmap +from calibre.gui2 import config + +class TagsView(QTreeView): + + def __init__(self, *args): + QTreeView.__init__(self, *args) + self.setUniformRowHeights(True) + self.setCursor(Qt.PointingHandCursor) + self.setIconSize(QSize(30, 30)) + + def set_database(self, db, match_all, popularity): + self._model = TagsModel(db) + self.popularity = popularity + self.match_all = match_all + self.setModel(self._model) + self.connect(self, SIGNAL('clicked(QModelIndex)'), self.toggle) + self.popularity.setChecked(config['sort_by_popularity']) + self.connect(self.popularity, SIGNAL('stateChanged(int)'), self.sort_changed) + + def sort_changed(self, state): + config.set('sort_by_popularity', state == Qt.Checked) + self.model().refresh() + + def toggle(self, index): + if self._model.toggle(index): + self.emit(SIGNAL('tags_marked(PyQt_PyObject, PyQt_PyObject)'), + self._model.tokens(), self.match_all.isChecked()) + + def recount(self, *args): + ci = self.currentIndex() + if not ci.isValid(): + ci = self.indexAt(QPoint(10, 10)) + self.model().refresh() + if ci.isValid(): + self.scrollTo(ci, QTreeView.PositionAtTop) + +class CategoryItem(QStandardItem): + + def __init__(self, category, display_text, tags, icon, font, icon_map): + self.category = category + self.tags = tags + QStandardItem.__init__(self, icon, display_text) + self.setFont(font) + self.setSelectable(False) + self.setSizeHint(QSize(100, 40)) + self.setEditable(False) + for tag in tags: + self.appendRow(TagItem(tag, icon_map)) + +class TagItem(QStandardItem): + + def __init__(self, tag, icon_map): + self.icon_map = icon_map + self.tag = tag + QStandardItem.__init__(self, tag.as_string()) + self.set_icon() + self.setEditable(False) + self.setSelectable(False) + + def toggle(self): + self.tag.state = (self.tag.state + 1)%3 + self.set_icon() + + def set_icon(self): + self.setIcon(self.icon_map[self.tag.state]) + + +class TagsModel(QStandardItemModel): + + categories = [_('Authors'), _('Series'), _('Formats'), _('Publishers'), _('News'), _('Tags')] + row_map = ['author', 'series', 'format', 'publisher', 'news', 'tag'] + + def __init__(self, db): + self.cmap = tuple(map(QIcon, [':/images/user_profile.svg', + ':/images/series.svg', ':/images/book.svg', ':/images/publisher.png', + ':/images/news.svg', ':/images/tags.svg'])) + p = QPixmap(30, 30) + p.fill(Qt.transparent) + self.icon_map = [QIcon(p), QIcon(':/images/plus.svg'), + QIcon(':/images/minus.svg')] + QStandardItemModel.__init__(self) + self.db = db + self.ignore_next_search = False + self._data = {} + self.bold_font = QFont() + self.bold_font.setBold(True) + self.refresh() + self.db.add_listener(self.database_changed) + + def database_changed(self, event, ids): + self.refresh() + + def refresh(self): + old_data = self._data + self._data = self.db.get_categories(config['sort_by_popularity']) + for key in old_data.keys(): + for tag in old_data[key]: + try: + index = self._data[key].index(tag) + if index > -1: + self._data[key][index].state = tag.state + except: + continue + self.clear() + root = self.invisibleRootItem() + for r, category in enumerate(self.row_map): + tags = self._data.get(category, []) + root.appendRow(CategoryItem(category, self.categories[r], + self._data[category], self.cmap[r], self.bold_font, self.icon_map)) + #self.reset() + + + def reinit(self, *args, **kwargs): + if not self.ignore_next_search: + for category in self._data.values(): + for tag in category: + tag.state = 0 + self.reset() + self.ignore_next_search = False + + def toggle(self, index): + if index.parent().isValid(): + category = self.row_map[index.parent().row()] + tag = self._data[category][index.row()] + self.invisibleRootItem().child(index.parent().row()).child(index.row()).toggle() + self.ignore_next_search = True + self.emit(SIGNAL('dataChanged(QModelIndex,QModelIndex)'), index, index) + return True + return False + + def tokens(self): + ans = [] + for key in self.row_map: + for tag in self._data[key]: + category = key if key != 'news' else 'tag' + if tag.state > 0: + prefix = ' not ' if tag.state == 2 else '' + ans.append('%s%s:"%s"'%(prefix, category, tag)) + return ans + + diff --git a/src/calibre/gui2/tags.py b/src/calibre/gui2/tags.py deleted file mode 100644 index a6772a3b44..0000000000 --- a/src/calibre/gui2/tags.py +++ /dev/null @@ -1,173 +0,0 @@ -#!/usr/bin/env python -__license__ = 'GPL v3' -__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net' -__docformat__ = 'restructuredtext en' - -''' -Browsing book collection by tags. -''' -from PyQt4.Qt import QAbstractItemModel, Qt, QVariant, QTreeView, QModelIndex, \ - QFont, SIGNAL, QSize, QColor, QIcon, QPoint -from calibre.gui2 import config -NONE = QVariant() - -class TagsView(QTreeView): - - def __init__(self, *args): - QTreeView.__init__(self, *args) - self.setUniformRowHeights(True) - self.setCursor(Qt.PointingHandCursor) - self.setIconSize(QSize(30, 30)) - - def set_database(self, db, match_all, popularity): - self._model = TagsModel(db) - self.popularity = popularity - self.match_all = match_all - self.setModel(self._model) - self.connect(self, SIGNAL('clicked(QModelIndex)'), self.toggle) - self.popularity.setChecked(config['sort_by_popularity']) - self.connect(self.popularity, SIGNAL('stateChanged(int)'), self.sort_changed) - - def sort_changed(self, state): - config.set('sort_by_popularity', state == Qt.Checked) - self.model().refresh() - - def toggle(self, index): - if self._model.toggle(index): - self.emit(SIGNAL('tags_marked(PyQt_PyObject, PyQt_PyObject)'), - self._model.tokens(), self.match_all.isChecked()) - - def recount(self, *args): - ci = self.currentIndex() - if not ci.isValid(): - ci = self.indexAt(QPoint(10, 10)) - self.model().refresh() - if ci.isValid(): - self.scrollTo(ci, QTreeView.PositionAtTop) - -class TagsModel(QAbstractItemModel): - - categories = [_('Authors'), _('Series'), _('Formats'), _('Publishers'), _('News'), _('Tags')] - row_map = {0: 'author', 1:'series', 2:'format', 3:'publisher', 4:'news', 5:'tag'} - - def __init__(self, db): - QAbstractItemModel.__init__(self) - self.db = db - self.ignore_next_search = False - self._data = {} - self.refresh() - self.bold_font = QFont() - self.bold_font.setBold(True) - self.bold_font = QVariant(self.bold_font) - self.status_map = [QColor(200,200,200, 0), QIcon(':/images/plus.svg'), QIcon(':/images/minus.svg')] - self.status_map = list(map(QVariant, self.status_map)) - self.cmap = [QIcon(':/images/user_profile.svg'), QIcon(':/images/series.svg'), QIcon(':/images/book.svg'), QIcon(':/images/publisher.png'), QIcon(':/images/news.svg'), QIcon(':/images/tags.svg')] - self.cmap = list(map(QVariant, self.cmap)) - self.db.add_listener(self.database_changed) - - def database_changed(self, event, ids): - self.refresh() - - def refresh(self): - old_data = self._data - self._data = self.db.get_categories(config['sort_by_popularity']) - for key in old_data.keys(): - for tag in old_data[key]: - try: - index = self._data[key].index(tag) - if index > -1: - self._data[key][index].state = tag.state - except: - continue - self.reset() - - def reinit(self, *args, **kwargs): - if not self.ignore_next_search: - for category in self._data.values(): - for tag in category: - tag.state = 0 - self.reset() - self.ignore_next_search = False - - def toggle(self, index): - if index.parent().isValid(): - category = self.row_map[index.parent().row()] - tag = self._data[category][index.row()] - tag.state = (tag.state + 1)%3 - self.ignore_next_search = True - self.emit(SIGNAL('dataChanged(QModelIndex,QModelIndex)'), index, index) - return True - return False - - def tokens(self): - ans = [] - for key in self.row_map.values(): - for tag in self._data[key]: - category = key if key != 'news' else 'tag' - if tag.state > 0: - prefix = ' not ' if tag.state == 2 else '' - ans.append('%s%s:"%s"'%(prefix, category, tag)) - return ans - - def index(self, row, col, parent=QModelIndex()): - if parent.isValid(): - if parent.parent().isValid(): # parent is a tag - return QModelIndex() - try: - category = self.row_map[parent.row()] - except KeyError: - return QModelIndex() - if col == 0 and row < len(self._data[category]): - return self.createIndex(row, col, parent.row()) - return QModelIndex() - if col == 0 and row < len(self.categories): - return self.createIndex(row, col, -1) - return QModelIndex() - - def parent(self, index): - if not index.isValid() or index.internalId() < 0: - return QModelIndex() - return self.createIndex(index.internalId(), 0, -1) - - def rowCount(self, parent): - if not parent or not parent.isValid(): - return len(self.categories) - if not parent.parent().isValid(): - return len(self._data[self.row_map[parent.row()]]) - return 0 - - def columnCount(self, parent): - return 1 - - def flags(self, index): - if not index.isValid(): - return Qt.NoItemFlags - return Qt.ItemIsEnabled - - def category_data(self, index, role): - if role == Qt.DisplayRole: - row = index.row() - return QVariant(self.categories[row]) - if role == Qt.FontRole: - return self.bold_font - if role == Qt.SizeHintRole: - return QVariant(QSize(100, 40)) - if role == Qt.DecorationRole: - return self.cmap[index.row()] - return NONE - - def tag_data(self, index, role): - category = self.row_map[index.parent().row()] - if role == Qt.DisplayRole: - return QVariant(self._data[category][index.row()].as_string()) - if role == Qt.DecorationRole: - return self.status_map[self._data[category][index.row()].state] - return NONE - - - def data(self, index, role): - if not index.parent().isValid(): - return self.category_data(index, role) - if not index.parent().parent().isValid(): - return self.tag_data(index, role) - return NONE diff --git a/src/calibre/linux.py b/src/calibre/linux.py index d9f6b0777e..11884a2e4e 100644 --- a/src/calibre/linux.py +++ b/src/calibre/linux.py @@ -334,7 +334,7 @@ def post_install(): os.chdir(config_dir) for f in os.listdir('.'): if os.stat(f).st_uid == 0: - os.rmdir(f) + os.rmdir(f) if os.path.isdir(f) else os.unlink(f) if os.stat(config_dir).st_uid == 0: os.rmdir(config_dir)