diff --git a/resources/default_tweaks.py b/resources/default_tweaks.py index 07aee5c6fa..e03b0680be 100644 --- a/resources/default_tweaks.py +++ b/resources/default_tweaks.py @@ -44,7 +44,7 @@ bool_custom_columns_are_tristate = 'yes' # title within authors. sort_columns_at_startup = None -# Format to be used for publication date +# Format to be used for publication date and the timestamp (date). # A string controlling how the publication date is displayed in the GUI # d the day as number without a leading zero (1 to 31) # dd the day as number with a leading zero (01 to 31) @@ -59,8 +59,10 @@ sort_columns_at_startup = None # For example, given the date of 9 Jan 2010, the following formats show # MMM yyyy ==> Jan 2010 yyyy ==> 2010 dd MMM yyyy ==> 09 Jan 2010 # MM/yyyy ==> 01/2010 d/M/yy ==> 9/1/10 yy ==> 10 -# default if not set: MMM yyyy +# publication default if not set: MMM yyyy +# timestamp default if not set: dd MMM yyyy gui_pubdate_display_format = 'MMM yyyy' +gui_timestamp_display_format = 'dd MMM yyyy' # Control title and series sorting in the library view. # If set to 'library_order', Leading articles such as The and A will be ignored. diff --git a/src/calibre/devices/prs505/sony_cache.py b/src/calibre/devices/prs505/sony_cache.py index 5f3e9118dc..b5a8f08541 100644 --- a/src/calibre/devices/prs505/sony_cache.py +++ b/src/calibre/devices/prs505/sony_cache.py @@ -354,19 +354,22 @@ class XMLCache(object): root = self.record_roots[i] lpath_map = self.build_lpath_map(root) gtz_count = ltz_count = 0 + use_tz_var = False for book in booklist: path = os.path.join(self.prefixes[i], *(book.lpath.split('/'))) record = lpath_map.get(book.lpath, None) if record is None: record = self.create_text_record(root, i, book.lpath) - (gtz_count, ltz_count) = self.update_text_record(record, book, - path, i, gtz_count, ltz_count) + (gtz_count, ltz_count, use_tz_var) = \ + self.update_text_record(record, book, path, i, + gtz_count, ltz_count, use_tz_var) # Ensure the collections in the XML database are recorded for # this book if book.device_collections is None: book.device_collections = [] book.device_collections = playlist_map.get(book.lpath, []) - debug_print('Timezone votes: %d GMT, %d LTZ'%(gtz_count, ltz_count)) + debug_print('Timezone votes: %d GMT, %d LTZ, use_tz_var='% + (gtz_count, ltz_count, use_tz_var)) self.update_playlists(i, root, booklist, collections_attributes) # Update the device collections because update playlist could have added # some new ones. @@ -464,21 +467,27 @@ class XMLCache(object): root.append(ans) return ans - def update_text_record(self, record, book, path, bl_index, gtz_count, ltz_count): + def update_text_record(self, record, book, path, bl_index, + gtz_count, ltz_count, use_tz_var): ''' Update the Sony database from the book. This is done if the timestamp in the db differs from the timestamp on the file. ''' # It seems that a Sony device can sometimes know what timezone it is in, - # and apparently converts the dates to GMT when it writes them to the - # db. Unfortunately, we can't tell when it does this, so we use a - # horrible heuristic. First, set dates only for new books, trying to - # avoid upsetting the sony. Use the timezone determined through the - # voting described next. Second, voting: if a book is not new, compare - # its Sony DB date against localtime and gmtime. Count the matches. When - # we must set a date, use the one with the most matches. Use localtime - # if the case of a tie, and hope it is right. + # and apparently converts the dates to GMT when it writes them to its + # DB. We can detect that a device is timezone-aware because there is a + # 'tz' variable in the Sony DB, which we can set to "0" to tell the + # device to ignore its own timezone when comparing mtime to the date in + # the DB. + + # Unfortunately, if there is no tz variable in the DB, then we can't + # tell when the device applies a timezone conversion. We use a horrible + # heuristic to work around this problem. First, set dates only for new + # books, trying to avoid upsetting the sony. Second, voting: if a book + # is not new, compare its Sony DB date against localtime and gmtime. + # Count the matches. When we must set a date, use the one with the most + # matches. Use localtime if the case of a tie, and hope it is right. timestamp = os.path.getmtime(path) rec_date = record.get('date', None) @@ -489,20 +498,25 @@ class XMLCache(object): return x if not getattr(book, '_new_book', False): # book is not new - if strftime(timestamp, zone=time.gmtime) == rec_date: - gtz_count += 1 - elif strftime(timestamp, zone=time.localtime) == rec_date: - ltz_count += 1 + if record.get('tz', None) is not None: + use_tz_var = True + if strftime(timestamp, zone=time.gmtime) == rec_date: + gtz_count += 1 + elif strftime(timestamp, zone=time.localtime) == rec_date: + ltz_count += 1 else: # book is new. Set the time using the current votes - if ltz_count >= gtz_count: + if use_tz_var: tz = time.localtime - debug_print("Using localtime TZ for new book", book.lpath) + record.set('tz', '0') + debug_print("Use localtime TZ and tz='0' for new book", book.lpath) + elif ltz_count >= gtz_count: + tz = time.localtime + debug_print("Use localtime TZ for new book", book.lpath) else: tz = time.gmtime - debug_print("Using GMT TZ for new book", book.lpath) + debug_print("Use GMT TZ for new book", book.lpath) date = strftime(timestamp, zone=tz) record.set('date', clean(date)) - record.set('size', clean(str(os.stat(path).st_size))) title = book.title if book.title else _('Unknown') record.set('title', clean(title)) @@ -532,7 +546,7 @@ class XMLCache(object): if 'id' not in record.attrib: num = self.max_id(record.getroottree().getroot()) record.set('id', str(num+1)) - return (gtz_count, ltz_count) + return (gtz_count, ltz_count, use_tz_var) # }}} # Writing the XML files {{{ diff --git a/src/calibre/gui2/custom_column_widgets.py b/src/calibre/gui2/custom_column_widgets.py index f364638f37..0e89358c53 100644 --- a/src/calibre/gui2/custom_column_widgets.py +++ b/src/calibre/gui2/custom_column_widgets.py @@ -550,9 +550,7 @@ class BulkText(BulkBase): remove_all, adding, rtext = self.gui_val remove = set() if remove_all: - for book_id in book_ids: - remove |= set(self.db.get_custom(book_id, num=self.col_id, - index_is_id=True)) + remove = set(self.db.all_custom(num=self.col_id)) else: txt = rtext if txt: diff --git a/src/calibre/gui2/dialogs/metadata_bulk.py b/src/calibre/gui2/dialogs/metadata_bulk.py index fc0a0c5840..de483720fc 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.py +++ b/src/calibre/gui2/dialogs/metadata_bulk.py @@ -199,7 +199,10 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog): for w in getattr(self, 'custom_column_widgets', []): w.gui_val - remove = unicode(self.remove_tags.text()).strip().split(',') + if self.remove_all_tags.isChecked(): + remove = self.db.all_tags() + else: + remove = unicode(self.remove_tags.text()).strip().split(',') add = unicode(self.tags.text()).strip().split(',') au = unicode(self.authors.text()) aus = unicode(self.author_sort.text()) diff --git a/src/calibre/gui2/dialogs/metadata_bulk.ui b/src/calibre/gui2/dialogs/metadata_bulk.ui index 2cdef2b12a..4287ca5c79 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.ui +++ b/src/calibre/gui2/dialogs/metadata_bulk.ui @@ -140,7 +140,7 @@ - + true @@ -191,14 +191,23 @@ - + Comma separated list of tags to remove from the books. - + + + + Remove all + + + Check this box to remove all tags from the books. + + + &Series: diff --git a/src/calibre/gui2/library/delegates.py b/src/calibre/gui2/library/delegates.py index 40f7a2e4e0..d98d9a240b 100644 --- a/src/calibre/gui2/library/delegates.py +++ b/src/calibre/gui2/library/delegates.py @@ -98,14 +98,14 @@ class DateDelegate(QStyledItemDelegate): # {{{ d = val.toDate() if d <= UNDEFINED_QDATE: return '' - return format_date(d.toPyDate(), 'dd MMM yyyy') + format = tweaks['gui_timestamp_display_format'] + if format is None: + format = 'dd MMM yyyy' + return format_date(d.toPyDate(), format) def createEditor(self, parent, option, index): qde = QStyledItemDelegate.createEditor(self, parent, option, index) - stdformat = unicode(qde.displayFormat()) - if 'yyyy' not in stdformat: - stdformat = stdformat.replace('yy', 'yyyy') - qde.setDisplayFormat(stdformat) + qde.setDisplayFormat('dd MMM yyyy') qde.setMinimumDate(UNDEFINED_QDATE) qde.setSpecialValueText(_('Undefined')) qde.setCalendarPopup(True)