mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Merge from trunk
This commit is contained in:
commit
7d4d42ea91
@ -45,7 +45,8 @@ class DailyTelegraph(BasicNewsRecipe):
|
|||||||
.caption{font-family:Trebuchet MS,Trebuchet,Helvetica,sans-serif; font-size: xx-small;}
|
.caption{font-family:Trebuchet MS,Trebuchet,Helvetica,sans-serif; font-size: xx-small;}
|
||||||
'''
|
'''
|
||||||
|
|
||||||
feeds = [ (u'News', u'http://feeds.news.com.au/public/rss/2.0/aus_news_807.xml'),
|
feeds = [
|
||||||
|
(u'News', u'http://feeds.news.com.au/public/rss/2.0/aus_news_807.xml'),
|
||||||
(u'Opinion', u'http://feeds.news.com.au/public/rss/2.0/aus_opinion_58.xml'),
|
(u'Opinion', u'http://feeds.news.com.au/public/rss/2.0/aus_opinion_58.xml'),
|
||||||
(u'The Nation', u'http://feeds.news.com.au/public/rss/2.0/aus_the_nation_62.xml'),
|
(u'The Nation', u'http://feeds.news.com.au/public/rss/2.0/aus_the_nation_62.xml'),
|
||||||
(u'World News', u'http://feeds.news.com.au/public/rss/2.0/aus_world_808.xml'),
|
(u'World News', u'http://feeds.news.com.au/public/rss/2.0/aus_world_808.xml'),
|
||||||
@ -68,7 +69,7 @@ class DailyTelegraph(BasicNewsRecipe):
|
|||||||
br = BasicNewsRecipe.get_browser(self)
|
br = BasicNewsRecipe.get_browser(self)
|
||||||
if self.username and self.password:
|
if self.username and self.password:
|
||||||
br.open('http://www.theaustralian.com.au')
|
br.open('http://www.theaustralian.com.au')
|
||||||
br.select_form(nr=0)
|
br.select_form(nr=1)
|
||||||
br['username'] = self.username
|
br['username'] = self.username
|
||||||
br['password'] = self.password
|
br['password'] = self.password
|
||||||
raw = br.submit().read()
|
raw = br.submit().read()
|
||||||
@ -87,3 +88,4 @@ class DailyTelegraph(BasicNewsRecipe):
|
|||||||
# return br.geturl()
|
# return br.geturl()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1661,6 +1661,7 @@ class StoreWoblinkStore(StoreBase):
|
|||||||
|
|
||||||
headquarters = 'PL'
|
headquarters = 'PL'
|
||||||
formats = ['EPUB', 'MOBI', 'PDF', 'WOBLINK']
|
formats = ['EPUB', 'MOBI', 'PDF', 'WOBLINK']
|
||||||
|
affiliate = True
|
||||||
|
|
||||||
class XinXiiStore(StoreBase):
|
class XinXiiStore(StoreBase):
|
||||||
name = 'XinXii'
|
name = 'XinXii'
|
||||||
|
@ -219,7 +219,7 @@ class ANDROID(USBMS):
|
|||||||
'POCKET', 'ONDA_MID', 'ZENITHIN', 'INGENIC', 'PMID701C', 'PD',
|
'POCKET', 'ONDA_MID', 'ZENITHIN', 'INGENIC', 'PMID701C', 'PD',
|
||||||
'PMP5097C', 'MASS', 'NOVO7', 'ZEKI', 'COBY', 'SXZ', 'USB_2.0',
|
'PMP5097C', 'MASS', 'NOVO7', 'ZEKI', 'COBY', 'SXZ', 'USB_2.0',
|
||||||
'COBY_MID', 'VS', 'AINOL', 'TOPWISE', 'PAD703', 'NEXT8D12',
|
'COBY_MID', 'VS', 'AINOL', 'TOPWISE', 'PAD703', 'NEXT8D12',
|
||||||
'MEDIATEK', 'KEENHI', 'TECLAST', 'SURFTAB']
|
'MEDIATEK', 'KEENHI', 'TECLAST', 'SURFTAB', 'XENTA',]
|
||||||
WINDOWS_MAIN_MEM = ['ANDROID_PHONE', 'A855', 'A853', 'A953', 'INC.NEXUS_ONE',
|
WINDOWS_MAIN_MEM = ['ANDROID_PHONE', 'A855', 'A853', 'A953', 'INC.NEXUS_ONE',
|
||||||
'__UMS_COMPOSITE', '_MB200', 'MASS_STORAGE', '_-_CARD', 'SGH-I897',
|
'__UMS_COMPOSITE', '_MB200', 'MASS_STORAGE', '_-_CARD', 'SGH-I897',
|
||||||
'GT-I9000', 'FILE-STOR_GADGET', 'SGH-T959_CARD', 'SGH-T959', 'SAMSUNG_ANDROID',
|
'GT-I9000', 'FILE-STOR_GADGET', 'SGH-T959_CARD', 'SGH-T959', 'SAMSUNG_ANDROID',
|
||||||
@ -241,6 +241,7 @@ class ANDROID(USBMS):
|
|||||||
'S5830I_CARD', 'MID7042', 'LINK-CREATE', '7035', 'VIEWPAD_7E',
|
'S5830I_CARD', 'MID7042', 'LINK-CREATE', '7035', 'VIEWPAD_7E',
|
||||||
'NOVO7', 'MB526', '_USB#WYK7MSF8KE', 'TABLET_PC', 'F', 'MT65XX_MS',
|
'NOVO7', 'MB526', '_USB#WYK7MSF8KE', 'TABLET_PC', 'F', 'MT65XX_MS',
|
||||||
'ICS', 'E400', '__FILE-STOR_GADG', 'ST80208-1', 'GT-S5660M_CARD', 'XT894', '_USB',
|
'ICS', 'E400', '__FILE-STOR_GADG', 'ST80208-1', 'GT-S5660M_CARD', 'XT894', '_USB',
|
||||||
|
'PROD_TAB13-201',
|
||||||
]
|
]
|
||||||
WINDOWS_CARD_A_MEM = ['ANDROID_PHONE', 'GT-I9000_CARD', 'SGH-I897',
|
WINDOWS_CARD_A_MEM = ['ANDROID_PHONE', 'GT-I9000_CARD', 'SGH-I897',
|
||||||
'FILE-STOR_GADGET', 'SGH-T959_CARD', 'SGH-T959', 'SAMSUNG_ANDROID', 'GT-P1000_CARD',
|
'FILE-STOR_GADGET', 'SGH-T959_CARD', 'SGH-T959', 'SAMSUNG_ANDROID', 'GT-P1000_CARD',
|
||||||
@ -253,7 +254,7 @@ class ANDROID(USBMS):
|
|||||||
'UMS_COMPOSITE', 'PRO', '.KOBO_VOX', 'SGH-T989_CARD', 'SGH-I727',
|
'UMS_COMPOSITE', 'PRO', '.KOBO_VOX', 'SGH-T989_CARD', 'SGH-I727',
|
||||||
'USB_FLASH_DRIVER', 'ANDROID', 'MID7042', '7035', 'VIEWPAD_7E',
|
'USB_FLASH_DRIVER', 'ANDROID', 'MID7042', '7035', 'VIEWPAD_7E',
|
||||||
'NOVO7', 'ADVANCED', 'TABLET_PC', 'F', 'E400_SD_CARD', 'ST80208-1', 'XT894',
|
'NOVO7', 'ADVANCED', 'TABLET_PC', 'F', 'E400_SD_CARD', 'ST80208-1', 'XT894',
|
||||||
'_USB',
|
'_USB', 'PROD_TAB13-201',
|
||||||
]
|
]
|
||||||
|
|
||||||
OSX_MAIN_MEM = 'Android Device Main Memory'
|
OSX_MAIN_MEM = 'Android Device Main Memory'
|
||||||
@ -369,7 +370,6 @@ class WEBOS(USBMS):
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
import Image, ImageDraw
|
import Image, ImageDraw
|
||||||
|
|
||||||
|
|
||||||
coverdata = getattr(metadata, 'thumbnail', None)
|
coverdata = getattr(metadata, 'thumbnail', None)
|
||||||
if coverdata and coverdata[2]:
|
if coverdata and coverdata[2]:
|
||||||
cover = Image.open(cStringIO.StringIO(coverdata[2]))
|
cover = Image.open(cStringIO.StringIO(coverdata[2]))
|
||||||
@ -418,3 +418,4 @@ class WEBOS(USBMS):
|
|||||||
coverfile.write(coverdata)
|
coverfile.write(coverdata)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -560,7 +560,9 @@ class OPF(object): # {{{
|
|||||||
self.package_version = 0
|
self.package_version = 0
|
||||||
self.metadata = self.metadata_path(self.root)
|
self.metadata = self.metadata_path(self.root)
|
||||||
if not self.metadata:
|
if not self.metadata:
|
||||||
raise ValueError('Malformed OPF file: No <metadata> element')
|
self.metadata = [self.root.makeelement('{http://www.idpf.org/2007/opf}metadata')]
|
||||||
|
self.root.insert(0, self.metadata[0])
|
||||||
|
self.metadata[0].tail = '\n'
|
||||||
self.metadata = self.metadata[0]
|
self.metadata = self.metadata[0]
|
||||||
if unquote_urls:
|
if unquote_urls:
|
||||||
self.unquote_urls()
|
self.unquote_urls()
|
||||||
|
@ -7,10 +7,10 @@ __docformat__ = 'restructuredtext en'
|
|||||||
|
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from PyQt4.Qt import QComboBox, QLabel, QSpinBox, QDoubleSpinBox, QDateTimeEdit, \
|
from PyQt4.Qt import (QComboBox, QLabel, QSpinBox, QDoubleSpinBox, QDateTimeEdit,
|
||||||
QDateTime, QGroupBox, QVBoxLayout, QSizePolicy, QGridLayout, \
|
QDateTime, QGroupBox, QVBoxLayout, QSizePolicy, QGridLayout,
|
||||||
QSpacerItem, QIcon, QCheckBox, QWidget, QHBoxLayout, SIGNAL, \
|
QSpacerItem, QIcon, QCheckBox, QWidget, QHBoxLayout, SIGNAL,
|
||||||
QPushButton, QMessageBox, QToolButton
|
QPushButton, QMessageBox, QToolButton, Qt)
|
||||||
|
|
||||||
from calibre.utils.date import qt_to_dt, now
|
from calibre.utils.date import qt_to_dt, now
|
||||||
from calibre.gui2.complete2 import EditWithComplete
|
from calibre.gui2.complete2 import EditWithComplete
|
||||||
@ -39,7 +39,6 @@ class Base(object):
|
|||||||
def gui_val(self):
|
def gui_val(self):
|
||||||
return self.getter()
|
return self.getter()
|
||||||
|
|
||||||
|
|
||||||
def commit(self, book_id, notify=False):
|
def commit(self, book_id, notify=False):
|
||||||
val = self.gui_val
|
val = self.gui_val
|
||||||
val = self.normalize_ui_val(val)
|
val = self.normalize_ui_val(val)
|
||||||
@ -159,6 +158,17 @@ class DateTimeEdit(QDateTimeEdit):
|
|||||||
def set_to_clear(self):
|
def set_to_clear(self):
|
||||||
self.setDateTime(UNDEFINED_QDATETIME)
|
self.setDateTime(UNDEFINED_QDATETIME)
|
||||||
|
|
||||||
|
def keyPressEvent(self, ev):
|
||||||
|
if ev.key() == Qt.Key_Minus:
|
||||||
|
ev.accept()
|
||||||
|
self.setDateTime(self.minimumDateTime())
|
||||||
|
elif ev.key() == Qt.Key_Equal:
|
||||||
|
ev.accept()
|
||||||
|
self.setDateTime(QDateTime.currentDateTime())
|
||||||
|
else:
|
||||||
|
return QDateTimeEdit.keyPressEvent(self, ev)
|
||||||
|
|
||||||
|
|
||||||
class DateTime(Base):
|
class DateTime(Base):
|
||||||
|
|
||||||
def setup_ui(self, parent):
|
def setup_ui(self, parent):
|
||||||
@ -595,7 +605,6 @@ class BulkBase(Base):
|
|||||||
self._cached_gui_val_ = self.getter()
|
self._cached_gui_val_ = self.getter()
|
||||||
return self._cached_gui_val_
|
return self._cached_gui_val_
|
||||||
|
|
||||||
|
|
||||||
def get_initial_value(self, book_ids):
|
def get_initial_value(self, book_ids):
|
||||||
values = set([])
|
values = set([])
|
||||||
for book_id in book_ids:
|
for book_id in book_ids:
|
||||||
@ -1054,3 +1063,5 @@ bulk_widgets = {
|
|||||||
'series': BulkSeries,
|
'series': BulkSeries,
|
||||||
'enumeration': BulkEnumeration,
|
'enumeration': BulkEnumeration,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -161,18 +161,18 @@ class StatusBar(QStatusBar): # {{{
|
|||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
QStatusBar.__init__(self, parent)
|
QStatusBar.__init__(self, parent)
|
||||||
self.default_message = __appname__ + ' ' + _('version') + ' ' + \
|
|
||||||
self.get_version() + ' ' + _('created by Kovid Goyal')
|
|
||||||
self.device_string = ''
|
self.device_string = ''
|
||||||
self.update_label = UpdateLabel('')
|
self.update_label = UpdateLabel('')
|
||||||
|
self.total = self.current = self.selected = 0
|
||||||
self.addPermanentWidget(self.update_label)
|
self.addPermanentWidget(self.update_label)
|
||||||
self.update_label.setVisible(False)
|
self.update_label.setVisible(False)
|
||||||
self._font = QFont()
|
self._font = QFont()
|
||||||
self._font.setBold(True)
|
self._font.setBold(True)
|
||||||
self.setFont(self._font)
|
self.setFont(self._font)
|
||||||
self.defmsg = QLabel(self.default_message)
|
self.defmsg = QLabel('')
|
||||||
self.defmsg.setFont(self._font)
|
self.defmsg.setFont(self._font)
|
||||||
self.addWidget(self.defmsg)
|
self.addWidget(self.defmsg)
|
||||||
|
self.set_label()
|
||||||
|
|
||||||
def initialize(self, systray=None):
|
def initialize(self, systray=None):
|
||||||
self.systray = systray
|
self.systray = systray
|
||||||
@ -180,17 +180,39 @@ class StatusBar(QStatusBar): # {{{
|
|||||||
|
|
||||||
def device_connected(self, devname):
|
def device_connected(self, devname):
|
||||||
self.device_string = _('Connected ') + devname
|
self.device_string = _('Connected ') + devname
|
||||||
self.defmsg.setText(self.default_message + ' ..::.. ' +
|
self.set_label()
|
||||||
self.device_string)
|
|
||||||
|
def update_state(self, total, current, selected):
|
||||||
|
self.total, self.current, self.selected = total, current, selected
|
||||||
|
self.set_label()
|
||||||
|
|
||||||
|
def set_label(self):
|
||||||
|
try:
|
||||||
|
self._set_label()
|
||||||
|
except:
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
def _set_label(self):
|
||||||
|
msg = '%s %s %s' % (__appname__, _('version'), get_version())
|
||||||
|
if self.device_string:
|
||||||
|
msg += ' ..::.. ' + self.device_string
|
||||||
|
else:
|
||||||
|
msg += _(' %(created)s %(name)s') % dict(created=_('created by'), name='Kovid Goyal')
|
||||||
|
|
||||||
|
if self.total != self.current:
|
||||||
|
base = _('%(num)d of %(total)d books') % dict(num=self.current, total=self.total)
|
||||||
|
else:
|
||||||
|
base = _('%d books') % self.total
|
||||||
|
if self.selected > 0:
|
||||||
|
base = _('%(num)s, %(sel)d selected') % dict(num=base, sel=self.selected)
|
||||||
|
|
||||||
|
self.defmsg.setText('%s [%s]' % (msg, base))
|
||||||
self.clearMessage()
|
self.clearMessage()
|
||||||
|
|
||||||
def device_disconnected(self):
|
def device_disconnected(self):
|
||||||
self.device_string = ''
|
self.device_string = ''
|
||||||
self.defmsg.setText(self.default_message)
|
self.set_label()
|
||||||
self.clearMessage()
|
|
||||||
|
|
||||||
def get_version(self):
|
|
||||||
return get_version()
|
|
||||||
|
|
||||||
def show_message(self, msg, timeout=0):
|
def show_message(self, msg, timeout=0):
|
||||||
self.showMessage(msg, timeout)
|
self.showMessage(msg, timeout)
|
||||||
@ -312,9 +334,15 @@ class LayoutMixin(object): # {{{
|
|||||||
|
|
||||||
def read_layout_settings(self):
|
def read_layout_settings(self):
|
||||||
# View states are restored automatically when set_database is called
|
# View states are restored automatically when set_database is called
|
||||||
|
|
||||||
for x in ('cb', 'tb', 'bd'):
|
for x in ('cb', 'tb', 'bd'):
|
||||||
getattr(self, x+'_splitter').restore_state()
|
getattr(self, x+'_splitter').restore_state()
|
||||||
|
|
||||||
|
def update_status_bar(self, *args):
|
||||||
|
v = self.current_view()
|
||||||
|
selected = len(v.selectionModel().selectedRows())
|
||||||
|
total, current = v.model().counts()
|
||||||
|
self.status_bar.update_state(total, current, selected)
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ __copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
|||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
import functools, re, os, traceback, errno, time
|
import functools, re, os, traceback, errno, time
|
||||||
from collections import defaultdict
|
from collections import defaultdict, namedtuple
|
||||||
|
|
||||||
from PyQt4.Qt import (QAbstractTableModel, Qt, pyqtSignal, QIcon, QImage,
|
from PyQt4.Qt import (QAbstractTableModel, Qt, pyqtSignal, QIcon, QImage,
|
||||||
QModelIndex, QVariant, QDateTime, QColor, QPixmap)
|
QModelIndex, QVariant, QDateTime, QColor, QPixmap)
|
||||||
@ -29,6 +29,8 @@ from calibre.gui2.library import DEFAULT_SORT
|
|||||||
from calibre.utils.localization import calibre_langcode_to_name
|
from calibre.utils.localization import calibre_langcode_to_name
|
||||||
from calibre.library.coloring import color_row_key
|
from calibre.library.coloring import color_row_key
|
||||||
|
|
||||||
|
Counts = namedtuple('Counts', 'total current')
|
||||||
|
|
||||||
def human_readable(size, precision=1):
|
def human_readable(size, precision=1):
|
||||||
""" Convert a size in bytes into megabytes """
|
""" Convert a size in bytes into megabytes """
|
||||||
return ('%.'+str(precision)+'f') % ((size/(1024.*1024.)),)
|
return ('%.'+str(precision)+'f') % ((size/(1024.*1024.)),)
|
||||||
@ -46,7 +48,7 @@ def default_image():
|
|||||||
_default_image = QImage(I('default_cover.png'))
|
_default_image = QImage(I('default_cover.png'))
|
||||||
return _default_image
|
return _default_image
|
||||||
|
|
||||||
class ColumnColor(object):
|
class ColumnColor(object): # {{{
|
||||||
|
|
||||||
def __init__(self, formatter, colors):
|
def __init__(self, formatter, colors):
|
||||||
self.mi = None
|
self.mi = None
|
||||||
@ -70,9 +72,9 @@ class ColumnColor(object):
|
|||||||
return color
|
return color
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
class ColumnIcon(object): # {{{
|
||||||
class ColumnIcon(object):
|
|
||||||
|
|
||||||
def __init__(self, formatter):
|
def __init__(self, formatter):
|
||||||
self.mi = None
|
self.mi = None
|
||||||
@ -108,6 +110,7 @@ class ColumnIcon(object):
|
|||||||
return icon_bitmap
|
return icon_bitmap
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
# }}}
|
||||||
|
|
||||||
class BooksModel(QAbstractTableModel): # {{{
|
class BooksModel(QAbstractTableModel): # {{{
|
||||||
|
|
||||||
@ -240,7 +243,6 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
# Would like to to a join here, but the thread might be waiting to
|
# Would like to to a join here, but the thread might be waiting to
|
||||||
# do something on the GUI thread. Deadlock.
|
# do something on the GUI thread. Deadlock.
|
||||||
|
|
||||||
|
|
||||||
def refresh_ids(self, ids, current_row=-1):
|
def refresh_ids(self, ids, current_row=-1):
|
||||||
self._clear_caches()
|
self._clear_caches()
|
||||||
rows = self.db.refresh_ids(ids)
|
rows = self.db.refresh_ids(ids)
|
||||||
@ -282,6 +284,13 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
self._clear_caches()
|
self._clear_caches()
|
||||||
self.count_changed_signal.emit(self.db.count())
|
self.count_changed_signal.emit(self.db.count())
|
||||||
|
|
||||||
|
def counts(self):
|
||||||
|
if self.db.data.search_restriction_applied():
|
||||||
|
total = self.db.data.get_search_restriction_book_count()
|
||||||
|
else:
|
||||||
|
total = self.db.count()
|
||||||
|
return Counts(total, self.count())
|
||||||
|
|
||||||
def row_indices(self, index):
|
def row_indices(self, index):
|
||||||
''' Return list indices of all cells in index.row()'''
|
''' Return list indices of all cells in index.row()'''
|
||||||
return [self.index(index.row(), c) for c in range(self.columnCount(None))]
|
return [self.index(index.row(), c) for c in range(self.columnCount(None))]
|
||||||
@ -332,7 +341,7 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
while True:
|
while True:
|
||||||
row_ += 1 if forward else -1
|
row_ += 1 if forward else -1
|
||||||
if row_ < 0:
|
if row_ < 0:
|
||||||
row_ = self.count() - 1;
|
row_ = self.count() - 1
|
||||||
elif row_ >= self.count():
|
elif row_ >= self.count():
|
||||||
row_ = 0
|
row_ = 0
|
||||||
if self.id(row_) in self.ids_to_highlight_set:
|
if self.id(row_) in self.ids_to_highlight_set:
|
||||||
@ -913,7 +922,6 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
return QVariant(section+1)
|
return QVariant(section+1)
|
||||||
return NONE
|
return NONE
|
||||||
|
|
||||||
|
|
||||||
def flags(self, index):
|
def flags(self, index):
|
||||||
flags = QAbstractTableModel.flags(self, index)
|
flags = QAbstractTableModel.flags(self, index)
|
||||||
if index.isValid():
|
if index.isValid():
|
||||||
@ -1082,7 +1090,6 @@ class OnDeviceSearch(SearchQueryParser): # {{{
|
|||||||
'inlibrary'
|
'inlibrary'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, model):
|
def __init__(self, model):
|
||||||
SearchQueryParser.__init__(self, locations=self.USABLE_LOCATIONS)
|
SearchQueryParser.__init__(self, locations=self.USABLE_LOCATIONS)
|
||||||
self.model = model
|
self.model = model
|
||||||
@ -1105,7 +1112,7 @@ class OnDeviceSearch(SearchQueryParser): # {{{
|
|||||||
elif query.startswith('~'):
|
elif query.startswith('~'):
|
||||||
matchkind = REGEXP_MATCH
|
matchkind = REGEXP_MATCH
|
||||||
query = query[1:]
|
query = query[1:]
|
||||||
if matchkind != REGEXP_MATCH: ### leave case in regexps because it can be significant e.g. \S \W \D
|
if matchkind != REGEXP_MATCH: # leave case in regexps because it can be significant e.g. \S \W \D
|
||||||
query = query.lower()
|
query = query.lower()
|
||||||
|
|
||||||
if location not in self.USABLE_LOCATIONS:
|
if location not in self.USABLE_LOCATIONS:
|
||||||
@ -1137,9 +1144,9 @@ class OnDeviceSearch(SearchQueryParser): # {{{
|
|||||||
if locvalue == 'inlibrary':
|
if locvalue == 'inlibrary':
|
||||||
continue # this is bool, so can't match below
|
continue # this is bool, so can't match below
|
||||||
try:
|
try:
|
||||||
### Can't separate authors because comma is used for name sep and author sep
|
# Can't separate authors because comma is used for name sep and author sep
|
||||||
### Exact match might not get what you want. For that reason, turn author
|
# Exact match might not get what you want. For that reason, turn author
|
||||||
### exactmatch searches into contains searches.
|
# exactmatch searches into contains searches.
|
||||||
if locvalue == 'author' and matchkind == EQUALS_MATCH:
|
if locvalue == 'author' and matchkind == EQUALS_MATCH:
|
||||||
m = CONTAINS_MATCH
|
m = CONTAINS_MATCH
|
||||||
else:
|
else:
|
||||||
@ -1202,6 +1209,12 @@ class DeviceBooksModel(BooksModel): # {{{
|
|||||||
self.editable = ['title', 'authors', 'collections']
|
self.editable = ['title', 'authors', 'collections']
|
||||||
self.book_in_library = None
|
self.book_in_library = None
|
||||||
|
|
||||||
|
def counts(self):
|
||||||
|
return Counts(len(self.db), len(self.map))
|
||||||
|
|
||||||
|
def count_changed(self, *args):
|
||||||
|
self.count_changed_signal.emit(len(self.db))
|
||||||
|
|
||||||
def mark_for_deletion(self, job, rows, rows_are_ids=False):
|
def mark_for_deletion(self, job, rows, rows_are_ids=False):
|
||||||
db_indices = rows if rows_are_ids else self.indices(rows)
|
db_indices = rows if rows_are_ids else self.indices(rows)
|
||||||
db_items = [self.db[i] for i in db_indices if -1 < i < len(self.db)]
|
db_items = [self.db[i] for i in db_indices if -1 < i < len(self.db)]
|
||||||
@ -1241,11 +1254,13 @@ class DeviceBooksModel(BooksModel): # {{{
|
|||||||
if not succeeded:
|
if not succeeded:
|
||||||
indices = self.row_indices(self.index(row, 0))
|
indices = self.row_indices(self.index(row, 0))
|
||||||
self.dataChanged.emit(indices[0], indices[-1])
|
self.dataChanged.emit(indices[0], indices[-1])
|
||||||
|
self.count_changed()
|
||||||
|
|
||||||
def paths_deleted(self, paths):
|
def paths_deleted(self, paths):
|
||||||
self.map = list(range(0, len(self.db)))
|
self.map = list(range(0, len(self.db)))
|
||||||
self.resort(False)
|
self.resort(False)
|
||||||
self.research(True)
|
self.research(True)
|
||||||
|
self.count_changed()
|
||||||
|
|
||||||
def is_row_marked_for_deletion(self, row):
|
def is_row_marked_for_deletion(self, row):
|
||||||
try:
|
try:
|
||||||
@ -1276,9 +1291,9 @@ class DeviceBooksModel(BooksModel): # {{{
|
|||||||
if index.isValid():
|
if index.isValid():
|
||||||
cname = self.column_map[index.column()]
|
cname = self.column_map[index.column()]
|
||||||
if cname in self.editable and \
|
if cname in self.editable and \
|
||||||
(cname != 'collections' or \
|
(cname != 'collections' or
|
||||||
(callable(getattr(self.db, 'supports_collections', None)) and \
|
(callable(getattr(self.db, 'supports_collections', None)) and
|
||||||
self.db.supports_collections() and \
|
self.db.supports_collections() and
|
||||||
device_prefs['manage_device_metadata']=='manual')):
|
device_prefs['manage_device_metadata']=='manual')):
|
||||||
flags |= Qt.ItemIsEditable
|
flags |= Qt.ItemIsEditable
|
||||||
return flags
|
return flags
|
||||||
@ -1308,6 +1323,7 @@ class DeviceBooksModel(BooksModel): # {{{
|
|||||||
self.last_search = text
|
self.last_search = text
|
||||||
if self.last_search:
|
if self.last_search:
|
||||||
self.searched.emit(True)
|
self.searched.emit(True)
|
||||||
|
self.count_changed()
|
||||||
|
|
||||||
def research(self, reset=True):
|
def research(self, reset=True):
|
||||||
self.search(self.last_search, reset)
|
self.search(self.last_search, reset)
|
||||||
@ -1377,6 +1393,7 @@ class DeviceBooksModel(BooksModel): # {{{
|
|||||||
self.map = list(range(0, len(db)))
|
self.map = list(range(0, len(db)))
|
||||||
self.research(reset=False)
|
self.research(reset=False)
|
||||||
self.resort()
|
self.resort()
|
||||||
|
self.count_changed()
|
||||||
|
|
||||||
def cover(self, row):
|
def cover(self, row):
|
||||||
item = self.db[self.map[row]]
|
item = self.db[self.map[row]]
|
||||||
@ -1521,7 +1538,7 @@ class DeviceBooksModel(BooksModel): # {{{
|
|||||||
elif role == Qt.ToolTipRole and index.isValid():
|
elif role == Qt.ToolTipRole and index.isValid():
|
||||||
if self.is_row_marked_for_deletion(row):
|
if self.is_row_marked_for_deletion(row):
|
||||||
return QVariant(_('Marked for deletion'))
|
return QVariant(_('Marked for deletion'))
|
||||||
if cname in ['title', 'authors'] or (cname == 'collections' and \
|
if cname in ['title', 'authors'] or (cname == 'collections' and
|
||||||
self.db.supports_collections()):
|
self.db.supports_collections()):
|
||||||
return QVariant(_("Double click to <b>edit</b> me<br><br>"))
|
return QVariant(_("Double click to <b>edit</b> me<br><br>"))
|
||||||
elif role == Qt.DecorationRole and cname == 'inlibrary':
|
elif role == Qt.DecorationRole and cname == 'inlibrary':
|
||||||
@ -1590,3 +1607,4 @@ class DeviceBooksModel(BooksModel): # {{{
|
|||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from __future__ import (unicode_literals, division, absolute_import, print_function)
|
from __future__ import (unicode_literals, division, absolute_import, print_function)
|
||||||
store_version = 1 # Needed for dynamic plugin loading
|
store_version = 2 # Needed for dynamic plugin loading
|
||||||
|
|
||||||
__license__ = 'GPL 3'
|
__license__ = 'GPL 3'
|
||||||
__copyright__ = '2011, John Schember <john@nachtimwald.com>'
|
__copyright__ = '2011, John Schember <john@nachtimwald.com>'
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from __future__ import (unicode_literals, division, absolute_import, print_function)
|
from __future__ import (unicode_literals, division, absolute_import, print_function)
|
||||||
store_version = 3 # Needed for dynamic plugin loading
|
store_version = 4 # Needed for dynamic plugin loading
|
||||||
|
|
||||||
__license__ = 'GPL 3'
|
__license__ = 'GPL 3'
|
||||||
__copyright__ = '2011-2013, Tomasz Długosz <tomek3d@gmail.com>'
|
__copyright__ = '2011-2013, Tomasz Długosz <tomek3d@gmail.com>'
|
||||||
@ -9,6 +9,7 @@ __docformat__ = 'restructuredtext en'
|
|||||||
|
|
||||||
import re
|
import re
|
||||||
import urllib
|
import urllib
|
||||||
|
from base64 import b64encode
|
||||||
from contextlib import closing
|
from contextlib import closing
|
||||||
|
|
||||||
from lxml import html
|
from lxml import html
|
||||||
@ -25,21 +26,19 @@ from calibre.gui2.store.web_store_dialog import WebStoreDialog
|
|||||||
class WoblinkStore(BasicStoreConfig, StorePlugin):
|
class WoblinkStore(BasicStoreConfig, StorePlugin):
|
||||||
|
|
||||||
def open(self, parent=None, detail_item=None, external=False):
|
def open(self, parent=None, detail_item=None, external=False):
|
||||||
#aff_root = 'https://www.a4b-tracking.com/pl/stat-click-text-link/16/58/'
|
aff_root = 'https://www.a4b-tracking.com/pl/stat-click-text-link/16/58/'
|
||||||
url = 'http://woblink.com/publication'
|
url = 'http://woblink.com/publication'
|
||||||
|
|
||||||
#aff_url = aff_root + str(b64encode(url))
|
aff_url = aff_root + str(b64encode(url))
|
||||||
detail_url = None
|
detail_url = None
|
||||||
|
|
||||||
if detail_item:
|
if detail_item:
|
||||||
detail_url = 'http://woblink.com' + detail_item #aff_root + str(b64encode('http://woblink.com' + detail_item))
|
detail_url = aff_root + str(b64encode('http://woblink.com' + detail_item))
|
||||||
|
|
||||||
if external or self.config.get('open_external', False):
|
if external or self.config.get('open_external', False):
|
||||||
#open_url(QUrl(url_slash_cleaner(detail_url if detail_url else aff_url)))
|
open_url(QUrl(url_slash_cleaner(detail_url if detail_url else aff_url)))
|
||||||
open_url(QUrl(url_slash_cleaner(detail_url if detail_url else url)))
|
|
||||||
else:
|
else:
|
||||||
#d = WebStoreDialog(self.gui, url, parent, detail_url if detail_url else aff_url)
|
d = WebStoreDialog(self.gui, url, parent, detail_url if detail_url else aff_url)
|
||||||
d = WebStoreDialog(self.gui, url, parent, detail_url if detail_url else url)
|
|
||||||
d.setWindowTitle(self.name)
|
d.setWindowTitle(self.name)
|
||||||
d.set_tags(self.config.get('tags', ''))
|
d.set_tags(self.config.get('tags', ''))
|
||||||
d.exec_()
|
d.exec_()
|
||||||
|
@ -325,6 +325,11 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
|
|||||||
if self.library_view.model().rowCount(None) < 3:
|
if self.library_view.model().rowCount(None) < 3:
|
||||||
self.library_view.resizeColumnsToContents()
|
self.library_view.resizeColumnsToContents()
|
||||||
|
|
||||||
|
for view in ('library', 'memory', 'card_a', 'card_b'):
|
||||||
|
v = getattr(self, '%s_view' % view)
|
||||||
|
v.selectionModel().selectionChanged.connect(self.update_status_bar)
|
||||||
|
v.model().count_changed_signal.connect(self.update_status_bar)
|
||||||
|
|
||||||
self.library_view.model().count_changed()
|
self.library_view.model().count_changed()
|
||||||
self.bars_manager.database_changed(self.library_view.model().db)
|
self.bars_manager.database_changed(self.library_view.model().db)
|
||||||
self.library_view.model().database_changed.connect(self.bars_manager.database_changed,
|
self.library_view.model().database_changed.connect(self.bars_manager.database_changed,
|
||||||
@ -661,6 +666,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
|
|||||||
# Reset the view in case something changed while it was invisible
|
# Reset the view in case something changed while it was invisible
|
||||||
self.current_view().reset()
|
self.current_view().reset()
|
||||||
self.set_number_of_books_shown()
|
self.set_number_of_books_shown()
|
||||||
|
self.update_status_bar()
|
||||||
|
|
||||||
def job_exception(self, job, dialog_title=_('Conversion Error')):
|
def job_exception(self, job, dialog_title=_('Conversion Error')):
|
||||||
if not hasattr(self, '_modeless_dialogs'):
|
if not hasattr(self, '_modeless_dialogs'):
|
||||||
|
@ -82,7 +82,8 @@ class FilenamePattern(QWidget, Ui_Form): # {{{
|
|||||||
val = prefs['filename_pattern']
|
val = prefs['filename_pattern']
|
||||||
self.re.lineEdit().setText(val)
|
self.re.lineEdit().setText(val)
|
||||||
|
|
||||||
val_hist += gprefs.get('filename_pattern_history', ['(?P<title>.+)', '(?P<author>[^_-]+) -?\s*(?P<series>[^_0-9-]*)(?P<series_index>[0-9]*)\s*-\s*(?P<title>[^_].+) ?'])
|
val_hist += gprefs.get('filename_pattern_history', [
|
||||||
|
'(?P<title>.+)', '(?P<author>[^_-]+) -?\s*(?P<series>[^_0-9-]*)(?P<series_index>[0-9]*)\s*-\s*(?P<title>[^_].+) ?'])
|
||||||
if val in val_hist:
|
if val in val_hist:
|
||||||
del val_hist[val_hist.index(val)]
|
del val_hist[val_hist.index(val)]
|
||||||
val_hist.insert(0, val)
|
val_hist.insert(0, val)
|
||||||
@ -136,7 +137,6 @@ class FilenamePattern(QWidget, Ui_Form): # {{{
|
|||||||
|
|
||||||
self.isbn.setText(_('No match') if mi.isbn is None else str(mi.isbn))
|
self.isbn.setText(_('No match') if mi.isbn is None else str(mi.isbn))
|
||||||
|
|
||||||
|
|
||||||
def pattern(self):
|
def pattern(self):
|
||||||
pat = unicode(self.re.lineEdit().text())
|
pat = unicode(self.re.lineEdit().text())
|
||||||
return re.compile(pat)
|
return re.compile(pat)
|
||||||
@ -186,7 +186,6 @@ class FormatList(QListWidget): # {{{
|
|||||||
if d.err is None:
|
if d.err is None:
|
||||||
self.formats_dropped.emit(event, [d.fpath])
|
self.formats_dropped.emit(event, [d.fpath])
|
||||||
|
|
||||||
|
|
||||||
def dragMoveEvent(self, event):
|
def dragMoveEvent(self, event):
|
||||||
event.acceptProposedAction()
|
event.acceptProposedAction()
|
||||||
|
|
||||||
@ -736,13 +735,11 @@ class PythonHighlighter(QSyntaxHighlighter): # {{{
|
|||||||
|
|
||||||
CONSTANTS = ["False", "True", "None", "NotImplemented", "Ellipsis"]
|
CONSTANTS = ["False", "True", "None", "NotImplemented", "Ellipsis"]
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super(PythonHighlighter, self).__init__(parent)
|
super(PythonHighlighter, self).__init__(parent)
|
||||||
if not self.Config:
|
if not self.Config:
|
||||||
self.loadConfig()
|
self.loadConfig()
|
||||||
|
|
||||||
|
|
||||||
self.initializeFormats()
|
self.initializeFormats()
|
||||||
|
|
||||||
PythonHighlighter.Rules.append((QRegExp(
|
PythonHighlighter.Rules.append((QRegExp(
|
||||||
@ -752,7 +749,7 @@ class PythonHighlighter(QSyntaxHighlighter): # {{{
|
|||||||
"|".join([r"\b%s\b" % builtin for builtin in self.BUILTINS])),
|
"|".join([r"\b%s\b" % builtin for builtin in self.BUILTINS])),
|
||||||
"builtin"))
|
"builtin"))
|
||||||
PythonHighlighter.Rules.append((QRegExp(
|
PythonHighlighter.Rules.append((QRegExp(
|
||||||
"|".join([r"\b%s\b" % constant \
|
"|".join([r"\b%s\b" % constant
|
||||||
for constant in self.CONSTANTS])), "constant"))
|
for constant in self.CONSTANTS])), "constant"))
|
||||||
PythonHighlighter.Rules.append((QRegExp(
|
PythonHighlighter.Rules.append((QRegExp(
|
||||||
r"\b[+-]?[0-9]+[lL]?\b"
|
r"\b[+-]?[0-9]+[lL]?\b"
|
||||||
@ -812,7 +809,6 @@ class PythonHighlighter(QSyntaxHighlighter): # {{{
|
|||||||
Config["%sfontbold" % name] = QVariant(bold).toBool()
|
Config["%sfontbold" % name] = QVariant(bold).toBool()
|
||||||
Config["%sfontitalic" % name] = QVariant(italic).toBool()
|
Config["%sfontitalic" % name] = QVariant(italic).toBool()
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def initializeFormats(cls):
|
def initializeFormats(cls):
|
||||||
Config = cls.Config
|
Config = cls.Config
|
||||||
@ -829,7 +825,6 @@ class PythonHighlighter(QSyntaxHighlighter): # {{{
|
|||||||
format.setFontItalic(Config["%sfontitalic" % name])
|
format.setFontItalic(Config["%sfontitalic" % name])
|
||||||
PythonHighlighter.Formats[name] = format
|
PythonHighlighter.Formats[name] = format
|
||||||
|
|
||||||
|
|
||||||
def highlightBlock(self, text):
|
def highlightBlock(self, text):
|
||||||
NORMAL, TRIPLESINGLE, TRIPLEDOUBLE, ERROR = range(4)
|
NORMAL, TRIPLESINGLE, TRIPLEDOUBLE, ERROR = range(4)
|
||||||
|
|
||||||
@ -900,7 +895,6 @@ class PythonHighlighter(QSyntaxHighlighter): # {{{
|
|||||||
self.setFormat(i, text.length(),
|
self.setFormat(i, text.length(),
|
||||||
PythonHighlighter.Formats["string"])
|
PythonHighlighter.Formats["string"])
|
||||||
|
|
||||||
|
|
||||||
def rehighlight(self):
|
def rehighlight(self):
|
||||||
QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
|
QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
|
||||||
QSyntaxHighlighter.rehighlight(self)
|
QSyntaxHighlighter.rehighlight(self)
|
||||||
@ -955,8 +949,8 @@ class LayoutButton(QToolButton):
|
|||||||
|
|
||||||
def set_state_to_hide(self, *args):
|
def set_state_to_hide(self, *args):
|
||||||
self.setChecked(True)
|
self.setChecked(True)
|
||||||
self.setText(_('Hide %(label)s %(shortcut)s'%dict(
|
self.setText(_('Hide %(label)s %(shortcut)s')%dict(
|
||||||
label=self.label, shortcut=self.shortcut)))
|
label=self.label, shortcut=self.shortcut))
|
||||||
self.setToolTip(self.text())
|
self.setToolTip(self.text())
|
||||||
self.setStatusTip(self.text())
|
self.setStatusTip(self.text())
|
||||||
|
|
||||||
@ -1045,11 +1039,13 @@ class Splitter(QSplitter):
|
|||||||
@dynamic_property
|
@dynamic_property
|
||||||
def side_index_size(self):
|
def side_index_size(self):
|
||||||
def fget(self):
|
def fget(self):
|
||||||
if self.count() < 2: return 0
|
if self.count() < 2:
|
||||||
|
return 0
|
||||||
return self.sizes()[self.side_index]
|
return self.sizes()[self.side_index]
|
||||||
|
|
||||||
def fset(self, val):
|
def fset(self, val):
|
||||||
if self.count() < 2: return
|
if self.count() < 2:
|
||||||
|
return
|
||||||
if val == 0 and not self.is_side_index_hidden:
|
if val == 0 and not self.is_side_index_hidden:
|
||||||
self.save_state()
|
self.save_state()
|
||||||
sizes = list(self.sizes())
|
sizes = list(self.sizes())
|
||||||
@ -1081,7 +1077,8 @@ class Splitter(QSplitter):
|
|||||||
self.resize_timer.start()
|
self.resize_timer.start()
|
||||||
|
|
||||||
def get_state(self):
|
def get_state(self):
|
||||||
if self.count() < 2: return (False, 200)
|
if self.count() < 2:
|
||||||
|
return (False, 200)
|
||||||
return (self.desired_show, self.desired_side_size)
|
return (self.desired_show, self.desired_side_size)
|
||||||
|
|
||||||
def apply_state(self, state, save_desired=True):
|
def apply_state(self, state, save_desired=True):
|
||||||
@ -1142,3 +1139,4 @@ class Splitter(QSplitter):
|
|||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user