Sync to trunk.

This commit is contained in:
John Schember 2010-01-05 17:51:47 -05:00
commit cc6932ee98
12 changed files with 211 additions and 72 deletions

View File

@ -4,13 +4,14 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
Profile to download CNN Profile to download CNN
''' '''
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
from calibre.ebooks.BeautifulSoup import BeautifulSoup
class CNN(BasicNewsRecipe): class CNN(BasicNewsRecipe):
title = 'CNN' title = 'CNN'
description = 'Global news' description = 'Global news'
timefmt = ' [%d %b %Y]' timefmt = ' [%d %b %Y]'
__author__ = 'Kovid Goyal and Sujata Raman' __author__ = 'Krittika Goyal and Sujata Raman'
language = 'en' language = 'en'
no_stylesheets = True no_stylesheets = True
@ -18,7 +19,8 @@ class CNN(BasicNewsRecipe):
oldest_article = 15 oldest_article = 15
recursions = 1 recursions = 1
match_regexps = [r'http://sportsillustrated.cnn.com/.*/[1-9].html'] match_regexps = [r'http://sportsillustrated.cnn.com/.*/[1-9].html']
max_articles_per_feed = 25
extra_css = ''' extra_css = '''
.cnn_strycntntlft{font-family :Arial,Helvetica,sans-serif;} .cnn_strycntntlft{font-family :Arial,Helvetica,sans-serif;}
h2{font-family :Arial,Helvetica,sans-serif; font-size:x-small} h2{font-family :Arial,Helvetica,sans-serif; font-size:x-small}
@ -44,7 +46,7 @@ class CNN(BasicNewsRecipe):
.cnnInlineT1Caption{font-family :Arial,Helvetica,sans-serif; font-size:x-small;font-weight:bold;} .cnnInlineT1Caption{font-family :Arial,Helvetica,sans-serif; font-size:x-small;font-weight:bold;}
.cnnInlineT1Credit{font-family :Arial,Helvetica,sans-serif; font-size:x-small;color:#333333;} .cnnInlineT1Credit{font-family :Arial,Helvetica,sans-serif; font-size:x-small;color:#333333;}
.col10{color:#5A637E;} .col10{color:#5A637E;}
.cnnInlineRailBulletList{color:black;} .cnnInlineRailBulletList{color:black;}
.cnnLine0{font-family :Arial,Helvetica,sans-serif; color:#666666;font-weight:bold;} .cnnLine0{font-family :Arial,Helvetica,sans-serif; color:#666666;font-weight:bold;}
.cnnTimeStamp{font-family :Arial,Helvetica,sans-serif; font-size:x-small;color:#333333;} .cnnTimeStamp{font-family :Arial,Helvetica,sans-serif; font-size:x-small;color:#333333;}
.galleryhedDek{font-family :Arial,Helvetica,sans-serif; font-size:x-small;color:#575757;} .galleryhedDek{font-family :Arial,Helvetica,sans-serif; font-size:x-small;color:#575757;}
@ -55,31 +57,22 @@ class CNN(BasicNewsRecipe):
.captionname{font-family :Arial,Helvetica,sans-serif; font-size:x-small;color:#575757;} .captionname{font-family :Arial,Helvetica,sans-serif; font-size:x-small;color:#575757;}
inStoryIE{{font-family :Arial,Helvetica,sans-serif; font-size:x-small;} inStoryIE{{font-family :Arial,Helvetica,sans-serif; font-size:x-small;}
''' '''
keep_only_tags = [
dict(name='div', attrs={'class':["cnnWCBoxContent","cnnContent","cnnMainBodySecs","cnn_storyarea","cnn_strycntntlft","cnn_strytmstmp"]}),
dict(name='div', attrs={'id':["contentBody","content"]}),
dict(name='td', attrs={'id':["cnnRecapStory"]}),
dict(name='td', attrs={'class':["cnnBigSideLeft"]}),
]
remove_tags = [
dict(name='div', attrs={'class':["cnnInlineRailSelectList","cnn_strycntntrgt","cnn_strybtntools","cnn_strylctcntr cnn_strylctcqrelt","cnn_strylceclbtn","cnn_stryftsbttm","cnn_strybtmmorebx","storyLink","article-tools clearfix","widget video related-video vList","cnnFooterBox","scrollArrows","boxHeading","cnnInlineMailbag","mainCol_lastBlock","cnn_bookmarks","cnnFooterBox","cnnEndOfStory","cnnInlineSL","cnnStoryHighlights","cnnFooterClick","cnnSnapShotHeader","cnnStoryToolsFooter","cnnWsnr","cnnUGCBox","cnnTopNewsModule","cnnStoryElementBox","cnnStoryPhotoBoxNavigation"]}),
dict(name='span', attrs={'class':["cnnEmbeddedMosLnk"]}),
dict(name='div', attrs={'id':["cnnIncldHlder","articleCommentsContainer","featuredContent","superstarsWidget","shareMenuContainer","rssMenuContainer","storyBrandingBanner","cnnRightCol","siteFeatures","quigo628","rightColumn","clickIncludeBox","cnnHeaderRightCol","cnnSCFontLabel","cnnSnapShotBottomRight","cnnSCFontButtons","rightColumn"]}),
dict(name='p', attrs={'class':["cnnTopics"]}),
dict(name='td', attrs={'class':["cnnRightRail"]}),
dict(name='table', attrs={'class':["cnnTMbox"]}),
dict(name='ul', attrs={'id':["cnnTopNav","cnnBotNav","cnnSBNav"]}),
dict(name='div', attrs={'id':["cnn_ftrcntnt"]})
]
# def print_version(self, url): #remove_tags_before = dict(name='h1', attrs={'class':'heading'})
# return 'http://www.printthis.clickability.com/pt/printThis?clickMap=printThis&fb=Y&url=' + url #remove_tags_after = dict(name='td', attrs={'class':'newptool1'})
remove_tags = [
dict(name='iframe'),
dict(name='div', attrs={'class':['cnnEndOfStory', 'cnnShareThisItem', 'cnn_strylctcntr cnn_strylctcqrelt', 'cnnShareBoxContent', 'cnn_strybtmcntnt', 'cnn_strycntntrgt']}),
dict(name='div', attrs={'id':['IEContainer', 'clickIncludeBox']}),
#dict(name='ul', attrs={'class':'article-tools'}),
#dict(name='ul', attrs={'class':'articleTools'}),
]
feeds = [ feeds = [
('Top News', 'http://rss.cnn.com/rss/cnn_topstories.rss'), ('Top News', 'http://rss.cnn.com/rss/cnn_topstories.rss'),
('World', 'http://rss.cnn.com/rss/cnn_world.rss'), ('World', 'http://rss.cnn.com/rss/cnn_world.rss'),
('U.S.', 'http://rss.cnn.com/rss/cnn_us.rss'), ('U.S.', 'http://rss.cnn.com/rss/cnn_us.rss'),
('Sports', 'http://rss.cnn.com/rss/si_topstories.rss'), #('Sports', 'http://rss.cnn.com/rss/si_topstories.rss'),
('Business', 'http://rss.cnn.com/rss/money_latest.rss'), ('Business', 'http://rss.cnn.com/rss/money_latest.rss'),
('Politics', 'http://rss.cnn.com/rss/cnn_allpolitics.rss'), ('Politics', 'http://rss.cnn.com/rss/cnn_allpolitics.rss'),
('Law', 'http://rss.cnn.com/rss/cnn_law.rss'), ('Law', 'http://rss.cnn.com/rss/cnn_law.rss'),
@ -91,10 +84,15 @@ class CNN(BasicNewsRecipe):
('Offbeat', 'http://rss.cnn.com/rss/cnn_offbeat.rss'), ('Offbeat', 'http://rss.cnn.com/rss/cnn_offbeat.rss'),
('Most Popular', 'http://rss.cnn.com/rss/cnn_mostpopular.rss') ('Most Popular', 'http://rss.cnn.com/rss/cnn_mostpopular.rss')
] ]
def preprocess_html(self, soup): def preprocess_html(self, soup):
story = soup.find(name='div', attrs={'class':'cnnBody_Left'})
for tag in soup.findAll(name=['ul','li']): if story is None:
tag.name = 'div' story = soup.find(name='div', attrs={'id':'cnnContentContainer'})
soup = BeautifulSoup('<html><head><title>t</title></head><body></body></html>')
return soup body = soup.find(name='body')
body.insert(0, story)
else:
soup = BeautifulSoup('<html><head><title>t</title></head><body></body></html>')
body = soup.find(name='body')
body.insert(0, story)
return soup

View File

@ -0,0 +1,93 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
'''
'''
from calibre.web.feeds.recipes import BasicNewsRecipe
class PeopleMag(BasicNewsRecipe):
title = 'People/US Magazine Mashup'
__author__ = 'BrianG'
language = 'en'
description = 'Headlines from People and US Magazine'
no_stylesheets = True
use_embedded_content = False
oldest_article = 2
max_articles_per_feed = 50
extra_css = '''
h1{font-family:verdana,arial,helvetica,sans-serif; font-size: large;}
h2{font-family:verdana,arial,helvetica,sans-serif; font-size: small;}
.body-content{font-family:verdana,arial,helvetica,sans-serif; font-size: small;}
.byline {font-size: small; color: #666666; font-style:italic; }
.lastline {font-size: small; color: #666666; font-style:italic;}
.contact {font-size: small; color: #666666;}
.contact p {font-size: small; color: #666666;}
.photoCaption { font-family:verdana,arial,helvetica,sans-serif; font-size:x-small;}
.photoCredit{ font-family:verdana,arial,helvetica,sans-serif; font-size:x-small; color:#666666;}
.article_timestamp{font-size:x-small; color:#666666;}
a {font-family:verdana,arial,helvetica,sans-serif; font-size: x-small;}
'''
keep_only_tags = [
dict(name='div', attrs={'class': 'panel_news_article_main'}),
dict(name='div', attrs={'class':'article_content'}),
dict(name='div', attrs={'class': 'headline'}),
dict(name='div', attrs={'class': 'post'}),
dict(name='div', attrs={'class': 'packageheadlines'}),
dict(name='div', attrs={'class': 'snap_preview'}),
dict(name='div', attrs={'id': 'articlebody'})
]
remove_tags = [
dict(name='div', attrs={'class':'share_comments'}),
dict(name='p', attrs={'class':'twitter_facebook'}),
dict(name='div', attrs={'class':'share_comments_bottom'}),
dict(name='h2', attrs={'id':'related_content'}),
dict(name='div', attrs={'class':'next_article'}),
dict(name='div', attrs={'class':'prev_article'}),
dict(name='ul', attrs={'id':'sharebar'}),
dict(name='div', attrs={'class':'sharelinkcont'}),
dict(name='div', attrs={'class':'categories'}),
dict(name='ul', attrs={'class':'categories'}),
dict(name='div', attrs={'id':'promo'}),
dict(name='div', attrs={'class':'linksWrapper'}),
dict(name='p', attrs={'class':'tag tvnews'}),
dict(name='p', attrs={'class':'tag movienews'}),
dict(name='p', attrs={'class':'tag musicnews'}),
dict(name='p', attrs={'class':'tag couples'}),
dict(name='p', attrs={'class':'tag gooddeeds'}),
dict(name='p', attrs={'class':'tag weddings'}),
dict(name='p', attrs={'class':'tag health'})
]
feeds = [
('PEOPLE Headlines', 'http://feeds.people.com/people/headlines'),
('US Headlines', 'http://www.usmagazine.com/celebrity_news/rss')
]
def get_article_url(self, article):
ans = article.link
try:
self.log('Looking for full story link in', ans)
soup = self.index_to_soup(ans)
x = soup.find(text="View All")
if x is not None:
ans = ans + '?viewAll=y'
self.log('Found full story link', ans)
except:
pass
return ans
def postprocess_html(self, soup,first):
for tag in soup.findAll(name='div',attrs={'class':"container_ate_qandatitle"}):
tag.extract()
for tag in soup.findAll(name='br'):
tag.extract()
return soup

View File

@ -464,6 +464,7 @@ plugins += [
IREXDR1000, IREXDR1000,
JETBOOK, JETBOOK,
SHINEBOOK, SHINEBOOK,
POCKETBOOK360,
KINDLE, KINDLE,
KINDLE2, KINDLE2,
KINDLE_DX, KINDLE_DX,
@ -479,7 +480,6 @@ plugins += [
ESLICK, ESLICK,
NUUT2, NUUT2,
IRIVER_STORY, IRIVER_STORY,
POCKETBOOK360,
GER2, GER2,
ITALICA, ITALICA,
ECLICTO, ECLICTO,

View File

@ -16,7 +16,6 @@ Windows PNP strings:
''' '''
from calibre.devices.usbms.driver import USBMS from calibre.devices.usbms.driver import USBMS
from calibre.constants import iswindows
class EB600(USBMS): class EB600(USBMS):
@ -88,17 +87,15 @@ class SHINEBOOK(EB600):
@classmethod @classmethod
def can_handle(cls, dev, debug=False): def can_handle(cls, dev, debug=False):
try: return dev[4] == 'ShineBook'
if not iswindows:
return dev[4] == 'ShineBook'
except:
pass
return True
class POCKETBOOK360(EB600): class POCKETBOOK360(EB600):
# Device info on OS X
# (8069L, 5768L, 272L, u'', u'', u'1.00')
name = 'PocketBook 360 Device Interface' name = 'PocketBook 360 Device Interface'
gui_name = 'PocketBook 360' gui_name = 'PocketBook 360'
@ -112,6 +109,10 @@ class POCKETBOOK360(EB600):
OSX_MAIN_MEM = 'Philips Mass Storge Media' OSX_MAIN_MEM = 'Philips Mass Storge Media'
OSX_CARD_A_MEM = 'Philips Mass Storge Media' OSX_CARD_A_MEM = 'Philips Mass Storge Media'
@classmethod
def can_handle(cls, dev, debug=False):
return dev[-1] == '1.00' and not dev[-2] and not dev[-3]
class GER2(EB600): class GER2(EB600):
name = 'Ganaxa GeR2 Device Interface' name = 'Ganaxa GeR2 Device Interface'

View File

@ -56,8 +56,9 @@ class PRS505(CLI, Device):
EBOOK_DIR_MAIN = 'database/media/books' EBOOK_DIR_MAIN = 'database/media/books'
EXTRA_CUSTOMIZATION_MESSAGE = _('Comma separated list of metadata fields ' EXTRA_CUSTOMIZATION_MESSAGE = _('Comma separated list of metadata fields '
'to turn into collections on the device.') 'to turn into collections on the device. Posiibilities include: ')+\
EXTRA_CUSTOMIZATION_DEFAULT = ', '.join(['series', 'tags', 'authors']) 'series, tags, authors'
EXTRA_CUSTOMIZATION_DEFAULT = ', '.join(['series', 'tags'])
def windows_filter_pnp_id(self, pnp_id): def windows_filter_pnp_id(self, pnp_id):
return '_LAUNCHER' in pnp_id return '_LAUNCHER' in pnp_id

View File

@ -529,6 +529,18 @@ class Application(QApplication):
self.load_translations() self.load_translations()
qt_app = self qt_app = self
if islinux:
self.setStyleSheet('''
QToolTip {
border: 2px solid black;
padding: 5px;
border-radius: 10px;
opacity: 200;
background-color: #e1e1ff;
}
''')
def load_translations(self): def load_translations(self):
if self._translator is not None: if self._translator is not None:
self.removeTranslator(self._translator) self.removeTranslator(self._translator)

View File

@ -145,10 +145,8 @@ class Widget(QWidget):
help = help_provider(name) help = help_provider(name)
if not help: continue if not help: continue
g._help = help g._help = help
g.setToolTip('\n'.join(w.wrap(help.replace('<', '&lt;').replace('>', g.setToolTip('\n'.join(w.wrap(help)))
'&gt;')))) g.setWhatsThis('\n'.join(w.wrap(help)))
g.setWhatsThis('\n'.join(w.wrap(help.replace('<', '&lt;').replace('>',
'&gt;'))))
g.__class__.enterEvent = lambda obj, event: self.set_help(getattr(obj, '_help', obj.toolTip())) g.__class__.enterEvent = lambda obj, event: self.set_help(getattr(obj, '_help', obj.toolTip()))

View File

@ -57,7 +57,13 @@ if pictureflow is not None:
return self.model.count() return self.model.count()
def caption(self, index): def caption(self, index):
return self.model.title(index) try:
ans = self.model.title(index)
if not ans:
ans = ''
except:
ans = ''
return ans
def reset(self): def reset(self):
self.emit(SIGNAL('dataChanged()')) self.emit(SIGNAL('dataChanged()'))

View File

@ -177,7 +177,7 @@ class PluginModel(QAbstractItemModel):
ans='%s (%s) %s %s\n%s'%(plugin.name, ver, _('by'), plugin.author, desc) ans='%s (%s) %s %s\n%s'%(plugin.name, ver, _('by'), plugin.author, desc)
c = plugin_customization(plugin) c = plugin_customization(plugin)
if c: if c:
ans += '\nCustomization: '+c ans += _('\nCustomization: ')+c
return QVariant(ans) return QVariant(ans)
if role == Qt.DecorationRole: if role == Qt.DecorationRole:
return self.disabled_icon if is_disabled(plugin) else self.icon return self.disabled_icon if is_disabled(plugin) else self.icon
@ -437,6 +437,8 @@ class ConfigDialog(ResizableDialog, Ui_Dialog):
self.priority_label.setVisible(iswindows) self.priority_label.setVisible(iswindows)
self._plugin_model = PluginModel() self._plugin_model = PluginModel()
self.plugin_view.setModel(self._plugin_model) self.plugin_view.setModel(self._plugin_model)
self.plugin_view.setStyleSheet(
"QTreeView::item { padding-bottom: 10px;}")
self.connect(self.toggle_plugin, SIGNAL('clicked()'), lambda : self.modify_plugin(op='toggle')) self.connect(self.toggle_plugin, SIGNAL('clicked()'), lambda : self.modify_plugin(op='toggle'))
self.connect(self.customize_plugin, SIGNAL('clicked()'), lambda : self.modify_plugin(op='customize')) self.connect(self.customize_plugin, SIGNAL('clicked()'), lambda : self.modify_plugin(op='customize'))
self.connect(self.remove_plugin, SIGNAL('clicked()'), lambda : self.modify_plugin(op='remove')) self.connect(self.remove_plugin, SIGNAL('clicked()'), lambda : self.modify_plugin(op='remove'))

View File

@ -15,7 +15,7 @@
<string>Preferences</string> <string>Preferences</string>
</property> </property>
<property name="windowIcon"> <property name="windowIcon">
<iconset> <iconset resource="../../../../../resources/images.qrc">
<normaloff>:/images/config.svg</normaloff>:/images/config.svg</iconset> <normaloff>:/images/config.svg</normaloff>:/images/config.svg</iconset>
</property> </property>
<layout class="QGridLayout"> <layout class="QGridLayout">
@ -148,7 +148,7 @@
<string>...</string> <string>...</string>
</property> </property>
<property name="icon"> <property name="icon">
<iconset> <iconset resource="../../../../../resources/images.qrc">
<normaloff>:/images/mimetypes/dir.svg</normaloff>:/images/mimetypes/dir.svg</iconset> <normaloff>:/images/mimetypes/dir.svg</normaloff>:/images/mimetypes/dir.svg</iconset>
</property> </property>
</widget> </widget>
@ -285,7 +285,7 @@
<string>...</string> <string>...</string>
</property> </property>
<property name="icon"> <property name="icon">
<iconset> <iconset resource="../../../../../resources/images.qrc">
<normaloff>:/images/arrow-up.svg</normaloff>:/images/arrow-up.svg</iconset> <normaloff>:/images/arrow-up.svg</normaloff>:/images/arrow-up.svg</iconset>
</property> </property>
</widget> </widget>
@ -309,7 +309,7 @@
<string>...</string> <string>...</string>
</property> </property>
<property name="icon"> <property name="icon">
<iconset> <iconset resource="../../../../../resources/images.qrc">
<normaloff>:/images/arrow-down.svg</normaloff>:/images/arrow-down.svg</iconset> <normaloff>:/images/arrow-down.svg</normaloff>:/images/arrow-down.svg</iconset>
</property> </property>
</widget> </widget>
@ -473,7 +473,7 @@
<string>...</string> <string>...</string>
</property> </property>
<property name="icon"> <property name="icon">
<iconset> <iconset resource="../../../../../resources/images.qrc">
<normaloff>:/images/arrow-up.svg</normaloff>:/images/arrow-up.svg</iconset> <normaloff>:/images/arrow-up.svg</normaloff>:/images/arrow-up.svg</iconset>
</property> </property>
</widget> </widget>
@ -497,7 +497,7 @@
<string>...</string> <string>...</string>
</property> </property>
<property name="icon"> <property name="icon">
<iconset> <iconset resource="../../../../../resources/images.qrc">
<normaloff>:/images/arrow-down.svg</normaloff>:/images/arrow-down.svg</iconset> <normaloff>:/images/arrow-down.svg</normaloff>:/images/arrow-down.svg</iconset>
</property> </property>
</widget> </widget>
@ -557,7 +557,7 @@
<string>&amp;Add email</string> <string>&amp;Add email</string>
</property> </property>
<property name="icon"> <property name="icon">
<iconset> <iconset resource="../../../../../resources/images.qrc">
<normaloff>:/images/plus.svg</normaloff>:/images/plus.svg</iconset> <normaloff>:/images/plus.svg</normaloff>:/images/plus.svg</iconset>
</property> </property>
<property name="iconSize"> <property name="iconSize">
@ -584,7 +584,7 @@
<string>&amp;Remove email</string> <string>&amp;Remove email</string>
</property> </property>
<property name="icon"> <property name="icon">
<iconset> <iconset resource="../../../../../resources/images.qrc">
<normaloff>:/images/minus.svg</normaloff>:/images/minus.svg</iconset> <normaloff>:/images/minus.svg</normaloff>:/images/minus.svg</iconset>
</property> </property>
<property name="iconSize"> <property name="iconSize">
@ -907,6 +907,9 @@
</item> </item>
<item> <item>
<widget class="QTreeView" name="plugin_view"> <widget class="QTreeView" name="plugin_view">
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="iconSize"> <property name="iconSize">
<size> <size>
<width>32</width> <width>32</width>
@ -916,6 +919,9 @@
<property name="animated"> <property name="animated">
<bool>true</bool> <bool>true</bool>
</property> </property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="headerHidden"> <property name="headerHidden">
<bool>true</bool> <bool>true</bool>
</property> </property>
@ -973,7 +979,7 @@
<string>...</string> <string>...</string>
</property> </property>
<property name="icon"> <property name="icon">
<iconset> <iconset resource="../../../../../resources/images.qrc">
<normaloff>:/images/document_open.svg</normaloff>:/images/document_open.svg</iconset> <normaloff>:/images/document_open.svg</normaloff>:/images/document_open.svg</iconset>
</property> </property>
</widget> </widget>
@ -1044,7 +1050,7 @@
</customwidget> </customwidget>
</customwidgets> </customwidgets>
<resources> <resources>
<include location="../../../../work/calibre/resources/images.qrc"/> <include location="../../../../../resources/images.qrc"/>
</resources> </resources>
<connections> <connections>
<connection> <connection>

View File

@ -152,9 +152,9 @@ class Delegate(QStyledItemDelegate):
class Shortcuts(QAbstractListModel): class Shortcuts(QAbstractListModel):
TEMPLATE = ''' TEMPLATE = u'''
<p><b>{0}</b><br> <p><b>{0}</b><br>
Keys: <code>{1}</code></p> {2}: <code>{1}</code></p>
''' '''
def __init__(self, shortcuts, config_file_base_name, parent=None): def __init__(self, shortcuts, config_file_base_name, parent=None):
@ -212,7 +212,7 @@ class Shortcuts(QAbstractListModel):
key = self.order[row] key = self.order[row]
if role == Qt.DisplayRole: if role == Qt.DisplayRole:
return QVariant(self.TEMPLATE.format(self.descriptions[key], return QVariant(self.TEMPLATE.format(self.descriptions[key],
_(' or ').join(self.get_shortcuts(key)))) _(' or ').join(self.get_shortcuts(key)), _('Keys')))
if role == Qt.ToolTipRole: if role == Qt.ToolTipRole:
return QVariant(_('Double click to change')) return QVariant(_('Double click to change'))
if role == DEFAULTS: if role == DEFAULTS:

View File

@ -518,6 +518,10 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
########################### Cover Flow ################################ ########################### Cover Flow ################################
self.cover_flow = None self.cover_flow = None
if CoverFlow is not None: if CoverFlow is not None:
self.cf_last_updated_at = None
self.cover_flow_sync_timer = QTimer(self)
self.cover_flow_sync_timer.timeout.connect(self.cover_flow_do_sync)
self.cover_flow_sync_flag = True
text_height = 40 if config['separate_cover_flow'] else 25 text_height = 40 if config['separate_cover_flow'] else 25
ah = available_height() ah = available_height()
cfh = ah-100 cfh = ah-100
@ -528,17 +532,13 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
self.cover_flow.setVisible(False) self.cover_flow.setVisible(False)
if not config['separate_cover_flow']: if not config['separate_cover_flow']:
self.library.layout().addWidget(self.cover_flow) self.library.layout().addWidget(self.cover_flow)
#self.connect(self.cover_flow, SIGNAL('currentChanged(int)'), self.cover_flow.currentChanged.connect(self.sync_listview_to_cf)
# self.sync_cf_to_listview)
#self.connect(self.cover_flow, SIGNAL('itemActivated(int)'),
# self.show_book_info)
self.connect(self.status_bar.cover_flow_button, self.connect(self.status_bar.cover_flow_button,
SIGNAL('toggled(bool)'), self.toggle_cover_flow) SIGNAL('toggled(bool)'), self.toggle_cover_flow)
self.connect(self.cover_flow, SIGNAL('stop()'), self.connect(self.cover_flow, SIGNAL('stop()'),
self.status_bar.cover_flow_button.toggle) self.status_bar.cover_flow_button.toggle)
#QObject.connect(self.library_view.selectionModel(), self.library_view.selectionModel().currentRowChanged.connect(
# SIGNAL('currentRowChanged(QModelIndex, QModelIndex)'), self.sync_cf_to_listview)
# self.sync_cf_to_listview)
self.db_images = DatabaseImages(self.library_view.model()) self.db_images = DatabaseImages(self.library_view.model())
self.cover_flow.setImages(self.db_images) self.cover_flow.setImages(self.db_images)
else: else:
@ -684,7 +684,9 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
self.connect(d, SIGNAL('finished(int)'), self.connect(d, SIGNAL('finished(int)'),
self.uncheck_cover_button) self.uncheck_cover_button)
self.cf_dialog = d self.cf_dialog = d
self.cover_flow_sync_timer.start(500)
else: else:
self.cover_flow_sync_timer.stop()
idx = self.library_view.model().index(self.cover_flow.currentSlide(), 0) idx = self.library_view.model().index(self.cover_flow.currentSlide(), 0)
if idx.isValid(): if idx.isValid():
sm = self.library_view.selectionModel() sm = self.library_view.selectionModel()
@ -705,7 +707,9 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
#self.status_bar.book_info.book_data.setMaximumHeight(100) #self.status_bar.book_info.book_data.setMaximumHeight(100)
#self.status_bar.setMaximumHeight(120) #self.status_bar.setMaximumHeight(120)
self.library_view.scrollTo(self.library_view.currentIndex()) self.library_view.scrollTo(self.library_view.currentIndex())
self.cover_flow_sync_timer.start(500)
else: else:
self.cover_flow_sync_timer.stop()
self.cover_flow.setVisible(False) self.cover_flow.setVisible(False)
idx = self.library_view.model().index(self.cover_flow.currentSlide(), 0) idx = self.library_view.model().index(self.cover_flow.currentSlide(), 0)
if idx.isValid(): if idx.isValid():
@ -731,14 +735,32 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
if view is self.current_view(): if view is self.current_view():
self.search.search_done(ok) self.search.search_done(ok)
def sync_cf_to_listview(self, index, *args): def sync_cf_to_listview(self, current, previous):
if not hasattr(index, 'row') and \ if self.cover_flow_sync_flag and self.cover_flow.isVisible() and \
self.library_view.currentIndex().row() != index: self.cover_flow.currentSlide() != current.row():
index = self.library_view.model().index(index, 0) self.cover_flow.setCurrentSlide(current.row())
self.library_view.setCurrentIndex(index) self.cover_flow_sync_flag = True
if hasattr(index, 'row') and self.cover_flow.isVisible() and \
self.cover_flow.currentSlide() != index.row(): def cover_flow_do_sync(self):
self.cover_flow.setCurrentSlide(index.row()) self.cover_flow_sync_flag = True
try:
if self.cover_flow.isVisible() and self.cf_last_updated_at is not None and \
time.time() - self.cf_last_updated_at > 0.5:
self.cf_last_updated_at = None
row = self.cover_flow.currentSlide()
m = self.library_view.model()
index = m.index(row, 0)
if self.library_view.currentIndex().row() != row and index.isValid():
self.cover_flow_sync_flag = False
sm = self.library_view.selectionModel()
sm.select(index, sm.ClearAndSelect|sm.Rows)
self.library_view.setCurrentIndex(index)
except:
pass
def sync_listview_to_cf(self, row):
self.cf_last_updated_at = time.time()
def another_instance_wants_to_talk(self): def another_instance_wants_to_talk(self):
try: try: