Merge from trunk

This commit is contained in:
Charles Haley 2012-06-14 15:27:09 +02:00
commit 13dbc7db42
17 changed files with 505 additions and 315 deletions

View File

@ -172,7 +172,7 @@ You can see the ``prefs`` object being used in main.py:
:pyobject: DemoDialog.config :pyobject: DemoDialog.config
The different types of plugins The plugin API
-------------------------------- --------------------------------
As you may have noticed above, a plugin in |app| is a class. There are different classes for the different types of plugins in |app|. As you may have noticed above, a plugin in |app| is a class. There are different classes for the different types of plugins in |app|.

View File

@ -4,6 +4,7 @@ __copyright__ = '2012, Darko Miletic <darko.miletic at gmail.com>'
www.csmonitor.com www.csmonitor.com
''' '''
import re
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
class CSMonitor(BasicNewsRecipe): class CSMonitor(BasicNewsRecipe):
@ -40,13 +41,15 @@ class CSMonitor(BasicNewsRecipe):
remove_tags = [ remove_tags = [
dict(name=['meta','link','iframe','object','embed']) dict(name=['meta','link','iframe','object','embed'])
,dict(attrs={'class':['podStoryRel','bottom-rel','hide']}) ,dict(attrs={'class':re.compile('(^|| )podStoryRel($|| )', re.DOTALL)})
,dict(attrs={'class':['bottom-rel','hide']})
,dict(attrs={'id':['pgallerycarousel_enlarge','pgallerycarousel_related']}) ,dict(attrs={'id':['pgallerycarousel_enlarge','pgallerycarousel_related']})
] ]
keep_only_tags = [ keep_only_tags = [
dict(name='h1', attrs={'class':'head'}) dict(name='h1', attrs={'class':'head'})
,dict(name='h2', attrs={'class':'subhead'}) ,dict(name='h2', attrs={'class':'subhead'})
,dict(attrs={'class':['sByline','podStoryGal','ui-body-header','sBody']}) ,dict(attrs={'class':['sByline','thePhoto','ui-body-header']})
,dict(attrs={'class':re.compile('(^|| )sBody($|| )', re.DOTALL)})
] ]
remove_attributes=['xmlns:fb'] remove_attributes=['xmlns:fb']
@ -74,10 +77,10 @@ class CSMonitor(BasicNewsRecipe):
if nexttag: if nexttag:
nurl = 'http://www.csmonitor.com' + nexttag['href'] nurl = 'http://www.csmonitor.com' + nexttag['href']
soup2 = self.index_to_soup(nurl) soup2 = self.index_to_soup(nurl)
texttag = soup2.find(attrs={'class':'sBody'}) texttag = soup2.find(attrs={'class':re.compile('(^|| )sBody($|| )', re.DOTALL)})
if texttag: if texttag:
appendtag = soup.find(attrs={'class':'sBody'}) appendtag = soup.find(attrs={'class':re.compile('(^|| )sBody($|| )', re.DOTALL)})
for citem in texttag.findAll(attrs={'class':['podStoryRel','bottom-rel','hide']}): for citem in texttag.findAll(attrs={'class':[re.compile('(^|| )podStoryRel($|| )', re.DOTALL),'bottom-rel','hide']}):
citem.extract() citem.extract()
self.append_page(soup2) self.append_page(soup2)
texttag.extract() texttag.extract()

View File

@ -15,7 +15,7 @@ function show_reference_panel(ref) {
panel = $("#calibre_reference_panel"); panel = $("#calibre_reference_panel");
} }
$("> p", panel).text(ref); $("> p", panel).text(ref);
panel.css({top:(window.pageYOffset+20)+"px"}); panel.css({top:(window.pageYOffset+20)+"px", left:(window.pageXOffset+20)+"px"});
panel.fadeIn(500); panel.fadeIn(500);
} }

View File

