Merge from custcol trunk

This commit is contained in:
Charles Haley 2010-05-05 21:50:17 +01:00
commit 301b78564d
4 changed files with 160 additions and 55 deletions

View File

@ -6,6 +6,7 @@ __copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import sys import sys
from functools import partial
from PyQt4.Qt import QComboBox, QLabel, QSpinBox, QDoubleSpinBox, QDateEdit, \ from PyQt4.Qt import QComboBox, QLabel, QSpinBox, QDoubleSpinBox, QDateEdit, \
QDate, QGroupBox, QVBoxLayout, QPlainTextEdit, QSizePolicy, \ QDate, QGroupBox, QVBoxLayout, QPlainTextEdit, QSizePolicy, \
@ -18,10 +19,11 @@ from calibre.utils.config import tweaks
class Base(object): class Base(object):
def __init__(self, db, col_id): def __init__(self, db, col_id, parent=None):
self.db, self.col_id = db, col_id self.db, self.col_id = db, col_id
self.col_metadata = db.custom_column_num_map[col_id] self.col_metadata = db.custom_column_num_map[col_id]
self.initial_val = None self.initial_val = None
self.setup_ui(parent)
def initialize(self, book_id): def initialize(self, book_id):
val = self.db.get_custom(book_id, num=self.col_id, index_is_id=True) val = self.db.get_custom(book_id, num=self.col_id, index_is_id=True)
@ -43,8 +45,7 @@ class Base(object):
class Bool(Base): class Bool(Base):
def __init__(self, db, col_id, parent=None): def setup_ui(self, parent):
Base.__init__(self, db, col_id)
self.widgets = [QLabel('&'+self.col_metadata['name'], parent), self.widgets = [QLabel('&'+self.col_metadata['name'], parent),
QComboBox(parent)] QComboBox(parent)]
w = self.widgets[1] w = self.widgets[1]
@ -69,8 +70,7 @@ class Bool(Base):
class Int(Base): class Int(Base):
def __init__(self, db, col_id, parent=None): def setup_ui(self, parent):
Base.__init__(self, db, col_id)
self.widgets = [QLabel('&'+self.col_metadata['name']+':', parent), self.widgets = [QLabel('&'+self.col_metadata['name']+':', parent),
QSpinBox(parent)] QSpinBox(parent)]
w = self.widgets[1] w = self.widgets[1]
@ -93,8 +93,7 @@ class Int(Base):
class Float(Int): class Float(Int):
def __init__(self, db, col_id, parent=None): def setup_ui(self, parent):
Base.__init__(self, db, col_id)
self.widgets = [QLabel('&'+self.col_metadata['name']+':', parent), self.widgets = [QLabel('&'+self.col_metadata['name']+':', parent),
QDoubleSpinBox(parent)] QDoubleSpinBox(parent)]
w = self.widgets[1] w = self.widgets[1]
@ -103,8 +102,8 @@ class Float(Int):
class Rating(Int): class Rating(Int):
def __init__(self, db, col_id, parent=None): def setup_ui(self, parent):
Int.__init__(self, db, col_id) Int.setup_ui(self, parent)
w = self.widgets[1] w = self.widgets[1]
w.setRange(0, 5) w.setRange(0, 5)
w.setSuffix(' '+_('stars')) w.setSuffix(' '+_('stars'))
@ -125,8 +124,7 @@ class Rating(Int):
class DateTime(Base): class DateTime(Base):
def __init__(self, db, col_id, parent=None): def setup_ui(self, parent):
Base.__init__(self, db, col_id)
self.widgets = [QLabel('&'+self.col_metadata['name']+':', parent), self.widgets = [QLabel('&'+self.col_metadata['name']+':', parent),
QDateEdit(parent)] QDateEdit(parent)]
w = self.widgets[1] w = self.widgets[1]
@ -153,8 +151,7 @@ class DateTime(Base):
class Comments(Base): class Comments(Base):
def __init__(self, db, col_id, parent=None): def setup_ui(self, parent):
Base.__init__(self, db, col_id)
self._box = QGroupBox(parent) self._box = QGroupBox(parent)
self._box.setTitle('&'+self.col_metadata['name']) self._box.setTitle('&'+self.col_metadata['name'])
self._layout = QVBoxLayout() self._layout = QVBoxLayout()
@ -178,9 +175,8 @@ class Comments(Base):
class Text(Base): class Text(Base):
def __init__(self, db, col_id, parent=None): def setup_ui(self, parent):
Base.__init__(self, db, col_id) values = self.all_values = list(self.db.all_custom(num=self.col_id))
values = self.all_values = list(self.db.all_custom(num=col_id))
values.sort(cmp = lambda x,y: cmp(x.lower(), y.lower())) values.sort(cmp = lambda x,y: cmp(x.lower(), y.lower()))
if self.col_metadata['is_multiple']: if self.col_metadata['is_multiple']:
w = TagsLineEdit(parent, values) w = TagsLineEdit(parent, values)
@ -238,16 +234,16 @@ widgets = {
'comments': Comments, 'comments': Comments,
} }
def populate_single_metadata_page(left, right, db, book_id, parent=None): def field_sort(y, z, x=None):
x = db.custom_column_num_map
cols = list(x)
def field_sort(y, z):
m1, m2 = x[y], x[z] m1, m2 = x[y], x[z]
n1 = 'zzzzz' if m1['datatype'] == 'comments' else m1['name'] n1 = 'zzzzz' if m1['datatype'] == 'comments' else m1['name']
n2 = 'zzzzz' if m2['datatype'] == 'comments' else m2['name'] n2 = 'zzzzz' if m2['datatype'] == 'comments' else m2['name']
return cmp(n1.lower(), n2.lower()) return cmp(n1.lower(), n2.lower())
cols.sort(cmp=field_sort) def populate_single_metadata_page(left, right, db, book_id, parent=None):
x = db.custom_column_num_map
cols = list(x)
cols.sort(cmp=partial(field_sort, x=x))
ans = [] ans = []
for i, col in enumerate(cols): for i, col in enumerate(cols):
w = widgets[x[col]['datatype']](db, col, parent) w = widgets[x[col]['datatype']](db, col, parent)
@ -275,6 +271,107 @@ def populate_single_metadata_page(left, right, db, book_id, parent=None):
return ans, items return ans, items
def populate_bulk_metadata_page(left, right, db, book_id, parent=None): class BulkBase(Base):
def get_initial_value(self, book_ids):
values = set([])
for book_id in book_ids:
val = self.db.get_custom(book_id, num=self.col_id, index_is_id=True)
if isinstance(val, list):
val = frozenset(val)
values.add(val)
if len(values) > 1:
break
ans = None
if len(values) == 1:
ans = iter(values).next()
if isinstance(ans, frozenset):
ans = list(ans)
return ans
def initialize(self, book_ids):
self.initial_val = val = self.get_initial_value(book_ids)
val = self.normalize_db_val(val)
self.setter(val)
def commit(self, book_ids, notify=False):
val = self.getter()
val = self.normalize_ui_val(val)
if val != self.initial_val:
for book_id in book_ids:
self.db.set_custom(book_id, val, num=self.col_id, notify=notify)
class BulkBool(BulkBase, Bool):
pass pass
class BulkRating(BulkBase, Rating):
pass
class BulkInt(BulkBase, Int):
pass
class BulkFloat(BulkBase, Float):
pass
class BulkRating(BulkBase, Rating):
pass
class BulkDateTime(BulkBase, DateTime):
pass
class BulkText(BulkBase, Text):
def initialize(self, book_ids):
val = self.get_initial_value(book_ids)
self.initial_val = val = self.normalize_db_val(val)
if self.col_metadata['is_multiple']:
self.setter(val)
self.widgets[1].update_tags_cache(self.all_values)
else:
idx = None
for i, c in enumerate(self.all_values):
if c == val:
idx = i
self.widgets[1].addItem(c)
self.widgets[1].setEditText('')
if idx is not None:
self.widgets[1].setCurrentIndex(idx)
bulk_widgets = {
'bool' : BulkBool,
'rating' : BulkRating,
'int': BulkInt,
'float': BulkFloat,
'datetime': BulkDateTime,
'text' : BulkText,
}
def populate_bulk_metadata_page(layout, db, book_ids, parent=None):
x = db.custom_column_num_map
cols = list(x)
cols.sort(cmp=partial(field_sort, x=x))
ans = []
for i, col in enumerate(cols):
dt = x[col]['datatype']
if dt == 'comments':
continue
w = bulk_widgets[dt](db, col, parent)
ans.append(w)
w.initialize(book_ids)
row = layout.rowCount()
if len(w.widgets) == 1:
layout.addWidget(w.widgets[0], row, 0, 1, -1)
else:
w.widgets[0].setBuddy(w.widgets[1])
for c, widget in enumerate(w.widgets):
layout.addWidget(widget, row, c)
items = []
if len(ans) > 0:
items.append(QSpacerItem(10, 10, QSizePolicy.Minimum,
QSizePolicy.Expanding))
layout.addItem(items[-1], layout.rowCount(), 0, 1, 1)
layout.setRowStretch(layout.rowCount()-1, 100)
return ans, items

