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
@ -26,14 +26,14 @@ class DailyTelegraph(BasicNewsRecipe):
|
|||||||
|
|
||||||
keep_only_tags = [dict(name='div', attrs={'id': 'story'})]
|
keep_only_tags = [dict(name='div', attrs={'id': 'story'})]
|
||||||
|
|
||||||
#remove_tags = [dict(name=['object','link'])]
|
# remove_tags = [dict(name=['object','link'])]
|
||||||
remove_tags = [dict(name ='div', attrs = {'class': 'story-info'}),
|
remove_tags = [dict(name='div', attrs={'class': 'story-info'}),
|
||||||
dict(name ='div', attrs = {'class': 'story-header-tools'}),
|
dict(name='div', attrs={'class': 'story-header-tools'}),
|
||||||
dict(name ='div', attrs = {'class': 'story-sidebar'}),
|
dict(name='div', attrs={'class': 'story-sidebar'}),
|
||||||
dict(name ='div', attrs = {'class': 'story-footer'}),
|
dict(name='div', attrs={'class': 'story-footer'}),
|
||||||
dict(name ='div', attrs = {'id': 'comments'}),
|
dict(name='div', attrs={'id': 'comments'}),
|
||||||
dict(name ='div', attrs = {'class': 'story-extras story-extras-2'}),
|
dict(name='div', attrs={'class': 'story-extras story-extras-2'}),
|
||||||
dict(name ='div', attrs = {'class': 'group item-count-1 story-related'})
|
dict(name='div', attrs={'class': 'group item-count-1 story-related'})
|
||||||
]
|
]
|
||||||
|
|
||||||
extra_css = '''
|
extra_css = '''
|
||||||
@ -45,30 +45,31 @@ 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'Opinion', u'http://feeds.news.com.au/public/rss/2.0/aus_opinion_58.xml'),
|
(u'News', u'http://feeds.news.com.au/public/rss/2.0/aus_news_807.xml'),
|
||||||
(u'The Nation', u'http://feeds.news.com.au/public/rss/2.0/aus_the_nation_62.xml'),
|
(u'Opinion', u'http://feeds.news.com.au/public/rss/2.0/aus_opinion_58.xml'),
|
||||||
(u'World News', u'http://feeds.news.com.au/public/rss/2.0/aus_world_808.xml'),
|
(u'The Nation', u'http://feeds.news.com.au/public/rss/2.0/aus_the_nation_62.xml'),
|
||||||
(u'US Election', u'http://feeds.news.com.au/public/rss/2.0/aus_uselection_687.xml'),
|
(u'World News', u'http://feeds.news.com.au/public/rss/2.0/aus_world_808.xml'),
|
||||||
(u'Climate', u'http://feeds.news.com.au/public/rss/2.0/aus_climate_809.xml'),
|
(u'US Election', u'http://feeds.news.com.au/public/rss/2.0/aus_uselection_687.xml'),
|
||||||
(u'Media', u'http://feeds.news.com.au/public/rss/2.0/aus_media_57.xml'),
|
(u'Climate', u'http://feeds.news.com.au/public/rss/2.0/aus_climate_809.xml'),
|
||||||
(u'IT', u'http://feeds.news.com.au/public/rss/2.0/ausit_itnews_topstories_367.xml'),
|
(u'Media', u'http://feeds.news.com.au/public/rss/2.0/aus_media_57.xml'),
|
||||||
(u'Exec Tech', u'http://feeds.news.com.au/public/rss/2.0/ausit_exec_topstories_385.xml'),
|
(u'IT', u'http://feeds.news.com.au/public/rss/2.0/ausit_itnews_topstories_367.xml'),
|
||||||
(u'Higher Education', u'http://feeds.news.com.au/public/rss/2.0/aus_higher_education_56.xml'),
|
(u'Exec Tech', u'http://feeds.news.com.au/public/rss/2.0/ausit_exec_topstories_385.xml'),
|
||||||
(u'Arts', u'http://feeds.news.com.au/public/rss/2.0/aus_arts_51.xml'),
|
(u'Higher Education', u'http://feeds.news.com.au/public/rss/2.0/aus_higher_education_56.xml'),
|
||||||
(u'Travel', u'http://feeds.news.com.au/public/rss/2.0/aus_travel_and_indulgence_63.xml'),
|
(u'Arts', u'http://feeds.news.com.au/public/rss/2.0/aus_arts_51.xml'),
|
||||||
(u'Property', u'http://feeds.news.com.au/public/rss/2.0/aus_property_59.xml'),
|
(u'Travel', u'http://feeds.news.com.au/public/rss/2.0/aus_travel_and_indulgence_63.xml'),
|
||||||
(u'Sport', u'http://feeds.news.com.au/public/rss/2.0/aus_sport_61.xml'),
|
(u'Property', u'http://feeds.news.com.au/public/rss/2.0/aus_property_59.xml'),
|
||||||
(u'Business', u'http://feeds.news.com.au/public/rss/2.0/aus_business_811.xml'),
|
(u'Sport', u'http://feeds.news.com.au/public/rss/2.0/aus_sport_61.xml'),
|
||||||
(u'Aviation', u'http://feeds.news.com.au/public/rss/2.0/aus_business_aviation_706.xml'),
|
(u'Business', u'http://feeds.news.com.au/public/rss/2.0/aus_business_811.xml'),
|
||||||
(u'Commercial Property', u'http://feeds.news.com.au/public/rss/2.0/aus_business_commercial_property_708.xml'),
|
(u'Aviation', u'http://feeds.news.com.au/public/rss/2.0/aus_business_aviation_706.xml'),
|
||||||
(u'Mining', u'http://feeds.news.com.au/public/rss/2.0/aus_business_mining_704.xml')]
|
(u'Commercial Property', u'http://feeds.news.com.au/public/rss/2.0/aus_business_commercial_property_708.xml'),
|
||||||
|
(u'Mining', u'http://feeds.news.com.au/public/rss/2.0/aus_business_mining_704.xml')]
|
||||||
|
|
||||||
def get_browser(self):
|
def get_browser(self):
|
||||||
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()
|
||||||
@ -80,10 +81,11 @@ class DailyTelegraph(BasicNewsRecipe):
|
|||||||
def get_article_url(self, article):
|
def get_article_url(self, article):
|
||||||
return article.id
|
return article.id
|
||||||
|
|
||||||
#br = self.get_browser()
|
# br = self.get_browser()
|
||||||
#br.open(article.link).read()
|
# br.open(article.link).read()
|
||||||
#print br.geturl()
|
# print br.geturl()
|
||||||
|
|
||||||
|
# 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'
|
||||||
|
@ -25,7 +25,7 @@ class ANDROID(USBMS):
|
|||||||
|
|
||||||
VENDOR_ID = {
|
VENDOR_ID = {
|
||||||
# HTC
|
# HTC
|
||||||
0x0bb4 : { 0xc02 : HTC_BCDS,
|
0x0bb4 : {0xc02 : HTC_BCDS,
|
||||||
0xc01 : HTC_BCDS,
|
0xc01 : HTC_BCDS,
|
||||||
0xff9 : HTC_BCDS,
|
0xff9 : HTC_BCDS,
|
||||||
0xc86 : HTC_BCDS,
|
0xc86 : HTC_BCDS,
|
||||||
@ -52,13 +52,13 @@ class ANDROID(USBMS):
|
|||||||
},
|
},
|
||||||
|
|
||||||
# Eken
|
# Eken
|
||||||
0x040d : { 0x8510 : [0x0001], 0x0851 : [0x1] },
|
0x040d : {0x8510 : [0x0001], 0x0851 : [0x1]},
|
||||||
|
|
||||||
# Trekstor
|
# Trekstor
|
||||||
0x1e68 : { 0x006a : [0x0231] },
|
0x1e68 : {0x006a : [0x0231]},
|
||||||
|
|
||||||
# Motorola
|
# Motorola
|
||||||
0x22b8 : { 0x41d9 : [0x216], 0x2d61 : [0x100], 0x2d67 : [0x100],
|
0x22b8 : {0x41d9 : [0x216], 0x2d61 : [0x100], 0x2d67 : [0x100],
|
||||||
0x2de8 : [0x229],
|
0x2de8 : [0x229],
|
||||||
0x41db : [0x216], 0x4285 : [0x216], 0x42a3 : [0x216],
|
0x41db : [0x216], 0x4285 : [0x216], 0x42a3 : [0x216],
|
||||||
0x4286 : [0x216], 0x42b3 : [0x216], 0x42b4 : [0x216],
|
0x4286 : [0x216], 0x42b3 : [0x216], 0x42b4 : [0x216],
|
||||||
@ -111,7 +111,7 @@ class ANDROID(USBMS):
|
|||||||
},
|
},
|
||||||
|
|
||||||
# Samsung
|
# Samsung
|
||||||
0x04e8 : { 0x681d : [0x0222, 0x0223, 0x0224, 0x0400],
|
0x04e8 : {0x681d : [0x0222, 0x0223, 0x0224, 0x0400],
|
||||||
0x681c : [0x0222, 0x0223, 0x0224, 0x0400],
|
0x681c : [0x0222, 0x0223, 0x0224, 0x0400],
|
||||||
0x6640 : [0x0100],
|
0x6640 : [0x0100],
|
||||||
0x685b : [0x0400, 0x0226],
|
0x685b : [0x0400, 0x0226],
|
||||||
@ -130,7 +130,7 @@ class ANDROID(USBMS):
|
|||||||
0xc001 : [0x0226],
|
0xc001 : [0x0226],
|
||||||
0xc004 : [0x0226],
|
0xc004 : [0x0226],
|
||||||
0x8801 : [0x0226, 0x0227],
|
0x8801 : [0x0226, 0x0227],
|
||||||
0xe115 : [0x0216], # PocketBook A10
|
0xe115 : [0x0216], # PocketBook A10
|
||||||
},
|
},
|
||||||
|
|
||||||
# Another Viewsonic
|
# Another Viewsonic
|
||||||
@ -139,10 +139,10 @@ class ANDROID(USBMS):
|
|||||||
},
|
},
|
||||||
|
|
||||||
# Acer
|
# Acer
|
||||||
0x502 : { 0x3203 : [0x0100, 0x224]},
|
0x502 : {0x3203 : [0x0100, 0x224]},
|
||||||
|
|
||||||
# Dell
|
# Dell
|
||||||
0x413c : { 0xb007 : [0x0100, 0x0224, 0x0226]},
|
0x413c : {0xb007 : [0x0100, 0x0224, 0x0226]},
|
||||||
|
|
||||||
# LG
|
# LG
|
||||||
0x1004 : {
|
0x1004 : {
|
||||||
@ -166,25 +166,25 @@ class ANDROID(USBMS):
|
|||||||
|
|
||||||
# Huawei
|
# Huawei
|
||||||
# Disabled as this USB id is used by various USB flash drives
|
# Disabled as this USB id is used by various USB flash drives
|
||||||
#0x45e : { 0x00e1 : [0x007], },
|
# 0x45e : { 0x00e1 : [0x007], },
|
||||||
|
|
||||||
# T-Mobile
|
# T-Mobile
|
||||||
0x0408 : { 0x03ba : [0x0109], },
|
0x0408 : {0x03ba : [0x0109], },
|
||||||
|
|
||||||
# Xperia
|
# Xperia
|
||||||
0x13d3 : { 0x3304 : [0x0001, 0x0002] },
|
0x13d3 : {0x3304 : [0x0001, 0x0002]},
|
||||||
|
|
||||||
# CREEL?? Also Nextbook and Wayteq
|
# CREEL?? Also Nextbook and Wayteq
|
||||||
0x5e3 : { 0x726 : [0x222] },
|
0x5e3 : {0x726 : [0x222]},
|
||||||
|
|
||||||
# ZTE
|
# ZTE
|
||||||
0x19d2 : { 0x1353 : [0x226], 0x1351 : [0x227] },
|
0x19d2 : {0x1353 : [0x226], 0x1351 : [0x227]},
|
||||||
|
|
||||||
# Advent
|
# Advent
|
||||||
0x0955 : { 0x7100 : [0x9999] }, # This is the same as the Notion Ink Adam
|
0x0955 : {0x7100 : [0x9999]}, # This is the same as the Notion Ink Adam
|
||||||
|
|
||||||
# Kobo
|
# Kobo
|
||||||
0x2237: { 0x2208 : [0x0226] },
|
0x2237: {0x2208 : [0x0226]},
|
||||||
|
|
||||||
# Lenovo
|
# Lenovo
|
||||||
0x17ef : {
|
0x17ef : {
|
||||||
@ -193,10 +193,10 @@ class ANDROID(USBMS):
|
|||||||
},
|
},
|
||||||
|
|
||||||
# Pantech
|
# Pantech
|
||||||
0x10a9 : { 0x6050 : [0x227] },
|
0x10a9 : {0x6050 : [0x227]},
|
||||||
|
|
||||||
# Prestigio and Teclast
|
# Prestigio and Teclast
|
||||||
0x2207 : { 0 : [0x222], 0x10 : [0x222] },
|
0x2207 : {0 : [0x222], 0x10 : [0x222]},
|
||||||
|
|
||||||
}
|
}
|
||||||
EBOOK_DIR_MAIN = ['eBooks/import', 'wordplayer/calibretransfer', 'Books',
|
EBOOK_DIR_MAIN = ['eBooks/import', 'wordplayer/calibretransfer', 'Books',
|
||||||
@ -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):
|
||||||
@ -211,7 +221,7 @@ class Comments(Base):
|
|||||||
self._layout = QVBoxLayout()
|
self._layout = QVBoxLayout()
|
||||||
self._tb = CommentsEditor(self._box)
|
self._tb = CommentsEditor(self._box)
|
||||||
self._tb.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
|
self._tb.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
|
||||||
#self._tb.setTabChangesFocus(True)
|
# self._tb.setTabChangesFocus(True)
|
||||||
self._layout.addWidget(self._tb)
|
self._layout.addWidget(self._tb)
|
||||||
self._box.setLayout(self._layout)
|
self._box.setLayout(self._layout)
|
||||||
self.widgets = [self._box]
|
self.widgets = [self._box]
|
||||||
@ -534,7 +544,7 @@ def populate_metadata_page(layout, db, book_id, bulk=False, two_column=False, pa
|
|||||||
column = row = base_row = max_row = 0
|
column = row = base_row = max_row = 0
|
||||||
for key in cols:
|
for key in cols:
|
||||||
if not fm[key]['is_editable']:
|
if not fm[key]['is_editable']:
|
||||||
continue # this almost never happens
|
continue # this almost never happens
|
||||||
dt = fm[key]['datatype']
|
dt = fm[key]['datatype']
|
||||||
if dt == 'composite' or (bulk and dt == 'comments'):
|
if dt == 'composite' or (bulk and dt == 'comments'):
|
||||||
continue
|
continue
|
||||||
@ -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:
|
||||||
@ -633,7 +642,7 @@ class BulkBase(Base):
|
|||||||
self.main_widget = main_widget_class(w)
|
self.main_widget = main_widget_class(w)
|
||||||
l.addWidget(self.main_widget)
|
l.addWidget(self.main_widget)
|
||||||
l.setStretchFactor(self.main_widget, 10)
|
l.setStretchFactor(self.main_widget, 10)
|
||||||
self.a_c_checkbox = QCheckBox( _('Apply changes'), w)
|
self.a_c_checkbox = QCheckBox(_('Apply changes'), w)
|
||||||
l.addWidget(self.a_c_checkbox)
|
l.addWidget(self.a_c_checkbox)
|
||||||
self.ignore_change_signals = True
|
self.ignore_change_signals = True
|
||||||
|
|
||||||
@ -1054,3 +1063,5 @@ bulk_widgets = {
|
|||||||
'series': BulkSeries,
|
'series': BulkSeries,
|
||||||
'enumeration': BulkEnumeration,
|
'enumeration': BulkEnumeration,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ def partial(*args, **kwargs):
|
|||||||
_keep_refs.append(ans)
|
_keep_refs.append(ans)
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
class LibraryViewMixin(object): # {{{
|
class LibraryViewMixin(object): # {{{
|
||||||
|
|
||||||
def __init__(self, db):
|
def __init__(self, db):
|
||||||
self.library_view.files_dropped.connect(self.iactions['Add Books'].files_dropped, type=Qt.QueuedConnection)
|
self.library_view.files_dropped.connect(self.iactions['Add Books'].files_dropped, type=Qt.QueuedConnection)
|
||||||
@ -100,7 +100,7 @@ class LibraryViewMixin(object): # {{{
|
|||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class LibraryWidget(Splitter): # {{{
|
class LibraryWidget(Splitter): # {{{
|
||||||
|
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
orientation = Qt.Vertical
|
orientation = Qt.Vertical
|
||||||
@ -119,7 +119,7 @@ class LibraryWidget(Splitter): # {{{
|
|||||||
self.addWidget(parent.library_view)
|
self.addWidget(parent.library_view)
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class Stack(QStackedWidget): # {{{
|
class Stack(QStackedWidget): # {{{
|
||||||
|
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
QStackedWidget.__init__(self, parent)
|
QStackedWidget.__init__(self, parent)
|
||||||
@ -147,7 +147,7 @@ class Stack(QStackedWidget): # {{{
|
|||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class UpdateLabel(QLabel): # {{{
|
class UpdateLabel(QLabel): # {{{
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
QLabel.__init__(self, *args, **kwargs)
|
QLabel.__init__(self, *args, **kwargs)
|
||||||
@ -157,22 +157,22 @@ class UpdateLabel(QLabel): # {{{
|
|||||||
pass
|
pass
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class StatusBar(QStatusBar): # {{{
|
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)
|
||||||
@ -207,11 +229,11 @@ class StatusBar(QStatusBar): # {{{
|
|||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class LayoutMixin(object): # {{{
|
class LayoutMixin(object): # {{{
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
if config['gui_layout'] == 'narrow': # narrow {{{
|
if config['gui_layout'] == 'narrow': # narrow {{{
|
||||||
self.book_details = BookDetails(False, self)
|
self.book_details = BookDetails(False, self)
|
||||||
self.stack = Stack(self)
|
self.stack = Stack(self)
|
||||||
self.bd_splitter = Splitter('book_details_splitter',
|
self.bd_splitter = Splitter('book_details_splitter',
|
||||||
@ -224,7 +246,7 @@ class LayoutMixin(object): # {{{
|
|||||||
self.centralwidget.layout().addWidget(self.bd_splitter)
|
self.centralwidget.layout().addWidget(self.bd_splitter)
|
||||||
button_order = ('tb', 'bd', 'cb')
|
button_order = ('tb', 'bd', 'cb')
|
||||||
# }}}
|
# }}}
|
||||||
else: # wide {{{
|
else: # wide {{{
|
||||||
self.bd_splitter = Splitter('book_details_splitter',
|
self.bd_splitter = Splitter('book_details_splitter',
|
||||||
_('Book Details'), I('book.png'), initial_side_size=200,
|
_('Book Details'), I('book.png'), initial_side_size=200,
|
||||||
orientation=Qt.Horizontal, parent=self, side_index=1,
|
orientation=Qt.Horizontal, parent=self, side_index=1,
|
||||||
@ -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,8 +110,9 @@ class ColumnIcon(object):
|
|||||||
return icon_bitmap
|
return icon_bitmap
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
# }}}
|
||||||
|
|
||||||
class BooksModel(QAbstractTableModel): # {{{
|
class BooksModel(QAbstractTableModel): # {{{
|
||||||
|
|
||||||
about_to_be_sorted = pyqtSignal(object, name='aboutToBeSorted')
|
about_to_be_sorted = pyqtSignal(object, name='aboutToBeSorted')
|
||||||
sorting_done = pyqtSignal(object, name='sortingDone')
|
sorting_done = pyqtSignal(object, name='sortingDone')
|
||||||
@ -150,7 +153,7 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
self.default_image = default_image()
|
self.default_image = default_image()
|
||||||
self.sorted_on = DEFAULT_SORT
|
self.sorted_on = DEFAULT_SORT
|
||||||
self.sort_history = [self.sorted_on]
|
self.sort_history = [self.sorted_on]
|
||||||
self.last_search = '' # The last search performed on this model
|
self.last_search = '' # The last search performed on this model
|
||||||
self.column_map = []
|
self.column_map = []
|
||||||
self.headers = {}
|
self.headers = {}
|
||||||
self.alignment_map = {}
|
self.alignment_map = {}
|
||||||
@ -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,9 +284,16 @@ 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))]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def by_author(self):
|
def by_author(self):
|
||||||
@ -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:
|
||||||
@ -611,7 +620,7 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
data = None
|
data = None
|
||||||
try:
|
try:
|
||||||
data = self.db.cover(row_number)
|
data = self.db.cover(row_number)
|
||||||
except IndexError: # Happens if database has not yet been refreshed
|
except IndexError: # Happens if database has not yet been refreshed
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if not data:
|
if not data:
|
||||||
@ -673,7 +682,7 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
return QVariant(UNDEFINED_QDATETIME)
|
return QVariant(UNDEFINED_QDATETIME)
|
||||||
|
|
||||||
def bool_type(r, idx=-1):
|
def bool_type(r, idx=-1):
|
||||||
return None # displayed using a decorator
|
return None # displayed using a decorator
|
||||||
|
|
||||||
def bool_type_decorator(r, idx=-1, bool_cols_are_tristate=True):
|
def bool_type_decorator(r, idx=-1, bool_cols_are_tristate=True):
|
||||||
val = force_to_bool(self.db.data[r][idx])
|
val = force_to_bool(self.db.data[r][idx])
|
||||||
@ -884,18 +893,18 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
ans = Qt.AlignVCenter | ALIGNMENT_MAP[self.alignment_map.get(cname,
|
ans = Qt.AlignVCenter | ALIGNMENT_MAP[self.alignment_map.get(cname,
|
||||||
'left')]
|
'left')]
|
||||||
return QVariant(ans)
|
return QVariant(ans)
|
||||||
#elif role == Qt.ToolTipRole and index.isValid():
|
# elif role == Qt.ToolTipRole and index.isValid():
|
||||||
# if self.column_map[index.column()] in self.editable_cols:
|
# if self.column_map[index.column()] in self.editable_cols:
|
||||||
# return QVariant(_("Double click to <b>edit</b> me<br><br>"))
|
# return QVariant(_("Double click to <b>edit</b> me<br><br>"))
|
||||||
return NONE
|
return NONE
|
||||||
|
|
||||||
def headerData(self, section, orientation, role):
|
def headerData(self, section, orientation, role):
|
||||||
if orientation == Qt.Horizontal:
|
if orientation == Qt.Horizontal:
|
||||||
if section >= len(self.column_map): # same problem as in data, the column_map can be wrong
|
if section >= len(self.column_map): # same problem as in data, the column_map can be wrong
|
||||||
return None
|
return None
|
||||||
if role == Qt.ToolTipRole:
|
if role == Qt.ToolTipRole:
|
||||||
ht = self.column_map[section]
|
ht = self.column_map[section]
|
||||||
if ht == 'timestamp': # change help text because users know this field as 'date'
|
if ht == 'timestamp': # change help text because users know this field as 'date'
|
||||||
ht = 'date'
|
ht = 'date'
|
||||||
if self.db.field_metadata[self.column_map[section]]['is_category']:
|
if self.db.field_metadata[self.column_map[section]]['is_category']:
|
||||||
is_cat = _('. This column can be Quickview\'ed')
|
is_cat = _('. This column can be Quickview\'ed')
|
||||||
@ -909,11 +918,10 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
col = self.db.field_metadata['uuid']['rec_index']
|
col = self.db.field_metadata['uuid']['rec_index']
|
||||||
return QVariant(_('This book\'s UUID is "{0}"').format(self.db.data[section][col]))
|
return QVariant(_('This book\'s UUID is "{0}"').format(self.db.data[section][col]))
|
||||||
|
|
||||||
if role == Qt.DisplayRole: # orientation is vertical
|
if role == Qt.DisplayRole: # orientation is vertical
|
||||||
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():
|
||||||
@ -973,7 +981,7 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
tmpl = unicode(value.toString()).strip()
|
tmpl = unicode(value.toString()).strip()
|
||||||
disp = cc['display']
|
disp = cc['display']
|
||||||
disp['composite_template'] = tmpl
|
disp['composite_template'] = tmpl
|
||||||
self.db.set_custom_column_metadata(cc['colnum'], display = disp)
|
self.db.set_custom_column_metadata(cc['colnum'], display=disp)
|
||||||
self.refresh(reset=True)
|
self.refresh(reset=True)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -991,7 +999,7 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
return self._set_data(index, value)
|
return self._set_data(index, value)
|
||||||
except (IOError, OSError) as err:
|
except (IOError, OSError) as err:
|
||||||
import traceback
|
import traceback
|
||||||
if getattr(err, 'errno', None) == errno.EACCES: # Permission denied
|
if getattr(err, 'errno', None) == errno.EACCES: # Permission denied
|
||||||
fname = getattr(err, 'filename', None)
|
fname = getattr(err, 'filename', None)
|
||||||
p = 'Locked file: %s\n\n'%fname if fname else ''
|
p = 'Locked file: %s\n\n'%fname if fname else ''
|
||||||
error_dialog(get_gui(), _('Permission denied'),
|
error_dialog(get_gui(), _('Permission denied'),
|
||||||
@ -1069,7 +1077,7 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class OnDeviceSearch(SearchQueryParser): # {{{
|
class OnDeviceSearch(SearchQueryParser): # {{{
|
||||||
|
|
||||||
USABLE_LOCATIONS = [
|
USABLE_LOCATIONS = [
|
||||||
'all',
|
'all',
|
||||||
@ -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:
|
||||||
@ -1152,13 +1159,13 @@ class OnDeviceSearch(SearchQueryParser): # {{{
|
|||||||
if _match(query, vals, m, use_primary_find_in_search=upf):
|
if _match(query, vals, m, use_primary_find_in_search=upf):
|
||||||
matches.add(index)
|
matches.add(index)
|
||||||
break
|
break
|
||||||
except ValueError: # Unicode errors
|
except ValueError: # Unicode errors
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return matches
|
return matches
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class DeviceDBSortKeyGen(object): # {{{
|
class DeviceDBSortKeyGen(object): # {{{
|
||||||
|
|
||||||
def __init__(self, attr, keyfunc, db):
|
def __init__(self, attr, keyfunc, db):
|
||||||
self.attr = attr
|
self.attr = attr
|
||||||
@ -1173,7 +1180,7 @@ class DeviceDBSortKeyGen(object): # {{{
|
|||||||
return ans
|
return ans
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class DeviceBooksModel(BooksModel): # {{{
|
class DeviceBooksModel(BooksModel): # {{{
|
||||||
|
|
||||||
booklist_dirtied = pyqtSignal()
|
booklist_dirtied = pyqtSignal()
|
||||||
upload_collections = pyqtSignal(object)
|
upload_collections = pyqtSignal(object)
|
||||||
@ -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]]
|
||||||
@ -1436,7 +1453,7 @@ class DeviceBooksModel(BooksModel): # {{{
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
def paths(self, rows):
|
def paths(self, rows):
|
||||||
return [self.db[self.map[r.row()]].path for r in rows ]
|
return [self.db[self.map[r.row()]].path for r in rows]
|
||||||
|
|
||||||
def paths_for_db_ids(self, db_ids, as_map=False):
|
def paths_for_db_ids(self, db_ids, as_map=False):
|
||||||
res = defaultdict(list) if as_map else []
|
res = defaultdict(list) if as_map else []
|
||||||
@ -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'):
|
||||||
|
@ -24,7 +24,7 @@ from calibre.gui2.dnd import (dnd_has_image, dnd_get_image, dnd_get_files,
|
|||||||
|
|
||||||
history = XMLConfig('history')
|
history = XMLConfig('history')
|
||||||
|
|
||||||
class ProgressIndicator(QWidget): # {{{
|
class ProgressIndicator(QWidget): # {{{
|
||||||
|
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
QWidget.__init__(self, *args)
|
QWidget.__init__(self, *args)
|
||||||
@ -57,7 +57,7 @@ class ProgressIndicator(QWidget): # {{{
|
|||||||
self.setVisible(False)
|
self.setVisible(False)
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class FilenamePattern(QWidget, Ui_Form): # {{{
|
class FilenamePattern(QWidget, Ui_Form): # {{{
|
||||||
|
|
||||||
changed_signal = pyqtSignal()
|
changed_signal = pyqtSignal()
|
||||||
|
|
||||||
@ -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)
|
||||||
@ -157,7 +157,7 @@ class FilenamePattern(QWidget, Ui_Form): # {{{
|
|||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class FormatList(QListWidget): # {{{
|
class FormatList(QListWidget): # {{{
|
||||||
DROPABBLE_EXTENSIONS = BOOK_EXTENSIONS
|
DROPABBLE_EXTENSIONS = BOOK_EXTENSIONS
|
||||||
formats_dropped = pyqtSignal(object, object)
|
formats_dropped = pyqtSignal(object, object)
|
||||||
delete_format = pyqtSignal()
|
delete_format = pyqtSignal()
|
||||||
@ -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()
|
||||||
|
|
||||||
@ -198,7 +197,7 @@ class FormatList(QListWidget): # {{{
|
|||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class ImageDropMixin(object): # {{{
|
class ImageDropMixin(object): # {{{
|
||||||
'''
|
'''
|
||||||
Adds support for dropping images onto widgets and a context menu for
|
Adds support for dropping images onto widgets and a context menu for
|
||||||
copy/pasting images.
|
copy/pasting images.
|
||||||
@ -272,7 +271,7 @@ class ImageDropMixin(object): # {{{
|
|||||||
pixmap_to_data(pmap))
|
pixmap_to_data(pmap))
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class ImageView(QWidget, ImageDropMixin): # {{{
|
class ImageView(QWidget, ImageDropMixin): # {{{
|
||||||
|
|
||||||
BORDER_WIDTH = 1
|
BORDER_WIDTH = 1
|
||||||
cover_changed = pyqtSignal(object)
|
cover_changed = pyqtSignal(object)
|
||||||
@ -338,7 +337,7 @@ class ImageView(QWidget, ImageDropMixin): # {{{
|
|||||||
p.end()
|
p.end()
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class CoverView(QGraphicsView, ImageDropMixin): # {{{
|
class CoverView(QGraphicsView, ImageDropMixin): # {{{
|
||||||
|
|
||||||
cover_changed = pyqtSignal(object)
|
cover_changed = pyqtSignal(object)
|
||||||
|
|
||||||
@ -393,7 +392,7 @@ class BasicList(QListWidget):
|
|||||||
yield self.item(i)
|
yield self.item(i)
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class LineEditECM(object): # {{{
|
class LineEditECM(object): # {{{
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Extend the context menu of a QLineEdit to include more actions.
|
Extend the context menu of a QLineEdit to include more actions.
|
||||||
@ -438,7 +437,7 @@ class LineEditECM(object): # {{{
|
|||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class EnLineEdit(LineEditECM, QLineEdit): # {{{
|
class EnLineEdit(LineEditECM, QLineEdit): # {{{
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Enhanced QLineEdit.
|
Enhanced QLineEdit.
|
||||||
@ -449,7 +448,7 @@ class EnLineEdit(LineEditECM, QLineEdit): # {{{
|
|||||||
pass
|
pass
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class ItemsCompleter(QCompleter): # {{{
|
class ItemsCompleter(QCompleter): # {{{
|
||||||
|
|
||||||
'''
|
'''
|
||||||
A completer object that completes a list of tags. It is used in conjunction
|
A completer object that completes a list of tags. It is used in conjunction
|
||||||
@ -541,7 +540,7 @@ class CompleteLineEdit(EnLineEdit): # {{{
|
|||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class EnComboBox(QComboBox): # {{{
|
class EnComboBox(QComboBox): # {{{
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Enhanced QComboBox.
|
Enhanced QComboBox.
|
||||||
@ -567,7 +566,7 @@ class EnComboBox(QComboBox): # {{{
|
|||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class CompleteComboBox(EnComboBox): # {{{
|
class CompleteComboBox(EnComboBox): # {{{
|
||||||
|
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
EnComboBox.__init__(self, *args)
|
EnComboBox.__init__(self, *args)
|
||||||
@ -584,7 +583,7 @@ class CompleteComboBox(EnComboBox): # {{{
|
|||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class HistoryLineEdit(QComboBox): # {{{
|
class HistoryLineEdit(QComboBox): # {{{
|
||||||
|
|
||||||
lost_focus = pyqtSignal()
|
lost_focus = pyqtSignal()
|
||||||
|
|
||||||
@ -637,7 +636,7 @@ class HistoryLineEdit(QComboBox): # {{{
|
|||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class ComboBoxWithHelp(QComboBox): # {{{
|
class ComboBoxWithHelp(QComboBox): # {{{
|
||||||
'''
|
'''
|
||||||
A combobox where item 0 is help text. CurrentText will return '' for item 0.
|
A combobox where item 0 is help text. CurrentText will return '' for item 0.
|
||||||
Be sure to always fetch the text with currentText. Don't use the signals
|
Be sure to always fetch the text with currentText. Don't use the signals
|
||||||
@ -686,7 +685,7 @@ class ComboBoxWithHelp(QComboBox): # {{{
|
|||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class EncodingComboBox(QComboBox): # {{{
|
class EncodingComboBox(QComboBox): # {{{
|
||||||
'''
|
'''
|
||||||
A combobox that holds text encodings support
|
A combobox that holds text encodings support
|
||||||
by Python. This is only populated with the most
|
by Python. This is only populated with the most
|
||||||
@ -711,7 +710,7 @@ class EncodingComboBox(QComboBox): # {{{
|
|||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class PythonHighlighter(QSyntaxHighlighter): # {{{
|
class PythonHighlighter(QSyntaxHighlighter): # {{{
|
||||||
|
|
||||||
Rules = []
|
Rules = []
|
||||||
Formats = {}
|
Formats = {}
|
||||||
@ -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)
|
||||||
|
|
||||||
@ -861,7 +856,7 @@ class PythonHighlighter(QSyntaxHighlighter): # {{{
|
|||||||
|
|
||||||
# Slow but good quality highlighting for comments. For more
|
# Slow but good quality highlighting for comments. For more
|
||||||
# speed, comment this out and add the following to __init__:
|
# speed, comment this out and add the following to __init__:
|
||||||
# PythonHighlighter.Rules.append((QRegExp(r"#.*"), "comment"))
|
# PythonHighlighter.Rules.append((QRegExp(r"#.*"), "comment"))
|
||||||
if text.isEmpty():
|
if text.isEmpty():
|
||||||
pass
|
pass
|
||||||
elif text[0] == "#":
|
elif text[0] == "#":
|
||||||
@ -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