@ -1177,6 +1177,16 @@ class StoreAmazonKindleStore(StoreBase):
formats = ['KINDLE'] formats = ['KINDLE']
affiliate = True affiliate = True
class StoreSonyStore(StoreBase):
name = 'SONY Reader Store'
description = u'SONY Reader books.'
author = 'Kovid Goyal'
actual_plugin = 'calibre.gui2.store.stores.sony_plugin:SonyStore'
headquarters = 'US'
formats = ['SONY']
affiliate = False
class StoreAmazonDEKindleStore(StoreBase): class StoreAmazonDEKindleStore(StoreBase):
name = 'Amazon DE Kindle' name = 'Amazon DE Kindle'
author = 'Charles Haley' author = 'Charles Haley'
@ -1623,7 +1633,7 @@ plugins += [
StoreAmazonITKindleStore, StoreAmazonITKindleStore,
StoreAmazonUKKindleStore, StoreAmazonUKKindleStore,
StoreBaenWebScriptionStore, StoreBaenWebScriptionStore,
StoreBNStore, StoreBNStore, StoreSonyStore,
StoreBeamEBooksDEStore, StoreBeamEBooksDEStore,
StoreBeWriteStore, StoreBeWriteStore,
StoreBiblioStore, StoreBiblioStore,

View File

@ -101,8 +101,6 @@ class AppleOpenFeedback(OpenFeedback):
return Dialog(parent, self) return Dialog(parent, self)
class DriverBase(DeviceConfig, DevicePlugin): class DriverBase(DeviceConfig, DevicePlugin):
# Needed for config_widget to work # Needed for config_widget to work
FORMATS = ['epub', 'pdf'] FORMATS = ['epub', 'pdf']
@ -212,6 +210,15 @@ class ITUNES(DriverBase):
"Unsupported direct connect mode. " "Unsupported direct connect mode. "
"See http://www.mobileread.com/forums/showthread.php?t=118559 " "See http://www.mobileread.com/forums/showthread.php?t=118559 "
"for instructions on using 'Connect to iTunes'") "for instructions on using 'Connect to iTunes'")
ITUNES_SANDBOX_LOCKOUT_MESSAGE = _(
'<p>Unable to communicate with iTunes.</p>'
"<p>As of iTunes version 10.6.3, application 'sandboxing' "
'was implemented by Apple, disabling inter-application communications '
'between iTunes and third-party applications.</p>'
'<p>Refer to the forum post '
'<a href="http://www.mobileread.com/forums/showpost.php?p=2113958&postcount=3">Apple implements sandboxing for iTunes 10.6.3</a> '
'for more information.</p>'
'<p></p>')
# Product IDs: # Product IDs:
# 0x1291 iPod Touch # 0x1291 iPod Touch
@ -840,6 +847,9 @@ class ITUNES(DriverBase):
we need to talk to iTunes to discover if there's a connected iPod we need to talk to iTunes to discover if there's a connected iPod
''' '''
if self.iTunes is None:
raise OpenFeedback(self.ITUNES_SANDBOX_LOCKOUT_MESSAGE)
if DEBUG: if DEBUG:
logger().info("ITUNES.open(connected_device: %s)" % repr(connected_device)) logger().info("ITUNES.open(connected_device: %s)" % repr(connected_device))
@ -2372,6 +2382,21 @@ class ITUNES(DriverBase):
self.iTunes = appscript.app('iTunes') self.iTunes = appscript.app('iTunes')
self.initial_status = 'already running' self.initial_status = 'already running'
'''
Test OSA. If we can't get the app name, we can't talk to iTunes.
As of iTunes 10.6.3 (June 2012), sandboxing was implemented disabling OSA
interapp communications.
If unable to communicate with iTunes, set self.iTunes to None, then
report to user in open()
'''
try:
foo = self.iTunes.name()
except:
self.iTunes = None
if DEBUG:
logger().info(" unable to communicate with iTunes, raising dialog to user")
return
''' '''
# Read the current storage path for iTunes media # Read the current storage path for iTunes media
cmd = "defaults read com.apple.itunes NSNavLastRootDirectory" cmd = "defaults read com.apple.itunes NSNavLastRootDirectory"
@ -3319,6 +3344,9 @@ class ITUNES_ASYNC(ITUNES):
Note that most of the initialization is necessarily performed in can_handle(), as Note that most of the initialization is necessarily performed in can_handle(), as
we need to talk to iTunes to discover if there's a connected iPod we need to talk to iTunes to discover if there's a connected iPod
''' '''
if self.iTunes is None:
raise OpenFeedback(self.ITUNES_SANDBOX_LOCKOUT_MESSAGE)
if DEBUG: if DEBUG:
logger().info("ITUNES_ASYNC.open(connected_device: %s)" % repr(connected_device)) logger().info("ITUNES_ASYNC.open(connected_device: %s)" % repr(connected_device))