View File

@ -4,7 +4,7 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
'''Dialog to edit metadata in bulk''' '''Dialog to edit metadata in bulk'''
from PyQt4.QtCore import SIGNAL, QObject from PyQt4.QtCore import SIGNAL, QObject
from PyQt4.QtGui import QDialog from PyQt4.QtGui import QDialog, QGridLayout
from calibre.gui2.dialogs.metadata_bulk_ui import Ui_MetadataBulkDialog from calibre.gui2.dialogs.metadata_bulk_ui import Ui_MetadataBulkDialog
from calibre.gui2.dialogs.tag_editor import TagEditor from calibre.gui2.dialogs.tag_editor import TagEditor
@ -48,7 +48,16 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
self.exec_() self.exec_()
def create_custom_column_editors(self): def create_custom_column_editors(self):
pass w = self.central_widget.widget(1)
layout = QGridLayout()
self.custom_column_widgets, self.__cc_spacers = populate_bulk_metadata_page(
layout, self.db, self.ids, w)
w.setLayout(layout)
self.__custom_col_layouts = [layout]
ans = self.custom_column_widgets
for i in range(len(ans)-1):
w.setTabOrder(ans[i].widgets[-1], ans[i+1].widgets[-1])
def initialize_combos(self): def initialize_combos(self):
self.initalize_authors() self.initalize_authors()
@ -143,6 +152,9 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
self.db.set_authors(id, new_authors, notify=False) self.db.set_authors(id, new_authors, notify=False)
self.changed = True self.changed = True
for w in getattr(self, 'custom_column_widgets', []):
w.commit(self.ids)
def series_changed(self): def series_changed(self):
self.write_series = True self.write_series = True

