mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Merge from custcol trunk
This commit is contained in:
commit
6f9063705e
@ -18,7 +18,8 @@ class ANDROID(USBMS):
|
|||||||
FORMATS = ['epub', 'pdf']
|
FORMATS = ['epub', 'pdf']
|
||||||
|
|
||||||
VENDOR_ID = {
|
VENDOR_ID = {
|
||||||
0x0bb4 : { 0x0c02 : [0x100], 0x0c01 : [0x100]},
|
# HTC
|
||||||
|
0x0bb4 : { 0x0c02 : [0x100], 0x0c01 : [0x100], 0x0ff9 : [0x0100]},
|
||||||
|
|
||||||
# Motorola
|
# Motorola
|
||||||
0x22b8 : { 0x41d9 : [0x216], 0x2d67 : [0x100], 0x41db : [0x216]},
|
0x22b8 : { 0x41d9 : [0x216], 0x2d67 : [0x100], 0x41db : [0x216]},
|
||||||
|
@ -69,13 +69,15 @@ class PRS505(CLI, Device):
|
|||||||
|
|
||||||
def write_cache(prefix):
|
def write_cache(prefix):
|
||||||
try:
|
try:
|
||||||
cachep = os.path.join(prefix, self.CACHE_XML)
|
cachep = os.path.join(prefix, *(self.CACHE_XML.split('/')))
|
||||||
if not os.path.exists(cachep):
|
if not os.path.exists(cachep):
|
||||||
try:
|
dname = os.path.dirname(cachep)
|
||||||
os.makedirs(os.path.dirname(cachep), mode=0777)
|
if not os.path.exists(dname):
|
||||||
except:
|
try:
|
||||||
time.sleep(5)
|
os.makedirs(dname, mode=0777)
|
||||||
os.makedirs(os.path.dirname(cachep), mode=0777)
|
except:
|
||||||
|
time.sleep(5)
|
||||||
|
os.makedirs(dname, mode=0777)
|
||||||
with open(cachep, 'wb') as f:
|
with open(cachep, 'wb') as f:
|
||||||
f.write(u'''<?xml version="1.0" encoding="UTF-8"?>
|
f.write(u'''<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<cache xmlns="http://www.kinoma.com/FskCache/1">
|
<cache xmlns="http://www.kinoma.com/FskCache/1">
|
||||||
|
@ -1190,7 +1190,8 @@ class Manifest(object):
|
|||||||
if item in self.ids:
|
if item in self.ids:
|
||||||
item = self.ids[item]
|
item = self.ids[item]
|
||||||
del self.ids[item.id]
|
del self.ids[item.id]
|
||||||
del self.hrefs[item.href]
|
if item.href in self.hrefs:
|
||||||
|
del self.hrefs[item.href]
|
||||||
self.items.remove(item)
|
self.items.remove(item)
|
||||||
if item in self.oeb.spine:
|
if item in self.oeb.spine:
|
||||||
self.oeb.spine.remove(item)
|
self.oeb.spine.remove(item)
|
||||||
|
@ -184,11 +184,14 @@ class MessageBox(QMessageBox):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def warning_dialog(parent, title, msg, det_msg='', show=False):
|
def warning_dialog(parent, title, msg, det_msg='', show=False,
|
||||||
|
show_copy_button=True):
|
||||||
d = MessageBox(QMessageBox.Warning, 'WARNING: '+title, msg, QMessageBox.Ok,
|
d = MessageBox(QMessageBox.Warning, 'WARNING: '+title, msg, QMessageBox.Ok,
|
||||||
parent, det_msg)
|
parent, det_msg)
|
||||||
d.setEscapeButton(QMessageBox.Ok)
|
d.setEscapeButton(QMessageBox.Ok)
|
||||||
d.setIconPixmap(QPixmap(I('dialog_warning.svg')))
|
d.setIconPixmap(QPixmap(I('dialog_warning.svg')))
|
||||||
|
if not show_copy_button:
|
||||||
|
d.cb.setVisible(False)
|
||||||
if show:
|
if show:
|
||||||
return d.exec_()
|
return d.exec_()
|
||||||
return d
|
return d
|
||||||
@ -205,11 +208,14 @@ def error_dialog(parent, title, msg, det_msg='', show=False,
|
|||||||
return d.exec_()
|
return d.exec_()
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def question_dialog(parent, title, msg, det_msg=''):
|
def question_dialog(parent, title, msg, det_msg='', show_copy_button=True):
|
||||||
d = MessageBox(QMessageBox.Question, title, msg, QMessageBox.Yes|QMessageBox.No,
|
d = MessageBox(QMessageBox.Question, title, msg, QMessageBox.Yes|QMessageBox.No,
|
||||||
parent, det_msg)
|
parent, det_msg)
|
||||||
d.setIconPixmap(QPixmap(I('dialog_information.svg')))
|
d.setIconPixmap(QPixmap(I('dialog_information.svg')))
|
||||||
d.setEscapeButton(QMessageBox.No)
|
d.setEscapeButton(QMessageBox.No)
|
||||||
|
if not show_copy_button:
|
||||||
|
d.cb.setVisible(False)
|
||||||
|
|
||||||
return d.exec_() == QMessageBox.Yes
|
return d.exec_() == QMessageBox.Yes
|
||||||
|
|
||||||
def info_dialog(parent, title, msg, det_msg='', show=False):
|
def info_dialog(parent, title, msg, det_msg='', show=False):
|
||||||
|
@ -656,7 +656,7 @@ class ConfigDialog(ResizableDialog, Ui_Dialog):
|
|||||||
_('The selected column is not a custom column'), show=True)
|
_('The selected column is not a custom column'), show=True)
|
||||||
if not question_dialog(self, _('Are you sure?'),
|
if not question_dialog(self, _('Are you sure?'),
|
||||||
_('Do you really want to delete column %s and all its data?') %
|
_('Do you really want to delete column %s and all its data?') %
|
||||||
self.custcols[col]['name']):
|
self.custcols[col]['name'], show_copy_button=False):
|
||||||
return
|
return
|
||||||
self.columns.item(idx).setCheckState(False)
|
self.columns.item(idx).setCheckState(False)
|
||||||
self.columns.takeItem(idx)
|
self.columns.takeItem(idx)
|
||||||
@ -831,7 +831,7 @@ class ConfigDialog(ResizableDialog, Ui_Dialog):
|
|||||||
warning_dialog(self, _('Must restart'),
|
warning_dialog(self, _('Must restart'),
|
||||||
_('The changes you made require that Calibre be '
|
_('The changes you made require that Calibre be '
|
||||||
'restarted. Please restart as soon as practical.'),
|
'restarted. Please restart as soon as practical.'),
|
||||||
show=True)
|
show=True, show_copy_button=False)
|
||||||
self.parent.must_restart_before_config = True
|
self.parent.must_restart_before_config = True
|
||||||
QDialog.accept(self)
|
QDialog.accept(self)
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Create a custom column</string>
|
<string>Create or edit custom columns</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item>
|
<item>
|
||||||
@ -126,7 +126,7 @@
|
|||||||
</font>
|
</font>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Create and edit custom columns</string>
|
<string>Create or edit custom columns</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -180,27 +180,34 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
|||||||
self.formats_changed = True
|
self.formats_changed = True
|
||||||
|
|
||||||
def get_selected_format_metadata(self):
|
def get_selected_format_metadata(self):
|
||||||
row = self.formats.currentRow()
|
old = prefs['read_file_metadata']
|
||||||
fmt = self.formats.item(row)
|
if not old:
|
||||||
if fmt is None:
|
prefs['read_file_metadata'] = True
|
||||||
if self.formats.count() == 1:
|
|
||||||
fmt = self.formats.item(0)
|
|
||||||
if fmt is None:
|
|
||||||
error_dialog(self, _('No format selected'),
|
|
||||||
_('No format selected')).exec_()
|
|
||||||
return None, None
|
|
||||||
ext = fmt.ext.lower()
|
|
||||||
if fmt.path is None:
|
|
||||||
stream = self.db.format(self.row, ext, as_file=True)
|
|
||||||
else:
|
|
||||||
stream = open(fmt.path, 'r+b')
|
|
||||||
try:
|
try:
|
||||||
mi = get_metadata(stream, ext)
|
row = self.formats.currentRow()
|
||||||
return mi, ext
|
fmt = self.formats.item(row)
|
||||||
except:
|
if fmt is None:
|
||||||
error_dialog(self, _('Could not read metadata'),
|
if self.formats.count() == 1:
|
||||||
_('Could not read metadata from %s format')%ext).exec_()
|
fmt = self.formats.item(0)
|
||||||
return None, None
|
if fmt is None:
|
||||||
|
error_dialog(self, _('No format selected'),
|
||||||
|
_('No format selected')).exec_()
|
||||||
|
return None, None
|
||||||
|
ext = fmt.ext.lower()
|
||||||
|
if fmt.path is None:
|
||||||
|
stream = self.db.format(self.row, ext, as_file=True)
|
||||||
|
else:
|
||||||
|
stream = open(fmt.path, 'r+b')
|
||||||
|
try:
|
||||||
|
mi = get_metadata(stream, ext)
|
||||||
|
return mi, ext
|
||||||
|
except:
|
||||||
|
error_dialog(self, _('Could not read metadata'),
|
||||||
|
_('Could not read metadata from %s format')%ext).exec_()
|
||||||
|
return None, None
|
||||||
|
finally:
|
||||||
|
if old != prefs['read_file_metadata']:
|
||||||
|
prefs['read_file_metadata'] = old
|
||||||
|
|
||||||
def set_metadata_from_format(self):
|
def set_metadata_from_format(self):
|
||||||
mi, ext = self.get_selected_format_metadata()
|
mi, ext = self.get_selected_format_metadata()
|
||||||
|
@ -150,7 +150,7 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout">
|
<layout class="QHBoxLayout" name="hl234">
|
||||||
<property name="spacing">
|
<property name="spacing">
|
||||||
<number>6</number>
|
<number>6</number>
|
||||||
</property>
|
</property>
|
||||||
@ -288,271 +288,285 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="Splitter" name="vertical_splitter">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
<property name="sizePolicy">
|
<item>
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
<widget class="Splitter" name="vertical_splitter">
|
||||||
<horstretch>0</horstretch>
|
<property name="sizePolicy">
|
||||||
<verstretch>100</verstretch>
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
</sizepolicy>
|
<horstretch>0</horstretch>
|
||||||
</property>
|
<verstretch>100</verstretch>
|
||||||
<property name="orientation">
|
</sizepolicy>
|
||||||
<enum>Qt::Vertical</enum>
|
</property>
|
||||||
</property>
|
<property name="orientation">
|
||||||
<widget class="QStackedWidget" name="stack">
|
<enum>Qt::Vertical</enum>
|
||||||
<property name="sizePolicy">
|
</property>
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
<widget class="QStackedWidget" name="stack">
|
||||||
<horstretch>100</horstretch>
|
<property name="sizePolicy">
|
||||||
<verstretch>100</verstretch>
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
</sizepolicy>
|
<horstretch>100</horstretch>
|
||||||
</property>
|
<verstretch>100</verstretch>
|
||||||
<property name="currentIndex">
|
</sizepolicy>
|
||||||
<number>0</number>
|
</property>
|
||||||
</property>
|
<property name="currentIndex">
|
||||||
<widget class="QWidget" name="library">
|
<number>0</number>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
</property>
|
||||||
<item>
|
<widget class="QWidget" name="library">
|
||||||
<widget class="Splitter" name="horizontal_splitter">
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
<property name="orientation">
|
<item>
|
||||||
<enum>Qt::Horizontal</enum>
|
<widget class="Splitter" name="horizontal_splitter">
|
||||||
</property>
|
<property name="orientation">
|
||||||
<widget class="QWidget" name="layoutWidget">
|
<enum>Qt::Horizontal</enum>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
</property>
|
||||||
<item>
|
<widget class="QWidget" name="layoutWidget">
|
||||||
<widget class="TagsView" name="tags_view">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<property name="tabKeyNavigation">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="alternatingRowColors">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="animated">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="headerHidden">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="popularity">
|
|
||||||
<property name="text">
|
|
||||||
<string>Sort by &popularity</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="QComboBox" name="tag_match">
|
<widget class="TagsView" name="tags_view">
|
||||||
<property name="currentIndex">
|
<property name="tabKeyNavigation">
|
||||||
<number>0</number>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="alternatingRowColors">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="animated">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="headerHidden">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="popularity">
|
||||||
|
<property name="text">
|
||||||
|
<string>Sort by &popularity</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<widget class="QComboBox" name="tag_match">
|
||||||
<string>Match any</string>
|
<property name="currentIndex">
|
||||||
</property>
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Match any</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Match all</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<widget class="QPushButton" name="edit_categories">
|
||||||
<string>Match all</string>
|
<property name="toolTip">
|
||||||
</property>
|
<string>Create, edit, and delete user categories</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Manage &user categories</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</widget>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="edit_categories">
|
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="10,50">
|
||||||
<property name="toolTip">
|
<item>
|
||||||
<string>Create, edit, and delete user categories</string>
|
<widget class="QLabel" name="restriction_label">
|
||||||
</property>
|
<property name="text">
|
||||||
<property name="text">
|
<string>&Restrict to:</string>
|
||||||
<string>Manage &user categories</string>
|
</property>
|
||||||
</property>
|
<property name="buddy">
|
||||||
</widget>
|
<cstring>search_restriction</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="search_restriction">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||||
|
<horstretch>50</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Books display will be restricted to those matching the selected saved search</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</widget>
|
||||||
<item>
|
<widget class="BooksView" name="library_view">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="10,50">
|
<property name="sizePolicy">
|
||||||
<item>
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
<widget class="QLabel" name="restriction_label">
|
<horstretch>100</horstretch>
|
||||||
<property name="text">
|
<verstretch>10</verstretch>
|
||||||
<string>&Restrict to:</string>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="buddy">
|
<property name="acceptDrops">
|
||||||
<cstring>search_restriction</cstring>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
<property name="dragEnabled">
|
||||||
</item>
|
<bool>true</bool>
|
||||||
<item>
|
</property>
|
||||||
<widget class="QComboBox" name="search_restriction">
|
<property name="dragDropOverwriteMode">
|
||||||
<property name="sizePolicy">
|
<bool>false</bool>
|
||||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
</property>
|
||||||
<horstretch>50</horstretch>
|
<property name="dragDropMode">
|
||||||
<verstretch>0</verstretch>
|
<enum>QAbstractItemView::DragDrop</enum>
|
||||||
</sizepolicy>
|
</property>
|
||||||
</property>
|
<property name="alternatingRowColors">
|
||||||
<property name="toolTip">
|
<bool>true</bool>
|
||||||
<string>Books display will be restricted to those matching the selected saved search</string>
|
</property>
|
||||||
</property>
|
<property name="selectionBehavior">
|
||||||
</widget>
|
<enum>QAbstractItemView::SelectRows</enum>
|
||||||
</item>
|
</property>
|
||||||
</layout>
|
<property name="showGrid">
|
||||||
</item>
|
<bool>false</bool>
|
||||||
</layout>
|
</property>
|
||||||
</widget>
|
<property name="wordWrap">
|
||||||
<widget class="BooksView" name="library_view">
|
<bool>false</bool>
|
||||||
<property name="sizePolicy">
|
</property>
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
</widget>
|
||||||
<horstretch>100</horstretch>
|
</widget>
|
||||||
<verstretch>10</verstretch>
|
</item>
|
||||||
</sizepolicy>
|
</layout>
|
||||||
</property>
|
</widget>
|
||||||
<property name="acceptDrops">
|
<widget class="QWidget" name="main_memory">
|
||||||
<bool>true</bool>
|
<layout class="QGridLayout">
|
||||||
</property>
|
<item row="0" column="0">
|
||||||
<property name="dragEnabled">
|
<widget class="DeviceBooksView" name="memory_view">
|
||||||
<bool>true</bool>
|
<property name="sizePolicy">
|
||||||
</property>
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
<property name="dragDropOverwriteMode">
|
<horstretch>100</horstretch>
|
||||||
<bool>false</bool>
|
<verstretch>10</verstretch>
|
||||||
</property>
|
</sizepolicy>
|
||||||
<property name="dragDropMode">
|
</property>
|
||||||
<enum>QAbstractItemView::DragDrop</enum>
|
<property name="acceptDrops">
|
||||||
</property>
|
<bool>true</bool>
|
||||||
<property name="alternatingRowColors">
|
</property>
|
||||||
<bool>true</bool>
|
<property name="dragEnabled">
|
||||||
</property>
|
<bool>true</bool>
|
||||||
<property name="selectionBehavior">
|
</property>
|
||||||
<enum>QAbstractItemView::SelectRows</enum>
|
<property name="dragDropOverwriteMode">
|
||||||
</property>
|
<bool>false</bool>
|
||||||
<property name="showGrid">
|
</property>
|
||||||
<bool>false</bool>
|
<property name="dragDropMode">
|
||||||
</property>
|
<enum>QAbstractItemView::DragDrop</enum>
|
||||||
<property name="wordWrap">
|
</property>
|
||||||
<bool>false</bool>
|
<property name="alternatingRowColors">
|
||||||
</property>
|
<bool>true</bool>
|
||||||
</widget>
|
</property>
|
||||||
</widget>
|
<property name="selectionBehavior">
|
||||||
</item>
|
<enum>QAbstractItemView::SelectRows</enum>
|
||||||
</layout>
|
</property>
|
||||||
|
<property name="showGrid">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="card_a_memory">
|
||||||
|
<layout class="QGridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="DeviceBooksView" name="card_a_view">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||||
|
<horstretch>10</horstretch>
|
||||||
|
<verstretch>10</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="acceptDrops">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="dragEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="dragDropOverwriteMode">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="dragDropMode">
|
||||||
|
<enum>QAbstractItemView::DragDrop</enum>
|
||||||
|
</property>
|
||||||
|
<property name="alternatingRowColors">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="selectionBehavior">
|
||||||
|
<enum>QAbstractItemView::SelectRows</enum>
|
||||||
|
</property>
|
||||||
|
<property name="showGrid">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="card_b_memory">
|
||||||
|
<layout class="QGridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="DeviceBooksView" name="card_b_view">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||||
|
<horstretch>10</horstretch>
|
||||||
|
<verstretch>10</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="acceptDrops">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="dragEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="dragDropOverwriteMode">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="dragDropMode">
|
||||||
|
<enum>QAbstractItemView::DragDrop</enum>
|
||||||
|
</property>
|
||||||
|
<property name="alternatingRowColors">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="selectionBehavior">
|
||||||
|
<enum>QAbstractItemView::SelectRows</enum>
|
||||||
|
</property>
|
||||||
|
<property name="showGrid">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<widget class="StatusBar" name="status_bar" native="true"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="main_memory">
|
</item>
|
||||||
<layout class="QGridLayout">
|
<item>
|
||||||
<item row="0" column="0">
|
<widget class="SideBar" name="sidebar" native="true">
|
||||||
<widget class="DeviceBooksView" name="memory_view">
|
<property name="sizePolicy">
|
||||||
<property name="sizePolicy">
|
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
<horstretch>0</horstretch>
|
||||||
<horstretch>100</horstretch>
|
<verstretch>0</verstretch>
|
||||||
<verstretch>10</verstretch>
|
</sizepolicy>
|
||||||
</sizepolicy>
|
</property>
|
||||||
</property>
|
|
||||||
<property name="acceptDrops">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="dragEnabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="dragDropOverwriteMode">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="dragDropMode">
|
|
||||||
<enum>QAbstractItemView::DragDrop</enum>
|
|
||||||
</property>
|
|
||||||
<property name="alternatingRowColors">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="selectionBehavior">
|
|
||||||
<enum>QAbstractItemView::SelectRows</enum>
|
|
||||||
</property>
|
|
||||||
<property name="showGrid">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="card_a_memory">
|
</item>
|
||||||
<layout class="QGridLayout">
|
</layout>
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="DeviceBooksView" name="card_a_view">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
|
||||||
<horstretch>10</horstretch>
|
|
||||||
<verstretch>10</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="acceptDrops">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="dragEnabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="dragDropOverwriteMode">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="dragDropMode">
|
|
||||||
<enum>QAbstractItemView::DragDrop</enum>
|
|
||||||
</property>
|
|
||||||
<property name="alternatingRowColors">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="selectionBehavior">
|
|
||||||
<enum>QAbstractItemView::SelectRows</enum>
|
|
||||||
</property>
|
|
||||||
<property name="showGrid">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<widget class="QWidget" name="card_b_memory">
|
|
||||||
<layout class="QGridLayout">
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="DeviceBooksView" name="card_b_view">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
|
||||||
<horstretch>10</horstretch>
|
|
||||||
<verstretch>10</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="acceptDrops">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="dragEnabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="dragDropOverwriteMode">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="dragDropMode">
|
|
||||||
<enum>QAbstractItemView::DragDrop</enum>
|
|
||||||
</property>
|
|
||||||
<property name="alternatingRowColors">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="selectionBehavior">
|
|
||||||
<enum>QAbstractItemView::SelectRows</enum>
|
|
||||||
</property>
|
|
||||||
<property name="showGrid">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</widget>
|
|
||||||
<widget class="StatusBar" name="status_bar" native="true"/>
|
|
||||||
</widget>
|
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
@ -832,6 +846,12 @@
|
|||||||
<header>calibre/gui2/widgets.h</header>
|
<header>calibre/gui2/widgets.h</header>
|
||||||
<container>1</container>
|
<container>1</container>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>SideBar</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header>calibre/gui2/sidebar.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="../../../resources/images.qrc"/>
|
<include location="../../../resources/images.qrc"/>
|
||||||
|
235
src/calibre/gui2/sidebar.py
Normal file
235
src/calibre/gui2/sidebar.py
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
import re
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
|
from PyQt4.Qt import QToolBar, Qt, QIcon, QSizePolicy, QWidget, \
|
||||||
|
QFrame, QVBoxLayout, QLabel, QSize, QCoreApplication, QToolButton
|
||||||
|
|
||||||
|
from calibre.gui2.progress_indicator import ProgressIndicator
|
||||||
|
from calibre.gui2 import dynamic
|
||||||
|
|
||||||
|
class JobsButton(QFrame):
|
||||||
|
|
||||||
|
def __init__(self, parent):
|
||||||
|
QFrame.__init__(self, parent)
|
||||||
|
self.setLayout(QVBoxLayout())
|
||||||
|
self.pi = ProgressIndicator(self)
|
||||||
|
self.layout().addWidget(self.pi)
|
||||||
|
self.jobs = QLabel('<b>'+_('Jobs:')+' 0')
|
||||||
|
self.jobs.setAlignment(Qt.AlignHCenter|Qt.AlignBottom)
|
||||||
|
self.layout().addWidget(self.jobs)
|
||||||
|
self.layout().setAlignment(self.jobs, Qt.AlignHCenter)
|
||||||
|
self.jobs.setMargin(0)
|
||||||
|
self.layout().setMargin(0)
|
||||||
|
self.jobs.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
|
||||||
|
self.setCursor(Qt.PointingHandCursor)
|
||||||
|
self.setToolTip(_('Click to see list of active jobs.'))
|
||||||
|
|
||||||
|
def initialize(self, jobs_dialog):
|
||||||
|
self.jobs_dialog = jobs_dialog
|
||||||
|
self.jobs_dialog.jobs_view.restore_column_widths()
|
||||||
|
|
||||||
|
def mouseReleaseEvent(self, event):
|
||||||
|
if self.jobs_dialog.isVisible():
|
||||||
|
self.jobs_dialog.jobs_view.write_settings()
|
||||||
|
self.jobs_dialog.hide()
|
||||||
|
else:
|
||||||
|
self.jobs_dialog.jobs_view.read_settings()
|
||||||
|
self.jobs_dialog.show()
|
||||||
|
self.jobs_dialog.jobs_view.restore_column_widths()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_running(self):
|
||||||
|
return self.pi.isAnimated()
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
self.pi.startAnimation()
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self.pi.stopAnimation()
|
||||||
|
|
||||||
|
|
||||||
|
class Jobs(ProgressIndicator):
|
||||||
|
|
||||||
|
def initialize(self, jobs_dialog):
|
||||||
|
self.jobs_dialog = jobs_dialog
|
||||||
|
|
||||||
|
def mouseClickEvent(self, event):
|
||||||
|
if self.jobs_dialog.isVisible():
|
||||||
|
self.jobs_dialog.jobs_view.write_settings()
|
||||||
|
self.jobs_dialog.hide()
|
||||||
|
else:
|
||||||
|
self.jobs_dialog.jobs_view.read_settings()
|
||||||
|
self.jobs_dialog.show()
|
||||||
|
self.jobs_dialog.jobs_view.restore_column_widths()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_running(self):
|
||||||
|
return self.isAnimated()
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
self.startAnimation()
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self.stopAnimation()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class SideBar(QToolBar):
|
||||||
|
|
||||||
|
toggle_texts = {
|
||||||
|
'book_info' : (_('Show Book Details'), _('Hide Book Details')),
|
||||||
|
'tag_browser' : (_('Show Tag Browser'), _('Hide Tag Browser')),
|
||||||
|
'cover_browser': (_('Show Cover Browser'), _('Hide Cover Browser')),
|
||||||
|
}
|
||||||
|
toggle_icons = {
|
||||||
|
'book_info' : 'book.svg',
|
||||||
|
'tag_browser' : 'tags.svg',
|
||||||
|
'cover_browser': 'cover_flow.svg',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
QToolBar.__init__(self, _('Side bar'), parent)
|
||||||
|
self.setOrientation(Qt.Vertical)
|
||||||
|
self.setMovable(False)
|
||||||
|
self.setFloatable(False)
|
||||||
|
self.setToolButtonStyle(Qt.ToolButtonIconOnly)
|
||||||
|
self.setIconSize(QSize(48, 48))
|
||||||
|
|
||||||
|
for ac in ('book_info', 'tag_browser', 'cover_browser'):
|
||||||
|
action = self.addAction(QIcon(I(self.toggle_icons[ac])),
|
||||||
|
self.toggle_texts[ac][1], getattr(self, '_toggle_'+ac))
|
||||||
|
setattr(self, 'action_toggle_'+ac, action)
|
||||||
|
w = self.widgetForAction(action)
|
||||||
|
w.setCheckable(True)
|
||||||
|
setattr(self, 'show_'+ac, partial(getattr(self, '_toggle_'+ac),
|
||||||
|
show=True))
|
||||||
|
setattr(self, 'hide_'+ac, partial(getattr(self, '_toggle_'+ac),
|
||||||
|
show=False))
|
||||||
|
|
||||||
|
|
||||||
|
self.spacer = QWidget(self)
|
||||||
|
self.spacer.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding)
|
||||||
|
self.addWidget(self.spacer)
|
||||||
|
self.jobs_button = JobsButton(self)
|
||||||
|
self.addWidget(self.jobs_button)
|
||||||
|
|
||||||
|
self.show_cover_browser = partial(self._toggle_cover_browser, show=True)
|
||||||
|
self.hide_cover_browser = partial(self._toggle_cover_browser,
|
||||||
|
show=False)
|
||||||
|
for ch in self.children():
|
||||||
|
if isinstance(ch, QToolButton):
|
||||||
|
ch.setCursor(Qt.PointingHandCursor)
|
||||||
|
|
||||||
|
def initialize(self, jobs_dialog, cover_browser, toggle_cover_browser,
|
||||||
|
cover_browser_error, vertical_splitter, horizontal_splitter):
|
||||||
|
self.jobs_button.initialize(jobs_dialog)
|
||||||
|
self.cover_browser, self.do_toggle_cover_browser = cover_browser, \
|
||||||
|
toggle_cover_browser
|
||||||
|
if self.cover_browser is None:
|
||||||
|
self.action_toggle_cover_browser.setEnabled(False)
|
||||||
|
self.action_toggle_cover_browser.setText(
|
||||||
|
_('Cover browser could not be loaded: ') + cover_browser_error)
|
||||||
|
else:
|
||||||
|
self.cover_browser.stop.connect(self.hide_cover_browser)
|
||||||
|
self._toggle_cover_browser(dynamic.get('cover_flow_visible', False))
|
||||||
|
|
||||||
|
self.horizontal_splitter = horizontal_splitter
|
||||||
|
self.vertical_splitter = vertical_splitter
|
||||||
|
|
||||||
|
tb_state = dynamic.get('tag_browser_state', None)
|
||||||
|
if tb_state is not None:
|
||||||
|
self.horizontal_splitter.restoreState(tb_state)
|
||||||
|
|
||||||
|
bi_state = dynamic.get('book_info_state', None)
|
||||||
|
if bi_state is not None:
|
||||||
|
self.vertical_splitter.restoreState(bi_state)
|
||||||
|
self.horizontal_splitter.initialize()
|
||||||
|
self.vertical_splitter.initialize()
|
||||||
|
self.view_status_changed('book_info', not
|
||||||
|
self.vertical_splitter.is_side_index_hidden)
|
||||||
|
self.view_status_changed('tag_browser', not
|
||||||
|
self.horizontal_splitter.is_side_index_hidden)
|
||||||
|
self.vertical_splitter.state_changed.connect(partial(self.view_status_changed,
|
||||||
|
'book_info'), type=Qt.QueuedConnection)
|
||||||
|
self.horizontal_splitter.state_changed.connect(partial(self.view_status_changed,
|
||||||
|
'tag_browser'), type=Qt.QueuedConnection)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def view_status_changed(self, name, visible):
|
||||||
|
action = getattr(self, 'action_toggle_'+name)
|
||||||
|
texts = self.toggle_texts[name]
|
||||||
|
action.setText(texts[int(visible)])
|
||||||
|
w = self.widgetForAction(action)
|
||||||
|
w.setCheckable(True)
|
||||||
|
w.setChecked(visible)
|
||||||
|
|
||||||
|
def location_changed(self, location):
|
||||||
|
is_lib = location == 'library'
|
||||||
|
for ac in ('cover_browser', 'tag_browser'):
|
||||||
|
ac = getattr(self, 'action_toggle_'+ac)
|
||||||
|
ac.setEnabled(is_lib)
|
||||||
|
self.widgetForAction(ac).setVisible(is_lib)
|
||||||
|
|
||||||
|
def save_state(self):
|
||||||
|
dynamic.set('cover_flow_visible', self.is_cover_browser_visible)
|
||||||
|
dynamic.set('tag_browser_state',
|
||||||
|
str(self.horizontal_splitter.saveState()))
|
||||||
|
dynamic.set('book_info_state',
|
||||||
|
str(self.vertical_splitter.saveState()))
|
||||||
|
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_cover_browser_visible(self):
|
||||||
|
return self.cover_browser is not None and self.cover_browser.isVisible()
|
||||||
|
|
||||||
|
def _toggle_cover_browser(self, show=None):
|
||||||
|
if show is None:
|
||||||
|
show = not self.is_cover_browser_visible
|
||||||
|
self.do_toggle_cover_browser(show)
|
||||||
|
self.view_status_changed('cover_browser', show)
|
||||||
|
|
||||||
|
def external_cover_flow_finished(self, *args):
|
||||||
|
self.view_status_changed('cover_browser', False)
|
||||||
|
|
||||||
|
def _toggle_tag_browser(self, show=None):
|
||||||
|
self.horizontal_splitter.toggle_side_index()
|
||||||
|
|
||||||
|
def _toggle_book_info(self, show=None):
|
||||||
|
self.vertical_splitter.toggle_side_index()
|
||||||
|
|
||||||
|
def jobs(self):
|
||||||
|
src = unicode(self.jobs_button.jobs.text())
|
||||||
|
return int(re.search(r'\d+', src).group())
|
||||||
|
|
||||||
|
def job_added(self, nnum):
|
||||||
|
jobs = self.jobs_button.jobs
|
||||||
|
src = unicode(jobs.text())
|
||||||
|
num = self.jobs()
|
||||||
|
text = src.replace(str(num), str(nnum))
|
||||||
|
jobs.setText(text)
|
||||||
|
self.jobs_button.start()
|
||||||
|
|
||||||
|
def job_done(self, nnum):
|
||||||
|
jobs = self.jobs_button.jobs
|
||||||
|
src = unicode(jobs.text())
|
||||||
|
num = self.jobs()
|
||||||
|
text = src.replace(str(num), str(nnum))
|
||||||
|
jobs.setText(text)
|
||||||
|
if nnum == 0:
|
||||||
|
self.no_more_jobs()
|
||||||
|
|
||||||
|
def no_more_jobs(self):
|
||||||
|
if self.jobs_button.is_running:
|
||||||
|
self.jobs_button.stop()
|
||||||
|
QCoreApplication.instance().alert(self, 5000)
|
||||||
|
|
||||||
|
|
@ -1,15 +1,14 @@
|
|||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
import os, re, collections
|
import os, collections
|
||||||
|
|
||||||
from PyQt4.QtGui import QStatusBar, QLabel, QWidget, QHBoxLayout, QPixmap, \
|
from PyQt4.QtGui import QStatusBar, QLabel, QWidget, QHBoxLayout, QPixmap, \
|
||||||
QVBoxLayout, QSizePolicy, QToolButton, QIcon, QScrollArea, QFrame
|
QSizePolicy, QScrollArea
|
||||||
from PyQt4.QtCore import Qt, QSize, SIGNAL, QCoreApplication, pyqtSignal
|
from PyQt4.QtCore import Qt, QSize, pyqtSignal
|
||||||
|
|
||||||
from calibre import fit_image, preferred_encoding, isosx
|
from calibre import fit_image, preferred_encoding, isosx
|
||||||
from calibre.gui2 import config
|
from calibre.gui2 import config
|
||||||
from calibre.gui2.widgets import IMAGE_EXTENSIONS
|
from calibre.gui2.widgets import IMAGE_EXTENSIONS
|
||||||
from calibre.gui2.progress_indicator import ProgressIndicator
|
|
||||||
from calibre.gui2.notify import get_notifier
|
from calibre.gui2.notify import get_notifier
|
||||||
from calibre.ebooks import BOOK_EXTENSIONS
|
from calibre.ebooks import BOOK_EXTENSIONS
|
||||||
from calibre.library.comments import comments_to_html
|
from calibre.library.comments import comments_to_html
|
||||||
@ -17,6 +16,7 @@ from calibre.library.comments import comments_to_html
|
|||||||
class BookInfoDisplay(QWidget):
|
class BookInfoDisplay(QWidget):
|
||||||
|
|
||||||
DROPABBLE_EXTENSIONS = IMAGE_EXTENSIONS+BOOK_EXTENSIONS
|
DROPABBLE_EXTENSIONS = IMAGE_EXTENSIONS+BOOK_EXTENSIONS
|
||||||
|
files_dropped = pyqtSignal(object, object)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def paths_from_event(cls, event):
|
def paths_from_event(cls, event):
|
||||||
@ -40,8 +40,7 @@ class BookInfoDisplay(QWidget):
|
|||||||
def dropEvent(self, event):
|
def dropEvent(self, event):
|
||||||
paths = self.paths_from_event(event)
|
paths = self.paths_from_event(event)
|
||||||
event.setDropAction(Qt.CopyAction)
|
event.setDropAction(Qt.CopyAction)
|
||||||
self.emit(SIGNAL('files_dropped(PyQt_PyObject, PyQt_PyObject)'), event,
|
self.files_dropped.emit(event, paths)
|
||||||
paths)
|
|
||||||
|
|
||||||
def dragMoveEvent(self, event):
|
def dragMoveEvent(self, event):
|
||||||
event.acceptProposedAction()
|
event.acceptProposedAction()
|
||||||
@ -87,6 +86,9 @@ class BookInfoDisplay(QWidget):
|
|||||||
|
|
||||||
|
|
||||||
class BookDataDisplay(QLabel):
|
class BookDataDisplay(QLabel):
|
||||||
|
|
||||||
|
mr = pyqtSignal(int)
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
QLabel.__init__(self)
|
QLabel.__init__(self)
|
||||||
self.setText('')
|
self.setText('')
|
||||||
@ -94,7 +96,7 @@ class BookInfoDisplay(QWidget):
|
|||||||
self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
|
self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
|
||||||
|
|
||||||
def mouseReleaseEvent(self, ev):
|
def mouseReleaseEvent(self, ev):
|
||||||
self.emit(SIGNAL('mr(int)'), 1)
|
self.mr.emit(1)
|
||||||
|
|
||||||
WEIGHTS = collections.defaultdict(lambda : 100)
|
WEIGHTS = collections.defaultdict(lambda : 100)
|
||||||
WEIGHTS[_('Path')] = 0
|
WEIGHTS[_('Path')] = 0
|
||||||
@ -103,6 +105,8 @@ class BookInfoDisplay(QWidget):
|
|||||||
WEIGHTS[_('Series')] = 2
|
WEIGHTS[_('Series')] = 2
|
||||||
WEIGHTS[_('Tags')] = 3
|
WEIGHTS[_('Tags')] = 3
|
||||||
|
|
||||||
|
show_book_info = pyqtSignal()
|
||||||
|
|
||||||
def __init__(self, clear_message):
|
def __init__(self, clear_message):
|
||||||
QWidget.__init__(self)
|
QWidget.__init__(self)
|
||||||
self.setCursor(Qt.PointingHandCursor)
|
self.setCursor(Qt.PointingHandCursor)
|
||||||
@ -113,14 +117,14 @@ class BookInfoDisplay(QWidget):
|
|||||||
self.cover_display = BookInfoDisplay.BookCoverDisplay()
|
self.cover_display = BookInfoDisplay.BookCoverDisplay()
|
||||||
self._layout.addWidget(self.cover_display)
|
self._layout.addWidget(self.cover_display)
|
||||||
self.book_data = BookInfoDisplay.BookDataDisplay()
|
self.book_data = BookInfoDisplay.BookDataDisplay()
|
||||||
self.connect(self.book_data, SIGNAL('mr(int)'), self.mouseReleaseEvent)
|
self.book_data.mr.connect(self.mouseReleaseEvent)
|
||||||
self._layout.addWidget(self.book_data)
|
self._layout.addWidget(self.book_data)
|
||||||
self.data = {}
|
self.data = {}
|
||||||
self.setVisible(False)
|
self.setVisible(False)
|
||||||
self._layout.setAlignment(self.cover_display, Qt.AlignTop|Qt.AlignLeft)
|
self._layout.setAlignment(self.cover_display, Qt.AlignTop|Qt.AlignLeft)
|
||||||
|
|
||||||
def mouseReleaseEvent(self, ev):
|
def mouseReleaseEvent(self, ev):
|
||||||
self.emit(SIGNAL('show_book_info()'))
|
self.show_book_info.emit()
|
||||||
|
|
||||||
def show_data(self, data):
|
def show_data(self, data):
|
||||||
if data.has_key('cover'):
|
if data.has_key('cover'):
|
||||||
@ -128,7 +132,7 @@ class BookInfoDisplay(QWidget):
|
|||||||
else:
|
else:
|
||||||
self.cover_display.setPixmap(self.cover_display.default_pixmap)
|
self.cover_display.setPixmap(self.cover_display.default_pixmap)
|
||||||
|
|
||||||
rows = u''
|
rows, comments = [], ''
|
||||||
self.book_data.setText('')
|
self.book_data.setText('')
|
||||||
self.data = data.copy()
|
self.data = data.copy()
|
||||||
keys = data.keys()
|
keys = data.keys()
|
||||||
@ -142,97 +146,43 @@ class BookInfoDisplay(QWidget):
|
|||||||
if isinstance(txt, str):
|
if isinstance(txt, str):
|
||||||
txt = txt.decode(preferred_encoding, 'replace')
|
txt = txt.decode(preferred_encoding, 'replace')
|
||||||
if key == _('Comments'):
|
if key == _('Comments'):
|
||||||
txt = comments_to_html(txt)
|
comments = comments_to_html(txt)
|
||||||
rows += u'<tr><td><b>%s:</b></td><td>%s</td></tr>'%(key, txt)
|
else:
|
||||||
self.book_data.setText(u'<table>'+rows+u'</table>')
|
rows.append((key, txt))
|
||||||
|
rows = '\n'.join([u'<tr><td valign="top"><b>%s:</b></td><td valign="top">%s</td></tr>'%(k,t) for
|
||||||
|
k, t in rows])
|
||||||
|
if comments:
|
||||||
|
comments = '<b>Comments:</b>'+comments
|
||||||
|
left_pane = u'<table>%s</table>'%rows
|
||||||
|
right_pane = u'<div>%s</div>'%comments
|
||||||
|
self.book_data.setText(u'<table><tr><td valign="top" '
|
||||||
|
'style="padding-right:2em">%s</td><td valign="top">%s</td></tr></table>'
|
||||||
|
% (left_pane, right_pane))
|
||||||
|
|
||||||
self.clear_message()
|
self.clear_message()
|
||||||
self.book_data.updateGeometry()
|
self.book_data.updateGeometry()
|
||||||
self.updateGeometry()
|
self.updateGeometry()
|
||||||
self.setVisible(True)
|
self.setVisible(True)
|
||||||
|
|
||||||
class MovieButton(QFrame):
|
|
||||||
|
|
||||||
def __init__(self, jobs_dialog):
|
|
||||||
QFrame.__init__(self)
|
|
||||||
self.setLayout(QVBoxLayout())
|
|
||||||
self.pi = ProgressIndicator(self)
|
|
||||||
self.layout().addWidget(self.pi)
|
|
||||||
self.jobs = QLabel('<b>'+_('Jobs:')+' 0')
|
|
||||||
self.jobs.setAlignment(Qt.AlignHCenter|Qt.AlignBottom)
|
|
||||||
self.layout().addWidget(self.jobs)
|
|
||||||
self.layout().setAlignment(self.jobs, Qt.AlignHCenter)
|
|
||||||
self.jobs.setMargin(0)
|
|
||||||
self.layout().setMargin(0)
|
|
||||||
self.jobs.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
|
|
||||||
self.jobs_dialog = jobs_dialog
|
|
||||||
self.setCursor(Qt.PointingHandCursor)
|
|
||||||
self.setToolTip(_('Click to see list of active jobs.'))
|
|
||||||
self.jobs_dialog.jobs_view.restore_column_widths()
|
|
||||||
|
|
||||||
def mouseReleaseEvent(self, event):
|
|
||||||
if self.jobs_dialog.isVisible():
|
|
||||||
self.jobs_dialog.jobs_view.write_settings()
|
|
||||||
self.jobs_dialog.hide()
|
|
||||||
else:
|
|
||||||
self.jobs_dialog.jobs_view.read_settings()
|
|
||||||
self.jobs_dialog.show()
|
|
||||||
self.jobs_dialog.jobs_view.restore_column_widths()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_running(self):
|
|
||||||
return self.pi.isAnimated()
|
|
||||||
|
|
||||||
def start(self):
|
|
||||||
self.pi.startAnimation()
|
|
||||||
|
|
||||||
def stop(self):
|
|
||||||
self.pi.stopAnimation()
|
|
||||||
|
|
||||||
|
|
||||||
class CoverFlowButton(QToolButton):
|
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
|
||||||
QToolButton.__init__(self, parent)
|
|
||||||
self.setIconSize(QSize(80, 80))
|
|
||||||
self.setIcon(QIcon(I('cover_flow.svg')))
|
|
||||||
self.setCheckable(True)
|
|
||||||
self.setChecked(False)
|
|
||||||
self.setAutoRaise(True)
|
|
||||||
self.setSizePolicy(QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding))
|
|
||||||
self.connect(self, SIGNAL('toggled(bool)'), self.adjust_tooltip)
|
|
||||||
self.adjust_tooltip(False)
|
|
||||||
self.setCursor(Qt.PointingHandCursor)
|
|
||||||
|
|
||||||
def adjust_tooltip(self, on):
|
|
||||||
tt = _('Click to turn off Cover Browsing') if on else _('Click to browse books by their covers')
|
|
||||||
self.setToolTip(tt)
|
|
||||||
|
|
||||||
def disable(self, reason):
|
|
||||||
self.setDisabled(True)
|
|
||||||
self.setToolTip(_('<p>Browsing books by their covers is disabled.<br>Import of pictureflow module failed:<br>')+reason)
|
|
||||||
|
|
||||||
|
|
||||||
class StatusBar(QStatusBar):
|
class StatusBar(QStatusBar):
|
||||||
|
|
||||||
resized = pyqtSignal(object)
|
resized = pyqtSignal(object)
|
||||||
|
files_dropped = pyqtSignal(object, object)
|
||||||
|
show_book_info = pyqtSignal()
|
||||||
|
|
||||||
def initialize(self, jobs_dialog, systray=None):
|
def initialize(self, systray=None):
|
||||||
self.systray = systray
|
self.systray = systray
|
||||||
self.notifier = get_notifier(systray)
|
self.notifier = get_notifier(systray)
|
||||||
self.movie_button = MovieButton(jobs_dialog)
|
|
||||||
self.cover_flow_button = CoverFlowButton()
|
|
||||||
self.addPermanentWidget(self.cover_flow_button)
|
|
||||||
self.addPermanentWidget(self.movie_button)
|
|
||||||
self.book_info = BookInfoDisplay(self.clearMessage)
|
self.book_info = BookInfoDisplay(self.clearMessage)
|
||||||
self.book_info.setAcceptDrops(True)
|
self.book_info.setAcceptDrops(True)
|
||||||
self.scroll_area = QScrollArea()
|
self.scroll_area = QScrollArea()
|
||||||
self.scroll_area.setWidget(self.book_info)
|
self.scroll_area.setWidget(self.book_info)
|
||||||
self.scroll_area.setWidgetResizable(True)
|
self.scroll_area.setWidgetResizable(True)
|
||||||
self.connect(self.book_info, SIGNAL('show_book_info()'), self.show_book_info)
|
self.book_info.show_book_info.connect(self.show_book_info.emit,
|
||||||
self.connect(self.book_info,
|
type=Qt.QueuedConnection)
|
||||||
SIGNAL('files_dropped(PyQt_PyObject,PyQt_PyObject)'),
|
self.book_info.files_dropped.connect(self.files_dropped.emit,
|
||||||
self.files_dropped, Qt.QueuedConnection)
|
type=Qt.QueuedConnection)
|
||||||
self.addWidget(self.scroll_area, 100)
|
self.addWidget(self.scroll_area, 100)
|
||||||
self.setMinimumHeight(120)
|
self.setMinimumHeight(120)
|
||||||
self.resized.connect(self.book_info.cover_display.relayout)
|
self.resized.connect(self.book_info.cover_display.relayout)
|
||||||
@ -241,10 +191,6 @@ class StatusBar(QStatusBar):
|
|||||||
def resizeEvent(self, ev):
|
def resizeEvent(self, ev):
|
||||||
self.resized.emit(self.size())
|
self.resized.emit(self.size())
|
||||||
|
|
||||||
def files_dropped(self, event, paths):
|
|
||||||
self.emit(SIGNAL('files_dropped(PyQt_PyObject, PyQt_PyObject)'), event,
|
|
||||||
paths)
|
|
||||||
|
|
||||||
def reset_info(self):
|
def reset_info(self):
|
||||||
self.book_info.show_data({})
|
self.book_info.show_data({})
|
||||||
|
|
||||||
@ -259,33 +205,4 @@ class StatusBar(QStatusBar):
|
|||||||
self.notifier(msg)
|
self.notifier(msg)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def jobs(self):
|
|
||||||
src = unicode(self.movie_button.jobs.text())
|
|
||||||
return int(re.search(r'\d+', src).group())
|
|
||||||
|
|
||||||
def show_book_info(self):
|
|
||||||
self.emit(SIGNAL('show_book_info()'))
|
|
||||||
|
|
||||||
def job_added(self, nnum):
|
|
||||||
jobs = self.movie_button.jobs
|
|
||||||
src = unicode(jobs.text())
|
|
||||||
num = self.jobs()
|
|
||||||
text = src.replace(str(num), str(nnum))
|
|
||||||
jobs.setText(text)
|
|
||||||
self.movie_button.start()
|
|
||||||
|
|
||||||
def job_done(self, nnum):
|
|
||||||
jobs = self.movie_button.jobs
|
|
||||||
src = unicode(jobs.text())
|
|
||||||
num = self.jobs()
|
|
||||||
text = src.replace(str(num), str(nnum))
|
|
||||||
jobs.setText(text)
|
|
||||||
if nnum == 0:
|
|
||||||
self.no_more_jobs()
|
|
||||||
|
|
||||||
def no_more_jobs(self):
|
|
||||||
if self.movie_button.is_running:
|
|
||||||
self.movie_button.stop()
|
|
||||||
QCoreApplication.instance().alert(self, 5000)
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -169,7 +169,7 @@ class TagTreeItem(object):
|
|||||||
|
|
||||||
def category_data(self, role):
|
def category_data(self, role):
|
||||||
if role == Qt.DisplayRole:
|
if role == Qt.DisplayRole:
|
||||||
return self.name
|
return QVariant(self.py_name + ' [%d]'%len(self.children))
|
||||||
if role == Qt.DecorationRole:
|
if role == Qt.DecorationRole:
|
||||||
return self.icon
|
return self.icon
|
||||||
if role == Qt.FontRole:
|
if role == Qt.FontRole:
|
||||||
|
@ -262,16 +262,10 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
SIGNAL('update_found(PyQt_PyObject)'), self.update_found)
|
SIGNAL('update_found(PyQt_PyObject)'), self.update_found)
|
||||||
self.update_checker.start(2000)
|
self.update_checker.start(2000)
|
||||||
####################### Status Bar #####################
|
####################### Status Bar #####################
|
||||||
self.status_bar.initialize(self.jobs_dialog, self.system_tray_icon)
|
self.status_bar.initialize(self.system_tray_icon)
|
||||||
#self.setStatusBar(self.status_bar)
|
self.status_bar.show_book_info.connect(self.show_book_info)
|
||||||
QObject.connect(self.job_manager, SIGNAL('job_added(int)'),
|
self.status_bar.files_dropped.connect(self.files_dropped_on_book)
|
||||||
self.status_bar.job_added, Qt.QueuedConnection)
|
|
||||||
QObject.connect(self.job_manager, SIGNAL('job_done(int)'),
|
|
||||||
self.status_bar.job_done, Qt.QueuedConnection)
|
|
||||||
QObject.connect(self.status_bar, SIGNAL('show_book_info()'),
|
|
||||||
self.show_book_info)
|
|
||||||
QObject.connect(self.status_bar, SIGNAL('files_dropped(PyQt_PyObject,PyQt_PyObject)'),
|
|
||||||
self.files_dropped_on_book)
|
|
||||||
####################### Setup Toolbar #####################
|
####################### Setup Toolbar #####################
|
||||||
md = QMenu()
|
md = QMenu()
|
||||||
md.addAction(_('Edit metadata individually'))
|
md.addAction(_('Edit metadata individually'))
|
||||||
@ -459,6 +453,10 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
QObject.connect(self.advanced_search_button, SIGNAL('clicked(bool)'),
|
QObject.connect(self.advanced_search_button, SIGNAL('clicked(bool)'),
|
||||||
self.do_advanced_search)
|
self.do_advanced_search)
|
||||||
|
|
||||||
|
for ch in self.tool_bar.children():
|
||||||
|
if isinstance(ch, QToolButton):
|
||||||
|
ch.setCursor(Qt.PointingHandCursor)
|
||||||
|
|
||||||
####################### Library view ########################
|
####################### Library view ########################
|
||||||
similar_menu = QMenu(_('Similar books...'))
|
similar_menu = QMenu(_('Similar books...'))
|
||||||
similar_menu.addAction(self.action_books_by_same_author)
|
similar_menu.addAction(self.action_books_by_same_author)
|
||||||
@ -554,12 +552,6 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
self.cover_cache = CoverCache(self.library_path)
|
self.cover_cache = CoverCache(self.library_path)
|
||||||
self.cover_cache.start()
|
self.cover_cache.start()
|
||||||
self.library_view.model().cover_cache = self.cover_cache
|
self.library_view.model().cover_cache = self.cover_cache
|
||||||
self.tags_view.setVisible(False)
|
|
||||||
self.tag_match.setVisible(False)
|
|
||||||
self.popularity.setVisible(False)
|
|
||||||
self.restriction_label.setVisible(False)
|
|
||||||
self.edit_categories.setVisible(False)
|
|
||||||
self.search_restriction.setVisible(False)
|
|
||||||
self.connect(self.edit_categories, SIGNAL('clicked()'), self.do_edit_categories)
|
self.connect(self.edit_categories, SIGNAL('clicked()'), self.do_edit_categories)
|
||||||
self.tags_view.set_database(db, self.tag_match, self.popularity, self.search_restriction)
|
self.tags_view.set_database(db, self.tag_match, self.popularity, self.search_restriction)
|
||||||
self.connect(self.tags_view,
|
self.connect(self.tags_view,
|
||||||
@ -626,22 +618,28 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
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.cover_flow.currentChanged.connect(self.sync_listview_to_cf)
|
self.cover_flow.currentChanged.connect(self.sync_listview_to_cf)
|
||||||
self.connect(self.status_bar.cover_flow_button,
|
|
||||||
SIGNAL('toggled(bool)'), self.toggle_cover_flow)
|
|
||||||
self.connect(self.cover_flow, SIGNAL('stop()'),
|
|
||||||
self.status_bar.cover_flow_button.toggle)
|
|
||||||
self.library_view.selectionModel().currentRowChanged.connect(
|
self.library_view.selectionModel().currentRowChanged.connect(
|
||||||
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:
|
|
||||||
self.status_bar.cover_flow_button.disable(pictureflowerror)
|
|
||||||
|
|
||||||
self._calculated_available_height = min(max_available_height()-15,
|
self._calculated_available_height = min(max_available_height()-15,
|
||||||
self.height())
|
self.height())
|
||||||
self.resize(self.width(), self._calculated_available_height)
|
self.resize(self.width(), self._calculated_available_height)
|
||||||
self.search.setMaximumWidth(self.width()-150)
|
self.search.setMaximumWidth(self.width()-150)
|
||||||
|
|
||||||
|
####################### Side Bar ###############################
|
||||||
|
|
||||||
|
self.sidebar.initialize(self.jobs_dialog, self.cover_flow,
|
||||||
|
self.toggle_cover_flow, pictureflowerror,
|
||||||
|
self.vertical_splitter, self.horizontal_splitter)
|
||||||
|
QObject.connect(self.job_manager, SIGNAL('job_added(int)'),
|
||||||
|
self.sidebar.job_added, Qt.QueuedConnection)
|
||||||
|
QObject.connect(self.job_manager, SIGNAL('job_done(int)'),
|
||||||
|
self.sidebar.job_done, Qt.QueuedConnection)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if config['autolaunch_server']:
|
if config['autolaunch_server']:
|
||||||
from calibre.library.server import start_threaded_server
|
from calibre.library.server import start_threaded_server
|
||||||
from calibre.library import server_config
|
from calibre.library import server_config
|
||||||
@ -668,19 +666,6 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
|
|
||||||
self.location_view.setCurrentIndex(self.location_view.model().index(0))
|
self.location_view.setCurrentIndex(self.location_view.model().index(0))
|
||||||
|
|
||||||
if self.cover_flow is not None and dynamic.get('cover_flow_visible', False):
|
|
||||||
self.status_bar.cover_flow_button.toggle()
|
|
||||||
|
|
||||||
tb_state = dynamic.get('tag_browser_state', None)
|
|
||||||
if tb_state is not None:
|
|
||||||
self.horizontal_splitter.restoreState(tb_state)
|
|
||||||
self.toggle_tags_view(True)
|
|
||||||
|
|
||||||
bi_state = dynamic.get('book_info_state', None)
|
|
||||||
if bi_state is not None:
|
|
||||||
self.vertical_splitter.restoreState(bi_state)
|
|
||||||
self.horizontal_splitter.initialize()
|
|
||||||
self.vertical_splitter.initialize()
|
|
||||||
|
|
||||||
self._add_filesystem_book = Dispatcher(self.__add_filesystem_book)
|
self._add_filesystem_book = Dispatcher(self.__add_filesystem_book)
|
||||||
v = self.library_view
|
v = self.library_view
|
||||||
@ -782,11 +767,6 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
if search:
|
if search:
|
||||||
self.search.set_search_string(join.join(search))
|
self.search.set_search_string(join.join(search))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def uncheck_cover_button(self, *args):
|
|
||||||
self.status_bar.cover_flow_button.setChecked(False)
|
|
||||||
|
|
||||||
def toggle_cover_flow(self, show):
|
def toggle_cover_flow(self, show):
|
||||||
if config['separate_cover_flow']:
|
if config['separate_cover_flow']:
|
||||||
if show:
|
if show:
|
||||||
@ -802,8 +782,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
self.cover_flow.setFocus(Qt.OtherFocusReason)
|
self.cover_flow.setFocus(Qt.OtherFocusReason)
|
||||||
self.library_view.scrollTo(self.library_view.currentIndex())
|
self.library_view.scrollTo(self.library_view.currentIndex())
|
||||||
d.show()
|
d.show()
|
||||||
self.connect(d, SIGNAL('finished(int)'),
|
d.finished.connect(self.sidebar.external_cover_flow_finished)
|
||||||
self.uncheck_cover_button)
|
|
||||||
self.cf_dialog = d
|
self.cf_dialog = d
|
||||||
self.cover_flow_sync_timer.start(500)
|
self.cover_flow_sync_timer.start(500)
|
||||||
else:
|
else:
|
||||||
@ -825,8 +804,6 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
self.library_view.currentIndex())
|
self.library_view.currentIndex())
|
||||||
self.cover_flow.setVisible(True)
|
self.cover_flow.setVisible(True)
|
||||||
self.cover_flow.setFocus(Qt.OtherFocusReason)
|
self.cover_flow.setFocus(Qt.OtherFocusReason)
|
||||||
#self.status_bar.book_info.book_data.setMaximumHeight(100)
|
|
||||||
#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)
|
self.cover_flow_sync_timer.start(500)
|
||||||
else:
|
else:
|
||||||
@ -837,26 +814,8 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
sm = self.library_view.selectionModel()
|
sm = self.library_view.selectionModel()
|
||||||
sm.select(idx, sm.ClearAndSelect|sm.Rows)
|
sm.select(idx, sm.ClearAndSelect|sm.Rows)
|
||||||
self.library_view.setCurrentIndex(idx)
|
self.library_view.setCurrentIndex(idx)
|
||||||
#self.status_bar.book_info.book_data.setMaximumHeight(1000)
|
|
||||||
#self.resize(self.width(), self._calculated_available_height)
|
|
||||||
#self.setMaximumHeight(available_height())
|
|
||||||
|
|
||||||
def toggle_tags_view(self, show):
|
|
||||||
if show:
|
|
||||||
self.tags_view.setVisible(True)
|
|
||||||
self.tag_match.setVisible(True)
|
|
||||||
self.popularity.setVisible(True)
|
|
||||||
self.restriction_label.setVisible(True)
|
|
||||||
self.edit_categories.setVisible(True)
|
|
||||||
self.search_restriction.setVisible(True)
|
|
||||||
self.tags_view.setFocus(Qt.OtherFocusReason)
|
|
||||||
else:
|
|
||||||
self.tags_view.setVisible(False)
|
|
||||||
self.tag_match.setVisible(False)
|
|
||||||
self.popularity.setVisible(False)
|
|
||||||
self.restriction_label.setVisible(False)
|
|
||||||
self.edit_categories.setVisible(False)
|
|
||||||
self.search_restriction.setVisible(False)
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Handling of the count of books in a restricted view requires that
|
Handling of the count of books in a restricted view requires that
|
||||||
@ -887,7 +846,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
self.restriction_count_of_books_in_view = self.current_view().row_count()
|
self.restriction_count_of_books_in_view = self.current_view().row_count()
|
||||||
t = _("({0} of {1})").format(self.current_view().row_count(),
|
t = _("({0} of {1})").format(self.current_view().row_count(),
|
||||||
self.restriction_count_of_books_in_view)
|
self.restriction_count_of_books_in_view)
|
||||||
self.search_count.setStyleSheet('QLabel { background-color: yellow; }')
|
self.search_count.setStyleSheet('QLabel { border-radius: 8px; background-color: yellow; }')
|
||||||
else: # No restriction
|
else: # No restriction
|
||||||
if all == 'yes':
|
if all == 'yes':
|
||||||
t = _("(all books)")
|
t = _("(all books)")
|
||||||
@ -2330,6 +2289,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
view.resizeColumnsToContents()
|
view.resizeColumnsToContents()
|
||||||
view.resize_on_select = False
|
view.resize_on_select = False
|
||||||
self.status_bar.reset_info()
|
self.status_bar.reset_info()
|
||||||
|
self.sidebar.location_changed(location)
|
||||||
if location == 'library':
|
if location == 'library':
|
||||||
self.action_edit.setEnabled(True)
|
self.action_edit.setEnabled(True)
|
||||||
self.action_merge.setEnabled(True)
|
self.action_merge.setEnabled(True)
|
||||||
@ -2337,7 +2297,6 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
self.view_menu.actions()[1].setEnabled(True)
|
self.view_menu.actions()[1].setEnabled(True)
|
||||||
self.action_open_containing_folder.setEnabled(True)
|
self.action_open_containing_folder.setEnabled(True)
|
||||||
self.action_sync.setEnabled(True)
|
self.action_sync.setEnabled(True)
|
||||||
self.status_bar.cover_flow_button.setEnabled(True)
|
|
||||||
for action in list(self.delete_menu.actions())[1:]:
|
for action in list(self.delete_menu.actions())[1:]:
|
||||||
action.setEnabled(True)
|
action.setEnabled(True)
|
||||||
else:
|
else:
|
||||||
@ -2347,7 +2306,6 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
self.view_menu.actions()[1].setEnabled(False)
|
self.view_menu.actions()[1].setEnabled(False)
|
||||||
self.action_open_containing_folder.setEnabled(False)
|
self.action_open_containing_folder.setEnabled(False)
|
||||||
self.action_sync.setEnabled(False)
|
self.action_sync.setEnabled(False)
|
||||||
self.status_bar.cover_flow_button.setEnabled(False)
|
|
||||||
for action in list(self.delete_menu.actions())[1:]:
|
for action in list(self.delete_menu.actions())[1:]:
|
||||||
action.setEnabled(False)
|
action.setEnabled(False)
|
||||||
|
|
||||||
@ -2463,11 +2421,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
def write_settings(self):
|
def write_settings(self):
|
||||||
config.set('main_window_geometry', self.saveGeometry())
|
config.set('main_window_geometry', self.saveGeometry())
|
||||||
dynamic.set('sort_history', self.library_view.model().sort_history)
|
dynamic.set('sort_history', self.library_view.model().sort_history)
|
||||||
dynamic.set('cover_flow_visible', self.cover_flow.isVisible())
|
self.sidebar.save_state()
|
||||||
dynamic.set('tag_browser_state',
|
|
||||||
str(self.horizontal_splitter.saveState()))
|
|
||||||
dynamic.set('book_info_state',
|
|
||||||
str(self.vertical_splitter.saveState()))
|
|
||||||
self.library_view.write_settings()
|
self.library_view.write_settings()
|
||||||
if self.device_connected:
|
if self.device_connected:
|
||||||
self.save_device_view_settings()
|
self.save_device_view_settings()
|
||||||
|
@ -982,6 +982,12 @@ class SplitterHandle(QSplitterHandle):
|
|||||||
|
|
||||||
class Splitter(QSplitter):
|
class Splitter(QSplitter):
|
||||||
|
|
||||||
|
state_changed = pyqtSignal(object)
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
QSplitter.__init__(self, *args)
|
||||||
|
self.splitterMoved.connect(self.splitter_moved, type=Qt.QueuedConnection)
|
||||||
|
|
||||||
def createHandle(self):
|
def createHandle(self):
|
||||||
return SplitterHandle(self.orientation(), self)
|
return SplitterHandle(self.orientation(), self)
|
||||||
|
|
||||||
@ -990,6 +996,22 @@ class Splitter(QSplitter):
|
|||||||
h = self.handle(i)
|
h = self.handle(i)
|
||||||
if h is not None:
|
if h is not None:
|
||||||
h.splitter_moved()
|
h.splitter_moved()
|
||||||
|
self.state_changed.emit(not self.is_side_index_hidden)
|
||||||
|
|
||||||
|
def splitter_moved(self, *args):
|
||||||
|
self.state_changed.emit(not self.is_side_index_hidden)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def side_index(self):
|
||||||
|
return 0 if self.orientation() == Qt.Horizontal else 1
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_side_index_hidden(self):
|
||||||
|
sizes = list(self.sizes())
|
||||||
|
return sizes[self.side_index] == 0
|
||||||
|
|
||||||
|
def toggle_side_index(self):
|
||||||
|
self.double_clicked(None)
|
||||||
|
|
||||||
def double_clicked(self, handle):
|
def double_clicked(self, handle):
|
||||||
sizes = list(self.sizes())
|
sizes = list(self.sizes())
|
||||||
@ -997,8 +1019,7 @@ class Splitter(QSplitter):
|
|||||||
idx = sizes.index(0)
|
idx = sizes.index(0)
|
||||||
sizes[idx] = 80
|
sizes[idx] = 80
|
||||||
else:
|
else:
|
||||||
idx = 0 if self.orientation() == Qt.Horizontal else 1
|
sizes[self.side_index] = 0
|
||||||
sizes[idx] = 0
|
|
||||||
self.setSizes(sizes)
|
self.setSizes(sizes)
|
||||||
self.initialize()
|
self.initialize()
|
||||||
|
|
||||||
|
@ -145,6 +145,8 @@ class CustomColumns(object):
|
|||||||
if v['normalized']:
|
if v['normalized']:
|
||||||
tn = 'custom_column_{0}'.format(i)
|
tn = 'custom_column_{0}'.format(i)
|
||||||
self.tag_browser_categories[tn] = [v['label'], 'value']
|
self.tag_browser_categories[tn] = [v['label'], 'value']
|
||||||
|
if v['datatype'] == 'rating':
|
||||||
|
self.tag_browser_formatters[tn] = lambda x:u'\u2605'*int(round(x/2.))
|
||||||
|
|
||||||
|
|
||||||
def get_custom(self, idx, label=None, num=None, index_is_id=False):
|
def get_custom(self, idx, label=None, num=None, index_is_id=False):
|
||||||
|
@ -127,6 +127,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
|||||||
'authors' : ['author', 'name'],
|
'authors' : ['author', 'name'],
|
||||||
'news' : ['news', 'name'],
|
'news' : ['news', 'name'],
|
||||||
}
|
}
|
||||||
|
self.tag_browser_formatters = {}
|
||||||
|
|
||||||
self.connect()
|
self.connect()
|
||||||
self.is_case_sensitive = not iswindows and not isosx and \
|
self.is_case_sensitive = not iswindows and not isosx and \
|
||||||
@ -632,11 +633,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
|||||||
else:
|
else:
|
||||||
icon = icon_map['*custom']
|
icon = icon_map['*custom']
|
||||||
tooltip = self.custom_column_label_map[category]['name']
|
tooltip = self.custom_column_label_map[category]['name']
|
||||||
if ids is None: # no filtering
|
formatter = self.tag_browser_formatters.get(tn, lambda x: x)
|
||||||
categories[category] = [Tag(r[1], count=r[2], id=r[0], icon=icon, tooltip = tooltip)
|
categories[category] = [Tag(formatter(r[1]), count=r[2], id=r[0], icon=icon, tooltip = tooltip)
|
||||||
for r in data if r[2] > 0]
|
|
||||||
else: # filter out zero-count tags
|
|
||||||
categories[category] = [Tag(r[1], count=r[2], id=r[0], icon=icon, tooltip = tooltip)
|
|
||||||
for r in data if r[2] > 0]
|
for r in data if r[2] > 0]
|
||||||
categories['format'] = []
|
categories['format'] = []
|
||||||
for fmt in self.conn.get('SELECT DISTINCT format FROM data'):
|
for fmt in self.conn.get('SELECT DISTINCT format FROM data'):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user