View File

@ -53,6 +53,7 @@ class KF8Writer(object):
self.log('\tGenerating KF8 markup...') self.log('\tGenerating KF8 markup...')
self.dup_data() self.dup_data()
self.cleanup_markup()
self.replace_resource_links() self.replace_resource_links()
self.extract_css_into_flows() self.extract_css_into_flows()
self.extract_svg_into_flows() self.extract_svg_into_flows()
@ -89,6 +90,15 @@ class KF8Writer(object):
def data(self, item): def data(self, item):
return self._data_cache.get(item.href, item.data) return self._data_cache.get(item.href, item.data)
def cleanup_markup(self):
for item in self.oeb.spine:
root = self.data(item)
# Remove empty script tags as they are pointless
for tag in XPath('//h:script')(root):
if not tag.text and not tag.get('src', False):
tag.getparent().remove(tag)
def replace_resource_links(self): def replace_resource_links(self):
''' Replace links to resources (raster images/fonts) with pointers to ''' Replace links to resources (raster images/fonts) with pointers to
the MOBI record containing the resource. The pointers are of the form: the MOBI record containing the resource. The pointers are of the form:

View File

@ -33,7 +33,8 @@ aid_able_tags = {'a', 'abbr', 'address', 'article', 'aside', 'audio', 'b',
'video'} 'video'}
_self_closing_pat = re.compile(bytes( _self_closing_pat = re.compile(bytes(
r'<(?P<tag>%s)(?=[\s/])(?P<arg>[^>]*)/>'%('|'.join(aid_able_tags))), r'<(?P<tag>%s)(?=[\s/])(?P<arg>[^>]*)/>'%('|'.join(aid_able_tags|{'script',
'style', 'title', 'head'}))),
re.IGNORECASE) re.IGNORECASE)
def close_self_closing_tags(raw): def close_self_closing_tags(raw):
@ -118,6 +119,7 @@ class Skeleton(object):
def render(self, root): def render(self, root):
raw = tostring(root, xml_declaration=True) raw = tostring(root, xml_declaration=True)
raw = raw.replace(b'<html', bytes('<html xmlns="%s"'%XHTML_NS), 1) raw = raw.replace(b'<html', bytes('<html xmlns="%s"'%XHTML_NS), 1)
raw = close_self_closing_tags(raw)
return raw return raw
def calculate_metrics(self, root): def calculate_metrics(self, root):

View File

@ -73,7 +73,7 @@ class TOCAdder(object):
id, href = oeb.manifest.generate('contents', 'contents.xhtml') id, href = oeb.manifest.generate('contents', 'contents.xhtml')
item = self.generated_item = oeb.manifest.add(id, href, XHTML_MIME, item = self.generated_item = oeb.manifest.add(id, href, XHTML_MIME,
data=root) data=root)
if opts.mobi_toc_at_start == 'end': if self.at_start:
oeb.spine.insert(0, item, linear=True) oeb.spine.insert(0, item, linear=True)
else: else:
oeb.spine.add(item, linear=False) oeb.spine.add(item, linear=False)