View File

@ -258,9 +258,9 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
self.device_info = ' ' self.device_info = ' '
if not opts.no_update_check: if not opts.no_update_check:
self.update_checker = CheckForUpdates(self) self.update_checker = CheckForUpdates(self)
QObject.connect(self.update_checker, self.update_checker.update_found.connect(self.update_found,
SIGNAL('update_found(PyQt_PyObject)'), self.update_found) type=Qt.QueuedConnection)
self.update_checker.start(2000) self.update_checker.start()
####################### Status Bar ##################### ####################### Status Bar #####################
self.status_bar.initialize(self.system_tray_icon) self.status_bar.initialize(self.system_tray_icon)
self.status_bar.show_book_info.connect(self.show_book_info) self.status_bar.show_book_info.connect(self.show_book_info)
@ -2493,7 +2493,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
if write_settings: if write_settings:
self.write_settings() self.write_settings()
self.check_messages_timer.stop() self.check_messages_timer.stop()
self.update_checker.stop() self.update_checker.terminate()
self.listener.close() self.listener.close()
self.job_manager.server.close() self.job_manager.server.close()
while self.spare_servers: while self.spare_servers:

View File

@ -3,7 +3,7 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
import traceback import traceback
from PyQt4.QtCore import QObject, SIGNAL, QTimer from PyQt4.QtCore import QThread, pyqtSignal
import mechanize import mechanize
from calibre.constants import __version__, iswindows, isosx from calibre.constants import __version__, iswindows, isosx
@ -12,21 +12,16 @@ from calibre.utils.config import prefs
URL = 'http://status.calibre-ebook.com/latest' URL = 'http://status.calibre-ebook.com/latest'
class CheckForUpdates(QObject): class CheckForUpdates(QThread):
update_found = pyqtSignal(object)
INTERVAL = 24*60*60
def __init__(self, parent): def __init__(self, parent):
QObject.__init__(self, parent) QThread.__init__(self, parent)
self.timer = QTimer(self)
self.first = True
self.connect(self.timer, SIGNAL('timeout()'), self)
self.start = self.timer.start
self.stop = self.timer.stop
def __call__(self):
if self.first:
self.timer.setInterval(1000*24*60*60)
self.first = False
def run(self):
while True:
try: try:
br = browser() br = browser()
req = mechanize.Request(URL) req = mechanize.Request(URL)
@ -36,7 +31,8 @@ class CheckForUpdates(QObject):
req.add_header('CALIBRE_INSTALL_UUID', prefs['installation_uuid']) req.add_header('CALIBRE_INSTALL_UUID', prefs['installation_uuid'])
version = br.open(req).read().strip() version = br.open(req).read().strip()
if version and version != __version__: if version and version != __version__:
self.emit(SIGNAL('update_found(PyQt_PyObject)'), version) self.update_found.emit(version)
except: except:
traceback.print_exc() traceback.print_exc()
self.sleep(self.INTERVAL)