View File

@ -106,7 +106,8 @@ gprefs.defaults['auto_add_path'] = None
gprefs.defaults['auto_add_check_for_duplicates'] = False gprefs.defaults['auto_add_check_for_duplicates'] = False
gprefs.defaults['blocked_auto_formats'] = [] gprefs.defaults['blocked_auto_formats'] = []
gprefs.defaults['auto_add_auto_convert'] = True gprefs.defaults['auto_add_auto_convert'] = True
gprefs.defaults['widget_style'] = 'system' gprefs.defaults['ui_style'] = 'calibre' if iswindows or isosx else 'system'
gprefs.defaults['tag_browser_old_look'] = False
# }}} # }}}
NONE = QVariant() #: Null value to return from the data function of item models NONE = QVariant() #: Null value to return from the data function of item models
@ -782,7 +783,7 @@ class Application(QApplication):
font.setStretch(s) font.setStretch(s)
QApplication.setFont(font) QApplication.setFont(font)
if force_calibre_style or gprefs['widget_style'] != 'system': if force_calibre_style or gprefs['ui_style'] != 'system':
self.load_calibre_style() self.load_calibre_style()
else: else:
st = self.style() st = self.style()

View File

@ -25,11 +25,11 @@ class StoreAction(InterfaceAction):
self.qaction.triggered.connect(self.do_search) self.qaction.triggered.connect(self.do_search)
self.store_menu = self.qaction.menu() self.store_menu = self.qaction.menu()
cm = partial(self.create_menu_action, self.store_menu) cm = partial(self.create_menu_action, self.store_menu)
for x, t in [('author', _('author')), ('title', _('title')), for x, t in [('author', _('this author')), ('title', _('this title')),
('book', _('book'))]: ('book', _('this book'))]:
func = getattr(self, 'search_%s'%('author_title' if x == 'book' func = getattr(self, 'search_%s'%('author_title' if x == 'book'
else x)) else x))
ac = cm(x, _('Search for this %s')%t, triggered=func) ac = cm(x, _('Search for %s')%t, triggered=func)
setattr(self, 'action_search_by_'+x, ac) setattr(self, 'action_search_by_'+x, ac)
self.store_menu.addSeparator() self.store_menu.addSeparator()
self.store_list_menu = self.store_menu.addMenu(_('Stores')) self.store_list_menu = self.store_menu.addMenu(_('Stores'))

View File

@ -101,9 +101,10 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
r('gui_layout', config, restart_required=True, choices= r('gui_layout', config, restart_required=True, choices=
[(_('Wide'), 'wide'), (_('Narrow'), 'narrow')]) [(_('Wide'), 'wide'), (_('Narrow'), 'narrow')])
r('widget_style', gprefs, restart_required=True, choices= r('ui_style', gprefs, restart_required=True, choices=
[(_('System default'), 'system'), (_('Calibre style'), [(_('System default'), 'system'), (_('Calibre style'),
'calibre')]) 'calibre')])
r('tag_browser_old_look', gprefs, restart_required=True)
r('cover_flow_queue_length', config, restart_required=True) r('cover_flow_queue_length', config, restart_required=True)

View File

@ -187,12 +187,12 @@
<string>User interface &amp;style (needs restart):</string> <string>User interface &amp;style (needs restart):</string>
</property> </property>
<property name="buddy"> <property name="buddy">
<cstring>opt_widget_style</cstring> <cstring>opt_ui_style</cstring>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1"> <item row="0" column="1">
<widget class="QComboBox" name="opt_widget_style"/> <widget class="QComboBox" name="opt_ui_style"/>
</item> </item>
</layout> </layout>
</widget> </widget>
@ -312,6 +312,18 @@ Manage Authors. You can use the values {author} and
<string>Tag Browser</string> <string>Tag Browser</string>
</attribute> </attribute>
<layout class="QGridLayout" name="gridLayout_10"> <layout class="QGridLayout" name="gridLayout_10">
<item row="3" column="2" colspan="3">
<widget class="MultiCompleteLineEdit" name="opt_categories_using_hierarchy">
<property name="toolTip">
<string>A comma-separated list of categories in which items containing
periods are displayed in the tag browser trees. For example, if
this box contains 'tags' then tags of the form 'Mystery.English'
and 'Mystery.Thriller' will be displayed with English and Thriller
both under 'Mystery'. If 'tags' is not in this box,
then the tags will be displayed each on their own line.</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2"> <item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_9"> <widget class="QLabel" name="label_9">
<property name="text"> <property name="text">
@ -354,6 +366,19 @@ up into subcategories. If the partition method is set to disable, this value is
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="0" colspan="5">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>690</width>
<height>252</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="2"> <item row="1" column="2">
<widget class="QLabel" name="label_8111"> <widget class="QLabel" name="label_8111">
<property name="text"> <property name="text">
@ -396,27 +421,9 @@ a few top-level elements.</string>
</widget> </widget>
</item> </item>
<item row="4" column="0" colspan="5"> <item row="4" column="0" colspan="5">
<spacer name="verticalSpacer_2"> <widget class="QCheckBox" name="opt_tag_browser_old_look">
<property name="orientation"> <property name="text">
<enum>Qt::Vertical</enum> <string>Use &amp;alternating row colors in the Tag Browser</string>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>690</width>
<height>252</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="2" colspan="3">
<widget class="MultiCompleteLineEdit" name="opt_categories_using_hierarchy">
<property name="toolTip">
<string>A comma-separated list of categories in which items containing
periods are displayed in the tag browser trees. For example, if
this box contains 'tags' then tags of the form 'Mystery.English'
and 'Mystery.Thriller' will be displayed with English and Thriller
both under 'Mystery'. If 'tags' is not in this box,
then the tags will be displayed each on their own line.</string>
</property> </property>
</widget> </widget>
</item> </item>

View File

@ -388,3 +388,14 @@ class SearchDialog(QDialog, Ui_Dialog):
self.do_search() self.do_search()
return QDialog.exec_(self) return QDialog.exec_(self)
if __name__ == '__main__':
from calibre.gui2 import Application
from calibre.gui2.preferences.main import init_gui
import sys
app = Application([])
app
gui = init_gui()
s = SearchDialog(gui, query=' '.join(sys.argv[1:]))
s.exec_()

View File

@ -0,0 +1,88 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai
from __future__ import (unicode_literals, division, absolute_import,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import urllib
from contextlib import closing
from lxml import html, etree
from PyQt4.Qt import QUrl
from calibre import browser, url_slash_cleaner
from calibre.gui2 import open_url
from calibre.gui2.store import StorePlugin
from calibre.gui2.store.basic_config import BasicStoreConfig
from calibre.gui2.store.search_result import SearchResult
from calibre.gui2.store.web_store_dialog import WebStoreDialog
class SonyStore(BasicStoreConfig, StorePlugin):
def open(self, parent=None, detail_item=None, external=False):
if detail_item:
if external or self.config.get('open_external', False):
open_url(QUrl(url_slash_cleaner(detail_item)))
else:
d = WebStoreDialog(self.gui, 'http://ebookstore.sony.com', parent, detail_item)
d.setWindowTitle(self.name)
d.set_tags(self.config.get('tags', ''))
d.exec_()
def search(self, query, max_results=10, timeout=60):
url = 'http://ebookstore.sony.com/search?keyword=%s'%urllib.quote_plus(
query)
br = browser()
counter = max_results
with closing(br.open(url, timeout=timeout)) as f:
doc = html.fromstring(f.read())
for item in doc.xpath('//div[contains(@class, "searchResult")]/'
'descendant::li[contains(@class, "hreview")]'):
if counter <= 0:
break
curr = ''.join(item.xpath('descendant::div[@class="pricing"]/descendant::*[@class="currency"]/@title')).strip()
if not curr:
curr = 'USD'
amt = ''.join(item.xpath('descendant::div[@class="pricing"]/descendant::*[@class="amount"]/text()')).strip()
if not amt:
amt = '0'
s = SearchResult()
s.price = curr+' '+amt
title = item.xpath('descendant::h3[@class="item"]')
if not title: continue
title = etree.tostring(title[0], method='text',
encoding=unicode)
if not title: continue
s.title = title.strip()
s.author = ''.join(item.xpath(
'descendant::li[contains(@class, "author")]/'
'a[@class="fn"]/text()')).strip()
if not s.author: continue
detail_url = ''.join(item.xpath('descendant::h3[@class="item"]'
'/descendant::a[@class="fn" and @href]/@href'))
if not detail_url: continue
s.detail_item = detail_url
counter -= 1
cover_url = ''.join(item.xpath(
'descendant::li[@class="coverart"]/'
'descendant::img[@src]/@src'))
if cover_url:
if cover_url.startswith('//'):
cover_url = 'http:' + cover_url
elif cover_url.startswith('/'):
cover_url = 'http://ebookstore.sony.com'+cover_url
s.cover_url = url_slash_cleaner(cover_url)
s.drm = SearchResult.DRM_UNKNOWN
s.formats = 'Sony'
yield s

View File

@ -40,39 +40,35 @@ class VirtualoStore(BasicStoreConfig, StorePlugin):
url = 'http://virtualo.pl/?q=' + urllib.quote(query) + '&f=format_id:4,6,3' url = 'http://virtualo.pl/?q=' + urllib.quote(query) + '&f=format_id:4,6,3'
br = browser() br = browser()
drm_pattern = re.compile("ADE") no_drm_pattern = re.compile("Znak wodny")
counter = max_results counter = max_results
with closing(br.open(url, timeout=timeout)) as f: with closing(br.open(url, timeout=timeout)) as f:
doc = html.fromstring(f.read()) doc = html.fromstring(f.read())
for data in doc.xpath('//div[@id="product_list"]/div/div[@class="column"]'): for data in doc.xpath('//div[@id="content"]//div[@class="list_box list_box_border"]'):
if counter <= 0: if counter <= 0:
break break
id = ''.join(data.xpath('.//table/tr[1]/td[1]/a/@href')) id = ''.join(data.xpath('.//div[@class="list_middle_left"]//a/@href'))
if not id: if not id:
continue continue
price = ''.join(data.xpath('.//span[@class="price"]/text() | .//span[@class="price abbr"]/text()')) price = ''.join(data.xpath('.//span[@class="price"]/text() | .//span[@class="price abbr"]/text()'))
cover_url = ''.join(data.xpath('.//table/tr[1]/td[1]/a/img/@src')) cover_url = ''.join(data.xpath('.//div[@class="list_middle_left"]//a/img/@src'))
title = ''.join(data.xpath('.//div[@class="title"]/a/text()')) title = ''.join(data.xpath('.//div[@class="list_title list_text_left"]/a/text()'))
title = re.sub(r'\ WM', '', title) author = ', '.join(data.xpath('.//div[@class="list_authors list_text_left"]/a/text()'))
author = ', '.join(data.xpath('.//div[@class="authors"]/a/text()')) formats = [ form.split('_')[-1].replace('.png', '') for form in data.xpath('.//div[@style="width:55%;float:left;text-align:left;height:18px;"]//img/@src')]
formats = ', '.join(data.xpath('.//span[@class="format"]/a/text()')) nodrm = no_drm_pattern.search(''.join(data.xpath('.//div[@style="width:45%;float:right;text-align:right;height:18px;"]/div/div/text()')))
formats = re.sub(r'(, )?ONLINE(, )?', '', formats)
drm = drm_pattern.search(formats)
formats = re.sub(r'(, )?ADE(, )?', '', formats)
formats = re.sub(r'\ WM', '', formats)
counter -= 1 counter -= 1
s = SearchResult() s = SearchResult()
s.cover_url = cover_url.split('.jpg')[0] + '.jpg' s.cover_url = cover_url.split('.jpg')[0] + '.jpg'
s.title = title.strip() + ' ' + formats s.title = title.strip()
s.author = author.strip() s.author = author.strip()
s.price = price + '' s.price = price + ''
s.detail_item = 'http://virtualo.pl' + id.strip().split('http://')[0] s.detail_item = 'http://virtualo.pl' + id.strip().split('http://')[0]
s.formats = formats.upper().strip() s.formats = ', '.join(formats).upper()
s.drm = SearchResult.DRM_LOCKED if drm else SearchResult.DRM_UNLOCKED s.drm = SearchResult.DRM_UNLOCKED if nodrm else SearchResult.DRM_UNKNOWN
yield s yield s

View File

@ -22,6 +22,10 @@ from calibre.utils.icu import sort_key
class TagDelegate(QStyledItemDelegate): # {{{ class TagDelegate(QStyledItemDelegate): # {{{
def __init__(self, *args, **kwargs):
QStyledItemDelegate.__init__(self, *args, **kwargs)
self.old_look = gprefs['tag_browser_old_look']
def paint(self, painter, option, index): def paint(self, painter, option, index):
item = index.data(Qt.UserRole).toPyObject() item = index.data(Qt.UserRole).toPyObject()
QStyledItemDelegate.paint(self, painter, option, index) QStyledItemDelegate.paint(self, painter, option, index)
@ -46,7 +50,12 @@ class TagDelegate(QStyledItemDelegate): # {{{
nr = r.adjusted(0, 0, 0, 0) nr = r.adjusted(0, 0, 0, 0)
nr.setBottom(r.bottom()-int(r.height()*(rating/5.0))) nr.setBottom(r.bottom()-int(r.height()*(rating/5.0)))
painter.setClipRect(nr) painter.setClipRect(nr)
painter.fillRect(r, widget.palette().window()) bg = option.palette.window()
if self.old_look:
bg = (option.palette.alternateBase() if
option.features&option.Alternate else
option.palette.base())
painter.fillRect(r, bg)
style.proxy().drawPrimitive(style.PE_PanelItemViewItem, option, style.proxy().drawPrimitive(style.PE_PanelItemViewItem, option,
painter, widget) painter, widget)
painter.setOpacity(0.3) painter.setOpacity(0.3)
@ -108,13 +117,14 @@ class TagsView(QTreeView): # {{{
self._model.user_categories_edited.connect(self.user_categories_edited, self._model.user_categories_edited.connect(self.user_categories_edited,
type=Qt.QueuedConnection) type=Qt.QueuedConnection)
self._model.drag_drop_finished.connect(self.drag_drop_finished) self._model.drag_drop_finished.connect(self.drag_drop_finished)
self.setStyleSheet(''' stylish_tb = '''
QTreeView { QTreeView {
background-color: palette(window); background-color: palette(window);
color: palette(window-text); color: palette(window-text);
border: none; border: none;
} }
'''
self.setStyleSheet('''
QTreeView::item { QTreeView::item {
border: 1px solid transparent; border: 1px solid transparent;
padding-top:0.9ex; padding-top:0.9ex;
@ -126,7 +136,9 @@ class TagsView(QTreeView): # {{{
border: 1px solid #bfcde4; border: 1px solid #bfcde4;
border-radius: 6px; border-radius: 6px;
} }
''') ''' + ('' if gprefs['tag_browser_old_look'] else stylish_tb))
if gprefs['tag_browser_old_look']:
self.setAlternatingRowColors(True)
@property @property
def hidden_categories(self): def hidden_categories(self):

File diff suppressed because it is too large Load Diff