43 Commits
0.3.1 ... 0.4

Author SHA1 Message Date
BasioMeusPuga
55bee210c6 Update version for release
Update translations
2018-05-13 18:40:24 -04:00
BasioMeusPuga
d3746c8e98 Merge branch 'master' of https://github.com/basiomeuspuga/lector 2018-05-13 18:28:52 -04:00
BasioMeusPuga
ffcf07414f Implement file drag drop 2018-05-13 18:16:17 -04:00
BasioMeusPuga
ffaace2eaa Uniform tab sizes
Path search
PDF parser exception handling
2018-05-13 15:54:17 -04:00
BasioMeusPuga
32455dd859 Merge pull request #52 from jaccsr/master
Language code
2018-05-05 09:38:19 -04:00
BasioMeusPuga
3e54340694 Account for older versions of Qt 2018-05-03 08:37:22 -04:00
jaccsr
bc6c7d1c36 I forgot the language code 2018-05-02 10:23:41 +08:00
jaccsr
ebd746b7b2 Merge pull request #1 from BasioMeusPuga/master
a
2018-05-02 09:11:23 +08:00
BasioMeusPuga
ebc3ef9f1b Update README.md 2018-05-01 18:33:44 -04:00
BasioMeusPuga
7238605441 Update translations: Chinese (simplified) 2018-05-01 18:29:59 -04:00
BasioMeusPuga
ea86737970 Merge pull request #50 from jaccsr/master
Chinese (simplified) translation
2018-05-01 18:22:19 -04:00
jaccsr
ab4c586c06 add chinese(simp) language 2018-05-02 06:06:23 +08:00
BasioMeusPuga
7977bde410 Multiple fixes 2018-04-29 08:11:46 -04:00
BasioMeusPuga
626472dd04 Comic view drag and drop
Menu icons
Polish for docks
2018-04-20 10:00:12 +05:30
BasioMeusPuga
d9efe2da3c Annotation notes 2018-04-19 20:35:22 +05:30
BasioMeusPuga
ec197f0829 Annotation saving, loading, and deletion 2018-04-19 15:19:20 +05:30
BasioMeusPuga
335479bcfb Small fixes 2018-04-17 11:24:16 +05:30
BasioMeusPuga
cbf01c6d16 Annotation placement 2018-04-16 13:00:49 +05:30
BasioMeusPuga
98ca118a60 Remove unnecessary shebangs
How this isn't a Ricky Martin song, we'll never know
2018-04-12 10:15:20 +05:30
BasioMeusPuga
c7aa0e28ee Web search for selection
Bugfixes
2018-04-11 01:43:21 +05:30
BasioMeusPuga
528c2e387c Improve spacebar navigation
Refactor variables
2018-04-10 12:39:52 +05:30
BasioMeusPuga
bc54d6b686 Complete annotation editor
Annotation saving and loading
2018-04-08 14:41:31 +05:30
BasioMeusPuga
8f298de58e Cleanup optional imports
Disable the multiprocessing module on Windows
Update translations
2018-04-02 19:57:46 +05:30
BasioMeusPuga
366859ebe0 Fix incorrect function argument 2018-04-02 01:06:53 +05:30
BasioMeusPuga
8c51cc047e Split content display widgets into new module 2018-03-31 10:43:13 +05:30
BasioMeusPuga
5081a31f1a Fine tune progress display
Option: Set consider read at percentage
Small fixes
2018-03-31 10:31:57 +05:30
BasioMeusPuga
aff69d95c1 Make progress work with block count
Break database thoroughly
Fix pdf year bug
2018-03-31 03:03:49 +05:30
BasioMeusPuga
0b8427c864 Flatpak manifest: No pdf support but otherwise functional 2018-03-30 21:03:37 +05:30
BasioMeusPuga
43dd6a34d9 Implement basic annotation editor / preview 2018-03-30 20:48:13 +05:30
BasioMeusPuga
2f4adfc183 Small fixes 2018-03-30 11:06:48 +05:30
BasioMeusPuga
0d015ad72e Auto hide Tab-bar and Statusbar 2018-03-29 02:50:01 +05:30
BasioMeusPuga
406ca0485f Position setting should work all the time now
Learn not to swear so much at the screen
Cover icons in the tab bar
Shift Scan Library button from the Library tab to the Library toolbar
2018-03-29 01:45:58 +05:30
BasioMeusPuga
ab6760226e Search position seeking fix for multiple tabs
Space navigation tries its best to not cut lines off
2018-03-28 20:17:00 +05:30
BasioMeusPuga
66c8626d43 Significant improvements to bookmark dock display 2018-03-28 00:46:12 +05:30
BasioMeusPuga
5fa724ae69 Implement scroll speed slider 2018-03-27 21:58:35 +05:30
BasioMeusPuga
d417a94829 Fix fullscreen toggle affecting reading position bug
Bookmark navigation much more reliable
Start annotations UI
2018-03-27 08:23:07 +05:30
BasioMeusPuga
9c85a1075e Fix context menu behavior 2018-03-24 01:34:42 +05:30
BasioMeusPuga
dd4b502861 Move contentView profile modification functions to guifunctions module 2018-03-24 01:15:33 +05:30
BasioMeusPuga
0f963b20f9 Move cover loading and culling to guifunctions module 2018-03-24 00:30:58 +05:30
BasioMeusPuga
f63b6627b2 Update README.md 2018-03-24 00:00:12 +05:30
BasioMeusPuga
00db5d5e0f Update translations 2018-03-23 23:57:49 +05:30
BasioMeusPuga
5e53d40e68 Redesign settings dialog
Remove dependency on requests
2018-03-23 23:56:01 +05:30
BasioMeusPuga
6ffa6934ed Fix splitting for a repeated anchor 2018-03-23 17:48:58 +05:30
54 changed files with 16869 additions and 8288 deletions

View File

@@ -22,12 +22,13 @@ SOURCES += lector/__main__.py \
lector/library.py \
lector/toolbars.py \
lector/settingsdialog.py \
resources/definitions.py \
resources/settingswindow.py \
resources/metadata.py \
resources/mainwindow.py
lector/resources/definitions.py \
lector/resources/settingswindow.py \
lector/resources/metadata.py \
lector/resources/mainwindow.py
TRANSLATIONS += resources/translations/Lector_es.ts \
resources/translations/Lector_fr.ts \
resources/translations/Lector_de.ts \
resources/translations/SAMPLE.ts
TRANSLATIONS += lector/resources/translations/Lector_es.ts \
lector/resources/translations/Lector_fr.ts \
lector/resources/translations/Lector_de.ts \
lector/resources/translations/Lector_zh.ts \
lector/resources/translations/SAMPLE.ts

View File

@@ -16,7 +16,6 @@ Support for a bunch of other formats is coming. Please see the TODO for addition
| Qt5 | 5.10.1 |
| Python | 3.6 |
| PyQt5 | 5.10.1 |
| python-requests | 2.18.4 |
| python-beautifulsoup4 | 4.6.0 |
| poppler-qt5 | 0.61.1 |
| python-poppler-qt5 | 0.24.2 |
@@ -38,13 +37,13 @@ poppler-qt5 and python-poppler-qt5 are optional.
* [Gentoo (unofficial)](https://bitbucket.org/szymonsz/gen2-overlay/src/master/app-text/lector/)
## Translations
1. There is a `SAMPLE.ts` file in `resources/translations`. Open it in `Qt Linguist`.
1. There is a `SAMPLE.ts` file [here](https://github.com/BasioMeusPuga/Lector/tree/master/lector/resources/translations). Open it in `Qt Linguist`.
2. Pick the language you wish to translate to.
3. Translate relevant strings.
4. Try to resist the urge to include profanity.
5. Save the file as `Lector_<language>` and send it to me, preferably as a pull request.
Oh, please keep the translations short. There's only so much space for UI elements.
Please keep the translations short. There's only so much space for UI elements.
## Screenshots

22
TODO
View File

@@ -1,8 +1,8 @@
TODO
General:
✓ Internationalization
Application icon
.desktop file
Application icon
.desktop file
Options:
✓ Automatic library management
✓ Recursive file addition
@@ -29,6 +29,7 @@ TODO
✓ Information dialog widget
✓ Allow editing of database data through the UI + for Bookmarks
✓ Include (action) icons with the applications
✓ Drag and drop support for the library
Set focus to newly added file
Reading:
✓ Drop down for TOC
@@ -57,8 +58,15 @@ TODO
✓ Paragraph indentation
✓ Comic view keyboard shortcuts
✓ Comic view context menu
✓ Make the bookmark dock float over the reading area
✓ Spacebar should not cut off lines at the top
✓ Track open bookmark windows so they can be closed quickly at exit
Annotations
✓ Text
Annotation preview in listView
Image
Adjust key navigation according to viewport dimensions
Search document using QTextCursor?
Search document using QTextCursor
Filetypes:
✓ pdf support
Parse TOC
@@ -72,28 +80,28 @@ TODO
Other:
✓ Define every widget in code
Bugs:
Slider position change might be acting up
Deselecting all directories in the settings dialog also filters out manually added books
Clean up 'switch' page layout
Colors aren't loaded properly for annotation previews
Secondary:
Annotations
Graphical themes
Change focus rectangle dimensions
Tab reordering
Universal Ctrl + Tab
Allow tabs to detach and form their own windows
Goodreads API: Ratings, Read, Recommendations
Get ISBN using python-isbnlib
Pagination
Use embedded fonts + CSS
Scrolling: Smooth / By Line
Spacebar should not cut off lines at the top
Shift to logging instead of print statements
txt, doc, chm, djvu, fb2 support
Include icons for filetype emblems
Drag and drop support for the library
Comic view modes
Continuous paging
Double pages
Ignore a / the / numbers for sorting purposes
? Add only one file type if multiple are present
? Create emblem per filetype
In application notifications

View File

@@ -0,0 +1,110 @@
{
"app-id":"com.basiomeuspuga.Lector",
"runtime":"org.kde.Platform",
"runtime-version":"5.10",
"sdk":"org.kde.Sdk",
"command":"lector",
"rename-icon":"Lector",
"rename-desktop-file":"lector.desktop",
"rename-appdata-file":"lector.appdata.xml",
"finish-args":[
"--filesystem=host",
"--socket=x11",
"--socket=wayland",
"--device=dri",
"--share=ipc",
"--share=network"
],
"build-options":{
"cflags":"-O2",
"cxxflags":"-O2"
},
"modules":[
{
"name": "python",
"sources": [
{
"type": "archive",
"url": "https://www.python.org/ftp/python/3.6.4/Python-3.6.4.tar.xz",
"sha256": "159b932bf56aeaa76fd66e7420522d8c8853d486b8567c459b84fe2ed13bcaba"
}
]
},
{
"name": "pyqt5",
"buildsystem": "simple",
"build-commands": [
"pip3 install --prefix=/app PyQt5-5.10.1-5.10.1-cp35.cp36.cp37.cp38-abi3-manylinux1_x86_64.whl"
],
"modules":[
{
"name":"sip",
"sources":[
{
"type":"file",
"url":"https://pypi.python.org/packages/8a/ea/d317ce5696dda4df7c156cd60447cda22833b38106c98250eae1451f03ec/sip-4.19.8-cp36-cp36m-manylinux1_x86_64.whl",
"sha256":"cf98150a99e43fda7ae22abe655b6f202e491d6291486548daa56cb15a2fcf85"
}
],
"buildsystem":"simple",
"build-commands":[
"pip3 install --prefix=/app sip-4.19.8-cp36-cp36m-manylinux1_x86_64.whl"
]
}
],
"sources": [
{
"type": "file",
"url": "https://pypi.python.org/packages/e4/15/4e2e49f64884edbab6f833c6fd3add24d7938f2429aec1f2883e645d4d8f/PyQt5-5.10.1-5.10.1-cp35.cp36.cp37.cp38-abi3-manylinux1_x86_64.whl",
"sha256": "1e652910bd1ffd23a3a48c510ecad23a57a853ed26b782cd54b16658e6f271ac"
}
]
},
{
"name":"beautifulsoup",
"buildsystem":"simple",
"sources":[
{
"type":"archive",
"url":"https://pypi.python.org/packages/fa/8d/1d14391fdaed5abada4e0f63543fef49b8331a34ca60c88bd521bcf7f782/beautifulsoup4-4.6.0.tar.gz",
"sha256":"808b6ac932dccb0a4126558f7dfdcf41710dd44a4ef497a0bb59a77f9f078e89"
}
],
"build-commands":[
"python3 setup.py build",
"python3 setup.py install --prefix=/app"
]
},
{
"name": "lxml",
"buildsystem": "simple",
"build-commands": [
"pip3 install --prefix=/app lxml-4.2.1-cp36-cp36m-manylinux1_x86_64.whl"
],
"sources": [
{
"type": "file",
"url": "https://pypi.python.org/packages/a7/b9/ccf46cea0f698b40bca2a9c1a44039c336fe1988b82de4f7353be7a8396a/lxml-4.2.1-cp36-cp36m-manylinux1_x86_64.whl",
"sha256": "0e3cd94c95d30ba9ca3cff40e9b2a14e1a10a4fd8131105b86c6b61648f57e4b"
}
]
},
{
"name":"lector",
"buildsystem":"simple",
"ensure-writable":[
"/lib/python*/site-packages/easy-install.pth"
],
"sources":[
{
"type":"git",
"url":"https://github.com/BasioMeusPuga/Lector.git"
}
],
"build-commands":[
"python3 setup.py build",
"python3 setup.py install --prefix=/app"
]
}
]
}

View File

@@ -21,7 +21,6 @@ import gc
import sys
import hashlib
import pathlib
from PyQt5 import QtWidgets, QtGui, QtCore
# This allows for the program to be launched from the
# dir where it's been copied instead of needing to be
@@ -30,19 +29,20 @@ install_dir = os.path.realpath(__file__)
install_dir = pathlib.Path(install_dir).parents[1]
sys.path.append(str(install_dir))
from PyQt5 import QtWidgets, QtGui, QtCore
from lector import database
from lector import sorter
from lector.toolbars import LibraryToolBar, BookToolBar
from lector.widgets import Tab
from lector.widgets import Tab, DragDropListView, DragDropTableView
from lector.delegates import LibraryDelegate
from lector.threaded import BackGroundTabUpdate, BackGroundBookAddition, BackGroundBookDeletion
from lector.library import Library
from lector.guifunctions import QImageFactory
from lector.guifunctions import QImageFactory, CoverLoadingAndCulling, ViewProfileModification
from lector.settings import Settings
from lector.settingsdialog import SettingsUI
from lector.metadatadialog import MetadataUI
from lector.definitionsdialog import DefinitionsUI
from lector.resources import mainwindow, resources
@@ -62,6 +62,13 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
# Initialize translation function
self._translate = QtCore.QCoreApplication.translate
# Create library widgets
self.listView = DragDropListView(self, self.listPage)
self.gridLayout_4.addWidget(self.listView, 0, 0, 1, 1)
self.tableView = DragDropTableView(self, self.tablePage)
self.gridLayout_3.addWidget(self.tableView, 0, 0, 1, 1)
# Empty variables that will be infested soon
self.settings = {}
self.thread = None # Background Thread
@@ -71,6 +78,7 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
self.comic_profile = {}
self.database_path = None
self.active_library_filters = []
self.active_bookmark_docks = []
# Initialize application
Settings(self).read_settings() # This should populate all variables that need
@@ -86,9 +94,13 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
# Widget declarations
self.libraryFilterMenu = QtWidgets.QMenu()
self.statusMessage = QtWidgets.QLabel()
self.distractionFreeToggle = QtWidgets.QToolButton()
# self.reloadLibrary = QtWidgets.QToolButton()
self.reloadLibrary = QtWidgets.QPushButton()
# Reference variables
self.alignment_dict = {
'left': self.bookToolBar.alignLeft,
'right': self.bookToolBar.alignRight,
'center': self.bookToolBar.alignCenter,
'justify': self.bookToolBar.alignJustify}
# Create the database in case it doesn't exist
database.DatabaseInit(self.database_path)
@@ -102,6 +114,9 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
# Initialize definition view dialog
self.definitionDialog = DefinitionsUI(self)
# Make the statusbar invisible by default
self.statusBar.setVisible(False)
# Statusbar widgets
self.statusMessage.setObjectName('statusMessage')
self.statusBar.addPermanentWidget(self.statusMessage)
@@ -113,25 +128,23 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
self.statusBar.addWidget(self.sorterProgress)
self.sorterProgress.setVisible(False)
# Statusbar + Toolbar Visibility
self.distractionFreeToggle.setIcon(self.QImageFactory.get_image('visibility'))
self.distractionFreeToggle.setObjectName('distractionFreeToggle')
self.distractionFreeToggle.setToolTip(
self._translate('Main_UI', 'Toggle distraction free mode (Ctrl + D)'))
self.distractionFreeToggle.setAutoRaise(True)
self.distractionFreeToggle.clicked.connect(self.toggle_distraction_free)
self.statusBar.addPermanentWidget(self.distractionFreeToggle)
# Application wide temporary directory
self.temp_dir = QtCore.QTemporaryDir()
# Init the Library
self.lib_ref = Library(self)
# Initialize Cover loading functions
# Must be after the Library init
self.cover_functions = CoverLoadingAndCulling(self)
# Init the culling timer
self.culling_timer = QtCore.QTimer()
self.culling_timer.setSingleShot(True)
self.culling_timer.timeout.connect(self.cull_covers)
self.culling_timer.timeout.connect(self.cover_functions.cull_covers)
# Init the Library
self.lib_ref = Library(self)
# Initialize profile modification functions
self.profile_functions = ViewProfileModification(self)
# Toolbar display
# Maybe make this a persistent option
@@ -142,11 +155,14 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
self.libraryToolBar.deleteButton.triggered.connect(self.delete_books)
self.libraryToolBar.coverViewButton.triggered.connect(self.switch_library_view)
self.libraryToolBar.tableViewButton.triggered.connect(self.switch_library_view)
self.libraryToolBar.reloadLibraryButton.triggered.connect(
self.settingsDialog.start_library_scan)
self.libraryToolBar.colorButton.triggered.connect(self.get_color)
self.libraryToolBar.settingsButton.triggered.connect(self.show_settings)
self.libraryToolBar.searchBar.textChanged.connect(self.lib_ref.update_proxymodels)
self.libraryToolBar.sortingBox.activated.connect(self.lib_ref.update_proxymodels)
self.libraryToolBar.libraryFilterButton.setPopupMode(QtWidgets.QToolButton.InstantPopup)
self.libraryToolBar.searchBar.textChanged.connect(self.statusbar_visibility)
self.addToolBar(self.libraryToolBar)
if self.settings['current_view'] == 0:
@@ -155,13 +171,16 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
self.libraryToolBar.tableViewButton.trigger()
# Book toolbar
self.bookToolBar.annotationButton.triggered.connect(self.toggle_dock_widgets)
self.bookToolBar.addBookmarkButton.triggered.connect(self.add_bookmark)
self.bookToolBar.bookmarkButton.triggered.connect(self.toggle_dock_widget)
self.bookToolBar.bookmarkButton.triggered.connect(self.toggle_dock_widgets)
self.bookToolBar.distractionFreeButton.triggered.connect(self.toggle_distraction_free)
self.bookToolBar.fullscreenButton.triggered.connect(self.set_fullscreen)
for count, i in enumerate(self.display_profiles):
self.bookToolBar.profileBox.setItemData(count, i, QtCore.Qt.UserRole)
self.bookToolBar.profileBox.currentIndexChanged.connect(self.format_contentView)
self.bookToolBar.profileBox.currentIndexChanged.connect(
self.profile_functions.format_contentView)
self.bookToolBar.profileBox.setCurrentIndex(self.current_profile_index)
self.bookToolBar.fontBox.currentFontChanged.connect(self.modify_font)
@@ -170,13 +189,8 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
self.bookToolBar.lineSpacingDown.triggered.connect(self.modify_font)
self.bookToolBar.paddingUp.triggered.connect(self.modify_font)
self.bookToolBar.paddingDown.triggered.connect(self.modify_font)
self.bookToolBar.resetProfile.triggered.connect(self.reset_profile)
self.alignment_dict = {
'left': self.bookToolBar.alignLeft,
'right': self.bookToolBar.alignRight,
'center': self.bookToolBar.alignCenter,
'justify': self.bookToolBar.alignJustify}
self.bookToolBar.resetProfile.triggered.connect(
self.profile_functions.reset_profile)
profile_index = self.bookToolBar.profileBox.currentIndex()
current_profile = self.bookToolBar.profileBox.itemData(
@@ -209,16 +223,11 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
self.available_parsers = '*.' + ' *.'.join(sorter.available_parsers)
print('Available parsers: ' + self.available_parsers)
# The library refresh button on the Library tab
self.reloadLibrary.setFlat(True)
self.reloadLibrary.setIcon(self.QImageFactory.get_image('reload'))
self.reloadLibrary.setObjectName('reloadLibrary')
self.reloadLibrary.setToolTip(self._translate('Main_UI', 'Scan library'))
self.reloadLibrary.clicked.connect(self.settingsDialog.start_library_scan)
# The Library tab gets no button
self.tabWidget.tabBar().setTabButton(
0, QtWidgets.QTabBar.RightSide, self.reloadLibrary)
0, QtWidgets.QTabBar.RightSide, None)
self.tabWidget.tabCloseRequested.connect(self.tab_close)
self.tabWidget.setTabBarAutoHide(True)
# Init display models
self.lib_ref.generate_model('build')
@@ -236,6 +245,8 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
self.listView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.listView.customContextMenuRequested.connect(self.generate_library_context_menu)
self.listView.verticalScrollBar().valueChanged.connect(self.start_culling_timer)
self.listView.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
self.listView.setAcceptDrops(True)
self.listView.setStyleSheet(
"QListView {{background-color: {0}}}".format(
@@ -260,10 +271,10 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
if self.settings['main_window_headers']:
for count, i in enumerate(self.settings['main_window_headers']):
self.tableView.horizontalHeader().resizeSection(count, int(i))
self.tableView.horizontalHeader().resizeSection(5, 1)
self.tableView.horizontalHeader().setStretchLastSection(True)
self.tableView.horizontalHeader().resizeSection(5, 30)
self.tableView.horizontalHeader().setStretchLastSection(False)
self.tableView.horizontalHeader().sectionClicked.connect(
self.lib_ref.table_proxy_model.sort_table_columns)
self.lib_ref.tableProxyModel.sort_table_columns)
self.tableView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.tableView.customContextMenuRequested.connect(
self.generate_library_context_menu)
@@ -314,117 +325,109 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
my_args = cl_parser.positionalArguments()
if my_args:
file_list = [QtCore.QFileInfo(i).absoluteFilePath() for i in my_args]
books = sorter.BookSorter(
file_list,
('addition', 'manual'),
self.database_path,
self.settings['auto_tags'],
self.temp_dir.path())
self.process_post_hoc_files(file_list, True)
parsed_books = books.initiate_threads()
if not parsed_books:
return
def process_post_hoc_files(self, file_list, open_files_after_processing):
# Takes care of both dragged and dropped files
# As well as files sent as command line arguments
books = sorter.BookSorter(
file_list,
('addition', 'manual'),
self.database_path,
self.settings['auto_tags'],
self.temp_dir.path())
database.DatabaseFunctions(self.database_path).add_to_database(parsed_books)
self.lib_ref.generate_model('addition', parsed_books, True)
parsed_books = books.initiate_threads()
if not parsed_books:
return
file_dict = {QtCore.QFileInfo(i).absoluteFilePath(): None for i in my_args}
database.DatabaseFunctions(self.database_path).add_to_database(parsed_books)
self.lib_ref.generate_model('addition', parsed_books, True)
file_dict = {i: None for i in file_list}
if open_files_after_processing:
self.open_files(file_dict)
self.move_on()
self.move_on()
def cull_covers(self, event=None):
blank_pixmap = QtGui.QPixmap()
blank_pixmap.load(':/images/blank.png') # Keep this. Removing it causes the
# listView to go blank on a resize
def open_files(self, path_hash_dictionary):
# file_paths is expected to be a dictionary
# This allows for threading file opening
# Which should speed up multiple file opening
# especially @ application start
all_indexes = set()
for i in range(self.lib_ref.item_proxy_model.rowCount()):
all_indexes.add(self.lib_ref.item_proxy_model.index(i, 0))
file_paths = [i for i in path_hash_dictionary]
y_range = list(range(0, self.listView.viewport().height(), 100))
y_range.extend((-20, self.listView.viewport().height() + 20))
x_range = range(0, self.listView.viewport().width(), 80)
for filename in path_hash_dictionary.items():
visible_indexes = set()
for i in y_range:
for j in x_range:
this_index = self.listView.indexAt(QtCore.QPoint(j, i))
visible_indexes.add(this_index)
file_md5 = filename[1]
if not file_md5:
try:
with open(filename[0], 'rb') as current_book:
first_bytes = current_book.read(1024 * 32) # First 32KB of the file
file_md5 = hashlib.md5(first_bytes).hexdigest()
except FileNotFoundError:
return
invisible_indexes = all_indexes - visible_indexes
for i in invisible_indexes:
model_index = self.lib_ref.item_proxy_model.mapToSource(i)
this_item = self.lib_ref.view_model.item(model_index.row())
# Remove any already open files
# Set focus to last file in case only one is open
for i in range(1, self.tabWidget.count()):
tab_metadata = self.tabWidget.widget(i).metadata
if tab_metadata['hash'] == file_md5:
file_paths.remove(filename[0])
if not file_paths:
self.tabWidget.setCurrentIndex(i)
return
if this_item:
this_item.setIcon(QtGui.QIcon(blank_pixmap))
this_item.setData(False, QtCore.Qt.UserRole + 8)
if not file_paths:
return
hash_index_dict = {}
hash_list = []
for i in visible_indexes:
model_index = self.lib_ref.item_proxy_model.mapToSource(i)
def finishing_touches():
self.profile_functions.format_contentView()
self.start_culling_timer()
book_hash = self.lib_ref.view_model.data(
model_index, QtCore.Qt.UserRole + 6)
cover_displayed = self.lib_ref.view_model.data(
model_index, QtCore.Qt.UserRole + 8)
print('Attempting to open: ' + ', '.join(file_paths))
if book_hash and not cover_displayed:
hash_list.append(book_hash)
hash_index_dict[book_hash] = model_index
contents = sorter.BookSorter(
file_paths,
('reading', None),
self.database_path,
True,
self.temp_dir.path()).initiate_threads()
all_covers = database.DatabaseFunctions(
self.database_path).fetch_covers_only(hash_list)
# TODO
# Notification feedback in case all books return nothing
for i in all_covers:
book_hash = i[0]
cover = i[1]
model_index = hash_index_dict[book_hash]
if not contents:
return
book_item = self.lib_ref.view_model.item(model_index.row())
self.cover_loader(book_item, cover)
for i in contents:
# New tabs are created here
# Initial position adjustment is carried out by the tab itself
file_data = contents[i]
Tab(file_data, self)
if self.settings['last_open_tab'] == 'library':
self.tabWidget.setCurrentIndex(0)
self.listView.setFocus()
self.settings['last_open_tab'] = None
return
for i in range(1, self.tabWidget.count()):
this_path = self.tabWidget.widget(i).metadata['path']
if self.settings['last_open_tab'] == this_path:
self.tabWidget.setCurrentIndex(i)
self.settings['last_open_tab'] = None
finishing_touches()
return
self.tabWidget.setCurrentIndex(self.tabWidget.count() - 1)
finishing_touches()
def start_culling_timer(self):
if self.settings['perform_culling']:
self.culling_timer.start(30)
def load_all_covers(self):
all_covers_db = database.DatabaseFunctions(
self.database_path).fetch_data(
('Hash', 'CoverImage',),
'books',
{'Hash': ''},
'LIKE')
if not all_covers_db:
return
all_covers = {
i[0]: i[1] for i in all_covers_db}
for i in range(self.lib_ref.view_model.rowCount()):
this_item = self.lib_ref.view_model.item(i, 0)
is_cover_already_displayed = this_item.data(QtCore.Qt.UserRole + 8)
if is_cover_already_displayed:
continue
book_hash = this_item.data(QtCore.Qt.UserRole + 6)
cover = all_covers[book_hash]
self.cover_loader(this_item, cover)
def cover_loader(self, item, cover):
img_pixmap = QtGui.QPixmap()
if cover:
img_pixmap.loadFromData(cover)
else:
img_pixmap.load(':/images/NotFound.png')
img_pixmap = img_pixmap.scaled(420, 600, QtCore.Qt.IgnoreAspectRatio)
item.setIcon(QtGui.QIcon(img_pixmap))
item.setData(True, QtCore.Qt.UserRole + 8)
def add_bookmark(self):
if self.tabWidget.currentIndex() != 0:
self.tabWidget.widget(self.tabWidget.currentIndex()).add_bookmark()
@@ -475,9 +478,10 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
return
self.settingsDialog.okButton.setEnabled(False)
self.reloadLibrary.setEnabled(False)
self.libraryToolBar.reloadLibraryButton.setEnabled(False)
self.settings['last_open_path'] = os.path.dirname(opened_files[0][0])
self.statusBar.setVisible(True)
self.sorterProgress.setVisible(True)
self.statusMessage.setText(self._translate('Main_UI', 'Adding books...'))
self.thread = BackGroundBookAddition(
@@ -489,14 +493,14 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
selected_indexes = None
if library_widget == self.listView:
selected_books = self.lib_ref.item_proxy_model.mapSelectionToSource(
selected_books = self.lib_ref.itemProxyModel.mapSelectionToSource(
self.listView.selectionModel().selection())
selected_indexes = [i.indexes()[0] for i in selected_books]
elif library_widget == self.tableView:
selected_books = self.tableView.selectionModel().selectedRows()
selected_indexes = [
self.lib_ref.table_proxy_model.mapToSource(i) for i in selected_books]
self.lib_ref.tableProxyModel.mapToSource(i) for i in selected_books]
return selected_indexes
@@ -522,12 +526,12 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
# Persistent model indexes are required beause deletion mutates the model
# Generate and delete by persistent index
delete_hashes = [
self.lib_ref.view_model.data(
self.lib_ref.libraryModel.data(
i, QtCore.Qt.UserRole + 6) for i in selected_indexes]
persistent_indexes = [QtCore.QPersistentModelIndex(i) for i in selected_indexes]
for i in persistent_indexes:
self.lib_ref.view_model.removeRow(i.row())
self.lib_ref.libraryModel.removeRow(i.row())
# Update the database in the background
self.thread = BackGroundBookDeletion(
@@ -557,20 +561,23 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
self.settingsDialog.okButton.setEnabled(True)
self.settingsDialog.okButton.setToolTip(
self._translate('Main_UI', 'Save changes and start library scan'))
self.reloadLibrary.setEnabled(True)
self.libraryToolBar.reloadLibraryButton.setEnabled(True)
self.sorterProgress.setVisible(False)
self.sorterProgress.setValue(0)
if self.libraryToolBar.searchBar.text() == '':
self.statusBar.setVisible(False)
self.lib_ref.update_proxymodels()
self.lib_ref.generate_library_tags()
self.statusMessage.setText(
str(self.lib_ref.item_proxy_model.rowCount()) +
str(self.lib_ref.itemProxyModel.rowCount()) +
self._translate('Main_UI', ' books'))
if not self.settings['perform_culling']:
self.load_all_covers()
self.cover_functions.load_all_covers()
def switch_library_view(self):
if self.libraryToolBar.coverViewButton.isChecked():
@@ -592,6 +599,11 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
self.current_tab = self.tabWidget.currentIndex()
# Hide bookmark and annotation widgets
for i in range(1, self.tabWidget.count()):
self.tabWidget.widget(i).bookmarkDock.setVisible(False)
self.tabWidget.widget(i).annotationDock.setVisible(False)
if self.tabWidget.currentIndex() == 0:
self.resizeEvent()
@@ -600,11 +612,11 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
self.bookToolBar.hide()
self.libraryToolBar.show()
if self.lib_ref.item_proxy_model:
if self.lib_ref.itemProxyModel:
# Making the proxy model available doesn't affect
# memory utilization at all. Bleh.
self.statusMessage.setText(
str(self.lib_ref.item_proxy_model.rowCount()) +
str(self.lib_ref.itemProxyModel.rowCount()) +
self._translate('Main_UI', ' Books'))
else:
@@ -631,10 +643,10 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
self.bookToolBar.tocBox.setCurrentIndex(
current_position['current_chapter'] - 1)
if not current_metadata['images_only']:
current_tab.set_scroll_value(False)
current_tab.hiddenButton.animateClick(25)
self.bookToolBar.tocBox.blockSignals(False)
self.format_contentView()
self.profile_functions.format_contentView()
self.statusMessage.setText(
current_author + ' - ' + current_title)
@@ -660,361 +672,53 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
def set_toc_position(self, event=None):
current_tab = self.tabWidget.widget(self.tabWidget.currentIndex())
# We're updating the underlying model to have real-time
# updates on the read status
# Set a baseline model index in case the item gets deleted
# E.g It's open in a tab and deleted from the library
model_index = None
start_index = self.lib_ref.view_model.index(0, 0)
# Find index of the model item that corresponds to the tab
matching_item = self.lib_ref.view_model.match(
start_index,
QtCore.Qt.UserRole + 6,
current_tab.metadata['hash'],
1, QtCore.Qt.MatchExactly)
if matching_item:
model_row = matching_item[0].row()
model_index = self.lib_ref.view_model.index(model_row, 0)
current_tab.metadata[
'position']['current_chapter'] = event + 1
current_tab.metadata[
'position']['is_read'] = False
# TODO
# This doesn't update correctly
# try:
# position_perc = (
# current_tab.metadata[
# 'current_chapter'] * 100 / current_tab.metadata['total_chapters'])
# except KeyError:
# position_perc = None
if model_index:
self.lib_ref.view_model.setData(
model_index, current_tab.metadata, QtCore.Qt.UserRole + 3)
# self.lib_ref.view_model.setData(
# model_index, position_perc, QtCore.Qt.UserRole + 7)
# Go on to change the value of the Table of Contents box
current_tab.change_chapter_tocBox()
self.format_contentView()
current_tab.contentView.record_position()
self.profile_functions.format_contentView()
def set_fullscreen(self):
current_tab = self.tabWidget.currentIndex()
current_tab_widget = self.tabWidget.widget(current_tab)
current_tab_widget.go_fullscreen()
def toggle_dock_widget(self):
sender = self.sender().objectName()
def toggle_dock_widgets(self):
sender = self.sender()
current_tab = self.tabWidget.currentIndex()
current_tab_widget = self.tabWidget.widget(current_tab)
# TODO
# Extend this to other context related functions
# Make this fullscreenable
if sender == 'bookmarkButton':
if sender == self.bookToolBar.bookmarkButton:
current_tab_widget.toggle_bookmarks()
if sender == self.bookToolBar.annotationButton:
current_tab_widget.toggle_annotations()
def library_doubleclick(self, index):
sender = self.sender().objectName()
if sender == 'listView':
source_index = self.lib_ref.item_proxy_model.mapToSource(index)
source_index = self.lib_ref.itemProxyModel.mapToSource(index)
elif sender == 'tableView':
source_index = self.lib_ref.table_proxy_model.mapToSource(index)
source_index = self.lib_ref.tableProxyModel.mapToSource(index)
item = self.lib_ref.view_model.item(source_index.row(), 0)
item = self.lib_ref.libraryModel.item(source_index.row(), 0)
metadata = item.data(QtCore.Qt.UserRole + 3)
path = {metadata['path']: metadata['hash']}
self.open_files(path)
def open_files(self, path_hash_dictionary):
# file_paths is expected to be a dictionary
# This allows for threading file opening
# Which should speed up multiple file opening
# especially @ application start
file_paths = [i for i in path_hash_dictionary]
for filename in path_hash_dictionary.items():
file_md5 = filename[1]
if not file_md5:
try:
with open(filename[0], 'rb') as current_book:
first_bytes = current_book.read(1024 * 32) # First 32KB of the file
file_md5 = hashlib.md5(first_bytes).hexdigest()
except FileNotFoundError:
return
# Remove any already open files
# Set focus to last file in case only one is open
for i in range(1, self.tabWidget.count()):
tab_metadata = self.tabWidget.widget(i).metadata
if tab_metadata['hash'] == file_md5:
file_paths.remove(filename[0])
if not file_paths:
self.tabWidget.setCurrentIndex(i)
return
if not file_paths:
return
def finishing_touches():
self.format_contentView()
self.start_culling_timer()
print('Attempting to open: ' + ', '.join(file_paths))
contents = sorter.BookSorter(
file_paths,
('reading', None),
self.database_path,
True,
self.temp_dir.path()).initiate_threads()
for i in contents:
# New tabs are created here
# Initial position adjustment is carried out by the tab itself
file_data = contents[i]
Tab(file_data, self)
if self.settings['last_open_tab'] == 'library':
self.tabWidget.setCurrentIndex(0)
self.listView.setFocus()
self.settings['last_open_tab'] = None
return
for i in range(1, self.tabWidget.count()):
this_path = self.tabWidget.widget(i).metadata['path']
if self.settings['last_open_tab'] == this_path:
self.tabWidget.setCurrentIndex(i)
self.settings['last_open_tab'] = None
finishing_touches()
return
self.tabWidget.setCurrentIndex(self.tabWidget.count() - 1)
finishing_touches()
# TODO
# def dropEvent
def get_color(self):
def open_color_dialog(current_color):
color_dialog = QtWidgets.QColorDialog()
new_color = color_dialog.getColor(current_color)
if new_color.isValid(): # Returned in case cancel is pressed
return new_color
def statusbar_visibility(self):
if self.sender() == self.libraryToolBar.searchBar:
if self.libraryToolBar.searchBar.text() == '':
self.statusBar.setVisible(False)
else:
return current_color
signal_sender = self.sender().objectName()
# Special cases that don't affect (comic)book display
if signal_sender == 'libraryBackground':
current_color = self.settings['listview_background']
new_color = open_color_dialog(current_color)
self.listView.setStyleSheet("QListView {{background-color: {0}}}".format(
new_color.name()))
self.settings['listview_background'] = new_color
return
if signal_sender == 'dialogBackground':
current_color = self.settings['dialog_background']
new_color = open_color_dialog(current_color)
self.settings['dialog_background'] = new_color
return new_color
profile_index = self.bookToolBar.profileBox.currentIndex()
current_profile = self.bookToolBar.profileBox.itemData(
profile_index, QtCore.Qt.UserRole)
# Retain current values on opening a new dialog
if signal_sender == 'fgColor':
current_color = current_profile['foreground']
new_color = open_color_dialog(current_color)
self.bookToolBar.colorBoxFG.setStyleSheet(
'background-color: %s' % new_color.name())
current_profile['foreground'] = new_color
elif signal_sender == 'bgColor':
current_color = current_profile['background']
new_color = open_color_dialog(current_color)
self.bookToolBar.colorBoxBG.setStyleSheet(
'background-color: %s' % new_color.name())
current_profile['background'] = new_color
elif signal_sender == 'comicBGColor':
current_color = self.comic_profile['background']
new_color = open_color_dialog(current_color)
self.bookToolBar.comicBGColor.setStyleSheet(
'background-color: %s' % new_color.name())
self.comic_profile['background'] = new_color
self.bookToolBar.profileBox.setItemData(
profile_index, current_profile, QtCore.Qt.UserRole)
self.format_contentView()
def modify_font(self):
signal_sender = self.sender().objectName()
profile_index = self.bookToolBar.profileBox.currentIndex()
current_profile = self.bookToolBar.profileBox.itemData(
profile_index, QtCore.Qt.UserRole)
if signal_sender == 'fontBox':
current_profile['font'] = self.bookToolBar.fontBox.currentFont().family()
if signal_sender == 'fontSizeBox':
old_size = current_profile['font_size']
new_size = self.bookToolBar.fontSizeBox.itemText(
self.bookToolBar.fontSizeBox.currentIndex())
if new_size.isdigit():
current_profile['font_size'] = new_size
else:
current_profile['font_size'] = old_size
if signal_sender == 'lineSpacingUp' and current_profile['line_spacing'] < 200:
current_profile['line_spacing'] += 5
if signal_sender == 'lineSpacingDown' and current_profile['line_spacing'] > 90:
current_profile['line_spacing'] -= 5
if signal_sender == 'paddingUp':
current_profile['padding'] += 5
if signal_sender == 'paddingDown':
current_profile['padding'] -= 5
alignment_dict = {
'alignLeft': 'left',
'alignRight': 'right',
'alignCenter': 'center',
'alignJustify': 'justify'}
if signal_sender in alignment_dict:
current_profile['text_alignment'] = alignment_dict[signal_sender]
self.bookToolBar.profileBox.setItemData(
profile_index, current_profile, QtCore.Qt.UserRole)
self.format_contentView()
def modify_comic_view(self, key_pressed=None):
if key_pressed:
signal_sender = None
else:
signal_sender = self.sender().objectName()
current_tab = self.tabWidget.widget(self.tabWidget.currentIndex())
self.bookToolBar.fitWidth.setChecked(False)
self.bookToolBar.bestFit.setChecked(False)
self.bookToolBar.originalSize.setChecked(False)
if signal_sender == 'zoomOut' or key_pressed == QtCore.Qt.Key_Minus:
self.comic_profile['zoom_mode'] = 'manualZoom'
self.comic_profile['padding'] += 50
# This prevents infinite zoom out
if self.comic_profile['padding'] * 2 > current_tab.contentView.viewport().width():
self.comic_profile['padding'] -= 50
if signal_sender == 'zoomIn' or key_pressed in (QtCore.Qt.Key_Plus, QtCore.Qt.Key_Equal):
self.comic_profile['zoom_mode'] = 'manualZoom'
self.comic_profile['padding'] -= 50
# This prevents infinite zoom in
if self.comic_profile['padding'] < 0:
self.comic_profile['padding'] = 0
if signal_sender == 'fitWidth' or key_pressed == QtCore.Qt.Key_W:
self.comic_profile['zoom_mode'] = 'fitWidth'
self.comic_profile['padding'] = 0
self.bookToolBar.fitWidth.setChecked(True)
# Padding in the following cases is decided by
# the image pixmap loaded by the widget
if signal_sender == 'bestFit' or key_pressed == QtCore.Qt.Key_B:
self.comic_profile['zoom_mode'] = 'bestFit'
self.bookToolBar.bestFit.setChecked(True)
if signal_sender == 'originalSize' or key_pressed == QtCore.Qt.Key_O:
self.comic_profile['zoom_mode'] = 'originalSize'
self.bookToolBar.originalSize.setChecked(True)
self.format_contentView()
def format_contentView(self):
# TODO
# See what happens if a font isn't installed
current_tab = self.tabWidget.widget(
self.tabWidget.currentIndex())
try:
current_metadata = current_tab.metadata
except AttributeError:
return
if current_metadata['images_only']:
background = self.comic_profile['background']
padding = self.comic_profile['padding']
zoom_mode = self.comic_profile['zoom_mode']
if zoom_mode == 'fitWidth':
self.bookToolBar.fitWidth.setChecked(True)
if zoom_mode == 'bestFit':
self.bookToolBar.bestFit.setChecked(True)
if zoom_mode == 'originalSize':
self.bookToolBar.originalSize.setChecked(True)
self.bookToolBar.comicBGColor.setStyleSheet(
'background-color: %s' % background.name())
current_tab.format_view(
None, None, None, background, padding, None, None)
else:
profile_index = self.bookToolBar.profileBox.currentIndex()
current_profile = self.bookToolBar.profileBox.itemData(
profile_index, QtCore.Qt.UserRole)
font = current_profile['font']
foreground = current_profile['foreground']
background = current_profile['background']
padding = current_profile['padding']
font_size = current_profile['font_size']
line_spacing = current_profile['line_spacing']
text_alignment = current_profile['text_alignment']
# Change toolbar widgets to match new settings
self.bookToolBar.fontBox.blockSignals(True)
self.bookToolBar.fontSizeBox.blockSignals(True)
self.bookToolBar.fontBox.setCurrentText(font)
current_index = self.bookToolBar.fontSizeBox.findText(
str(font_size), QtCore.Qt.MatchExactly)
self.bookToolBar.fontSizeBox.setCurrentIndex(current_index)
self.bookToolBar.fontBox.blockSignals(False)
self.bookToolBar.fontSizeBox.blockSignals(False)
self.alignment_dict[current_profile['text_alignment']].setChecked(True)
self.bookToolBar.colorBoxFG.setStyleSheet(
'background-color: %s' % foreground.name())
self.bookToolBar.colorBoxBG.setStyleSheet(
'background-color: %s' % background.name())
current_tab.format_view(
font, font_size, foreground,
background, padding, line_spacing,
text_alignment)
def reset_profile(self):
current_profile_index = self.bookToolBar.profileBox.currentIndex()
current_profile_default = Settings(self).default_profiles[current_profile_index]
self.bookToolBar.profileBox.setItemData(
current_profile_index, current_profile_default, QtCore.Qt.UserRole)
self.format_contentView()
self.statusBar.setVisible(True)
def show_settings(self):
if not self.settingsDialog.isVisible():
@@ -1022,12 +726,34 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
else:
self.settingsDialog.hide()
#____________________________________________
# The contentView modification functions are in the guifunctions
# module. self.profile_functions is the reference here.
def get_color(self):
self.profile_functions.get_color(
self.sender().objectName())
def modify_font(self):
self.profile_functions.modify_font(
self.sender().objectName())
def modify_comic_view(self, key_pressed=None):
if key_pressed:
signal_sender = None
else:
signal_sender = self.sender().objectName()
self.profile_functions.modify_comic_view(
signal_sender, key_pressed)
#____________________________________________
def generate_library_context_menu(self, position):
index = self.sender().indexAt(position)
if not index.isValid():
return
# It's worth remembering that these are indexes of the view_model
# It's worth remembering that these are indexes of the libraryModel
# and NOT of the proxy models
selected_indexes = self.get_selection(self.sender())
@@ -1058,28 +784,28 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
if action == openAction:
books_to_open = {}
for i in selected_indexes:
metadata = self.lib_ref.view_model.data(i, QtCore.Qt.UserRole + 3)
metadata = self.lib_ref.libraryModel.data(i, QtCore.Qt.UserRole + 3)
books_to_open[metadata['path']] = metadata['hash']
self.open_files(books_to_open)
if action == editAction:
edit_book = selected_indexes[0]
metadata = self.lib_ref.view_model.data(
metadata = self.lib_ref.libraryModel.data(
edit_book, QtCore.Qt.UserRole + 3)
is_cover_loaded = self.lib_ref.view_model.data(
is_cover_loaded = self.lib_ref.libraryModel.data(
edit_book, QtCore.Qt.UserRole + 8)
# Loads a cover in case culling is enabled and the table view is visible
if not is_cover_loaded:
book_hash = self.lib_ref.view_model.data(
book_hash = self.lib_ref.libraryModel.data(
edit_book, QtCore.Qt.UserRole + 6)
book_item = self.lib_ref.view_model.item(edit_book.row())
book_item = self.lib_ref.libraryModel.item(edit_book.row())
book_cover = database.DatabaseFunctions(
self.database_path).fetch_covers_only([book_hash])[0][1]
self.cover_loader(book_item, book_cover)
self.cover_functions.cover_loader(book_item, book_cover)
cover = self.lib_ref.view_model.item(edit_book.row()).icon()
cover = self.lib_ref.libraryModel.item(edit_book.row()).icon()
title = metadata['title']
author = metadata['author']
year = str(metadata['year'])
@@ -1095,8 +821,8 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
if action == readAction or action == unreadAction:
for i in selected_indexes:
metadata = self.lib_ref.view_model.data(i, QtCore.Qt.UserRole + 3)
book_hash = self.lib_ref.view_model.data(i, QtCore.Qt.UserRole + 6)
metadata = self.lib_ref.libraryModel.data(i, QtCore.Qt.UserRole + 3)
book_hash = self.lib_ref.libraryModel.data(i, QtCore.Qt.UserRole + 6)
position = metadata['position']
if position:
@@ -1118,11 +844,11 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
last_accessed_time = None
if action == readAction:
last_accessed_time = QtCore.QDateTime().currentDateTime()
position_perc = 100
position_perc = 1
self.lib_ref.view_model.setData(i, metadata, QtCore.Qt.UserRole + 3)
self.lib_ref.view_model.setData(i, position_perc, QtCore.Qt.UserRole + 7)
self.lib_ref.view_model.setData(i, last_accessed_time, QtCore.Qt.UserRole + 12)
self.lib_ref.libraryModel.setData(i, metadata, QtCore.Qt.UserRole + 3)
self.lib_ref.libraryModel.setData(i, position_perc, QtCore.Qt.UserRole + 7)
self.lib_ref.libraryModel.setData(i, last_accessed_time, QtCore.Qt.UserRole + 12)
self.lib_ref.update_proxymodels()
database_dict = {
@@ -1189,10 +915,9 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
def toggle_distraction_free(self):
self.settings['show_bars'] = not self.settings['show_bars']
self.statusBar.setVisible(
not self.statusBar.isVisible())
self.tabWidget.tabBar().setVisible(
not self.tabWidget.tabBar().isVisible())
if self.tabWidget.count() > 1:
self.tabWidget.tabBar().setVisible(
self.settings['show_bars'])
current_tab = self.tabWidget.currentIndex()
if current_tab == 0:
@@ -1213,6 +938,11 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
self.settingsDialog.hide()
self.definitionDialog.hide()
self.temp_dir.remove()
for this_dock in self.active_bookmark_docks:
try:
this_dock.setVisible(False)
except RuntimeError:
pass
self.settings['last_open_books'] = []
if self.tabWidget.count() > 1:

311
lector/annotations.py Normal file
View File

@@ -0,0 +1,311 @@
# This file is a part of Lector, a Qt based ebook reader
# Copyright (C) 2017-2018 BasioMeusPuga
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from PyQt5 import QtWidgets, QtCore, QtGui
from lector.resources import annotationswindow
class AnnotationsUI(QtWidgets.QDialog, annotationswindow.Ui_Dialog):
def __init__(self, parent=None):
super(AnnotationsUI, self).__init__()
self.setupUi(self)
self.parent = parent
self._translate = QtCore.QCoreApplication.translate
# Current annotation
self.modelIndex = None # The index of the annotations list model in the parent dialog
self.current_annotation = {}
# Populate annotation type
textmarkup_string = self._translate('AnnotationsUI', 'Text markup')
all_types = [textmarkup_string]
for i in all_types:
self.typeBox.addItem(i)
# Init defaults
self.default_stylesheet = self.foregroundCheck.styleSheet()
self.foregroundColor = QtGui.QColor.fromRgb(0, 0, 0)
self.underlineColor = QtGui.QColor.fromRgb(255, 0, 0)
self.highlightColor = QtGui.QColor.fromRgb(66, 209, 56)
self.underline_styles = {
'Solid': QtGui.QTextCharFormat.SingleUnderline,
'Dashes': QtGui.QTextCharFormat.DashUnderline,
'Dots': QtGui.QTextCharFormat.DotLine,
'Wavy': QtGui.QTextCharFormat.WaveUnderline}
# Push buttons
self.foregroundColorButton.clicked.connect(self.modify_annotation)
self.highlightColorButton.clicked.connect(self.modify_annotation)
self.underlineColorButton.clicked.connect(self.modify_annotation)
self.okButton.clicked.connect(self.ok_pressed)
self.cancelButton.clicked.connect(self.hide)
# Underline combo box
underline_items = ['Solid', 'Dashes', 'Dots', 'Wavy']
self.underlineType.addItems(underline_items)
self.underlineType.currentIndexChanged.connect(self.modify_annotation)
# Text markup related checkboxes
self.foregroundCheck.clicked.connect(self.modify_annotation)
self.highlightCheck.clicked.connect(self.modify_annotation)
self.boldCheck.clicked.connect(self.modify_annotation)
self.italicCheck.clicked.connect(self.modify_annotation)
self.underlineCheck.clicked.connect(self.modify_annotation)
def show_dialog(self, mode, index=None):
# TODO
# Account for annotation type here
# and point to a relevant set of widgets accordingly
if mode == 'edit' or mode == 'preview':
self.modelIndex = index
this_annotation = self.parent.annotationModel.data(
index, QtCore.Qt.UserRole)
annotation_name = this_annotation['name']
self.nameEdit.setText(annotation_name)
annotation_components = this_annotation['components']
if 'foregroundColor' in annotation_components:
self.foregroundCheck.setChecked(True)
self.set_button_background_color(
self.foregroundColorButton, annotation_components['foregroundColor'])
else:
self.foregroundCheck.setChecked(False)
if 'highlightColor' in annotation_components:
self.highlightCheck.setChecked(True)
self.set_button_background_color(
self.highlightColorButton, annotation_components['highlightColor'])
else:
self.highlightCheck.setChecked(False)
if 'bold' in annotation_components:
self.boldCheck.setChecked(True)
else:
self.boldCheck.setChecked(False)
if 'italic' in annotation_components:
self.italicCheck.setChecked(True)
else:
self.italicCheck.setChecked(False)
if 'underline' in annotation_components:
self.underlineCheck.setChecked(True)
underline_params = annotation_components['underline']
self.underlineType.setCurrentText(underline_params[0])
self.set_button_background_color(
self.underlineColorButton, underline_params[1])
else:
self.underlineCheck.setChecked(False)
elif mode == 'add':
new_annotation_string = self._translate('AnnotationsUI', 'New annotation')
self.nameEdit.setText(new_annotation_string)
all_checkboxes = (
self.foregroundCheck, self.highlightCheck,
self.boldCheck, self.italicCheck, self.underlineCheck)
for i in all_checkboxes:
i.setChecked(False)
self.modelIndex = None
self.set_button_background_color(
self.foregroundColorButton, self.foregroundColor)
self.set_button_background_color(
self.highlightColorButton, self.highlightColor)
self.set_button_background_color(
self.underlineColorButton, self.underlineColor)
self.update_preview()
if mode != 'preview':
self.show()
def set_button_background_color(self, button, color):
button.setStyleSheet(
"QPushButton {{background-color: {0}}}".format(color.name()))
def update_preview(self):
cursor = self.parent.previewView.textCursor()
cursor.setPosition(0)
cursor.movePosition(QtGui.QTextCursor.End, QtGui.QTextCursor.KeepAnchor)
# TODO
# Other kinds of text markup
previewCharFormat = QtGui.QTextCharFormat()
if self.foregroundCheck.isChecked():
previewCharFormat.setForeground(self.foregroundColor)
highlight = QtCore.Qt.transparent
if self.highlightCheck.isChecked():
highlight = self.highlightColor
previewCharFormat.setBackground(highlight)
font_weight = QtGui.QFont.Normal
if self.boldCheck.isChecked():
font_weight = QtGui.QFont.Bold
previewCharFormat.setFontWeight(font_weight)
if self.italicCheck.isChecked():
previewCharFormat.setFontItalic(True)
if self.underlineCheck.isChecked():
previewCharFormat.setFontUnderline(True)
previewCharFormat.setUnderlineColor(self.underlineColor)
previewCharFormat.setUnderlineStyle(
self.underline_styles[self.underlineType.currentText()])
previewCharFormat.setFontStyleStrategy(
QtGui.QFont.PreferAntialias)
cursor.setCharFormat(previewCharFormat)
cursor.clearSelection()
self.parent.previewView.setTextCursor(cursor)
def modify_annotation(self):
sender = self.sender()
if isinstance(sender, QtWidgets.QCheckBox):
if not sender.isChecked():
self.update_preview()
return
new_color = None
if sender == self.foregroundColorButton:
new_color = self.get_color(self.foregroundColor)
self.foregroundColor = new_color
if sender == self.highlightColorButton:
new_color = self.get_color(self.highlightColor)
self.highlightColor = new_color
if sender == self.underlineColorButton:
new_color = self.get_color(self.underlineColor)
self.underlineColor = new_color
if new_color:
self.set_button_background_color(sender, new_color)
self.update_preview()
def get_color(self, current_color):
color_dialog = QtWidgets.QColorDialog()
new_color = color_dialog.getColor(current_color)
if new_color.isValid(): # Returned in case cancel is pressed
return new_color
else:
return current_color
def ok_pressed(self):
annotation_name = self.nameEdit.text()
if annotation_name == '':
self.nameEdit.setText('Why do you like bugs? WHY?')
return
annotation_components = {}
if self.foregroundCheck.isChecked():
annotation_components['foregroundColor'] = self.foregroundColor
if self.highlightCheck.isChecked():
annotation_components['highlightColor'] = self.highlightColor
if self.boldCheck.isChecked():
annotation_components['bold'] = True
if self.italicCheck.isChecked():
annotation_components['italic'] = True
if self.underlineCheck.isChecked():
annotation_components['underline'] = (
self.underlineType.currentText(), self.underlineColor)
self.current_annotation = {
'name': annotation_name,
'applicable_to': 'text',
'type': 'text_markup',
'components': annotation_components}
if self.modelIndex:
self.parent.annotationModel.setData(
self.modelIndex, annotation_name, QtCore.Qt.DisplayRole)
self.parent.annotationModel.setData(
self.modelIndex, self.current_annotation, QtCore.Qt.UserRole)
else: # New annotation
new_annotation_item = QtGui.QStandardItem()
new_annotation_item.setText(annotation_name)
new_annotation_item.setData(self.current_annotation, QtCore.Qt.UserRole)
self.parent.annotationModel.appendRow(new_annotation_item)
self.hide()
class AnnotationPlacement:
def __init__(self):
self.annotation_type = None
self.annotation_components = None
self.underline_styles = {
'Solid': QtGui.QTextCharFormat.SingleUnderline,
'Dashes': QtGui.QTextCharFormat.DashUnderline,
'Dots': QtGui.QTextCharFormat.DotLine,
'Wavy': QtGui.QTextCharFormat.WaveUnderline}
def set_current_annotation(self, annotation_type, annotation_components):
# Components expected to be a dictionary
self.annotation_type = annotation_type # This is currently unused
self.annotation_components = annotation_components
def format_text(self, cursor, start_here, end_here):
# This is applicable only to the PliantQTextBrowser
# for the text_markup style of annotation
# The cursor is the textCursor of the QTextEdit
# containing the text that has to be modified
if not self.annotation_components:
return
cursor.setPosition(start_here)
cursor.setPosition(end_here, QtGui.QTextCursor.KeepAnchor)
newCharFormat = QtGui.QTextCharFormat()
if 'foregroundColor' in self.annotation_components:
newCharFormat.setForeground(
self.annotation_components['foregroundColor'])
if 'highlightColor' in self.annotation_components:
newCharFormat.setBackground(
self.annotation_components['highlightColor'])
if 'bold' in self.annotation_components:
newCharFormat.setFontWeight(QtGui.QFont.Bold)
if 'italic' in self.annotation_components:
newCharFormat.setFontItalic(True)
if 'underline' in self.annotation_components:
newCharFormat.setFontUnderline(True)
newCharFormat.setUnderlineStyle(
self.underline_styles[self.annotation_components['underline'][0]])
newCharFormat.setUnderlineColor(
self.annotation_components['underline'][1])
newCharFormat.setFontStyleStrategy(
QtGui.QFont.PreferAntialias)
cursor.setCharFormat(newCharFormat)
cursor.clearSelection()
return cursor

764
lector/contentwidgets.py Normal file
View File

@@ -0,0 +1,764 @@
# This file is a part of Lector, a Qt based ebook reader
# Copyright (C) 2017-2018 BasioMeusPuga
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import zipfile
import webbrowser
try:
import popplerqt5
except ImportError:
pass
from PyQt5 import QtWidgets, QtGui, QtCore
from lector.rarfile import rarfile
from lector.threaded import BackGroundCacheRefill
from lector.annotations import AnnotationPlacement
class PliantQGraphicsView(QtWidgets.QGraphicsView):
def __init__(self, filepath, main_window, parent=None):
super(PliantQGraphicsView, self).__init__(parent)
self._translate = QtCore.QCoreApplication.translate
self.parent = parent
self.main_window = main_window
self.qimage = None # Will be needed to resize pdf
self.image_pixmap = None
self.image_cache = [None for _ in range(4)]
self.thread = None
self.annotation_dict = self.parent.metadata['annotations']
self.filepath = filepath
self.filetype = os.path.splitext(self.filepath)[1][1:]
if self.filetype == 'cbz':
self.book = zipfile.ZipFile(self.filepath)
elif self.filetype == 'cbr':
self.book = rarfile.RarFile(self.filepath)
elif self.filetype == 'pdf':
self.book = popplerqt5.Poppler.Document.load(self.filepath)
self.book.setRenderHint(
popplerqt5.Poppler.Document.Antialiasing
and popplerqt5.Poppler.Document.TextAntialiasing)
self.common_functions = PliantWidgetsCommonFunctions(
self, self.main_window)
self.ignore_wheel_event = False
self.ignore_wheel_event_number = 0
self.setMouseTracking(True)
self.setDragMode(QtWidgets.QGraphicsView.ScrollHandDrag)
self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.customContextMenuRequested.connect(
self.generate_graphicsview_context_menu)
def loadImage(self, current_page):
# TODO
# For double page view: 1 before, 1 after
all_pages = [i[1] for i in self.parent.metadata['content']]
def load_page(current_page):
image_pixmap = QtGui.QPixmap()
if self.filetype in ('cbz', 'cbr'):
page_data = self.book.read(current_page)
image_pixmap.loadFromData(page_data)
elif self.filetype == 'pdf':
page_data = self.book.page(current_page)
page_qimage = page_data.renderToImage(400, 400) # TODO Maybe this needs a setting?
image_pixmap.convertFromImage(page_qimage)
return image_pixmap
def generate_image_cache(current_page):
print('Building image cache')
current_page_index = all_pages.index(current_page)
for i in (-1, 0, 1, 2):
try:
this_page = all_pages[current_page_index + i]
this_pixmap = load_page(this_page)
self.image_cache[i + 1] = (this_page, this_pixmap)
except IndexError:
self.image_cache[i + 1] = None
def refill_cache(remove_value):
# Do NOT put a parent in here or the mother of all
# memory leaks will result
self.thread = BackGroundCacheRefill(
self.image_cache, remove_value,
self.filetype, self.book, all_pages)
self.thread.finished.connect(overwrite_cache)
self.thread.start()
def overwrite_cache():
self.image_cache = self.thread.image_cache
def check_cache(current_page):
for i in self.image_cache:
if i:
if i[0] == current_page:
return_pixmap = i[1]
refill_cache(i)
return return_pixmap
# No return happened so the image isn't in the cache
generate_image_cache(current_page)
if self.main_window.settings['caching_enabled']:
return_pixmap = None
while not return_pixmap:
return_pixmap = check_cache(current_page)
else:
return_pixmap = load_page(current_page)
self.image_pixmap = return_pixmap
self.resizeEvent()
def resizeEvent(self, *args):
if not self.image_pixmap:
return
zoom_mode = self.main_window.comic_profile['zoom_mode']
padding = self.main_window.comic_profile['padding']
if zoom_mode == 'fitWidth':
available_width = self.viewport().width()
image_pixmap = self.image_pixmap.scaledToWidth(
available_width, QtCore.Qt.SmoothTransformation)
elif zoom_mode == 'originalSize':
image_pixmap = self.image_pixmap
new_padding = (self.viewport().width() - image_pixmap.width()) // 2
if new_padding < 0: # The image is larger than the viewport
self.main_window.comic_profile['padding'] = 0
else:
self.main_window.comic_profile['padding'] = new_padding
elif zoom_mode == 'bestFit':
available_width = self.viewport().width()
available_height = self.viewport().height()
image_pixmap = self.image_pixmap.scaled(
available_width, available_height,
QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
self.main_window.comic_profile['padding'] = (
self.viewport().width() - image_pixmap.width()) // 2
elif zoom_mode == 'manualZoom':
available_width = self.viewport().width() - 2 * padding
image_pixmap = self.image_pixmap.scaledToWidth(
available_width, QtCore.Qt.SmoothTransformation)
graphics_scene = QtWidgets.QGraphicsScene()
graphics_scene.addPixmap(image_pixmap)
self.setScene(graphics_scene)
self.show()
def wheelEvent(self, event):
self.common_functions.wheelEvent(event)
def keyPressEvent(self, event):
vertical = self.verticalScrollBar().value()
maximum = self.verticalScrollBar().maximum()
def scroller(increment, move_forward=True):
if move_forward:
if vertical == maximum:
self.common_functions.change_chapter(1, True)
else:
next_val = vertical + increment
if next_val >= .95 * maximum:
next_val = maximum
self.verticalScrollBar().setValue(next_val)
else:
if vertical == 0:
self.common_functions.change_chapter(-1, False)
else:
next_val = vertical - increment
if next_val <= .05 * maximum:
next_val = 0
self.verticalScrollBar().setValue(next_val)
small_increment = maximum // 4
big_increment = maximum // 2
if event.key() == QtCore.Qt.Key_Up:
scroller(small_increment, False)
if event.key() == QtCore.Qt.Key_Down:
scroller(small_increment)
if event.key() == QtCore.Qt.Key_Space:
scroller(big_increment)
view_modification_keys = (
QtCore.Qt.Key_Plus, QtCore.Qt.Key_Minus, QtCore.Qt.Key_Equal,
QtCore.Qt.Key_B, QtCore.Qt.Key_W, QtCore.Qt.Key_O)
if event.key() in view_modification_keys:
self.main_window.modify_comic_view(event.key())
def record_position(self):
self.parent.metadata['position']['is_read'] = False
self.common_functions.update_model()
def mouseMoveEvent(self, event):
if QtWidgets.QApplication.mouseButtons() == QtCore.Qt.NoButton:
self.viewport().setCursor(QtCore.Qt.OpenHandCursor)
else:
self.viewport().setCursor(QtCore.Qt.ClosedHandCursor)
self.parent.mouse_hide_timer.start(3000)
QtWidgets.QGraphicsView.mouseMoveEvent(self, event)
def generate_graphicsview_context_menu(self, position):
contextMenu = QtWidgets.QMenu()
saveAction = contextMenu.addAction(
self.main_window.QImageFactory.get_image('filesaveas'),
self._translate('PliantQGraphicsView', 'Save page as...'))
fsToggleAction = dfToggleAction = 'Caesar si viveret, ad remum dareris'
if self.parent.is_fullscreen:
fsToggleAction = contextMenu.addAction(
self.main_window.QImageFactory.get_image('view-fullscreen'),
self._translate('PliantQGraphicsView', 'Exit fullscreen'))
else:
if self.main_window.settings['show_bars']:
distraction_free_prompt = self._translate(
'PliantQGraphicsView', 'Distraction Free mode')
else:
distraction_free_prompt = self._translate(
'PliantQGraphicsView', 'Exit Distraction Free mode')
dfToggleAction = contextMenu.addAction(
self.main_window.QImageFactory.get_image('visibility'),
distraction_free_prompt)
view_submenu_string = self._translate('PliantQGraphicsView', 'View')
viewSubMenu = contextMenu.addMenu(view_submenu_string)
viewSubMenu.setIcon(
self.main_window.QImageFactory.get_image('mail-thread-watch'))
zoominAction = viewSubMenu.addAction(
self.main_window.QImageFactory.get_image('zoom-in'),
self._translate('PliantQGraphicsView', 'Zoom in (+)'))
zoomoutAction = viewSubMenu.addAction(
self.main_window.QImageFactory.get_image('zoom-out'),
self._translate('PliantQGraphicsView', 'Zoom out (-)'))
fitWidthAction = viewSubMenu.addAction(
self.main_window.QImageFactory.get_image('zoom-fit-width'),
self._translate('PliantQGraphicsView', 'Fit width (W)'))
bestFitAction = viewSubMenu.addAction(
self.main_window.QImageFactory.get_image('zoom-fit-best'),
self._translate('PliantQGraphicsView', 'Best fit (B)'))
originalSizeAction = viewSubMenu.addAction(
self.main_window.QImageFactory.get_image('zoom-original'),
self._translate('PliantQGraphicsView', 'Original size (O)'))
bookmarksToggleAction = 'Latin quote 2. Electric Boogaloo.'
if not self.main_window.settings['show_bars'] or self.parent.is_fullscreen:
bookmarksToggleAction = contextMenu.addAction(
self.main_window.QImageFactory.get_image('bookmarks'),
self._translate('PliantQGraphicsView', 'Bookmarks'))
self.common_functions.generate_combo_box_action(contextMenu)
action = contextMenu.exec_(self.sender().mapToGlobal(position))
if action == saveAction:
dialog_prompt = self._translate('Main_UI', 'Save page as...')
extension_string = self._translate('Main_UI', 'Images')
save_file = QtWidgets.QFileDialog.getSaveFileName(
self, dialog_prompt, self.main_window.settings['last_open_path'],
f'{extension_string} (*.png *.jpg *.bmp)')
if save_file:
self.image_pixmap.save(save_file[0])
if action == bookmarksToggleAction:
self.parent.toggle_bookmarks()
if action == dfToggleAction:
self.main_window.toggle_distraction_free()
if action == fsToggleAction:
self.parent.exit_fullscreen()
view_action_dict = {
zoominAction: QtCore.Qt.Key_Plus,
zoomoutAction: QtCore.Qt.Key_Minus,
fitWidthAction: QtCore.Qt.Key_W,
bestFitAction: QtCore.Qt.Key_B,
originalSizeAction: QtCore.Qt.Key_O}
if action in view_action_dict:
self.main_window.modify_comic_view(view_action_dict[action])
def closeEvent(self, *args):
# In case the program is closed when a contentView is fullscreened
self.main_window.closeEvent()
def toggle_annotation_mode(self):
pass
class PliantQTextBrowser(QtWidgets.QTextBrowser):
def __init__(self, main_window, parent=None):
super(PliantQTextBrowser, self).__init__(parent)
self._translate = QtCore.QCoreApplication.translate
self.parent = parent
self.main_window = main_window
self.annotation_mode = False
self.annotator = AnnotationPlacement()
self.current_annotation = None
self.annotation_dict = self.parent.metadata['annotations']
self.common_functions = PliantWidgetsCommonFunctions(
self, self.main_window)
self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.customContextMenuRequested.connect(
self.generate_textbrowser_context_menu)
self.setMouseTracking(True)
self.verticalScrollBar().sliderMoved.connect(
self.record_position)
self.ignore_wheel_event = False
self.ignore_wheel_event_number = 0
self.at_end = False
def wheelEvent(self, event):
self.record_position()
self.common_functions.wheelEvent(event)
def keyPressEvent(self, event):
QtWidgets.QTextEdit.keyPressEvent(self, event)
if event.key() == QtCore.Qt.Key_Space:
if self.verticalScrollBar().value() == self.verticalScrollBar().maximum():
if self.at_end: # This makes sure the last lines of the chapter don't get skipped
self.common_functions.change_chapter(1, True)
self.at_end = True
else:
self.at_end = False
self.set_top_line_cleanly()
self.record_position()
def set_top_line_cleanly(self):
# Find the cursor position of the top line and move to it
find_cursor = self.cursorForPosition(QtCore.QPoint(0, 0))
find_cursor.movePosition(
find_cursor.position(), QtGui.QTextCursor.KeepAnchor)
self.setTextCursor(find_cursor)
self.ensureCursorVisible()
def record_position(self, return_as_bookmark=False):
self.parent.metadata['position']['is_read'] = False
cursor = self.cursorForPosition(QtCore.QPoint(0, 0))
cursor_position = cursor.position()
# Current block for progress measurement
current_block = cursor.block().blockNumber()
current_chapter = self.parent.metadata['position']['current_chapter']
blocks_per_chapter = self.parent.metadata['position']['blocks_per_chapter']
block_sum = sum(blocks_per_chapter[:(current_chapter - 1)])
block_sum += current_block
# This 'current_block' refers to the number of
# blocks in the book upto this one
self.parent.metadata['position']['current_block'] = block_sum
self.common_functions.update_model()
if return_as_bookmark:
return (self.parent.metadata['position']['current_chapter'],
cursor_position)
else:
self.parent.metadata['position']['cursor_position'] = cursor_position
def toggle_annotation_mode(self):
if self.annotation_mode:
self.annotation_mode = False
self.viewport().setCursor(QtCore.Qt.ArrowCursor)
self.parent.annotationDock.show()
self.parent.annotationDock.setWindowOpacity(.95)
self.current_annotation = None
self.parent.annotationListView.clearSelection()
else:
self.annotation_mode = True
self.viewport().setCursor(QtCore.Qt.IBeamCursor)
self.parent.annotationDock.hide()
selected_index = self.parent.annotationListView.currentIndex()
self.current_annotation = self.parent.annotationModel.data(
selected_index, QtCore.Qt.UserRole)
print('Current annotation: ' + self.current_annotation['name'])
def mouseReleaseEvent(self, event):
# This takes care of annotation placement
# and addition to the list that holds all current annotations
if not self.current_annotation:
QtWidgets.QTextBrowser.mouseReleaseEvent(self, event)
return
current_chapter = self.parent.metadata['position']['current_chapter']
cursor = self.textCursor()
cursor_start = cursor.selectionStart()
cursor_end = cursor.selectionEnd()
annotation_type = 'text_markup'
applicable_to = 'text'
annotation_components = self.current_annotation['components']
self.annotator.set_current_annotation(
annotation_type, annotation_components)
new_cursor = self.annotator.format_text(
cursor, cursor_start, cursor_end)
self.setTextCursor(new_cursor)
# TODO
# Maybe use annotation name for a consolidated annotation list
this_annotation = {
'name': self.current_annotation['name'],
'applicable_to': applicable_to,
'type': annotation_type,
'cursor': (cursor_start, cursor_end),
'components': annotation_components,
'note': None}
try:
self.annotation_dict[current_chapter].append(this_annotation)
except KeyError:
self.annotation_dict[current_chapter] = []
self.annotation_dict[current_chapter].append(this_annotation)
self.toggle_annotation_mode()
def generate_textbrowser_context_menu(self, position):
selection = self.textCursor().selection()
selection = selection.toPlainText()
current_chapter = self.parent.metadata['position']['current_chapter']
cursor_at_mouse = self.cursorForPosition(position)
annotation_is_present = self.common_functions.annotation_specific(
'check', 'text', current_chapter, cursor_at_mouse.position())
contextMenu = QtWidgets.QMenu()
# The following cannot be None because a click
# outside the menu means that the action variable is None.
defineAction = fsToggleAction = dfToggleAction = 'Caesar si viveret, ad remum dareris'
searchWikipediaAction = searchYoutubeAction = 'Does anyone know something funny in Latin?'
searchAction = searchGoogleAction = bookmarksToggleAction = 'TODO Insert Latin Joke'
deleteAnnotationAction = editAnnotationNoteAction = 'Latin quote 2. Electric Boogaloo.'
if selection and selection != '':
first_selected_word = selection.split()[0]
define_string = self._translate('PliantQTextBrowser', 'Define')
defineAction = contextMenu.addAction(
self.main_window.QImageFactory.get_image('view-readermode'),
f'{define_string} "{first_selected_word}"')
search_submenu_string = self._translate('PliantQTextBrowser', 'Search for')
searchSubMenu = contextMenu.addMenu(search_submenu_string + f' "{selection}"')
searchSubMenu.setIcon(self.main_window.QImageFactory.get_image('search'))
searchAction = searchSubMenu.addAction(
self.main_window.QImageFactory.get_image('search'),
self._translate('PliantQTextBrowser', 'In this book'))
searchSubMenu.addSeparator()
searchGoogleAction = searchSubMenu.addAction(
QtGui.QIcon(':/images/Google.png'),
'Google')
searchWikipediaAction = searchSubMenu.addAction(
QtGui.QIcon(':/images/Wikipedia.png'),
'Wikipedia')
searchYoutubeAction = searchSubMenu.addAction(
QtGui.QIcon(':/images/Youtube.png'),
'Youtube')
if annotation_is_present:
annotationsubMenu = contextMenu.addMenu('Annotation')
annotationsubMenu.setIcon(self.main_window.QImageFactory.get_image('annotate'))
editAnnotationNoteAction = annotationsubMenu.addAction(
self.main_window.QImageFactory.get_image('edit-rename'),
self._translate('PliantQTextBrowser', 'Edit note'))
deleteAnnotationAction = annotationsubMenu.addAction(
self.main_window.QImageFactory.get_image('remove'),
self._translate('PliantQTextBrowser', 'Delete annotation'))
if self.parent.is_fullscreen:
fsToggleAction = contextMenu.addAction(
self.main_window.QImageFactory.get_image('view-fullscreen'),
self._translate('PliantQTextBrowser', 'Exit fullscreen'))
else:
if self.main_window.settings['show_bars']:
distraction_free_prompt = self._translate(
'PliantQTextBrowser', 'Distraction Free mode')
else:
distraction_free_prompt = self._translate(
'PliantQTextBrowser', 'Exit Distraction Free mode')
dfToggleAction = contextMenu.addAction(
self.main_window.QImageFactory.get_image('visibility'),
distraction_free_prompt)
if not self.main_window.settings['show_bars'] or self.parent.is_fullscreen:
bookmarksToggleAction = contextMenu.addAction(
self.main_window.QImageFactory.get_image('bookmarks'),
self._translate('PliantQTextBrowser', 'Bookmarks'))
self.common_functions.generate_combo_box_action(contextMenu)
action = contextMenu.exec_(self.sender().mapToGlobal(position))
if action == defineAction:
self.main_window.definitionDialog.find_definition(selection)
if action == searchAction:
self.main_window.bookToolBar.searchBar.setText(selection)
self.main_window.bookToolBar.searchBar.setFocus()
if action == searchGoogleAction:
webbrowser.open_new_tab(
f'https://www.google.com/search?q={selection}')
if action == searchWikipediaAction:
webbrowser.open_new_tab(
f'https://en.wikipedia.org/wiki/Special:Search?search={selection}')
if action == searchYoutubeAction:
webbrowser.open_new_tab(
f'https://www.youtube.com/results?search_query={selection}')
if action == editAnnotationNoteAction:
self.common_functions.annotation_specific(
'note', 'text', current_chapter, cursor_at_mouse.position())
if action == deleteAnnotationAction:
self.common_functions.annotation_specific(
'delete', 'text', current_chapter, cursor_at_mouse.position())
if action == bookmarksToggleAction:
self.parent.toggle_bookmarks()
if action == fsToggleAction:
self.parent.exit_fullscreen()
if action == dfToggleAction:
self.main_window.toggle_distraction_free()
def closeEvent(self, *args):
self.main_window.closeEvent()
def mouseMoveEvent(self, event):
if self.annotation_mode:
self.viewport().setCursor(QtCore.Qt.IBeamCursor)
else:
self.viewport().setCursor(QtCore.Qt.ArrowCursor)
self.parent.mouse_hide_timer.start(3000)
QtWidgets.QTextBrowser.mouseMoveEvent(self, event)
class PliantWidgetsCommonFunctions:
def __init__(self, parent_widget, main_window):
self.pw = parent_widget
self.main_window = main_window
self.are_we_doing_images_only = self.pw.parent.are_we_doing_images_only
def wheelEvent(self, event):
ignore_events = 20
if self.are_we_doing_images_only:
ignore_events = 10
if self.pw.ignore_wheel_event:
self.pw.ignore_wheel_event_number += 1
if self.pw.ignore_wheel_event_number > ignore_events:
self.pw.ignore_wheel_event = False
self.pw.ignore_wheel_event_number = 0
return
if self.are_we_doing_images_only:
QtWidgets.QGraphicsView.wheelEvent(self.pw, event)
else:
QtWidgets.QTextBrowser.wheelEvent(self.pw, event)
# Since this is a delta on a mouse move event, it cannot ever be 0
vertical_pdelta = event.pixelDelta().y()
if vertical_pdelta > 0:
moving_up = True
elif vertical_pdelta < 0:
moving_up = False
if abs(vertical_pdelta) > 80: # Adjust sensitivity here
# Implies that no scrollbar movement is possible
if self.pw.verticalScrollBar().value() == self.pw.verticalScrollBar().maximum() == 0:
if moving_up:
self.change_chapter(-1)
else:
self.change_chapter(1)
# Implies that the scrollbar is at the bottom
elif self.pw.verticalScrollBar().value() == self.pw.verticalScrollBar().maximum():
if not moving_up:
self.change_chapter(1)
# Implies scrollbar is at the top
elif self.pw.verticalScrollBar().value() == 0:
if moving_up:
self.change_chapter(-1)
def change_chapter(self, direction, was_button_pressed=None):
current_toc_index = self.main_window.bookToolBar.tocBox.currentIndex()
max_toc_index = self.main_window.bookToolBar.tocBox.count() - 1
if (current_toc_index < max_toc_index and direction == 1) or (
current_toc_index > 0 and direction == -1):
self.main_window.bookToolBar.tocBox.setCurrentIndex(
current_toc_index + direction)
# Set page position depending on if the chapter number is increasing or decreasing
if direction == 1 or was_button_pressed:
self.pw.verticalScrollBar().setValue(0)
else:
self.pw.verticalScrollBar().setValue(
self.pw.verticalScrollBar().maximum())
if not was_button_pressed:
self.pw.ignore_wheel_event = True
def load_annotations(self, chapter):
try:
chapter_annotations = self.pw.annotation_dict[chapter]
except KeyError:
return
for i in chapter_annotations:
applicable_to = i['applicable_to']
annotation_type = i['type']
annotation_components = i['components']
if not self.are_we_doing_images_only and applicable_to == 'text':
cursor = self.pw.textCursor()
cursor_start = i['cursor'][0]
cursor_end = i['cursor'][1]
self.pw.annotator.set_current_annotation(
annotation_type, annotation_components)
new_cursor = self.pw.annotator.format_text(
cursor, cursor_start, cursor_end)
self.pw.setTextCursor(new_cursor)
def clear_annotations(self):
if not self.are_we_doing_images_only:
cursor = self.pw.textCursor()
cursor.setPosition(0)
cursor.movePosition(QtGui.QTextCursor.End, QtGui.QTextCursor.KeepAnchor)
previewCharFormat = QtGui.QTextCharFormat()
previewCharFormat.setFontStyleStrategy(
QtGui.QFont.PreferAntialias)
cursor.setCharFormat(previewCharFormat)
cursor.clearSelection()
self.pw.setTextCursor(cursor)
def annotation_specific(self, mode, annotation_type, chapter, cursor_position):
try:
chapter_annotations = self.pw.annotation_dict[chapter]
except KeyError:
return False
for i in chapter_annotations:
if annotation_type == 'text':
cursor_start = i['cursor'][0]
cursor_end = i['cursor'][1]
if cursor_start <= cursor_position <= cursor_end:
if mode == 'check':
return True
if mode == 'delete':
self.pw.annotation_dict[chapter].remove(i)
if mode == 'note':
note = i['note']
self.pw.parent.annotationNoteDock.set_annotation(i)
self.pw.parent.annotationNoteEdit.setText(note)
self.pw.parent.annotationNoteDock.show()
# Post iteration
if mode == 'check':
return False
if mode == 'delete':
scroll_position = self.pw.verticalScrollBar().value()
self.clear_annotations()
self.load_annotations(chapter)
self.pw.verticalScrollBar().setValue(scroll_position)
def update_model(self):
# We're updating the underlying model to have real-time
# updates on the read status
# Set a baseline model index in case the item gets deleted
# E.g It's open in a tab and deleted from the library
model_index = None
start_index = self.main_window.lib_ref.libraryModel.index(0, 0)
# Find index of the model item that corresponds to the tab
model_index = self.main_window.lib_ref.libraryModel.match(
start_index,
QtCore.Qt.UserRole + 6,
self.pw.parent.metadata['hash'],
1, QtCore.Qt.MatchExactly)
if self.are_we_doing_images_only:
position_percentage = (self.pw.parent.metadata['position']['current_chapter'] /
self.pw.parent.metadata['position']['total_chapters'])
else:
position_percentage = (self.pw.parent.metadata['position']['current_block'] /
self.pw.parent.metadata['position']['total_blocks'])
# Update position percentage
if model_index:
self.main_window.lib_ref.libraryModel.setData(
model_index[0], position_percentage, QtCore.Qt.UserRole + 7)
def generate_combo_box_action(self, contextMenu):
contextMenu.addSeparator()
toc_combobox = QtWidgets.QComboBox()
toc_data = [i[0] for i in self.pw.parent.metadata['content']]
toc_combobox.addItems(toc_data)
toc_combobox.setCurrentIndex(
self.pw.main_window.bookToolBar.tocBox.currentIndex())
toc_combobox.currentIndexChanged.connect(
self.pw.main_window.bookToolBar.tocBox.setCurrentIndex)
comboboxAction = QtWidgets.QWidgetAction(self.pw)
comboboxAction.setDefaultWidget(toc_combobox)
contextMenu.addAction(comboboxAction)

View File

@@ -1,7 +1,5 @@
#!/usr/bin/env python3
# This file is a part of Lector, a Qt based ebook reader
# Copyright (C) 2017 BasioMeusPuga
# Copyright (C) 2017-2018 BasioMeusPuga
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -19,6 +17,7 @@
import os
import pickle
import sqlite3
from PyQt5 import QtCore
@@ -41,7 +40,8 @@ class DatabaseInit:
'LastAccessed': 'BLOB',
'Bookmarks': 'BLOB',
'CoverImage': 'BLOB',
'Addition': 'TEXT'}
'Addition': 'TEXT',
'Annotations': 'BLOB'}
self.directories_table_columns = {
'id': 'INTEGER PRIMARY KEY',
@@ -51,7 +51,7 @@ class DatabaseInit:
'CheckState': 'INTEGER'}
if os.path.exists(self.database_path):
self.check_database()
self.check_columns()
else:
self.create_database()
@@ -70,7 +70,7 @@ class DatabaseInit:
self.database.commit()
self.database.close()
def check_database(self):
def check_columns(self):
self.database = sqlite3.connect(self.database_path)
database_return = self.database.execute("PRAGMA table_info(books)").fetchall()
@@ -81,13 +81,12 @@ class DatabaseInit:
for i in self.books_table_columns.items():
if i[0] not in database_columns:
commit_required = True
print(f'Database: Adding column {i[0]}')
print(f'Database: Adding column "{i[0]}"')
sql_command = f"ALTER TABLE books ADD COLUMN {i[0]} {i[1]}"
self.database.execute(sql_command)
if commit_required:
self.database.commit()
self.database.close()
class DatabaseFunctions:
@@ -220,7 +219,7 @@ class DatabaseFunctions:
def modify_metadata(self, metadata_dict, book_hash):
def generate_binary(column, data):
if column in ('Position', 'LastAccessed', 'Bookmarks'):
if column in ('Position', 'LastAccessed', 'Bookmarks', 'Annotations'):
return sqlite3.Binary(pickle.dumps(data))
elif column == 'CoverImage':
return sqlite3.Binary(data)

View File

@@ -1,7 +1,5 @@
#!/usr/bin/env python3
# This file is a part of Lector, a Qt based ebook reader
# Copyright (C) 2017 BasioMeusPuga
# Copyright (C) 2017-2018 BasioMeusPuga
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -16,8 +14,11 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import requests
import json
import urllib.request
from PyQt5 import QtWidgets, QtCore, QtGui, QtMultimedia
from lector.resources import definitions
@@ -37,8 +38,12 @@ class DefinitionsUI(QtWidgets.QDialog, definitions.Ui_Dialog):
radius = 15
path = QtGui.QPainterPath()
path.addRoundedRect(QtCore.QRectF(self.rect()), radius, radius)
mask = QtGui.QRegion(path.toFillPolygon().toPolygon())
self.setMask(mask)
try:
mask = QtGui.QRegion(path.toFillPolygon().toPolygon())
self.setMask(mask)
except TypeError: # Required for older versions of Qt
pass
self.definitionView.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
@@ -52,21 +57,24 @@ class DefinitionsUI(QtWidgets.QDialog, definitions.Ui_Dialog):
self.okButton.clicked.connect(self.hide)
self.pronounceButton.clicked.connect(self.play_pronunciation)
self.dialogBackground.clicked.connect(self.color_background)
def api_call(self, url, word):
language = self.parent.settings['dictionary_language']
url = url + language + '/' + word.lower()
r = requests.get(
url,
headers={'app_id': self.app_id, 'app_key': self.app_key})
req = urllib.request.Request(url)
req.add_header('app_id', self.app_id)
req.add_header('app_key', self.app_key)
if r.status_code != 200:
print('A firm nope on the dictionary finding thing')
try:
response = urllib.request.urlopen(req)
if response.getcode() == 200:
return_json = json.loads(response.read())
return return_json
except urllib.error.HTTPError:
return None
return r.json()
def find_definition(self, word):
word_root_json = self.api_call(self.root_url, word)
if not word_root_json:
@@ -78,6 +86,7 @@ class DefinitionsUI(QtWidgets.QDialog, definitions.Ui_Dialog):
definition_json = self.api_call(self.define_url, word_root)
if not definition_json:
self.set_text(word, None, None, True)
return
definitions = {}
@@ -137,7 +146,8 @@ class DefinitionsUI(QtWidgets.QDialog, definitions.Ui_Dialog):
background = self.parent.settings['dialog_background']
else:
self.previous_position = self.pos()
background = self.parent.get_color()
self.parent.get_color()
background = self.parent.settings['dialog_background']
self.setStyleSheet(
"QDialog {{background-color: {0}}}".format(background.name()))

View File

@@ -1,7 +1,5 @@
#!/usr/bin/env python3
# This file is a part of Lector, a Qt based ebook reader
# Copyright (C) 2017 BasioMeusPuga
# Copyright (C) 2017-2018 BasioMeusPuga
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -34,11 +32,7 @@ class LibraryDelegate(QtWidgets.QStyledItemDelegate):
option = option.__class__(option)
file_exists = index.data(QtCore.Qt.UserRole + 5)
metadata = index.data(QtCore.Qt.UserRole + 3)
position = metadata['position']
if position:
is_read = position['is_read']
position_percent = index.data(QtCore.Qt.UserRole + 7)
# The shadow pixmap currently is set to 420 x 600
# Only draw the cover shadow in case the setting is enabled
@@ -55,36 +49,29 @@ class LibraryDelegate(QtWidgets.QStyledItemDelegate):
if not file_exists:
painter.setOpacity(.7)
QtWidgets.QStyledItemDelegate.paint(self, painter, option, index)
read_icon = pie_chart.pixmapper(-1, None, None, 36)
painter.setOpacity(1)
read_icon = pie_chart.pixmapper(
-1, None, self.parent.settings['consider_read_at'], 36)
x_draw = option.rect.bottomRight().x() - 30
y_draw = option.rect.bottomRight().y() - 35
painter.drawPixmap(x_draw, y_draw, read_icon)
painter.setOpacity(1)
return
QtWidgets.QStyledItemDelegate.paint(self, painter, option, index)
if position:
if is_read:
current_chapter = total_chapters = 100
else:
try:
current_chapter = position['current_chapter']
total_chapters = position['total_chapters']
except KeyError:
return
if position_percent:
read_icon = pie_chart.pixmapper(
current_chapter, total_chapters, self.temp_dir, 36)
position_percent, self.temp_dir, self.parent.settings['consider_read_at'], 36)
x_draw = option.rect.bottomRight().x() - 30
y_draw = option.rect.bottomRight().y() - 35
if current_chapter != 1:
painter.drawPixmap(x_draw, y_draw, read_icon)
painter.drawPixmap(x_draw, y_draw, read_icon)
class BookmarkDelegate(QtWidgets.QStyledItemDelegate):
def __init__(self, parent=None):
super(BookmarkDelegate, self).__init__(parent)
def __init__(self, main_window, parent=None):
super(BookmarkDelegate, self).__init__()
self.main_window = main_window
self.parent = parent
def sizeHint(self, *args):
@@ -98,7 +85,7 @@ class BookmarkDelegate(QtWidgets.QStyledItemDelegate):
option = option.__class__(option)
chapter_index = index.data(QtCore.Qt.UserRole)
chapter_name = self.parent.window().bookToolBar.tocBox.itemText(chapter_index - 1)
chapter_name = self.main_window.bookToolBar.tocBox.itemText(chapter_index - 1)
if len(chapter_name) > 25:
chapter_name = chapter_name[:25] + '...'

View File

@@ -314,7 +314,8 @@ def get_split_content(chapter_data, split_by):
return_list.append(
(chapter_titles[count - 1], bs_obj_string))
xml_string = this_split[1]
xml_string = ''.join(this_split[1:])
bs_obj = BeautifulSoup(xml_string, 'lxml')
bs_obj_string = str(bs_obj).replace('"&gt;', '', 1) + ('<br/>' * 8)

View File

@@ -1,7 +1,5 @@
#!usr/bin/env python3
# This file is a part of Lector, a Qt based ebook reader
# Copyright (C) 2018 BasioMeusPuga
# Copyright (C) 2017-2018 BasioMeusPuga
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -16,7 +14,10 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from PyQt5 import QtGui
from PyQt5 import QtCore, QtGui, QtWidgets
from lector import database
from lector.settings import Settings
from lector.resources import resources
@@ -30,3 +31,316 @@ class QImageFactory:
this_qicon = QtGui.QIcon(icon_path)
return this_qicon
# For nearly all cases below, code remains unchanged from its
# state in the __main__ module. References to objects have been
# made in the respective __init__ functions of the classes here
class CoverLoadingAndCulling:
def __init__(self, main_window):
self.main_window = main_window
self.lib_ref = self.main_window.lib_ref
self.listView = self.main_window.listView
self.database_path = self.main_window.database_path
def cull_covers(self, event=None):
blank_pixmap = QtGui.QPixmap()
blank_pixmap.load(':/images/blank.png') # Keep this. Removing it causes the
# listView to go blank on a resize
all_indexes = set()
for i in range(self.lib_ref.itemProxyModel.rowCount()):
all_indexes.add(self.lib_ref.itemProxyModel.index(i, 0))
y_range = list(range(0, self.listView.viewport().height(), 100))
y_range.extend((-20, self.listView.viewport().height() + 20))
x_range = range(0, self.listView.viewport().width(), 80)
visible_indexes = set()
for i in y_range:
for j in x_range:
this_index = self.listView.indexAt(QtCore.QPoint(j, i))
visible_indexes.add(this_index)
invisible_indexes = all_indexes - visible_indexes
for i in invisible_indexes:
model_index = self.lib_ref.itemProxyModel.mapToSource(i)
this_item = self.lib_ref.libraryModel.item(model_index.row())
if this_item:
this_item.setIcon(QtGui.QIcon(blank_pixmap))
this_item.setData(False, QtCore.Qt.UserRole + 8)
hash_index_dict = {}
hash_list = []
for i in visible_indexes:
model_index = self.lib_ref.itemProxyModel.mapToSource(i)
book_hash = self.lib_ref.libraryModel.data(
model_index, QtCore.Qt.UserRole + 6)
cover_displayed = self.lib_ref.libraryModel.data(
model_index, QtCore.Qt.UserRole + 8)
if book_hash and not cover_displayed:
hash_list.append(book_hash)
hash_index_dict[book_hash] = model_index
all_covers = database.DatabaseFunctions(
self.database_path).fetch_covers_only(hash_list)
for i in all_covers:
book_hash = i[0]
cover = i[1]
model_index = hash_index_dict[book_hash]
book_item = self.lib_ref.libraryModel.item(model_index.row())
self.cover_loader(book_item, cover)
def load_all_covers(self):
all_covers_db = database.DatabaseFunctions(
self.database_path).fetch_data(
('Hash', 'CoverImage',),
'books',
{'Hash': ''},
'LIKE')
if not all_covers_db:
return
all_covers = {
i[0]: i[1] for i in all_covers_db}
for i in range(self.lib_ref.libraryModel.rowCount()):
this_item = self.lib_ref.libraryModel.item(i, 0)
is_cover_already_displayed = this_item.data(QtCore.Qt.UserRole + 8)
if is_cover_already_displayed:
continue
book_hash = this_item.data(QtCore.Qt.UserRole + 6)
cover = all_covers[book_hash]
self.cover_loader(this_item, cover)
def cover_loader(self, item, cover):
img_pixmap = QtGui.QPixmap()
if cover:
img_pixmap.loadFromData(cover)
else:
img_pixmap.load(':/images/NotFound.png')
img_pixmap = img_pixmap.scaled(420, 600, QtCore.Qt.IgnoreAspectRatio)
item.setIcon(QtGui.QIcon(img_pixmap))
item.setData(True, QtCore.Qt.UserRole + 8)
class ViewProfileModification:
def __init__(self, main_window):
self.main_window = main_window
self.listView = self.main_window.listView
self.settings = self.main_window.settings
self.bookToolBar = self.main_window.bookToolBar
self.comic_profile = self.main_window.comic_profile
self.tabWidget = self.main_window.tabWidget
self.alignment_dict = self.main_window.alignment_dict
def get_color(self, signal_sender):
def open_color_dialog(current_color):
color_dialog = QtWidgets.QColorDialog()
new_color = color_dialog.getColor(current_color)
if new_color.isValid(): # Returned in case cancel is pressed
return new_color
else:
return current_color
# Special cases that don't affect (comic)book display
if signal_sender == 'libraryBackground':
current_color = self.settings['listview_background']
new_color = open_color_dialog(current_color)
self.listView.setStyleSheet("QListView {{background-color: {0}}}".format(
new_color.name()))
self.settings['listview_background'] = new_color
return
if signal_sender == 'dialogBackground':
current_color = self.settings['dialog_background']
new_color = open_color_dialog(current_color)
self.settings['dialog_background'] = new_color
return
profile_index = self.bookToolBar.profileBox.currentIndex()
current_profile = self.bookToolBar.profileBox.itemData(
profile_index, QtCore.Qt.UserRole)
# Retain current values on opening a new dialog
if signal_sender == 'fgColor':
current_color = current_profile['foreground']
new_color = open_color_dialog(current_color)
self.bookToolBar.colorBoxFG.setStyleSheet(
'background-color: %s' % new_color.name())
current_profile['foreground'] = new_color
elif signal_sender == 'bgColor':
current_color = current_profile['background']
new_color = open_color_dialog(current_color)
self.bookToolBar.colorBoxBG.setStyleSheet(
'background-color: %s' % new_color.name())
current_profile['background'] = new_color
elif signal_sender == 'comicBGColor':
current_color = self.comic_profile['background']
new_color = open_color_dialog(current_color)
self.bookToolBar.comicBGColor.setStyleSheet(
'background-color: %s' % new_color.name())
self.comic_profile['background'] = new_color
self.bookToolBar.profileBox.setItemData(
profile_index, current_profile, QtCore.Qt.UserRole)
self.format_contentView()
def modify_font(self, signal_sender):
profile_index = self.bookToolBar.profileBox.currentIndex()
current_profile = self.bookToolBar.profileBox.itemData(
profile_index, QtCore.Qt.UserRole)
if signal_sender == 'fontBox':
current_profile['font'] = self.bookToolBar.fontBox.currentFont().family()
if signal_sender == 'fontSizeBox':
old_size = current_profile['font_size']
new_size = self.bookToolBar.fontSizeBox.itemText(
self.bookToolBar.fontSizeBox.currentIndex())
if new_size.isdigit():
current_profile['font_size'] = new_size
else:
current_profile['font_size'] = old_size
if signal_sender == 'lineSpacingUp' and current_profile['line_spacing'] < 200:
current_profile['line_spacing'] += 5
if signal_sender == 'lineSpacingDown' and current_profile['line_spacing'] > 90:
current_profile['line_spacing'] -= 5
if signal_sender == 'paddingUp':
current_profile['padding'] += 5
if signal_sender == 'paddingDown':
current_profile['padding'] -= 5
alignment_dict = {
'alignLeft': 'left',
'alignRight': 'right',
'alignCenter': 'center',
'alignJustify': 'justify'}
if signal_sender in alignment_dict:
current_profile['text_alignment'] = alignment_dict[signal_sender]
self.bookToolBar.profileBox.setItemData(
profile_index, current_profile, QtCore.Qt.UserRole)
self.format_contentView()
def modify_comic_view(self, signal_sender, key_pressed):
current_tab = self.tabWidget.widget(self.tabWidget.currentIndex())
self.bookToolBar.fitWidth.setChecked(False)
self.bookToolBar.bestFit.setChecked(False)
self.bookToolBar.originalSize.setChecked(False)
if signal_sender == 'zoomOut' or key_pressed == QtCore.Qt.Key_Minus:
self.comic_profile['zoom_mode'] = 'manualZoom'
self.comic_profile['padding'] += 50
# This prevents infinite zoom out
if self.comic_profile['padding'] * 2 > current_tab.contentView.viewport().width():
self.comic_profile['padding'] -= 50
if signal_sender == 'zoomIn' or key_pressed in (QtCore.Qt.Key_Plus, QtCore.Qt.Key_Equal):
self.comic_profile['zoom_mode'] = 'manualZoom'
self.comic_profile['padding'] -= 50
# This prevents infinite zoom in
if self.comic_profile['padding'] < 0:
self.comic_profile['padding'] = 0
if signal_sender == 'fitWidth' or key_pressed == QtCore.Qt.Key_W:
self.comic_profile['zoom_mode'] = 'fitWidth'
self.comic_profile['padding'] = 0
self.bookToolBar.fitWidth.setChecked(True)
# Padding in the following cases is decided by
# the image pixmap loaded by the widget
if signal_sender == 'bestFit' or key_pressed == QtCore.Qt.Key_B:
self.comic_profile['zoom_mode'] = 'bestFit'
self.bookToolBar.bestFit.setChecked(True)
if signal_sender == 'originalSize' or key_pressed == QtCore.Qt.Key_O:
self.comic_profile['zoom_mode'] = 'originalSize'
self.bookToolBar.originalSize.setChecked(True)
self.format_contentView()
def format_contentView(self):
current_tab = self.tabWidget.widget(
self.tabWidget.currentIndex())
try:
current_metadata = current_tab.metadata
except AttributeError:
return
if current_metadata['images_only']:
background = self.comic_profile['background']
padding = self.comic_profile['padding']
zoom_mode = self.comic_profile['zoom_mode']
if zoom_mode == 'fitWidth':
self.bookToolBar.fitWidth.setChecked(True)
if zoom_mode == 'bestFit':
self.bookToolBar.bestFit.setChecked(True)
if zoom_mode == 'originalSize':
self.bookToolBar.originalSize.setChecked(True)
self.bookToolBar.comicBGColor.setStyleSheet(
'background-color: %s' % background.name())
current_tab.format_view(
None, None, None, background, padding, None, None)
else:
profile_index = self.bookToolBar.profileBox.currentIndex()
current_profile = self.bookToolBar.profileBox.itemData(
profile_index, QtCore.Qt.UserRole)
font = current_profile['font']
foreground = current_profile['foreground']
background = current_profile['background']
padding = current_profile['padding']
font_size = current_profile['font_size']
line_spacing = current_profile['line_spacing']
text_alignment = current_profile['text_alignment']
# Change toolbar widgets to match new settings
self.bookToolBar.fontBox.blockSignals(True)
self.bookToolBar.fontSizeBox.blockSignals(True)
self.bookToolBar.fontBox.setCurrentText(font)
current_index = self.bookToolBar.fontSizeBox.findText(
str(font_size), QtCore.Qt.MatchExactly)
self.bookToolBar.fontSizeBox.setCurrentIndex(current_index)
self.bookToolBar.fontBox.blockSignals(False)
self.bookToolBar.fontSizeBox.blockSignals(False)
self.alignment_dict[current_profile['text_alignment']].setChecked(True)
self.bookToolBar.colorBoxFG.setStyleSheet(
'background-color: %s' % foreground.name())
self.bookToolBar.colorBoxBG.setStyleSheet(
'background-color: %s' % background.name())
current_tab.format_view(
font, font_size, foreground,
background, padding, line_spacing,
text_alignment)
def reset_profile(self):
current_profile_index = self.bookToolBar.profileBox.currentIndex()
current_profile_default = Settings(self).default_profiles[current_profile_index]
self.bookToolBar.profileBox.setItemData(
current_profile_index, current_profile_default, QtCore.Qt.UserRole)
self.format_contentView()

View File

@@ -1,7 +1,5 @@
#!/usr/bin/env python3
# This file is a part of Lector, a Qt based ebook reader
# Copyright (C) 2017 BasioMeusPuga
# Copyright (C) 2017-2018 BasioMeusPuga
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -19,26 +17,28 @@
import os
import pickle
import pathlib
from PyQt5 import QtGui, QtCore
from lector import database
from lector.models import TableProxyModel, ItemProxyModel
class Library:
def __init__(self, parent):
self.parent = parent
self.view_model = None
self.item_proxy_model = None
self.table_proxy_model = None
self.main_window = parent
self.libraryModel = None
self.itemProxyModel = None
self.tableProxyModel = None
self._translate = QtCore.QCoreApplication.translate
def generate_model(self, mode, parsed_books=None, is_database_ready=True):
if mode == 'build':
self.view_model = QtGui.QStandardItemModel()
self.view_model.setColumnCount(10)
self.libraryModel = QtGui.QStandardItemModel()
self.libraryModel.setColumnCount(10)
books = database.DatabaseFunctions(
self.parent.database_path).fetch_data(
self.main_window.database_path).fetch_data(
('Title', 'Author', 'Year', 'DateAdded', 'Path',
'Position', 'ISBN', 'Tags', 'Hash', 'LastAccessed',
'Addition'),
@@ -51,7 +51,7 @@ class Library:
return
elif mode == 'addition':
# Assumes self.view_model already exists and may be extended
# Assumes self.libraryModel already exists and may be extended
# Because any additional books have already been added to the
# database using background threads
@@ -99,18 +99,22 @@ class Library:
if position:
position = pickle.loads(position)
if position['is_read']:
position_perc = 100
position_perc = 1
else:
try:
position_perc = (
position['current_chapter'] * 100 / position['total_chapters'])
except KeyError:
position_perc = None
position['current_block'] / position['total_blocks'])
except (KeyError, ZeroDivisionError):
try:
position_perc = (
position['current_chapter'] / position['total_chapters'])
except KeyError:
position_perc = None
try:
file_exists = os.path.exists(path)
except UnicodeEncodeError:
print('Error with unicode encoding in the library module')
print('Library: Unicode encoding error')
all_metadata = {
'title': title,
@@ -156,57 +160,60 @@ class Library:
item.setData(False, QtCore.Qt.UserRole + 8) # Is the cover being displayed?
item.setData(date_added, QtCore.Qt.UserRole + 9)
item.setData(last_accessed, QtCore.Qt.UserRole + 12)
item.setData(path, QtCore.Qt.UserRole + 13)
item.setIcon(QtGui.QIcon(img_pixmap))
self.view_model.appendRow(item)
self.libraryModel.appendRow(item)
# The is_database_ready boolean is required when a new thread sends
# books here for model generation.
if not self.parent.settings['perform_culling'] and is_database_ready:
self.parent.load_all_covers()
if not self.main_window.settings['perform_culling'] and is_database_ready:
self.main_window.cover_functions.load_all_covers()
def generate_proxymodels(self):
self.item_proxy_model = ItemProxyModel()
self.item_proxy_model.setSourceModel(self.view_model)
self.item_proxy_model.setSortCaseSensitivity(False)
self.itemProxyModel = ItemProxyModel()
self.itemProxyModel.setSourceModel(self.libraryModel)
self.itemProxyModel.setSortCaseSensitivity(False)
s = QtCore.QSize(160, 250) # Set icon sizing here
self.parent.listView.setIconSize(s)
self.parent.listView.setModel(self.item_proxy_model)
self.main_window.listView.setIconSize(s)
self.main_window.listView.setModel(self.itemProxyModel)
self.table_proxy_model = TableProxyModel(
self.parent.temp_dir.path(), self.parent.tableView.horizontalHeader())
self.table_proxy_model.setSourceModel(self.view_model)
self.table_proxy_model.setSortCaseSensitivity(False)
self.parent.tableView.setModel(self.table_proxy_model)
self.tableProxyModel = TableProxyModel(
self.main_window.temp_dir.path(),
self.main_window.tableView.horizontalHeader(),
self.main_window.settings['consider_read_at'])
self.tableProxyModel.setSourceModel(self.libraryModel)
self.tableProxyModel.setSortCaseSensitivity(False)
self.main_window.tableView.setModel(self.tableProxyModel)
self.update_proxymodels()
def update_proxymodels(self):
# Table proxy model
self.table_proxy_model.invalidateFilter()
self.table_proxy_model.setFilterParams(
self.parent.libraryToolBar.searchBar.text(),
self.parent.active_library_filters,
self.tableProxyModel.invalidateFilter()
self.tableProxyModel.setFilterParams(
self.main_window.libraryToolBar.searchBar.text(),
self.main_window.active_library_filters,
0) # This doesn't need to know the sorting box position
self.table_proxy_model.setFilterFixedString(
self.parent.libraryToolBar.searchBar.text())
self.tableProxyModel.setFilterFixedString(
self.main_window.libraryToolBar.searchBar.text())
# ^^^ This isn't needed, but it forces a model update every time the
# text in the line edit changes. So I guess it is needed.
self.table_proxy_model.sort_table_columns(
self.parent.tableView.horizontalHeader().sortIndicatorSection())
self.table_proxy_model.sort_table_columns()
self.tableProxyModel.sort_table_columns(
self.main_window.tableView.horizontalHeader().sortIndicatorSection())
self.tableProxyModel.sort_table_columns()
# Item proxy model
self.item_proxy_model.invalidateFilter()
self.item_proxy_model.setFilterParams(
self.parent.libraryToolBar.searchBar.text(),
self.parent.active_library_filters,
self.parent.libraryToolBar.sortingBox.currentIndex())
self.item_proxy_model.setFilterFixedString(
self.parent.libraryToolBar.searchBar.text())
self.itemProxyModel.invalidateFilter()
self.itemProxyModel.setFilterParams(
self.main_window.libraryToolBar.searchBar.text(),
self.main_window.active_library_filters,
self.main_window.libraryToolBar.sortingBox.currentIndex())
self.itemProxyModel.setFilterFixedString(
self.main_window.libraryToolBar.searchBar.text())
self.parent.statusMessage.setText(
str(self.item_proxy_model.rowCount()) +
self.main_window.statusMessage.setText(
str(self.itemProxyModel.rowCount()) +
self._translate('Library', ' books'))
# TODO
@@ -221,23 +228,25 @@ class Library:
1: 1,
2: 2,
3: 9,
4: 12}
4: 12,
5: 7}
# Sorting according to roles and the drop down in the library toolbar
self.item_proxy_model.setSortRole(
QtCore.Qt.UserRole + sort_roles[self.parent.libraryToolBar.sortingBox.currentIndex()])
self.itemProxyModel.setSortRole(
QtCore.Qt.UserRole +
sort_roles[self.main_window.libraryToolBar.sortingBox.currentIndex()])
# This can be expanded to other fields by appending to the list
sort_order = QtCore.Qt.AscendingOrder
if self.parent.libraryToolBar.sortingBox.currentIndex() in [3, 4]:
if self.main_window.libraryToolBar.sortingBox.currentIndex() in [3, 4, 5]:
sort_order = QtCore.Qt.DescendingOrder
self.item_proxy_model.sort(0, sort_order)
self.parent.start_culling_timer()
self.itemProxyModel.sort(0, sort_order)
self.main_window.start_culling_timer()
def generate_library_tags(self):
db_library_directories = database.DatabaseFunctions(
self.parent.database_path).fetch_data(
self.main_window.database_path).fetch_data(
('Path', 'Name', 'Tags'),
'directories', # This checks the directories table NOT the book one
{'Path': ''},
@@ -249,7 +258,7 @@ class Library:
else:
db_library_directories = database.DatabaseFunctions(
self.parent.database_path).fetch_data(
self.main_window.database_path).fetch_data(
('Path',),
'books', # THIS CHECKS THE BOOKS TABLE
{'Path': ''},
@@ -285,8 +294,8 @@ class Library:
# Generate tags for the QStandardItemModel
# This isn't triggered for an empty view model
for i in range(self.view_model.rowCount()):
this_item = self.view_model.item(i, 0)
for i in range(self.libraryModel.rowCount()):
this_item = self.libraryModel.item(i, 0)
all_metadata = this_item.data(QtCore.Qt.UserRole + 3)
directory_name, directory_tags = get_tags(all_metadata)
@@ -301,8 +310,8 @@ class Library:
invalid_paths = []
deletable_persistent_indexes = []
for i in range(self.view_model.rowCount()):
item = self.view_model.item(i)
for i in range(self.libraryModel.rowCount()):
item = self.libraryModel.item(i)
item_metadata = item.data(QtCore.Qt.UserRole + 3)
book_path = item_metadata['path']
@@ -321,8 +330,8 @@ class Library:
if deletable_persistent_indexes:
for i in deletable_persistent_indexes:
self.view_model.removeRow(i.row())
self.libraryModel.removeRow(i.row())
# Remove invalid paths from the database as well
database.DatabaseFunctions(
self.parent.database_path).delete_from_database('Path', invalid_paths)
self.main_window.database_path).delete_from_database('Path', invalid_paths)

View File

@@ -1,7 +1,5 @@
#!/usr/bin/env python3
# This file is a part of Lector, a Qt based ebook reader
# Copyright (C) 2017 BasioMeusPuga
# Copyright (C) 2017-2018 BasioMeusPuga
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -38,8 +36,12 @@ class MetadataUI(QtWidgets.QDialog, metadata.Ui_Dialog):
radius = 15
path = QtGui.QPainterPath()
path.addRoundedRect(QtCore.QRectF(self.rect()), radius, radius)
mask = QtGui.QRegion(path.toFillPolygon().toPolygon())
self.setMask(mask)
try:
mask = QtGui.QRegion(path.toFillPolygon().toPolygon())
self.setMask(mask)
except TypeError: # Required for older versions of Qt
pass
self.parent = parent
self.database_path = self.parent.database_path
@@ -86,7 +88,7 @@ class MetadataUI(QtWidgets.QDialog, metadata.Ui_Dialog):
self.coverView.setScene(graphics_scene)
def ok_pressed(self, event=None):
book_item = self.parent.lib_ref.view_model.item(self.book_index.row())
book_item = self.parent.lib_ref.libraryModel.item(self.book_index.row())
title = self.titleLine.text()
author = self.authorLine.text()
@@ -116,7 +118,7 @@ class MetadataUI(QtWidgets.QDialog, metadata.Ui_Dialog):
if self.cover_for_database:
database_dict['CoverImage'] = self.cover_for_database
self.parent.cover_loader(
self.parent.cover_functions.cover_loader(
book_item, self.cover_for_database)
self.parent.lib_ref.update_proxymodels()
@@ -148,7 +150,8 @@ class MetadataUI(QtWidgets.QDialog, metadata.Ui_Dialog):
background = self.parent.settings['dialog_background']
else:
self.previous_position = self.pos()
background = self.parent.get_color()
self.parent.get_color()
background = self.parent.settings['dialog_background']
self.setStyleSheet(
"QDialog {{background-color: {0}}}".format(background.name()))

View File

@@ -1,7 +1,5 @@
#!/usr/bin/env python3
# This file is a part of Lector, a Qt based ebook reader
# Copyright (C) 2017 BasioMeusPuga
# Copyright (C) 2017-2018 BasioMeusPuga
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -65,9 +63,10 @@ class ItemProxyModel(QtCore.QSortFilterProxyModel):
class TableProxyModel(QtCore.QSortFilterProxyModel):
def __init__(self, temp_dir, tableViewHeader, parent=None):
def __init__(self, temp_dir, tableViewHeader, consider_read_at, parent=None):
super(TableProxyModel, self).__init__(parent)
self.tableViewHeader = tableViewHeader
self.consider_read_at = consider_read_at
self._translate = QtCore.QCoreApplication.translate
title_string = self._translate('TableProxyModel', 'Title')
@@ -101,6 +100,7 @@ class TableProxyModel(QtCore.QSortFilterProxyModel):
return self.header_data[column]
except IndexError:
print('Table proxy model: Can\'t find header for column', column)
# The column will be called IndexError. Not a typo.
return 'IndexError'
def flags(self, index):
@@ -121,38 +121,22 @@ class TableProxyModel(QtCore.QSortFilterProxyModel):
return_pixmap = None
file_exists = item.data(QtCore.Qt.UserRole + 5)
metadata = item.data(QtCore.Qt.UserRole + 3)
position = metadata['position']
if position:
is_read = position['is_read']
position_percent = item.data(QtCore.Qt.UserRole + 7)
if not file_exists:
return pie_chart.pixmapper(
-1, None, None, QtCore.Qt.SizeHintRole + 10)
if position:
if is_read:
current_chapter = total_chapters = 100
else:
try:
current_chapter = position['current_chapter']
total_chapters = position['total_chapters']
# TODO
# See if there's any rationale for this
if current_chapter == 1:
raise KeyError
except KeyError:
return
if position_percent:
return_pixmap = pie_chart.pixmapper(
current_chapter, total_chapters, self.temp_dir,
position_percent, self.temp_dir,
self.consider_read_at,
QtCore.Qt.SizeHintRole + 10)
return return_pixmap
elif role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole:
if index.column() in (0, 5): # Cover and Status
if index.column() in (0, 5): # Cover and Status
return QtCore.QVariant()
if index.column() == 4:
@@ -214,14 +198,20 @@ class ProxyModelsCommonFunctions:
title = model.data(this_index, QtCore.Qt.UserRole)
author = model.data(this_index, QtCore.Qt.UserRole + 1)
tags = model.data(this_index, QtCore.Qt.UserRole + 4)
progress = model.data(this_index, QtCore.Qt.UserRole + 7)
directory_name = model.data(this_index, QtCore.Qt.UserRole + 10)
directory_tags = model.data(this_index, QtCore.Qt.UserRole + 11)
last_accessed = model.data(this_index, QtCore.Qt.UserRole + 12)
file_path = model.data(this_index, QtCore.Qt.UserRole + 13)
# Hide untouched files when sorting by last accessed
if self.parent_model.sorting_box_position == 4 and not last_accessed:
return False
# Hide untouched files when sorting by progress
if self.parent_model.sorting_box_position == 5 and not progress:
return False
if self.parent_model.active_library_filters:
if directory_name not in self.parent_model.active_library_filters:
return False
@@ -233,7 +223,9 @@ class ProxyModelsCommonFunctions:
else:
valid_data = [
i.lower() for i in (
title, author, tags, directory_name, directory_tags) if i is not None]
title, author, tags, directory_name,
directory_tags, file_path)
if i is not None]
for i in valid_data:
if self.parent_model.filter_text.lower() in i:
return True

View File

@@ -22,6 +22,7 @@
import os
import time
import zipfile
from lector.rarfile import rarfile
@@ -53,7 +54,7 @@ class ParseCOMIC:
return title
def get_author(self):
return None
return 'Unknown'
def get_year(self):
creation_time = time.ctime(os.path.getctime(self.filename))

View File

@@ -18,15 +18,12 @@
import io
import os
from PyQt5 import QtCore
from bs4 import BeautifulSoup
proceed = True
try:
import popplerqt5
except ImportError:
print('python-poppler-qt5 is not installed. Pdf files will not work.')
proceed = False
import popplerqt5
class ParsePDF:
def __init__(self, filename, *args):
@@ -35,9 +32,6 @@ class ParsePDF:
self.metadata = None
def read_book(self):
if not proceed:
return
self.book = popplerqt5.Poppler.Document.load(self.filename)
if not self.book:
return
@@ -61,8 +55,8 @@ class ParsePDF:
def get_year(self):
try:
year = self.metadata.find('MetadataDate').text
return year.replace('\n', '')
except AttributeError:
return int(year.replace('\n', '')[:4])
except (AttributeError, ValueError):
return 9999
def get_cover_image(self):
@@ -70,9 +64,12 @@ class ParsePDF:
popplerqt5.Poppler.Document.Antialiasing
and popplerqt5.Poppler.Document.TextAntialiasing)
cover_page = self.book.page(0)
cover_image = cover_page.renderToImage(300, 300)
return resize_image(cover_image)
try:
cover_page = self.book.page(0)
cover_image = cover_page.renderToImage(300, 300)
return resize_image(cover_image)
except AttributeError:
return None
def get_isbn(self):
return None

View File

@@ -0,0 +1,146 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'raw/annotations.ui'
#
# Created by: PyQt5 UI code generator 5.10.1
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(306, 387)
self.gridLayout = QtWidgets.QGridLayout(Dialog)
self.gridLayout.setObjectName("gridLayout")
self.verticalLayout = QtWidgets.QVBoxLayout()
self.verticalLayout.setObjectName("verticalLayout")
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.nameEdit = QtWidgets.QLineEdit(Dialog)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.nameEdit.sizePolicy().hasHeightForWidth())
self.nameEdit.setSizePolicy(sizePolicy)
self.nameEdit.setObjectName("nameEdit")
self.horizontalLayout_2.addWidget(self.nameEdit)
self.verticalLayout.addLayout(self.horizontalLayout_2)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.typeLabel = QtWidgets.QLabel(Dialog)
self.typeLabel.setObjectName("typeLabel")
self.horizontalLayout.addWidget(self.typeLabel)
self.typeBox = QtWidgets.QComboBox(Dialog)
self.typeBox.setObjectName("typeBox")
self.horizontalLayout.addWidget(self.typeBox)
self.verticalLayout.addLayout(self.horizontalLayout)
self.stackedWidget = QtWidgets.QStackedWidget(Dialog)
self.stackedWidget.setObjectName("stackedWidget")
self.page = QtWidgets.QWidget()
self.page.setObjectName("page")
self.gridLayout_2 = QtWidgets.QGridLayout(self.page)
self.gridLayout_2.setObjectName("gridLayout_2")
self.verticalLayout_12 = QtWidgets.QVBoxLayout()
self.verticalLayout_12.setObjectName("verticalLayout_12")
self.horizontalLayout_15 = QtWidgets.QHBoxLayout()
self.horizontalLayout_15.setObjectName("horizontalLayout_15")
self.foregroundCheck = QtWidgets.QCheckBox(self.page)
self.foregroundCheck.setObjectName("foregroundCheck")
self.horizontalLayout_15.addWidget(self.foregroundCheck)
self.foregroundColorButton = QtWidgets.QPushButton(self.page)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.foregroundColorButton.sizePolicy().hasHeightForWidth())
self.foregroundColorButton.setSizePolicy(sizePolicy)
self.foregroundColorButton.setMinimumSize(QtCore.QSize(30, 0))
self.foregroundColorButton.setMaximumSize(QtCore.QSize(45, 40))
self.foregroundColorButton.setText("")
self.foregroundColorButton.setObjectName("foregroundColorButton")
self.horizontalLayout_15.addWidget(self.foregroundColorButton)
self.verticalLayout_12.addLayout(self.horizontalLayout_15)
self.horizontalLayout_16 = QtWidgets.QHBoxLayout()
self.horizontalLayout_16.setObjectName("horizontalLayout_16")
self.highlightCheck = QtWidgets.QCheckBox(self.page)
self.highlightCheck.setObjectName("highlightCheck")
self.horizontalLayout_16.addWidget(self.highlightCheck)
self.highlightColorButton = QtWidgets.QPushButton(self.page)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.highlightColorButton.sizePolicy().hasHeightForWidth())
self.highlightColorButton.setSizePolicy(sizePolicy)
self.highlightColorButton.setMinimumSize(QtCore.QSize(30, 24))
self.highlightColorButton.setMaximumSize(QtCore.QSize(45, 40))
self.highlightColorButton.setText("")
self.highlightColorButton.setObjectName("highlightColorButton")
self.horizontalLayout_16.addWidget(self.highlightColorButton)
self.verticalLayout_12.addLayout(self.horizontalLayout_16)
self.horizontalLayout_17 = QtWidgets.QHBoxLayout()
self.horizontalLayout_17.setObjectName("horizontalLayout_17")
self.boldCheck = QtWidgets.QCheckBox(self.page)
self.boldCheck.setObjectName("boldCheck")
self.horizontalLayout_17.addWidget(self.boldCheck)
self.verticalLayout_12.addLayout(self.horizontalLayout_17)
self.horizontalLayout_18 = QtWidgets.QHBoxLayout()
self.horizontalLayout_18.setObjectName("horizontalLayout_18")
self.italicCheck = QtWidgets.QCheckBox(self.page)
self.italicCheck.setObjectName("italicCheck")
self.horizontalLayout_18.addWidget(self.italicCheck)
self.verticalLayout_12.addLayout(self.horizontalLayout_18)
self.horizontalLayout_19 = QtWidgets.QHBoxLayout()
self.horizontalLayout_19.setObjectName("horizontalLayout_19")
self.underlineCheck = QtWidgets.QCheckBox(self.page)
self.underlineCheck.setObjectName("underlineCheck")
self.horizontalLayout_19.addWidget(self.underlineCheck)
self.underlineType = QtWidgets.QComboBox(self.page)
self.underlineType.setObjectName("underlineType")
self.horizontalLayout_19.addWidget(self.underlineType)
self.underlineColorButton = QtWidgets.QPushButton(self.page)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.underlineColorButton.sizePolicy().hasHeightForWidth())
self.underlineColorButton.setSizePolicy(sizePolicy)
self.underlineColorButton.setMinimumSize(QtCore.QSize(45, 24))
self.underlineColorButton.setMaximumSize(QtCore.QSize(45, 40))
self.underlineColorButton.setText("")
self.underlineColorButton.setObjectName("underlineColorButton")
self.horizontalLayout_19.addWidget(self.underlineColorButton)
self.verticalLayout_12.addLayout(self.horizontalLayout_19)
self.gridLayout_2.addLayout(self.verticalLayout_12, 0, 0, 1, 1)
self.stackedWidget.addWidget(self.page)
self.verticalLayout.addWidget(self.stackedWidget)
self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1)
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_3.addItem(spacerItem)
self.okButton = QtWidgets.QPushButton(Dialog)
self.okButton.setObjectName("okButton")
self.horizontalLayout_3.addWidget(self.okButton)
self.cancelButton = QtWidgets.QPushButton(Dialog)
self.cancelButton.setObjectName("cancelButton")
self.horizontalLayout_3.addWidget(self.cancelButton)
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_3.addItem(spacerItem1)
self.gridLayout.addLayout(self.horizontalLayout_3, 1, 0, 1, 1)
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Annotation Editor"))
self.nameEdit.setPlaceholderText(_translate("Dialog", "Annotation Name"))
self.typeLabel.setText(_translate("Dialog", "Type"))
self.foregroundCheck.setText(_translate("Dialog", "Foreground"))
self.highlightCheck.setText(_translate("Dialog", "Highlight"))
self.boldCheck.setText(_translate("Dialog", "Bold"))
self.italicCheck.setText(_translate("Dialog", "Italic"))
self.underlineCheck.setText(_translate("Dialog", "Underline"))
self.okButton.setText(_translate("Dialog", "OK"))
self.cancelButton.setText(_translate("Dialog", "Cancel"))

View File

@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'raw/main.ui'
#
# Created by: PyQt5 UI code generator 5.9.2
# Created by: PyQt5 UI code generator 5.10.1
#
# WARNING! All changes made in this file will be lost!
@@ -35,20 +35,6 @@ class Ui_MainWindow(object):
self.gridLayout_4.setContentsMargins(0, 0, 0, 0)
self.gridLayout_4.setSpacing(0)
self.gridLayout_4.setObjectName("gridLayout_4")
self.listView = QtWidgets.QListView(self.listPage)
self.listView.setFrameShape(QtWidgets.QFrame.NoFrame)
self.listView.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
self.listView.setProperty("showDropIndicator", False)
self.listView.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
self.listView.setMovement(QtWidgets.QListView.Static)
self.listView.setProperty("isWrapping", True)
self.listView.setResizeMode(QtWidgets.QListView.Fixed)
self.listView.setLayoutMode(QtWidgets.QListView.SinglePass)
self.listView.setViewMode(QtWidgets.QListView.IconMode)
self.listView.setUniformItemSizes(True)
self.listView.setWordWrap(True)
self.listView.setObjectName("listView")
self.gridLayout_4.addWidget(self.listView, 0, 0, 1, 1)
self.stackedWidget.addWidget(self.listPage)
self.tablePage = QtWidgets.QWidget()
self.tablePage.setObjectName("tablePage")
@@ -56,20 +42,6 @@ class Ui_MainWindow(object):
self.gridLayout_3.setContentsMargins(0, 0, 0, 0)
self.gridLayout_3.setSpacing(0)
self.gridLayout_3.setObjectName("gridLayout_3")
self.tableView = QtWidgets.QTableView(self.tablePage)
self.tableView.setFrameShape(QtWidgets.QFrame.Box)
self.tableView.setFrameShadow(QtWidgets.QFrame.Plain)
self.tableView.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContentsOnFirstShow)
self.tableView.setEditTriggers(QtWidgets.QAbstractItemView.DoubleClicked|QtWidgets.QAbstractItemView.EditKeyPressed|QtWidgets.QAbstractItemView.SelectedClicked)
self.tableView.setAlternatingRowColors(True)
self.tableView.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
self.tableView.setGridStyle(QtCore.Qt.NoPen)
self.tableView.setSortingEnabled(True)
self.tableView.setWordWrap(False)
self.tableView.setObjectName("tableView")
self.tableView.horizontalHeader().setVisible(True)
self.tableView.verticalHeader().setVisible(False)
self.gridLayout_3.addWidget(self.tableView, 0, 0, 1, 1)
self.stackedWidget.addWidget(self.tablePage)
self.gridLayout_2.addWidget(self.stackedWidget, 0, 0, 1, 1)
self.tabWidget.addTab(self.tab, "")

View File

@@ -94,26 +94,26 @@ def generate_pie(progress_percent, temp_dir=None):
return lSvg
def pixmapper(current_chapter, total_chapters, temp_dir, size):
def pixmapper(position_percent, temp_dir, consider_read_at, size):
# A current_chapter of -1 implies the files does not exist
# A chapter number == Total chapters implies the file is unread
return_pixmap = None
# position_percent and consider_read_at are expected as a <1 decimal value
if current_chapter == -1:
return_pixmap = None
consider_read_at = consider_read_at / 100
if position_percent == -1:
return_pixmap = QtGui.QIcon(':/images/error.svg').pixmap(size)
return return_pixmap
if current_chapter == total_chapters:
if position_percent >= consider_read_at: # Consider book read @ this progress
return_pixmap = QtGui.QIcon(':/images/checkmark.svg').pixmap(size)
else:
# TODO
# See if saving the svg to disk can be avoided
# Shift to lines to track progress
# Maybe make the alignment a little more uniform across emblems
progress_percent = int(current_chapter * 100 / total_chapters)
generate_pie(progress_percent, temp_dir)
generate_pie(int(position_percent * 100), temp_dir)
svg_path = os.path.join(temp_dir, 'lector_progress.svg')
return_pixmap = QtGui.QIcon(svg_path).pixmap(size - 4) ## The -4 looks more proportional

View File

@@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<defs>
<style id="current-color-scheme" type="text/css">
.ColorScheme-Text { color:#5c616c; } .ColorScheme-Highlight { color:#5294e2; }
</style>
</defs>
<path style="fill:currentColor" class="ColorScheme-Text" d="M 8 1.0039062 C 4.134 1.0039062 1 4.1380063 1 8.0039062 C 1 11.869906 4.134 15.003906 8 15.003906 C 11.866 15.003906 15 11.869906 15 8.0039062 C 15 4.1380063 11.866 1.0039062 8 1.0039062 z M 8 3.7539062 C 8.69036 3.7539062 9.25 4.3135463 9.25 5.0039062 C 9.25 5.6942662 8.69036 6.2539062 8 6.2539062 C 7.30964 6.2539062 6.75 5.6942662 6.75 5.0039062 C 6.75 4.3135463 7.30964 3.7539062 8 3.7539062 z M 7 7.0039062 L 9 7.0039062 L 9 12.003906 L 7 12.003906 L 7 7.0039062 z" transform="translate(4 4)"/>
</svg>

After

Width:  |  Height:  |  Size: 815 B

View File

@@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<defs>
<style id="current-color-scheme" type="text/css">
.ColorScheme-Text { color:#5c616c; } .ColorScheme-Highlight { color:#5294e2; }
</style>
</defs>
<path style="fill:currentColor" class="ColorScheme-Text" d="m12.213 1c-0.213 0-0.425 0.083-0.59 0.248l-1.6308 1.6387 3.1208 3.1211 1.639-1.6308c0.33-0.33 0.33-0.8497 0-1.1797l-1.949-1.9493c-0.165-0.165-0.378-0.248-0.59-0.248zm-3.34 3.0078l-7.8808 7.8792-0.00001 3.121h3.1211l0.0078-0.008h10.879v-2h-8.8789l5.8709-5.873-3.119-3.1192z" transform="translate(4 4)"/>
</svg>

After

Width:  |  Height:  |  Size: 617 B

View File

@@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 22 22">
<defs>
<style id="current-color-scheme" type="text/css">
.ColorScheme-Text { color:#5c616c; } .ColorScheme-Highlight { color:#5294e2; }
</style>
</defs>
<path style="fill:currentColor" class="ColorScheme-Text" d="M 3 6 L 8 11 L 13 6 L 3 6 z" transform="translate(3 3)"/>
</svg>

After

Width:  |  Height:  |  Size: 372 B

View File

@@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 22 22">
<defs>
<style id="current-color-scheme" type="text/css">
.ColorScheme-Text { color:#5c616c; } .ColorScheme-Highlight { color:#5294e2; }
</style>
</defs>
<path style="fill:currentColor" class="ColorScheme-Text" d="M 8 5 L 3 10 L 13 10 L 8 5 z" transform="translate(3 3)"/>
</svg>

After

Width:  |  Height:  |  Size: 373 B

View File

@@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<defs>
<style id="current-color-scheme" type="text/css">
.ColorScheme-Text { color:#5c616c; } .ColorScheme-Highlight { color:#5294e2; }
</style>
</defs>
<path style="fill:currentColor" class="ColorScheme-Text" d="M 2 0 C 0.892 0 0 0.892 0 2 L 0 14 C 0 15.108 0.892 16 2 16 L 14 16 C 15.108 16 16 15.108 16 14 L 16 2 C 16 0.892 15.108 0 14 0 L 2 0 z M 3.7148438 2 L 12.285156 2 C 13.235156 2 14 2.7651437 14 3.7148438 L 14 12.285156 C 14 13.235156 13.235156 14 12.285156 14 L 3.7148438 14 C 2.7651438 14 2 13.235156 2 12.285156 L 2 3.7148438 C 2 2.7651438 2.7651437 2 3.7148438 2 z M 6.7402344 3 L 6.6289062 4.3164062 A 3.964 3.9286 0 0 0 5.4707031 4.9804688 L 4.2617188 4.4179688 L 3.0019531 6.5820312 L 4.0976562 7.3378906 A 3.964 3.9286 0 0 0 4.0371094 8 A 3.964 3.9286 0 0 0 4.0957031 8.6660156 L 3.0019531 9.4179688 L 4.2617188 11.582031 L 5.4667969 11.019531 A 3.964 3.9286 0 0 0 6.6289062 11.679688 L 6.7402344 13 L 9.2617188 13 L 9.3730469 11.683594 A 3.964 3.9286 0 0 0 10.53125 11.019531 L 11.740234 11.582031 L 13.001953 9.4179688 L 11.904297 8.6621094 A 3.964 3.9286 0 0 0 11.964844 8 A 3.964 3.9286 0 0 0 11.908203 7.3339844 L 13.001953 6.5820312 L 11.740234 4.4179688 L 10.535156 4.9804688 A 3.964 3.9286 0 0 0 9.3730469 4.3203125 L 9.2617188 3 L 6.7402344 3 z M 8.0019531 6.5722656 A 1.4414 1.4286 0 0 1 9.4433594 8 A 1.4414 1.4286 0 0 1 8.0019531 9.4277344 A 1.4414 1.4286 0 0 1 6.5605469 8 A 1.4414 1.4286 0 0 1 8.0019531 6.5722656 z" transform="translate(4 4)"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<defs>
<style id="current-color-scheme" type="text/css">
.ColorScheme-Text { color:#5c616c; } .ColorScheme-Highlight { color:#5294e2; }
</style>
</defs>
<path style="fill:currentColor" class="ColorScheme-Text" d="M 8 0.99609375 C 4.134 0.99609375 1 4.1300937 1 7.9960938 C 1 11.862094 4.134 14.996094 8 14.996094 C 11.866 14.996094 15 11.862094 15 7.9960938 C 15 4.1300937 11.866 0.99609375 8 0.99609375 z M 7.5 2.9335938 C 7.5669 2.9265937 7.65125 2.9375937 7.71875 2.9335938 C 7.72675 2.9655938 7.67005 3.0794638 7.59375 3.2460938 C 7.10789 4.3074937 7.08033 5.5504437 7.53125 6.2148438 C 7.61285 6.3353038 7.6875 6.4499437 7.6875 6.4648438 C 7.6875 6.4797438 7.5995 6.4960938 7.5 6.4960938 C 7.26642 6.4960938 7.04538 6.3537238 6.59375 5.9960938 C 6.39312 5.8372237 6.1323 5.7037938 6.03125 5.6835938 C 5.87257 5.6518937 5.83028 5.6657938 5.625 5.8710938 C 5.43401 6.0620537 5.375 6.1650237 5.375 6.3398438 C 5.375 7.0027837 6.16208 7.5297437 7.625 7.8398438 C 9.6117 8.2609137 10.10145 8.6389138 10.15625 9.6835938 C 10.22505 10.993594 9.5276 11.981394 8 12.746094 C 7.81767 12.837394 7.7015 12.872844 7.625 12.902344 C 7.5911 12.899344 7.56505 12.905344 7.53125 12.902344 C 7.51825 12.861844 7.5 12.767884 7.5 12.589844 C 7.5 11.894064 7.22575 11.177844 6.8125 10.777344 C 6.70157 10.669824 6.39098 10.441994 6.125 10.277344 C 5.85903 10.112704 5.59105 9.9214438 5.53125 9.8398438 C 5.43215 9.7044337 5.42386 9.6212437 5.5 9.3710938 C 5.63876 8.9142237 5.80392 8.6597637 6.125 8.3710938 C 6.29333 8.2197537 6.46271 8.0928437 6.5 8.0898438 C 6.5373 8.0868438 6.28485 8.0110437 5.90625 7.9335938 C 5.52767 7.8559938 4.97383 7.6934738 4.6875 7.5898438 C 4.16392 7.4003938 3.457 7.0026837 3.1875 6.7148438 C 3.1761 6.7026437 3.16615 6.6943938 3.15625 6.6835938 C 3.54238 5.1454938 4.626 3.8848438 6.0625 3.2773438 C 6.36307 3.1502138 6.67292 3.0629938 7 2.9960938 C 7.16292 2.9627938 7.33178 2.9506937 7.5 2.9335938 z M 12.1875 5.2773438 C 12.30495 5.3499437 12.74841 6.3093438 12.875 6.7773438 C 13.03844 7.3815337 13.02661 8.4271437 12.875 9.0273438 C 12.8173 9.2557838 12.74335 9.4694937 12.71875 9.4960938 C 12.69415 9.5226938 12.60494 9.3695637 12.5 9.1835938 C 12.39505 8.9976538 12.05984 8.6025437 11.78125 8.3085938 C 10.97711 7.4600637 10.85066 7.0170437 11.1875 6.3398438 C 11.35737 5.9983538 12.0966 5.2212438 12.1875 5.2773438 z" transform="translate(4 4)"/>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<defs>
<style id="current-color-scheme" type="text/css">
.ColorScheme-Text { color:#d3dae3; } .ColorScheme-Highlight { color:#5294e2; }
</style>
</defs>
<path style="fill:currentColor" class="ColorScheme-Text" d="M 8 1.0039062 C 4.134 1.0039062 1 4.1380063 1 8.0039062 C 1 11.869906 4.134 15.003906 8 15.003906 C 11.866 15.003906 15 11.869906 15 8.0039062 C 15 4.1380063 11.866 1.0039062 8 1.0039062 z M 8 3.7539062 C 8.69036 3.7539062 9.25 4.3135463 9.25 5.0039062 C 9.25 5.6942662 8.69036 6.2539062 8 6.2539062 C 7.30964 6.2539062 6.75 5.6942662 6.75 5.0039062 C 6.75 4.3135463 7.30964 3.7539062 8 3.7539062 z M 7 7.0039062 L 9 7.0039062 L 9 12.003906 L 7 12.003906 L 7 7.0039062 z" transform="translate(4 4)"/>
</svg>

After

Width:  |  Height:  |  Size: 815 B

View File

@@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<defs>
<style id="current-color-scheme" type="text/css">
.ColorScheme-Text { color:#d3dae3; } .ColorScheme-Highlight { color:#5294e2; }
</style>
</defs>
<path style="fill:currentColor" class="ColorScheme-Text" d="m12.213 1c-0.213 0-0.425 0.083-0.59 0.248l-1.6308 1.6387 3.1208 3.1211 1.639-1.6308c0.33-0.33 0.33-0.8497 0-1.1797l-1.949-1.9493c-0.165-0.165-0.378-0.248-0.59-0.248zm-3.34 3.0078l-7.8808 7.8792-0.00001 3.121h3.1211l0.0078-0.008h10.879v-2h-8.8789l5.8709-5.873-3.119-3.1192z" transform="translate(4 4)"/>
</svg>

After

Width:  |  Height:  |  Size: 617 B

View File

@@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 22 22">
<defs>
<style id="current-color-scheme" type="text/css">
.ColorScheme-Text { color:#d3dae3; } .ColorScheme-Highlight { color:#5294e2; }
</style>
</defs>
<path style="fill:currentColor" class="ColorScheme-Text" d="M 3 6 L 8 11 L 13 6 L 3 6 z" transform="translate(3 3)"/>
</svg>

After

Width:  |  Height:  |  Size: 372 B

View File

@@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 22 22">
<defs>
<style id="current-color-scheme" type="text/css">
.ColorScheme-Text { color:#d3dae3; } .ColorScheme-Highlight { color:#5294e2; }
</style>
</defs>
<path style="fill:currentColor" class="ColorScheme-Text" d="M 8 5 L 3 10 L 13 10 L 8 5 z" transform="translate(3 3)"/>
</svg>

After

Width:  |  Height:  |  Size: 373 B

View File

@@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<defs>
<style id="current-color-scheme" type="text/css">
.ColorScheme-Text { color:#d3dae3; } .ColorScheme-Highlight { color:#5294e2; }
</style>
</defs>
<path style="fill:currentColor" class="ColorScheme-Text" d="M 2 0 C 0.892 0 0 0.892 0 2 L 0 14 C 0 15.108 0.892 16 2 16 L 14 16 C 15.108 16 16 15.108 16 14 L 16 2 C 16 0.892 15.108 0 14 0 L 2 0 z M 3.7148438 2 L 12.285156 2 C 13.235156 2 14 2.7651437 14 3.7148438 L 14 12.285156 C 14 13.235156 13.235156 14 12.285156 14 L 3.7148438 14 C 2.7651438 14 2 13.235156 2 12.285156 L 2 3.7148438 C 2 2.7651438 2.7651437 2 3.7148438 2 z M 6.7402344 3 L 6.6289062 4.3164062 A 3.964 3.9286 0 0 0 5.4707031 4.9804688 L 4.2617188 4.4179688 L 3.0019531 6.5820312 L 4.0976562 7.3378906 A 3.964 3.9286 0 0 0 4.0371094 8 A 3.964 3.9286 0 0 0 4.0957031 8.6660156 L 3.0019531 9.4179688 L 4.2617188 11.582031 L 5.4667969 11.019531 A 3.964 3.9286 0 0 0 6.6289062 11.679688 L 6.7402344 13 L 9.2617188 13 L 9.3730469 11.683594 A 3.964 3.9286 0 0 0 10.53125 11.019531 L 11.740234 11.582031 L 13.001953 9.4179688 L 11.904297 8.6621094 A 3.964 3.9286 0 0 0 11.964844 8 A 3.964 3.9286 0 0 0 11.908203 7.3339844 L 13.001953 6.5820312 L 11.740234 4.4179688 L 10.535156 4.9804688 A 3.964 3.9286 0 0 0 9.3730469 4.3203125 L 9.2617188 3 L 6.7402344 3 z M 8.0019531 6.5722656 A 1.4414 1.4286 0 0 1 9.4433594 8 A 1.4414 1.4286 0 0 1 8.0019531 9.4277344 A 1.4414 1.4286 0 0 1 6.5605469 8 A 1.4414 1.4286 0 0 1 8.0019531 6.5722656 z" transform="translate(4 4)"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<defs>
<style id="current-color-scheme" type="text/css">
.ColorScheme-Text { color:#d3dae3; } .ColorScheme-Highlight { color:#5294e2; }
</style>
</defs>
<path style="fill:currentColor" class="ColorScheme-Text" d="M 8 0.99609375 C 4.134 0.99609375 1 4.1300937 1 7.9960938 C 1 11.862094 4.134 14.996094 8 14.996094 C 11.866 14.996094 15 11.862094 15 7.9960938 C 15 4.1300937 11.866 0.99609375 8 0.99609375 z M 7.5 2.9335938 C 7.5669 2.9265937 7.65125 2.9375937 7.71875 2.9335938 C 7.72675 2.9655938 7.67005 3.0794638 7.59375 3.2460938 C 7.10789 4.3074937 7.08033 5.5504437 7.53125 6.2148438 C 7.61285 6.3353038 7.6875 6.4499437 7.6875 6.4648438 C 7.6875 6.4797438 7.5995 6.4960938 7.5 6.4960938 C 7.26642 6.4960938 7.04538 6.3537238 6.59375 5.9960938 C 6.39312 5.8372237 6.1323 5.7037938 6.03125 5.6835938 C 5.87257 5.6518937 5.83028 5.6657938 5.625 5.8710938 C 5.43401 6.0620537 5.375 6.1650237 5.375 6.3398438 C 5.375 7.0027837 6.16208 7.5297437 7.625 7.8398438 C 9.6117 8.2609137 10.10145 8.6389138 10.15625 9.6835938 C 10.22505 10.993594 9.5276 11.981394 8 12.746094 C 7.81767 12.837394 7.7015 12.872844 7.625 12.902344 C 7.5911 12.899344 7.56505 12.905344 7.53125 12.902344 C 7.51825 12.861844 7.5 12.767884 7.5 12.589844 C 7.5 11.894064 7.22575 11.177844 6.8125 10.777344 C 6.70157 10.669824 6.39098 10.441994 6.125 10.277344 C 5.85903 10.112704 5.59105 9.9214438 5.53125 9.8398438 C 5.43215 9.7044337 5.42386 9.6212437 5.5 9.3710938 C 5.63876 8.9142237 5.80392 8.6597637 6.125 8.3710938 C 6.29333 8.2197537 6.46271 8.0928437 6.5 8.0898438 C 6.5373 8.0868438 6.28485 8.0110437 5.90625 7.9335938 C 5.52767 7.8559938 4.97383 7.6934738 4.6875 7.5898438 C 4.16392 7.4003938 3.457 7.0026837 3.1875 6.7148438 C 3.1761 6.7026437 3.16615 6.6943938 3.15625 6.6835938 C 3.54238 5.1454938 4.626 3.8848438 6.0625 3.2773438 C 6.36307 3.1502138 6.67292 3.0629938 7 2.9960938 C 7.16292 2.9627938 7.33178 2.9506937 7.5 2.9335938 z M 12.1875 5.2773438 C 12.30495 5.3499437 12.74841 6.3093438 12.875 6.7773438 C 13.03844 7.3815337 13.02661 8.4271437 12.875 9.0273438 C 12.8173 9.2557838 12.74335 9.4694937 12.71875 9.4960938 C 12.69415 9.5226938 12.60494 9.3695637 12.5 9.1835938 C 12.39505 8.9976538 12.05984 8.6025437 11.78125 8.3085938 C 10.97711 7.4600637 10.85066 7.0170437 11.1875 6.3398438 C 11.35737 5.9983538 12.0966 5.2212438 12.1875 5.2773438 z" transform="translate(4 4)"/>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@@ -0,0 +1,245 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>306</width>
<height>387</height>
</rect>
</property>
<property name="windowTitle">
<string>Annotation Editor</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLineEdit" name="nameEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="placeholderText">
<string>Annotation Name</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="typeLabel">
<property name="text">
<string>Type</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="typeBox"/>
</item>
</layout>
</item>
<item>
<widget class="QStackedWidget" name="stackedWidget">
<widget class="QWidget" name="page">
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_12">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_15">
<item>
<widget class="QCheckBox" name="foregroundCheck">
<property name="text">
<string>Foreground</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="foregroundColorButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>30</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>45</width>
<height>40</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_16">
<item>
<widget class="QCheckBox" name="highlightCheck">
<property name="text">
<string>Highlight</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="highlightColorButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>30</width>
<height>24</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>45</width>
<height>40</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_17">
<item>
<widget class="QCheckBox" name="boldCheck">
<property name="text">
<string>Bold</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_18">
<item>
<widget class="QCheckBox" name="italicCheck">
<property name="text">
<string>Italic</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_19">
<item>
<widget class="QCheckBox" name="underlineCheck">
<property name="text">
<string>Underline</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="underlineType"/>
</item>
<item>
<widget class="QPushButton" name="underlineColorButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>45</width>
<height>24</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>45</width>
<height>40</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="okButton">
<property name="text">
<string>OK</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="cancelButton">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -55,46 +55,6 @@
<property name="spacing">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QListView" name="listView">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="showDropIndicator" stdset="0">
<bool>false</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="movement">
<enum>QListView::Static</enum>
</property>
<property name="isWrapping" stdset="0">
<bool>true</bool>
</property>
<property name="resizeMode">
<enum>QListView::Fixed</enum>
</property>
<property name="layoutMode">
<enum>QListView::SinglePass</enum>
</property>
<property name="spacing">
<number>0</number>
</property>
<property name="viewMode">
<enum>QListView::IconMode</enum>
</property>
<property name="uniformItemSizes">
<bool>true</bool>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tablePage">
@@ -114,43 +74,6 @@
<property name="spacing">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QTableView" name="tableView">
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContentsOnFirstShow</enum>
</property>
<property name="editTriggers">
<set>QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked</set>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="gridStyle">
<enum>Qt::NoPen</enum>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
<attribute name="horizontalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
</layout>
</widget>
</widget>

View File

@@ -1,5 +1,20 @@
<RCC>
<qresource prefix="images">
<file>DarkIcons/about.svg</file>
<file>DarkIcons/switches.svg</file>
<file>LightIcons/about.svg</file>
<file>LightIcons/switches.svg</file>
<file>LightIcons/annotate.svg</file>
<file>DarkIcons/annotate.svg</file>
<file>Google.png</file>
<file>Wikipedia.png</file>
<file>Youtube.png</file>
<file>DarkIcons/web-browser.svg</file>
<file>LightIcons/web-browser.svg</file>
<file>DarkIcons/arrow-down.svg</file>
<file>DarkIcons/arrow-up.svg</file>
<file>LightIcons/arrow-down.svg</file>
<file>LightIcons/arrow-up.svg</file>
<file>Lector.png</file>
<file>DarkIcons/tableofcontents.svg</file>
<file>LightIcons/tableofcontents.svg</file>
@@ -78,5 +93,6 @@
<file>translations_bin/Lector_es.qm</file>
<file>translations_bin/Lector_de.qm</file>
<file>translations_bin/Lector_fr.qm</file>
<file>translations_bin/Lector_zh.qm</file>
</qresource>
</RCC>

View File

@@ -6,206 +6,581 @@
<rect>
<x>0</x>
<y>0</y>
<width>1216</width>
<height>658</height>
<width>1119</width>
<height>612</height>
</rect>
</property>
<property name="windowTitle">
<string>Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Library</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QTreeView" name="treeView"/>
</item>
<item row="1" column="0">
<widget class="QTextBrowser" name="aboutBox">
<property name="openExternalLinks">
<bool>true</bool>
</property>
<property name="openLinks">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Switches</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QCheckBox" name="refreshLibrary">
<property name="text">
<string>Startup: Refresh library</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="fileRemember">
<property name="text">
<string>Remember open files</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="performCulling">
<property name="toolTip">
<string>Enabling reduces startup time and memory usage</string>
</property>
<property name="text">
<string>Load covers only when needed</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QCheckBox" name="coverShadows">
<property name="text">
<string>Cover shadows</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="autoTags">
<property name="text">
<string>Generate tags from files</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cachingEnabled">
<property name="toolTip">
<string>Greatly reduces page transition time at the cost of more memory</string>
</property>
<property name="text">
<string>Cache comic / pdf pages</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="languageLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Dictionary:</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="languageBox"/>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="hideScrollBars">
<property name="toolTip">
<string>Horizontal scrolling with Alt + Scroll
Reopen book to see changes</string>
</property>
<property name="text">
<string>Hide scrollbars when reading</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="label">
<property name="toolTip">
<string>Restart application to see changes</string>
</property>
<property name="text">
<string>Icon theme: </string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="darkIconsRadio">
<property name="toolTip">
<string>Restart application to see changes</string>
</property>
<property name="text">
<string>Dar&amp;k</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="lightIconsRadio">
<property name="toolTip">
<string>Restart application to see changes</string>
</property>
<property name="text">
<string>&amp;Light</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
<widget class="QListView" name="listView">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
</widget>
</item>
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item row="0" column="1">
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QPushButton" name="okButton">
<property name="text">
<string>Scan Library</string>
</property>
<widget class="QStackedWidget" name="stackedWidget">
<widget class="QWidget" name="treeViewPage">
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="0">
<widget class="QTreeView" name="treeView"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="switchPage">
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Library</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_13">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_14">
<item>
<widget class="QLabel" name="readAtLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Consider book read at percent</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="readAtPercent">
<property name="minimum">
<number>90</number>
</property>
<property name="value">
<number>95</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
<widget class="QLabel" name="label">
<property name="toolTip">
<string>Restart application to see changes</string>
</property>
<property name="text">
<string>Icon theme: </string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="darkIconsRadio">
<property name="toolTip">
<string>Restart application to see changes</string>
</property>
<property name="text">
<string>&amp;Dark</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="lightIconsRadio">
<property name="toolTip">
<string>Restart application to see changes</string>
</property>
<property name="text">
<string>L&amp;ight</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QCheckBox" name="refreshLibrary">
<property name="text">
<string>Startup: Refresh library</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="fileRemember">
<property name="text">
<string>Remember open files</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QCheckBox" name="coverShadows">
<property name="text">
<string>Cover shadows</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="performCulling">
<property name="toolTip">
<string>Enabling reduces startup time and memory usage</string>
</property>
<property name="text">
<string>Load covers only when needed</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_9">
<item>
<widget class="QCheckBox" name="autoTags">
<property name="text">
<string>Generate tags from files</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="attenuateTitles">
<property name="text">
<string>Shrink long book titles</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Reading</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="2" column="0">
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QCheckBox" name="hideScrollBars">
<property name="toolTip">
<string>Horizontal scrolling with Alt + Scroll
Reopen book to see changes</string>
</property>
<property name="text">
<string>Hide scrollbars when reading</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cachingEnabled">
<property name="toolTip">
<string>Greatly reduces page transition time at the cost of more memory</string>
</property>
<property name="text">
<string>Cache comic / pdf pages</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="languageLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Dictionary language</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="languageBox"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="scrollSpeedLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Scroll speed</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="scrollSpeedSlider">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimum">
<number>3</number>
</property>
<property name="maximum">
<number>15</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="annotationsPage">
<layout class="QGridLayout" name="gridLayout_7">
<item row="0" column="0">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="textTab">
<attribute name="title">
<string>Text</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_8">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_11">
<item>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="newAnnotation">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>30</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>45</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>New</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="deleteAnnotation">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>30</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>45</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Delete</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="editAnnotation">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>30</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>45</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Edit</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="moveUp">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>30</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>45</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Move Up</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="moveDown">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>30</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>45</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Move Down</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QListView" name="annotationsList">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="showDropIndicator" stdset="0">
<bool>false</bool>
</property>
<property name="defaultDropAction">
<enum>Qt::IgnoreAction</enum>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QTextBrowser" name="previewView">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>100</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="imageTab">
<attribute name="title">
<string>Image</string>
</attribute>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="aboutPage">
<layout class="QGridLayout" name="gridLayout_6">
<item row="0" column="0">
<widget class="QTextBrowser" name="aboutBox">
<property name="openExternalLinks">
<bool>true</bool>
</property>
<property name="openLinks">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QPushButton" name="cancelButton">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="aboutButton">
<property name="text">
<string>About</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
<layout class="QHBoxLayout" name="horizontalLayout_10">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="okButton">
<property name="text">
<string>Scan Library</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="cancelButton">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -11,30 +11,74 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(1216, 658)
self.gridLayout_3 = QtWidgets.QGridLayout(Dialog)
self.gridLayout_3.setObjectName("gridLayout_3")
self.verticalLayout_2 = QtWidgets.QVBoxLayout()
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.groupBox_2 = QtWidgets.QGroupBox(Dialog)
self.groupBox_2.setObjectName("groupBox_2")
self.gridLayout_2 = QtWidgets.QGridLayout(self.groupBox_2)
self.gridLayout_2.setObjectName("gridLayout_2")
self.treeView = QtWidgets.QTreeView(self.groupBox_2)
self.treeView.setObjectName("treeView")
self.gridLayout_2.addWidget(self.treeView, 0, 0, 1, 1)
self.aboutBox = QtWidgets.QTextBrowser(self.groupBox_2)
self.aboutBox.setOpenExternalLinks(True)
self.aboutBox.setOpenLinks(False)
self.aboutBox.setObjectName("aboutBox")
self.gridLayout_2.addWidget(self.aboutBox, 1, 0, 1, 1)
self.verticalLayout_2.addWidget(self.groupBox_2)
self.groupBox = QtWidgets.QGroupBox(Dialog)
self.groupBox.setObjectName("groupBox")
self.gridLayout = QtWidgets.QGridLayout(self.groupBox)
Dialog.resize(1119, 612)
self.gridLayout = QtWidgets.QGridLayout(Dialog)
self.gridLayout.setObjectName("gridLayout")
self.listView = QtWidgets.QListView(Dialog)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.listView.sizePolicy().hasHeightForWidth())
self.listView.setSizePolicy(sizePolicy)
self.listView.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
self.listView.setObjectName("listView")
self.gridLayout.addWidget(self.listView, 0, 0, 1, 1)
self.verticalLayout_4 = QtWidgets.QVBoxLayout()
self.verticalLayout_4.setObjectName("verticalLayout_4")
self.stackedWidget = QtWidgets.QStackedWidget(Dialog)
self.stackedWidget.setObjectName("stackedWidget")
self.treeViewPage = QtWidgets.QWidget()
self.treeViewPage.setObjectName("treeViewPage")
self.gridLayout_5 = QtWidgets.QGridLayout(self.treeViewPage)
self.gridLayout_5.setObjectName("gridLayout_5")
self.treeView = QtWidgets.QTreeView(self.treeViewPage)
self.treeView.setObjectName("treeView")
self.gridLayout_5.addWidget(self.treeView, 0, 0, 1, 1)
self.stackedWidget.addWidget(self.treeViewPage)
self.switchPage = QtWidgets.QWidget()
self.switchPage.setObjectName("switchPage")
self.gridLayout_2 = QtWidgets.QGridLayout(self.switchPage)
self.gridLayout_2.setObjectName("gridLayout_2")
self.verticalLayout = QtWidgets.QVBoxLayout()
self.verticalLayout.setObjectName("verticalLayout")
self.groupBox = QtWidgets.QGroupBox(self.switchPage)
self.groupBox.setObjectName("groupBox")
self.gridLayout_4 = QtWidgets.QGridLayout(self.groupBox)
self.gridLayout_4.setObjectName("gridLayout_4")
self.verticalLayout_2 = QtWidgets.QVBoxLayout()
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.horizontalLayout_13 = QtWidgets.QHBoxLayout()
self.horizontalLayout_13.setObjectName("horizontalLayout_13")
self.horizontalLayout_14 = QtWidgets.QHBoxLayout()
self.horizontalLayout_14.setObjectName("horizontalLayout_14")
self.readAtLabel = QtWidgets.QLabel(self.groupBox)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.readAtLabel.sizePolicy().hasHeightForWidth())
self.readAtLabel.setSizePolicy(sizePolicy)
self.readAtLabel.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
self.readAtLabel.setObjectName("readAtLabel")
self.horizontalLayout_14.addWidget(self.readAtLabel)
self.readAtPercent = QtWidgets.QSpinBox(self.groupBox)
self.readAtPercent.setMinimum(90)
self.readAtPercent.setProperty("value", 95)
self.readAtPercent.setObjectName("readAtPercent")
self.horizontalLayout_14.addWidget(self.readAtPercent)
self.horizontalLayout_13.addLayout(self.horizontalLayout_14)
self.horizontalLayout_7 = QtWidgets.QHBoxLayout()
self.horizontalLayout_7.setObjectName("horizontalLayout_7")
self.label = QtWidgets.QLabel(self.groupBox)
self.label.setObjectName("label")
self.horizontalLayout_7.addWidget(self.label)
self.darkIconsRadio = QtWidgets.QRadioButton(self.groupBox)
self.darkIconsRadio.setObjectName("darkIconsRadio")
self.horizontalLayout_7.addWidget(self.darkIconsRadio)
self.lightIconsRadio = QtWidgets.QRadioButton(self.groupBox)
self.lightIconsRadio.setObjectName("lightIconsRadio")
self.horizontalLayout_7.addWidget(self.lightIconsRadio)
self.horizontalLayout_13.addLayout(self.horizontalLayout_7)
self.verticalLayout_2.addLayout(self.horizontalLayout_13)
self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
self.horizontalLayout_4.setObjectName("horizontalLayout_4")
self.refreshLibrary = QtWidgets.QCheckBox(self.groupBox)
@@ -43,28 +87,47 @@ class Ui_Dialog(object):
self.fileRemember = QtWidgets.QCheckBox(self.groupBox)
self.fileRemember.setObjectName("fileRemember")
self.horizontalLayout_4.addWidget(self.fileRemember)
self.performCulling = QtWidgets.QCheckBox(self.groupBox)
self.performCulling.setObjectName("performCulling")
self.horizontalLayout_4.addWidget(self.performCulling)
self.verticalLayout.addLayout(self.horizontalLayout_4)
self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.coverShadows = QtWidgets.QCheckBox(self.groupBox)
self.coverShadows.setObjectName("coverShadows")
self.horizontalLayout.addWidget(self.coverShadows)
self.autoTags = QtWidgets.QCheckBox(self.groupBox)
self.autoTags.setObjectName("autoTags")
self.horizontalLayout.addWidget(self.autoTags)
self.cachingEnabled = QtWidgets.QCheckBox(self.groupBox)
self.cachingEnabled.setObjectName("cachingEnabled")
self.horizontalLayout.addWidget(self.cachingEnabled)
self.gridLayout.addLayout(self.horizontalLayout, 1, 0, 1, 1)
self.horizontalLayout_6 = QtWidgets.QHBoxLayout()
self.horizontalLayout_6.setObjectName("horizontalLayout_6")
self.verticalLayout_2.addLayout(self.horizontalLayout_4)
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
self.languageLabel = QtWidgets.QLabel(self.groupBox)
self.coverShadows = QtWidgets.QCheckBox(self.groupBox)
self.coverShadows.setObjectName("coverShadows")
self.horizontalLayout_3.addWidget(self.coverShadows)
self.performCulling = QtWidgets.QCheckBox(self.groupBox)
self.performCulling.setObjectName("performCulling")
self.horizontalLayout_3.addWidget(self.performCulling)
self.verticalLayout_2.addLayout(self.horizontalLayout_3)
self.horizontalLayout_9 = QtWidgets.QHBoxLayout()
self.horizontalLayout_9.setObjectName("horizontalLayout_9")
self.autoTags = QtWidgets.QCheckBox(self.groupBox)
self.autoTags.setObjectName("autoTags")
self.horizontalLayout_9.addWidget(self.autoTags)
self.attenuateTitles = QtWidgets.QCheckBox(self.groupBox)
self.attenuateTitles.setObjectName("attenuateTitles")
self.horizontalLayout_9.addWidget(self.attenuateTitles)
self.verticalLayout_2.addLayout(self.horizontalLayout_9)
self.gridLayout_4.addLayout(self.verticalLayout_2, 0, 0, 1, 1)
self.verticalLayout.addWidget(self.groupBox)
self.groupBox_2 = QtWidgets.QGroupBox(self.switchPage)
self.groupBox_2.setObjectName("groupBox_2")
self.gridLayout_3 = QtWidgets.QGridLayout(self.groupBox_2)
self.gridLayout_3.setObjectName("gridLayout_3")
self.verticalLayout_3 = QtWidgets.QVBoxLayout()
self.verticalLayout_3.setObjectName("verticalLayout_3")
self.horizontalLayout_6 = QtWidgets.QHBoxLayout()
self.horizontalLayout_6.setObjectName("horizontalLayout_6")
self.hideScrollBars = QtWidgets.QCheckBox(self.groupBox_2)
self.hideScrollBars.setObjectName("hideScrollBars")
self.horizontalLayout_6.addWidget(self.hideScrollBars)
self.cachingEnabled = QtWidgets.QCheckBox(self.groupBox_2)
self.cachingEnabled.setObjectName("cachingEnabled")
self.horizontalLayout_6.addWidget(self.cachingEnabled)
self.verticalLayout_3.addLayout(self.horizontalLayout_6)
self.horizontalLayout_8 = QtWidgets.QHBoxLayout()
self.horizontalLayout_8.setObjectName("horizontalLayout_8")
self.horizontalLayout_5 = QtWidgets.QHBoxLayout()
self.horizontalLayout_5.setObjectName("horizontalLayout_5")
self.languageLabel = QtWidgets.QLabel(self.groupBox_2)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
@@ -72,70 +135,204 @@ class Ui_Dialog(object):
self.languageLabel.setSizePolicy(sizePolicy)
self.languageLabel.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
self.languageLabel.setObjectName("languageLabel")
self.horizontalLayout_3.addWidget(self.languageLabel)
self.languageBox = QtWidgets.QComboBox(self.groupBox)
self.horizontalLayout_5.addWidget(self.languageLabel)
self.languageBox = QtWidgets.QComboBox(self.groupBox_2)
self.languageBox.setObjectName("languageBox")
self.horizontalLayout_3.addWidget(self.languageBox)
self.horizontalLayout_6.addLayout(self.horizontalLayout_3)
self.hideScrollBars = QtWidgets.QCheckBox(self.groupBox)
self.hideScrollBars.setObjectName("hideScrollBars")
self.horizontalLayout_6.addWidget(self.hideScrollBars)
self.horizontalLayout_5 = QtWidgets.QHBoxLayout()
self.horizontalLayout_5.setObjectName("horizontalLayout_5")
self.label = QtWidgets.QLabel(self.groupBox)
self.label.setObjectName("label")
self.horizontalLayout_5.addWidget(self.label)
self.darkIconsRadio = QtWidgets.QRadioButton(self.groupBox)
self.darkIconsRadio.setObjectName("darkIconsRadio")
self.horizontalLayout_5.addWidget(self.darkIconsRadio)
self.lightIconsRadio = QtWidgets.QRadioButton(self.groupBox)
self.lightIconsRadio.setObjectName("lightIconsRadio")
self.horizontalLayout_5.addWidget(self.lightIconsRadio)
self.horizontalLayout_6.addLayout(self.horizontalLayout_5)
self.gridLayout.addLayout(self.horizontalLayout_6, 2, 0, 1, 1)
self.verticalLayout_2.addWidget(self.groupBox)
self.gridLayout_3.addLayout(self.verticalLayout_2, 0, 0, 1, 1)
self.horizontalLayout_5.addWidget(self.languageBox)
self.horizontalLayout_8.addLayout(self.horizontalLayout_5)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.scrollSpeedLabel = QtWidgets.QLabel(self.groupBox_2)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.scrollSpeedLabel.sizePolicy().hasHeightForWidth())
self.scrollSpeedLabel.setSizePolicy(sizePolicy)
self.scrollSpeedLabel.setObjectName("scrollSpeedLabel")
self.horizontalLayout.addWidget(self.scrollSpeedLabel)
self.scrollSpeedSlider = QtWidgets.QSlider(self.groupBox_2)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.scrollSpeedSlider.sizePolicy().hasHeightForWidth())
self.scrollSpeedSlider.setSizePolicy(sizePolicy)
self.scrollSpeedSlider.setMinimum(3)
self.scrollSpeedSlider.setMaximum(15)
self.scrollSpeedSlider.setOrientation(QtCore.Qt.Horizontal)
self.scrollSpeedSlider.setObjectName("scrollSpeedSlider")
self.horizontalLayout.addWidget(self.scrollSpeedSlider)
self.horizontalLayout_8.addLayout(self.horizontalLayout)
self.verticalLayout_3.addLayout(self.horizontalLayout_8)
self.gridLayout_3.addLayout(self.verticalLayout_3, 2, 0, 1, 1)
self.verticalLayout.addWidget(self.groupBox_2)
self.gridLayout_2.addLayout(self.verticalLayout, 0, 0, 1, 1)
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.gridLayout_2.addItem(spacerItem, 1, 0, 1, 1)
self.stackedWidget.addWidget(self.switchPage)
self.annotationsPage = QtWidgets.QWidget()
self.annotationsPage.setObjectName("annotationsPage")
self.gridLayout_7 = QtWidgets.QGridLayout(self.annotationsPage)
self.gridLayout_7.setObjectName("gridLayout_7")
self.tabWidget = QtWidgets.QTabWidget(self.annotationsPage)
self.tabWidget.setObjectName("tabWidget")
self.textTab = QtWidgets.QWidget()
self.textTab.setObjectName("textTab")
self.gridLayout_8 = QtWidgets.QGridLayout(self.textTab)
self.gridLayout_8.setObjectName("gridLayout_8")
self.verticalLayout_5 = QtWidgets.QVBoxLayout()
self.verticalLayout_5.setObjectName("verticalLayout_5")
self.horizontalLayout_11 = QtWidgets.QHBoxLayout()
self.horizontalLayout_11.setObjectName("horizontalLayout_11")
self.verticalLayout_6 = QtWidgets.QVBoxLayout()
self.verticalLayout_6.setObjectName("verticalLayout_6")
spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout_6.addItem(spacerItem1)
self.newAnnotation = QtWidgets.QPushButton(self.textTab)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.newAnnotation.sizePolicy().hasHeightForWidth())
self.newAnnotation.setSizePolicy(sizePolicy)
self.newAnnotation.setMinimumSize(QtCore.QSize(30, 0))
self.newAnnotation.setMaximumSize(QtCore.QSize(45, 16777215))
self.newAnnotation.setText("")
self.newAnnotation.setObjectName("newAnnotation")
self.verticalLayout_6.addWidget(self.newAnnotation)
self.deleteAnnotation = QtWidgets.QPushButton(self.textTab)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.deleteAnnotation.sizePolicy().hasHeightForWidth())
self.deleteAnnotation.setSizePolicy(sizePolicy)
self.deleteAnnotation.setMinimumSize(QtCore.QSize(30, 0))
self.deleteAnnotation.setMaximumSize(QtCore.QSize(45, 16777215))
self.deleteAnnotation.setText("")
self.deleteAnnotation.setObjectName("deleteAnnotation")
self.verticalLayout_6.addWidget(self.deleteAnnotation)
self.editAnnotation = QtWidgets.QPushButton(self.textTab)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.editAnnotation.sizePolicy().hasHeightForWidth())
self.editAnnotation.setSizePolicy(sizePolicy)
self.editAnnotation.setMinimumSize(QtCore.QSize(30, 0))
self.editAnnotation.setMaximumSize(QtCore.QSize(45, 16777215))
self.editAnnotation.setText("")
self.editAnnotation.setObjectName("editAnnotation")
self.verticalLayout_6.addWidget(self.editAnnotation)
self.moveUp = QtWidgets.QPushButton(self.textTab)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.moveUp.sizePolicy().hasHeightForWidth())
self.moveUp.setSizePolicy(sizePolicy)
self.moveUp.setMinimumSize(QtCore.QSize(30, 0))
self.moveUp.setMaximumSize(QtCore.QSize(45, 16777215))
self.moveUp.setText("")
self.moveUp.setObjectName("moveUp")
self.verticalLayout_6.addWidget(self.moveUp)
self.moveDown = QtWidgets.QPushButton(self.textTab)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.moveDown.sizePolicy().hasHeightForWidth())
self.moveDown.setSizePolicy(sizePolicy)
self.moveDown.setMinimumSize(QtCore.QSize(30, 0))
self.moveDown.setMaximumSize(QtCore.QSize(45, 16777215))
self.moveDown.setText("")
self.moveDown.setObjectName("moveDown")
self.verticalLayout_6.addWidget(self.moveDown)
spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout_6.addItem(spacerItem2)
self.horizontalLayout_11.addLayout(self.verticalLayout_6)
self.annotationsList = QtWidgets.QListView(self.textTab)
self.annotationsList.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
self.annotationsList.setProperty("showDropIndicator", False)
self.annotationsList.setDefaultDropAction(QtCore.Qt.IgnoreAction)
self.annotationsList.setObjectName("annotationsList")
self.horizontalLayout_11.addWidget(self.annotationsList)
self.verticalLayout_5.addLayout(self.horizontalLayout_11)
self.gridLayout_8.addLayout(self.verticalLayout_5, 0, 0, 1, 1)
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.previewView = QtWidgets.QTextBrowser(self.textTab)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Maximum)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.previewView.sizePolicy().hasHeightForWidth())
self.previewView.setSizePolicy(sizePolicy)
self.previewView.setMaximumSize(QtCore.QSize(16777215, 100))
self.previewView.setFocusPolicy(QtCore.Qt.NoFocus)
self.previewView.setObjectName("previewView")
self.horizontalLayout_2.addWidget(self.previewView)
self.gridLayout_8.addLayout(self.horizontalLayout_2, 1, 0, 1, 1)
self.tabWidget.addTab(self.textTab, "")
self.imageTab = QtWidgets.QWidget()
self.imageTab.setObjectName("imageTab")
self.tabWidget.addTab(self.imageTab, "")
self.gridLayout_7.addWidget(self.tabWidget, 0, 0, 1, 1)
self.stackedWidget.addWidget(self.annotationsPage)
self.aboutPage = QtWidgets.QWidget()
self.aboutPage.setObjectName("aboutPage")
self.gridLayout_6 = QtWidgets.QGridLayout(self.aboutPage)
self.gridLayout_6.setObjectName("gridLayout_6")
self.aboutBox = QtWidgets.QTextBrowser(self.aboutPage)
self.aboutBox.setOpenExternalLinks(True)
self.aboutBox.setOpenLinks(False)
self.aboutBox.setObjectName("aboutBox")
self.gridLayout_6.addWidget(self.aboutBox, 0, 0, 1, 1)
self.stackedWidget.addWidget(self.aboutPage)
self.verticalLayout_4.addWidget(self.stackedWidget)
self.horizontalLayout_10 = QtWidgets.QHBoxLayout()
self.horizontalLayout_10.setObjectName("horizontalLayout_10")
spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_10.addItem(spacerItem3)
self.okButton = QtWidgets.QPushButton(Dialog)
self.okButton.setObjectName("okButton")
self.horizontalLayout_2.addWidget(self.okButton)
self.horizontalLayout_10.addWidget(self.okButton)
self.cancelButton = QtWidgets.QPushButton(Dialog)
self.cancelButton.setObjectName("cancelButton")
self.horizontalLayout_2.addWidget(self.cancelButton)
self.aboutButton = QtWidgets.QPushButton(Dialog)
self.aboutButton.setCheckable(True)
self.aboutButton.setObjectName("aboutButton")
self.horizontalLayout_2.addWidget(self.aboutButton)
self.gridLayout_3.addLayout(self.horizontalLayout_2, 1, 0, 1, 1)
self.horizontalLayout_10.addWidget(self.cancelButton)
self.verticalLayout_4.addLayout(self.horizontalLayout_10)
self.gridLayout.addLayout(self.verticalLayout_4, 0, 1, 1, 1)
self.retranslateUi(Dialog)
self.tabWidget.setCurrentIndex(0)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Settings"))
self.groupBox_2.setTitle(_translate("Dialog", "Library"))
self.groupBox.setTitle(_translate("Dialog", "Switches"))
self.refreshLibrary.setText(_translate("Dialog", "Startup: Refresh library"))
self.fileRemember.setText(_translate("Dialog", "Remember open files"))
self.performCulling.setToolTip(_translate("Dialog", "Enabling reduces startup time and memory usage"))
self.performCulling.setText(_translate("Dialog", "Load covers only when needed"))
self.coverShadows.setText(_translate("Dialog", "Cover shadows"))
self.autoTags.setText(_translate("Dialog", "Generate tags from files"))
self.cachingEnabled.setToolTip(_translate("Dialog", "Greatly reduces page transition time at the cost of more memory"))
self.cachingEnabled.setText(_translate("Dialog", "Cache comic / pdf pages"))
self.languageLabel.setText(_translate("Dialog", "Dictionary:"))
self.hideScrollBars.setToolTip(_translate("Dialog", "Horizontal scrolling with Alt + Scroll\n"
"Reopen book to see changes"))
self.hideScrollBars.setText(_translate("Dialog", "Hide scrollbars when reading"))
self.groupBox.setTitle(_translate("Dialog", "Library"))
self.readAtLabel.setText(_translate("Dialog", "Consider book read at percent"))
self.label.setToolTip(_translate("Dialog", "Restart application to see changes"))
self.label.setText(_translate("Dialog", "Icon theme: "))
self.darkIconsRadio.setToolTip(_translate("Dialog", "Restart application to see changes"))
self.darkIconsRadio.setText(_translate("Dialog", "Dar&k"))
self.darkIconsRadio.setText(_translate("Dialog", "&Dark"))
self.lightIconsRadio.setToolTip(_translate("Dialog", "Restart application to see changes"))
self.lightIconsRadio.setText(_translate("Dialog", "&Light"))
self.lightIconsRadio.setText(_translate("Dialog", "L&ight"))
self.refreshLibrary.setText(_translate("Dialog", "Startup: Refresh library"))
self.fileRemember.setText(_translate("Dialog", "Remember open files"))
self.coverShadows.setText(_translate("Dialog", "Cover shadows"))
self.performCulling.setToolTip(_translate("Dialog", "Enabling reduces startup time and memory usage"))
self.performCulling.setText(_translate("Dialog", "Load covers only when needed"))
self.autoTags.setText(_translate("Dialog", "Generate tags from files"))
self.attenuateTitles.setText(_translate("Dialog", "Shrink long book titles"))
self.groupBox_2.setTitle(_translate("Dialog", "Reading"))
self.hideScrollBars.setToolTip(_translate("Dialog", "Horizontal scrolling with Alt + Scroll\n"
"Reopen book to see changes"))
self.hideScrollBars.setText(_translate("Dialog", "Hide scrollbars when reading"))
self.cachingEnabled.setToolTip(_translate("Dialog", "Greatly reduces page transition time at the cost of more memory"))
self.cachingEnabled.setText(_translate("Dialog", "Cache comic / pdf pages"))
self.languageLabel.setText(_translate("Dialog", "Dictionary language"))
self.scrollSpeedLabel.setText(_translate("Dialog", "Scroll speed"))
self.newAnnotation.setToolTip(_translate("Dialog", "New"))
self.deleteAnnotation.setToolTip(_translate("Dialog", "Delete"))
self.editAnnotation.setToolTip(_translate("Dialog", "Edit"))
self.moveUp.setToolTip(_translate("Dialog", "Move Up"))
self.moveDown.setToolTip(_translate("Dialog", "Move Down"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.textTab), _translate("Dialog", "Text"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.imageTab), _translate("Dialog", "Image"))
self.okButton.setText(_translate("Dialog", "Scan Library"))
self.cancelButton.setText(_translate("Dialog", "Close"))
self.aboutButton.setText(_translate("Dialog", "About"))

View File

@@ -3,120 +3,135 @@
<context>
<name>BookToolBar</name>
<message>
<location filename="../../lector/toolbars.py" line="45"/>
<location filename="../../toolbars.py" line="42"/>
<source>View settings</source>
<translation>Einstellungen anzeigen</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="49"/>
<location filename="../../toolbars.py" line="48"/>
<source>Fullscreen</source>
<translation>Vollbild</translation>
<translation type="obsolete">Vollbild</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="53"/>
<location filename="../../toolbars.py" line="50"/>
<source>Add bookmark</source>
<translation>Lesezeichen hinzufügen</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="57"/>
<location filename="../../toolbars.py" line="56"/>
<source>Bookmarks</source>
<translation>Lesezeichen</translation>
<translation type="obsolete">Lesezeichen</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="62"/>
<location filename="../../toolbars.py" line="66"/>
<source>Reset profile</source>
<translation>Profil zurücksetzen</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="83"/>
<location filename="../../toolbars.py" line="91"/>
<source>Font size</source>
<translation>Schriftgröße</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="87"/>
<location filename="../../toolbars.py" line="95"/>
<source>Increase padding</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="92"/>
<location filename="../../toolbars.py" line="100"/>
<source>Decrease padding</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="98"/>
<location filename="../../toolbars.py" line="106"/>
<source>Increase line spacing</source>
<translation>Zeilenabstand vergrößern</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="103"/>
<location filename="../../toolbars.py" line="111"/>
<source>Decrease line spacing</source>
<translation>Zeilenabstand verkleinern</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="109"/>
<location filename="../../toolbars.py" line="117"/>
<source>Left align text</source>
<translation>Text linksbündig ausrichten</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="116"/>
<location filename="../../toolbars.py" line="124"/>
<source>Right align text</source>
<translation>Text rechtsbündig ausrichten</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="123"/>
<location filename="../../toolbars.py" line="131"/>
<source>Center align text</source>
<translation>Text zentrieren</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="130"/>
<location filename="../../toolbars.py" line="138"/>
<source>Justify text</source>
<translation>Blocksatz</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="233"/>
<location filename="../../toolbars.py" line="241"/>
<source>Background color</source>
<translation>Hintergrund</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="202"/>
<location filename="../../toolbars.py" line="210"/>
<source>Zoom in</source>
<translation>Vergrößern</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="207"/>
<location filename="../../toolbars.py" line="215"/>
<source>Zoom Out</source>
<translation>Verkleinern</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="213"/>
<location filename="../../toolbars.py" line="221"/>
<source>Fit Width</source>
<translation>An Fensterbreite anpassen</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="219"/>
<location filename="../../toolbars.py" line="227"/>
<source>Best Fit</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="225"/>
<location filename="../../toolbars.py" line="233"/>
<source>Original size</source>
<translation>Original Größe</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="260"/>
<location filename="../../toolbars.py" line="268"/>
<source>Search...</source>
<translation>Suchen...</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="269"/>
<location filename="../../toolbars.py" line="277"/>
<source>Table of Contents</source>
<translation>Inhaltsverzeichnis</translation>
</message>
<message>
<location filename="../../toolbars.py" line="54"/>
<source>Bookmarks (Ctrl + B)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../toolbars.py" line="62"/>
<source>Fullscreen (F11)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../toolbars.py" line="46"/>
<source>Annotations</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>DefinitionsUI</name>
<message>
<location filename="../../lector/definitionsdialog.py" line="117"/>
<location filename="../../definitionsdialog.py" line="125"/>
<source>No definitions found in</source>
<translation>Keine Definition gefunden in</translation>
</message>
@@ -139,62 +154,62 @@
<translation>Aussprache des Root-Wortes abspielen</translation>
</message>
<message>
<location filename="../settingswindow.py" line="117"/>
<location filename="../settingswindow.py" line="305"/>
<source>Settings</source>
<translation>Einstellungen</translation>
</message>
<message>
<location filename="../settingswindow.py" line="118"/>
<location filename="../settingswindow.py" line="306"/>
<source>Library</source>
<translation>Bibliothek</translation>
</message>
<message>
<location filename="../settingswindow.py" line="119"/>
<source>Switches</source>
<translation>Schalter</translation>
<translation type="obsolete">Schalter</translation>
</message>
<message>
<location filename="../settingswindow.py" line="120"/>
<location filename="../settingswindow.py" line="314"/>
<source>Startup: Refresh library</source>
<translation>Start: Bibliothek neu laden</translation>
</message>
<message>
<location filename="../settingswindow.py" line="121"/>
<location filename="../settingswindow.py" line="315"/>
<source>Remember open files</source>
<translation>Offen Dateien merken</translation>
</message>
<message>
<location filename="../settingswindow.py" line="125"/>
<location filename="../settingswindow.py" line="319"/>
<source>Generate tags from files</source>
<translation>Tags aus Dateien generieren</translation>
</message>
<message>
<location filename="../settingswindow.py" line="128"/>
<source>Dictionary:</source>
<translation>Wörterbuch:</translation>
<translation type="obsolete">Wörterbuch:</translation>
</message>
<message>
<location filename="../settingswindow.py" line="124"/>
<location filename="../settingswindow.py" line="316"/>
<source>Cover shadows</source>
<translation>Cover Schatten</translation>
</message>
<message>
<location filename="../settingswindow.py" line="122"/>
<location filename="../settingswindow.py" line="317"/>
<source>Enabling reduces startup time and memory usage</source>
<translation>Aktivierung verringert die benötigte Zeit zum Starten und die Speicher Nutzung</translation>
</message>
<message>
<location filename="../settingswindow.py" line="123"/>
<location filename="../settingswindow.py" line="318"/>
<source>Load covers only when needed</source>
<translation>Cover nur laden wenn benötigt</translation>
</message>
<message>
<location filename="../settingswindow.py" line="126"/>
<location filename="../settingswindow.py" line="325"/>
<source>Greatly reduces page transition time at the cost of more memory</source>
<translation>Drastische verkürzung der Seitenübergangszeit auf Kosten des Speichers</translation>
</message>
<message>
<location filename="../settingswindow.py" line="127"/>
<location filename="../settingswindow.py" line="326"/>
<source>Cache comic / pdf pages</source>
<translation>Comic / PDF Seiten zwischenspeichern</translation>
</message>
@@ -204,34 +219,34 @@
<translation type="obsolete">Neustarten um Änderungen zu übernehmen</translation>
</message>
<message>
<location filename="../settingswindow.py" line="133"/>
<location filename="../settingswindow.py" line="309"/>
<source>Icon theme: </source>
<translation>Symbol Thema:</translation>
</message>
<message>
<location filename="../settingswindow.py" line="135"/>
<source>Dar&amp;k</source>
<translation>Dun&amp;kel</translation>
<translation type="obsolete">Dun&amp;kel</translation>
</message>
<message>
<location filename="../settingswindow.py" line="137"/>
<source>&amp;Light</source>
<translation>He&amp;ll</translation>
<translation type="obsolete">He&amp;ll</translation>
</message>
<message>
<location filename="../settingswindow.py" line="138"/>
<location filename="../settingswindow.py" line="336"/>
<source>Scan Library</source>
<translation>Bibliothek scannen</translation>
</message>
<message>
<location filename="../settingswindow.py" line="139"/>
<location filename="../settingswindow.py" line="337"/>
<source>Close</source>
<translation>Schließen</translation>
</message>
<message>
<location filename="../settingswindow.py" line="140"/>
<source>About</source>
<translation>Über</translation>
<translation type="obsolete">Über</translation>
</message>
<message>
<location filename="../metadata.py" line="88"/>
@@ -279,41 +294,111 @@
<translation>Abbrechen</translation>
</message>
<message>
<location filename="../settingswindow.py" line="129"/>
<location filename="../settingswindow.py" line="322"/>
<source>Horizontal scrolling with Alt + Scroll
Reopen book to see changes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="131"/>
<location filename="../settingswindow.py" line="324"/>
<source>Hide scrollbars when reading</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="136"/>
<location filename="../settingswindow.py" line="312"/>
<source>Restart application to see changes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="311"/>
<source>&amp;Dark</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="313"/>
<source>L&amp;ight</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="321"/>
<source>Reading</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="307"/>
<source>Consider book read at percent</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="327"/>
<source>Dictionary language</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="328"/>
<source>Scroll speed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="334"/>
<source>Text</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="329"/>
<source>New</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="330"/>
<source>Delete</source>
<translation type="unfinished">Löschen</translation>
</message>
<message>
<location filename="../settingswindow.py" line="331"/>
<source>Edit</source>
<translation type="unfinished">Bearbeiten</translation>
</message>
<message>
<location filename="../settingswindow.py" line="332"/>
<source>Move Up</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="333"/>
<source>Move Down</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="335"/>
<source>Image</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="320"/>
<source>Shrink long book titles</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Library</name>
<message>
<location filename="../../lector/library.py" line="130"/>
<location filename="../../library.py" line="133"/>
<source>Author</source>
<translation>Autor</translation>
</message>
<message>
<location filename="../../lector/library.py" line="131"/>
<location filename="../../library.py" line="134"/>
<source>Year</source>
<translation>Jahr</translation>
</message>
<message>
<location filename="../../lector/library.py" line="282"/>
<location filename="../../library.py" line="292"/>
<source>manually added</source>
<translation>Manuell hinzugefügt</translation>
</message>
<message>
<location filename="../../lector/library.py" line="209"/>
<location filename="../../library.py" line="215"/>
<source> books</source>
<translation type="unfinished"></translation>
</message>
@@ -321,148 +406,191 @@ Reopen book to see changes</source>
<context>
<name>LibraryToolBar</name>
<message>
<location filename="../../lector/toolbars.py" line="349"/>
<location filename="../../toolbars.py" line="360"/>
<source>Add book</source>
<translation>Buch hinzufügen</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="353"/>
<location filename="../../toolbars.py" line="364"/>
<source>Delete book</source>
<translation>Buch löschen</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="357"/>
<location filename="../../toolbars.py" line="368"/>
<source>Library background color</source>
<translation>Hintergrund der Bibliothek</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="362"/>
<location filename="../../toolbars.py" line="373"/>
<source>Settings</source>
<translation>Einstellungen</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="368"/>
<location filename="../../toolbars.py" line="379"/>
<source>View as covers</source>
<translation>Als Cover anzeigen</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="373"/>
<location filename="../../toolbars.py" line="384"/>
<source>View as table</source>
<translation>Als Tabelle anzeigen</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="383"/>
<location filename="../../toolbars.py" line="399"/>
<source>Filter library</source>
<translation>Bibliothek filtern</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="410"/>
<location filename="../../toolbars.py" line="427"/>
<source>Search for Title, Author, Tags...</source>
<translation>Suche nach Titel, Autor, Tags...</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="430"/>
<location filename="../../toolbars.py" line="449"/>
<source>Sort by</source>
<translation>Sortieren nach</translation>
</message>
<message>
<location filename="../../toolbars.py" line="390"/>
<source>Scan Library</source>
<translation type="unfinished">Bibliothek scannen</translation>
</message>
<message>
<location filename="../../toolbars.py" line="434"/>
<source>Title</source>
<translation type="unfinished">Titel</translation>
</message>
<message>
<location filename="../../toolbars.py" line="435"/>
<source>Author</source>
<translation type="unfinished">Autor</translation>
</message>
<message>
<location filename="../../toolbars.py" line="436"/>
<source>Year</source>
<translation type="unfinished">Jahr</translation>
</message>
<message>
<location filename="../../toolbars.py" line="437"/>
<source>Newest</source>
<translation type="unfinished">Neueste</translation>
</message>
<message>
<location filename="../../toolbars.py" line="438"/>
<source>Last Read</source>
<translation type="unfinished">Zuletzt gelesen</translation>
</message>
<message>
<location filename="../../toolbars.py" line="439"/>
<source>Progress</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../mainwindow.py" line="95"/>
<location filename="../mainwindow.py" line="67"/>
<source>Lector</source>
<translation>Lector</translation>
</message>
<message>
<location filename="../mainwindow.py" line="96"/>
<location filename="../mainwindow.py" line="68"/>
<source>Library</source>
<translation>Bibliothek</translation>
</message>
</context>
<context>
<name>Main_BookToolBarUI</name>
<message>
<location filename="../../toolbars.py" line="58"/>
<source>Toggle distraction free mode (Ctrl + D)</source>
<translation type="unfinished">Ablenkungsfreien Modus ein-/ausschalten (Strg + D)</translation>
</message>
</context>
<context>
<name>Main_UI</name>
<message>
<location filename="../../lector/__main__.py" line="114"/>
<location filename="../../__main__.py" line="119"/>
<source>Toggle distraction free mode (Ctrl + D)</source>
<translation>Ablenkungsfreien Modus ein-/ausschalten (Strg + D)</translation>
<translation type="obsolete">Ablenkungsfreien Modus ein-/ausschalten (Strg + D)</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="211"/>
<location filename="../../__main__.py" line="216"/>
<source>Scan library</source>
<translation>Biblothek scannen </translation>
<translation type="obsolete">Biblothek scannen </translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="463"/>
<location filename="../../__main__.py" line="471"/>
<source>Add books to database</source>
<translation>Bücher zur Datenbank hinzufügen</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="464"/>
<location filename="../../__main__.py" line="472"/>
<source>eBooks</source>
<translation>eBooks</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="477"/>
<location filename="../../__main__.py" line="486"/>
<source>Adding books...</source>
<translation>Bücher werden hinzugefügt...</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="540"/>
<location filename="../../__main__.py" line="549"/>
<source>Confirm deletion</source>
<translation>Löschen bestätigen</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="553"/>
<location filename="../../__main__.py" line="562"/>
<source>Save changes and start library scan</source>
<translation>Änderungen speichern &amp; Bibliotheksscan starten</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="601"/>
<location filename="../../__main__.py" line="618"/>
<source> Books</source>
<translation>Bücher</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="1028"/>
<location filename="../../__main__.py" line="762"/>
<source>Start reading</source>
<translation>Lesen</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="1034"/>
<location filename="../../__main__.py" line="768"/>
<source>Edit</source>
<translation>Bearbeiten</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="1038"/>
<location filename="../../__main__.py" line="772"/>
<source>Delete</source>
<translation>Löschen</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="1041"/>
<location filename="../../__main__.py" line="775"/>
<source>Mark read</source>
<translation>Als gelesen kennzeichnen</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="1044"/>
<location filename="../../__main__.py" line="778"/>
<source>Mark unread</source>
<translation>Als ungelesen kennzeichnen</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="1144"/>
<location filename="../../__main__.py" line="878"/>
<source>Manually Added</source>
<translation>Manuell hinzugefügt</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="747"/>
<location filename="../../widgets.py" line="747"/>
<source>Save page as...</source>
<translation>Seite speichern als...</translation>
<translation type="obsolete">Seite speichern als...</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="748"/>
<location filename="../../widgets.py" line="748"/>
<source>Images</source>
<translation>Bilder</translation>
<translation type="obsolete">Bilder</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="563"/>
<location filename="../../__main__.py" line="575"/>
<source> books</source>
<translation type="unfinished"></translation>
</message>
@@ -470,12 +598,12 @@ Reopen book to see changes</source>
<context>
<name>MetadataUI</name>
<message>
<location filename="../../lector/metadatadialog.py" line="101"/>
<location filename="../../metadatadialog.py" line="102"/>
<source>Author</source>
<translation>Autor</translation>
</message>
<message>
<location filename="../../lector/metadatadialog.py" line="102"/>
<location filename="../../metadatadialog.py" line="103"/>
<source>Year</source>
<translation>Jahr</translation>
</message>
@@ -483,12 +611,12 @@ Reopen book to see changes</source>
<context>
<name>PliantQGraphicsScene</name>
<message>
<location filename="../../lector/widgets.py" line="1002"/>
<location filename="../../widgets.py" line="647"/>
<source>Select new cover</source>
<translation>Neues Cover auswählen</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="1003"/>
<location filename="../../widgets.py" line="648"/>
<source>Images</source>
<translation>Bilder</translation>
</message>
@@ -496,181 +624,176 @@ Reopen book to see changes</source>
<context>
<name>PliantQGraphicsView</name>
<message>
<location filename="../../lector/widgets.py" line="695"/>
<location filename="../../widgets.py" line="695"/>
<source>Save page as...</source>
<translation>Seite speichern als...</translation>
<translation type="obsolete">Seite speichern als...</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="721"/>
<location filename="../../widgets.py" line="721"/>
<source>Zoom in (+)</source>
<translation>Vergrößern (+)</translation>
<translation type="obsolete">Vergrößern (+)</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="725"/>
<location filename="../../widgets.py" line="725"/>
<source>Zoom out (-)</source>
<translation>Verkleinern (-)</translation>
<translation type="obsolete">Verkleinern (-)</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="729"/>
<location filename="../../widgets.py" line="729"/>
<source>Fit width (W)</source>
<translation>An Fensterbreite anpassen</translation>
<translation type="obsolete">An Fensterbreite anpassen</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="733"/>
<source>Best fit (B)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="737"/>
<location filename="../../widgets.py" line="737"/>
<source>Original size (O)</source>
<translation>Original Größe (O)</translation>
<translation type="obsolete">Original Größe (O)</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="685"/>
<source>Toggle distraction free mode</source>
<translation type="obsolete">Ablenkungsfreien Modus ein-/ausschalten</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="702"/>
<source>Exit fullscreen</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="707"/>
<source>Distraction Free mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="710"/>
<source>Exit Distraction Free mode</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>PliantQTextBrowser</name>
<message>
<location filename="../../lector/widgets.py" line="848"/>
<location filename="../../widgets.py" line="848"/>
<source>Define</source>
<translation>Definieren</translation>
<translation type="obsolete">Definieren</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="853"/>
<location filename="../../widgets.py" line="853"/>
<source>Search</source>
<translation>Suchen</translation>
<translation type="obsolete">Suchen</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="827"/>
<source>Toggle distraction free mode</source>
<translation type="obsolete">Ablenkungsfreien Modus ein-/ausschalten</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="860"/>
<source>Exit fullscreen</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="865"/>
<source>Distraction Free mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="868"/>
<source>Exit Distraction Free mode</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SettingsUI</name>
<message>
<location filename="../../lector/settingsdialog.py" line="58"/>
<location filename="../../settingsdialog.py" line="62"/>
<source>English</source>
<translation>Englisch</translation>
</message>
<message>
<location filename="../../lector/settingsdialog.py" line="59"/>
<location filename="../../settingsdialog.py" line="63"/>
<source>Spanish</source>
<translation>Spanisch</translation>
</message>
<message>
<location filename="../../lector/settingsdialog.py" line="60"/>
<location filename="../../settingsdialog.py" line="64"/>
<source>Hindi</source>
<translation>Hindi</translation>
</message>
<message>
<location filename="../../lector/settingsdialog.py" line="73"/>
<location filename="../../settingsdialog.py" line="77"/>
<source>Save changes and start library scan</source>
<translation>Änderungen speichern &amp; Bibliotheksscan starten</translation>
</message>
<message>
<location filename="../../lector/settingsdialog.py" line="213"/>
<location filename="../../settingsdialog.py" line="280"/>
<source>Library scan in progress...</source>
<translation>Bibliotheksscan in Arbeit...</translation>
</message>
<message>
<location filename="../../lector/settingsdialog.py" line="217"/>
<location filename="../../settingsdialog.py" line="284"/>
<source>Checking library folders</source>
<translation>Bibliotheksverzeichnisse werden überprüft</translation>
</message>
<message>
<location filename="../../lector/settingsdialog.py" line="232"/>
<location filename="../../settingsdialog.py" line="300"/>
<source>Parsing files</source>
<translation>Dateien werden analysiert</translation>
</message>
<message>
<location filename="../../settingsdialog.py" line="116"/>
<source>Library</source>
<translation type="unfinished">Bibliothek</translation>
</message>
<message>
<location filename="../../settingsdialog.py" line="117"/>
<source>Switches</source>
<translation type="unfinished">Schalter</translation>
</message>
<message>
<location filename="../../settingsdialog.py" line="119"/>
<source>About</source>
<translation type="unfinished">Über</translation>
</message>
<message>
<location filename="../../settingsdialog.py" line="118"/>
<source>Annotations</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Tab</name>
<message>
<location filename="../../lector/widgets.py" line="130"/>
<location filename="../../widgets.py" line="154"/>
<source>Bookmarks</source>
<translation>Lesezeichen</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="391"/>
<location filename="../../widgets.py" line="458"/>
<source>New bookmark</source>
<translation>Lesezeichen hinzufügen</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="463"/>
<location filename="../../widgets.py" line="537"/>
<source>Edit</source>
<translation>Bearbeiten</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="466"/>
<location filename="../../widgets.py" line="540"/>
<source>Delete</source>
<translation>Löschen</translation>
</message>
<message>
<location filename="../../widgets.py" line="127"/>
<source>Annotations</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../widgets.py" line="143"/>
<source>Note</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>TableProxyModel</name>
<message>
<location filename="../../lector/toolbars.py" line="417"/>
<location filename="../../models.py" line="72"/>
<source>Title</source>
<translation>Titel</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="418"/>
<location filename="../../models.py" line="73"/>
<source>Author</source>
<translation>Autor</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="419"/>
<location filename="../../models.py" line="74"/>
<source>Year</source>
<translation>Jahr</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="421"/>
<location filename="../../models.py" line="75"/>
<source>Last Read</source>
<translation>Zuletzt gelesen</translation>
</message>
<message>
<location filename="../../lector/models.py" line="77"/>
<location filename="../../models.py" line="76"/>
<source>Tags</source>
<translation>Tags</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="420"/>
<location filename="../../toolbars.py" line="419"/>
<source>Newest</source>
<translation>Neueste</translation>
<translation type="obsolete">Neueste</translation>
</message>
</context>
</TS>

View File

@@ -3,120 +3,135 @@
<context>
<name>BookToolBar</name>
<message>
<location filename="../../lector/toolbars.py" line="45"/>
<location filename="../../toolbars.py" line="42"/>
<source>View settings</source>
<translation>Opciones de visualización</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="49"/>
<location filename="../../toolbars.py" line="48"/>
<source>Fullscreen</source>
<translation>Pantalla completa</translation>
<translation type="obsolete">Pantalla completa</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="53"/>
<location filename="../../toolbars.py" line="50"/>
<source>Add bookmark</source>
<translation>Añadir un marcador</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="57"/>
<location filename="../../toolbars.py" line="56"/>
<source>Bookmarks</source>
<translation>Marcadores</translation>
<translation type="obsolete">Marcadores</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="62"/>
<location filename="../../toolbars.py" line="66"/>
<source>Reset profile</source>
<translation>Restablecer el perfil</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="83"/>
<location filename="../../toolbars.py" line="91"/>
<source>Font size</source>
<translation>Tamaño del texto</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="87"/>
<location filename="../../toolbars.py" line="95"/>
<source>Increase padding</source>
<translation>Aumentar el espaciado</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="92"/>
<location filename="../../toolbars.py" line="100"/>
<source>Decrease padding</source>
<translation>Reducir el espaciado</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="98"/>
<location filename="../../toolbars.py" line="106"/>
<source>Increase line spacing</source>
<translation>Aumentar el interlineado</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="103"/>
<location filename="../../toolbars.py" line="111"/>
<source>Decrease line spacing</source>
<translation>Reducir el interlineado</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="109"/>
<location filename="../../toolbars.py" line="117"/>
<source>Left align text</source>
<translation>Alinear el texto a la izquierda</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="116"/>
<location filename="../../toolbars.py" line="124"/>
<source>Right align text</source>
<translation>Alinear el texto a la derecha</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="123"/>
<location filename="../../toolbars.py" line="131"/>
<source>Center align text</source>
<translation>Centrar el texto</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="130"/>
<location filename="../../toolbars.py" line="138"/>
<source>Justify text</source>
<translation>Justificar el texto</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="233"/>
<location filename="../../toolbars.py" line="241"/>
<source>Background color</source>
<translation>Color del fondo</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="202"/>
<location filename="../../toolbars.py" line="210"/>
<source>Zoom in</source>
<translation>Ampliar</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="207"/>
<location filename="../../toolbars.py" line="215"/>
<source>Zoom Out</source>
<translation>Reducir</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="213"/>
<location filename="../../toolbars.py" line="221"/>
<source>Fit Width</source>
<translation>Ajustar a la anchura</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="219"/>
<location filename="../../toolbars.py" line="227"/>
<source>Best Fit</source>
<translation>Ajuste perfecto</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="225"/>
<location filename="../../toolbars.py" line="233"/>
<source>Original size</source>
<translation>Tamaño original</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="260"/>
<location filename="../../toolbars.py" line="268"/>
<source>Search...</source>
<translation>Buscar</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="269"/>
<location filename="../../toolbars.py" line="277"/>
<source>Table of Contents</source>
<translation>Sumario</translation>
</message>
<message>
<location filename="../../toolbars.py" line="54"/>
<source>Bookmarks (Ctrl + B)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../toolbars.py" line="62"/>
<source>Fullscreen (F11)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../toolbars.py" line="46"/>
<source>Annotations</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>DefinitionsUI</name>
<message>
<location filename="../../lector/definitionsdialog.py" line="117"/>
<location filename="../../definitionsdialog.py" line="125"/>
<source>No definitions found in</source>
<translation>No se encontró ninguna definición en</translation>
</message>
@@ -139,62 +154,62 @@
<translation>Reproducir la pronunciación de la palabra raíz</translation>
</message>
<message>
<location filename="../settingswindow.py" line="117"/>
<location filename="../settingswindow.py" line="305"/>
<source>Settings</source>
<translation>Configuración</translation>
</message>
<message>
<location filename="../settingswindow.py" line="118"/>
<location filename="../settingswindow.py" line="306"/>
<source>Library</source>
<translation>Biblioteca</translation>
</message>
<message>
<location filename="../settingswindow.py" line="119"/>
<source>Switches</source>
<translation>Modificadores</translation>
<translation type="obsolete">Modificadores</translation>
</message>
<message>
<location filename="../settingswindow.py" line="120"/>
<location filename="../settingswindow.py" line="314"/>
<source>Startup: Refresh library</source>
<translation>Inicio: actualizar la biblioteca</translation>
</message>
<message>
<location filename="../settingswindow.py" line="121"/>
<location filename="../settingswindow.py" line="315"/>
<source>Remember open files</source>
<translation>Recordar los archivos abiertos</translation>
</message>
<message>
<location filename="../settingswindow.py" line="125"/>
<location filename="../settingswindow.py" line="319"/>
<source>Generate tags from files</source>
<translation>Generar etiquetas a partir de los archivos</translation>
</message>
<message>
<location filename="../settingswindow.py" line="128"/>
<source>Dictionary:</source>
<translation>Diccionario:</translation>
<translation type="obsolete">Diccionario:</translation>
</message>
<message>
<location filename="../settingswindow.py" line="124"/>
<location filename="../settingswindow.py" line="316"/>
<source>Cover shadows</source>
<translation>Sombras en las cubiertas</translation>
</message>
<message>
<location filename="../settingswindow.py" line="122"/>
<location filename="../settingswindow.py" line="317"/>
<source>Enabling reduces startup time and memory usage</source>
<translation>Activar esta opción reduce el tiempo de inicio y el uso de memoria</translation>
</message>
<message>
<location filename="../settingswindow.py" line="123"/>
<location filename="../settingswindow.py" line="318"/>
<source>Load covers only when needed</source>
<translation>Cargar las cubiertas solo cuando se necesiten</translation>
</message>
<message>
<location filename="../settingswindow.py" line="126"/>
<location filename="../settingswindow.py" line="325"/>
<source>Greatly reduces page transition time at the cost of more memory</source>
<translation>Reduce en gran medida el tiempo de transición de las páginas a costa de más memoria</translation>
</message>
<message>
<location filename="../settingswindow.py" line="127"/>
<location filename="../settingswindow.py" line="326"/>
<source>Cache comic / pdf pages</source>
<translation>Almacenar en antememoria las páginas de cómics/PDF</translation>
</message>
@@ -204,34 +219,34 @@
<translation type="obsolete">Reinicie la aplicación para ver los cambios</translation>
</message>
<message>
<location filename="../settingswindow.py" line="133"/>
<location filename="../settingswindow.py" line="309"/>
<source>Icon theme: </source>
<translation>Tema de iconos: </translation>
</message>
<message>
<location filename="../settingswindow.py" line="135"/>
<source>Dar&amp;k</source>
<translation>&amp;Oscuro</translation>
<translation type="obsolete">&amp;Oscuro</translation>
</message>
<message>
<location filename="../settingswindow.py" line="137"/>
<source>&amp;Light</source>
<translation>&amp;Claro</translation>
<translation type="obsolete">&amp;Claro</translation>
</message>
<message>
<location filename="../settingswindow.py" line="138"/>
<location filename="../settingswindow.py" line="336"/>
<source>Scan Library</source>
<translation>Explorar la biblioteca</translation>
</message>
<message>
<location filename="../settingswindow.py" line="139"/>
<location filename="../settingswindow.py" line="337"/>
<source>Close</source>
<translation>Cerrar</translation>
</message>
<message>
<location filename="../settingswindow.py" line="140"/>
<source>About</source>
<translation>Acerca de</translation>
<translation type="obsolete">Acerca de</translation>
</message>
<message>
<location filename="../metadata.py" line="88"/>
@@ -279,41 +294,111 @@
<translation>Cancelar</translation>
</message>
<message>
<location filename="../settingswindow.py" line="129"/>
<location filename="../settingswindow.py" line="322"/>
<source>Horizontal scrolling with Alt + Scroll
Reopen book to see changes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="131"/>
<location filename="../settingswindow.py" line="324"/>
<source>Hide scrollbars when reading</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="136"/>
<location filename="../settingswindow.py" line="312"/>
<source>Restart application to see changes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="311"/>
<source>&amp;Dark</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="313"/>
<source>L&amp;ight</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="321"/>
<source>Reading</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="307"/>
<source>Consider book read at percent</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="327"/>
<source>Dictionary language</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="328"/>
<source>Scroll speed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="334"/>
<source>Text</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="329"/>
<source>New</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="330"/>
<source>Delete</source>
<translation type="unfinished">Eliminar</translation>
</message>
<message>
<location filename="../settingswindow.py" line="331"/>
<source>Edit</source>
<translation type="unfinished">Editar</translation>
</message>
<message>
<location filename="../settingswindow.py" line="332"/>
<source>Move Up</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="333"/>
<source>Move Down</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="335"/>
<source>Image</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="320"/>
<source>Shrink long book titles</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Library</name>
<message>
<location filename="../../lector/library.py" line="130"/>
<location filename="../../library.py" line="133"/>
<source>Author</source>
<translation>Autor</translation>
</message>
<message>
<location filename="../../lector/library.py" line="131"/>
<location filename="../../library.py" line="134"/>
<source>Year</source>
<translation>Año</translation>
</message>
<message>
<location filename="../../lector/library.py" line="282"/>
<location filename="../../library.py" line="292"/>
<source>manually added</source>
<translation>añadido manualmente</translation>
</message>
<message>
<location filename="../../lector/library.py" line="209"/>
<location filename="../../library.py" line="215"/>
<source> books</source>
<translation type="unfinished"></translation>
</message>
@@ -321,148 +406,191 @@ Reopen book to see changes</source>
<context>
<name>LibraryToolBar</name>
<message>
<location filename="../../lector/toolbars.py" line="349"/>
<location filename="../../toolbars.py" line="360"/>
<source>Add book</source>
<translation>Añadir un libro</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="353"/>
<location filename="../../toolbars.py" line="364"/>
<source>Delete book</source>
<translation>Eliminar el libro</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="357"/>
<location filename="../../toolbars.py" line="368"/>
<source>Library background color</source>
<translation>Color de fondo de la biblioteca</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="362"/>
<location filename="../../toolbars.py" line="373"/>
<source>Settings</source>
<translation>Configuración</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="368"/>
<location filename="../../toolbars.py" line="379"/>
<source>View as covers</source>
<translation>Ver como cubiertas</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="373"/>
<location filename="../../toolbars.py" line="384"/>
<source>View as table</source>
<translation>Ver como tabla</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="383"/>
<location filename="../../toolbars.py" line="399"/>
<source>Filter library</source>
<translation>Filtrar la biblioteca</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="410"/>
<location filename="../../toolbars.py" line="427"/>
<source>Search for Title, Author, Tags...</source>
<translation>Buscar títulos, autores, etiquetas</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="430"/>
<location filename="../../toolbars.py" line="449"/>
<source>Sort by</source>
<translation>Ordenar por</translation>
</message>
<message>
<location filename="../../toolbars.py" line="390"/>
<source>Scan Library</source>
<translation type="unfinished">Explorar la biblioteca</translation>
</message>
<message>
<location filename="../../toolbars.py" line="434"/>
<source>Title</source>
<translation type="unfinished">Título</translation>
</message>
<message>
<location filename="../../toolbars.py" line="435"/>
<source>Author</source>
<translation type="unfinished">Autor</translation>
</message>
<message>
<location filename="../../toolbars.py" line="436"/>
<source>Year</source>
<translation type="unfinished">Año</translation>
</message>
<message>
<location filename="../../toolbars.py" line="437"/>
<source>Newest</source>
<translation type="unfinished">Más recientes</translation>
</message>
<message>
<location filename="../../toolbars.py" line="438"/>
<source>Last Read</source>
<translation type="unfinished">Última lectura</translation>
</message>
<message>
<location filename="../../toolbars.py" line="439"/>
<source>Progress</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../mainwindow.py" line="95"/>
<location filename="../mainwindow.py" line="67"/>
<source>Lector</source>
<translation>Lector</translation>
</message>
<message>
<location filename="../mainwindow.py" line="96"/>
<location filename="../mainwindow.py" line="68"/>
<source>Library</source>
<translation>Biblioteca</translation>
</message>
</context>
<context>
<name>Main_BookToolBarUI</name>
<message>
<location filename="../../toolbars.py" line="58"/>
<source>Toggle distraction free mode (Ctrl + D)</source>
<translation type="unfinished">Alternar el modo de concentración (Ctrl + D)</translation>
</message>
</context>
<context>
<name>Main_UI</name>
<message>
<location filename="../../lector/__main__.py" line="114"/>
<location filename="../../__main__.py" line="119"/>
<source>Toggle distraction free mode (Ctrl + D)</source>
<translation>Alternar el modo de concentración (Ctrl + D)</translation>
<translation type="obsolete">Alternar el modo de concentración (Ctrl + D)</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="211"/>
<location filename="../../__main__.py" line="216"/>
<source>Scan library</source>
<translation>Explorar la biblioteca</translation>
<translation type="obsolete">Explorar la biblioteca</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="463"/>
<location filename="../../__main__.py" line="471"/>
<source>Add books to database</source>
<translation>Añadir libros a la base de datos</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="464"/>
<location filename="../../__main__.py" line="472"/>
<source>eBooks</source>
<translation>Libros electrónicos</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="477"/>
<location filename="../../__main__.py" line="486"/>
<source>Adding books...</source>
<translation>Añadiendo los libros</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="540"/>
<location filename="../../__main__.py" line="549"/>
<source>Confirm deletion</source>
<translation>Confirmar la eliminación</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="553"/>
<location filename="../../__main__.py" line="562"/>
<source>Save changes and start library scan</source>
<translation>Guardar cambios e iniciar exploración de biblioteca</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="601"/>
<location filename="../../__main__.py" line="618"/>
<source> Books</source>
<translation> Libros</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="1028"/>
<location filename="../../__main__.py" line="762"/>
<source>Start reading</source>
<translation>Comenzar a leer</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="1034"/>
<location filename="../../__main__.py" line="768"/>
<source>Edit</source>
<translation>Editar</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="1038"/>
<location filename="../../__main__.py" line="772"/>
<source>Delete</source>
<translation>Eliminar</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="1041"/>
<location filename="../../__main__.py" line="775"/>
<source>Mark read</source>
<translation>Marcar como leído</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="1044"/>
<location filename="../../__main__.py" line="778"/>
<source>Mark unread</source>
<translation>Marcar como no leído</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="1144"/>
<location filename="../../__main__.py" line="878"/>
<source>Manually Added</source>
<translation>Añadido manualmente</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="747"/>
<location filename="../../widgets.py" line="747"/>
<source>Save page as...</source>
<translation type="unfinished">Guardar la página como</translation>
<translation type="obsolete">Guardar la página como</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="748"/>
<location filename="../../widgets.py" line="748"/>
<source>Images</source>
<translation type="unfinished">Imágenes</translation>
<translation type="obsolete">Imágenes</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="563"/>
<location filename="../../__main__.py" line="575"/>
<source> books</source>
<translation type="unfinished"></translation>
</message>
@@ -470,12 +598,12 @@ Reopen book to see changes</source>
<context>
<name>MetadataUI</name>
<message>
<location filename="../../lector/metadatadialog.py" line="101"/>
<location filename="../../metadatadialog.py" line="102"/>
<source>Author</source>
<translation>Autor</translation>
</message>
<message>
<location filename="../../lector/metadatadialog.py" line="102"/>
<location filename="../../metadatadialog.py" line="103"/>
<source>Year</source>
<translation>Año</translation>
</message>
@@ -483,12 +611,12 @@ Reopen book to see changes</source>
<context>
<name>PliantQGraphicsScene</name>
<message>
<location filename="../../lector/widgets.py" line="1002"/>
<location filename="../../widgets.py" line="647"/>
<source>Select new cover</source>
<translation>Seleccione una cubierta nueva</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="1003"/>
<location filename="../../widgets.py" line="648"/>
<source>Images</source>
<translation>Imágenes</translation>
</message>
@@ -496,34 +624,34 @@ Reopen book to see changes</source>
<context>
<name>PliantQGraphicsView</name>
<message>
<location filename="../../lector/widgets.py" line="695"/>
<location filename="../../widgets.py" line="695"/>
<source>Save page as...</source>
<translation>Guardar la página como</translation>
<translation type="obsolete">Guardar la página como</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="721"/>
<location filename="../../widgets.py" line="721"/>
<source>Zoom in (+)</source>
<translation>Ampliar (+)</translation>
<translation type="obsolete">Ampliar (+)</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="725"/>
<location filename="../../widgets.py" line="725"/>
<source>Zoom out (-)</source>
<translation>Reducir (-)</translation>
<translation type="obsolete">Reducir (-)</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="729"/>
<location filename="../../widgets.py" line="729"/>
<source>Fit width (W)</source>
<translation>Ajustar a la anchura (W)</translation>
<translation type="obsolete">Ajustar a la anchura (W)</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="733"/>
<location filename="../../widgets.py" line="733"/>
<source>Best fit (B)</source>
<translation>Ajuste perfecto (B)</translation>
<translation type="obsolete">Ajuste perfecto (B)</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="737"/>
<location filename="../../widgets.py" line="737"/>
<source>Original size (O)</source>
<translation>Tamaño original (O)</translation>
<translation type="obsolete">Tamaño original (O)</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="685"/>
@@ -535,33 +663,18 @@ Reopen book to see changes</source>
<source>Table of Contents</source>
<translation type="obsolete">Sumario</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="702"/>
<source>Exit fullscreen</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="707"/>
<source>Distraction Free mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="710"/>
<source>Exit Distraction Free mode</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>PliantQTextBrowser</name>
<message>
<location filename="../../lector/widgets.py" line="848"/>
<location filename="../../widgets.py" line="848"/>
<source>Define</source>
<translation>Definir</translation>
<translation type="obsolete">Definir</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="853"/>
<location filename="../../widgets.py" line="853"/>
<source>Search</source>
<translation>Buscar</translation>
<translation type="obsolete">Buscar</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="827"/>
@@ -573,114 +686,129 @@ Reopen book to see changes</source>
<source>Table of Contents</source>
<translation type="obsolete">Sumario</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="860"/>
<source>Exit fullscreen</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="865"/>
<source>Distraction Free mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="868"/>
<source>Exit Distraction Free mode</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SettingsUI</name>
<message>
<location filename="../../lector/settingsdialog.py" line="58"/>
<location filename="../../settingsdialog.py" line="62"/>
<source>English</source>
<translation>Inglés</translation>
</message>
<message>
<location filename="../../lector/settingsdialog.py" line="59"/>
<location filename="../../settingsdialog.py" line="63"/>
<source>Spanish</source>
<translation>Español</translation>
</message>
<message>
<location filename="../../lector/settingsdialog.py" line="60"/>
<location filename="../../settingsdialog.py" line="64"/>
<source>Hindi</source>
<translation>Hindi</translation>
</message>
<message>
<location filename="../../lector/settingsdialog.py" line="73"/>
<location filename="../../settingsdialog.py" line="77"/>
<source>Save changes and start library scan</source>
<translation>Guardar cambios e iniciar exploración de biblioteca</translation>
</message>
<message>
<location filename="../../lector/settingsdialog.py" line="213"/>
<location filename="../../settingsdialog.py" line="280"/>
<source>Library scan in progress...</source>
<translation>Se está explorando la biblioteca</translation>
</message>
<message>
<location filename="../../lector/settingsdialog.py" line="217"/>
<location filename="../../settingsdialog.py" line="284"/>
<source>Checking library folders</source>
<translation>Comprobando las carpetas de la biblioteca</translation>
</message>
<message>
<location filename="../../lector/settingsdialog.py" line="232"/>
<location filename="../../settingsdialog.py" line="300"/>
<source>Parsing files</source>
<translation>Procesando los archivos</translation>
</message>
<message>
<location filename="../../settingsdialog.py" line="116"/>
<source>Library</source>
<translation type="unfinished">Biblioteca</translation>
</message>
<message>
<location filename="../../settingsdialog.py" line="117"/>
<source>Switches</source>
<translation type="unfinished">Modificadores</translation>
</message>
<message>
<location filename="../../settingsdialog.py" line="119"/>
<source>About</source>
<translation type="unfinished">Acerca de</translation>
</message>
<message>
<location filename="../../settingsdialog.py" line="118"/>
<source>Annotations</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Tab</name>
<message>
<location filename="../../lector/widgets.py" line="130"/>
<location filename="../../widgets.py" line="154"/>
<source>Bookmarks</source>
<translation>Marcadores</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="391"/>
<location filename="../../widgets.py" line="458"/>
<source>New bookmark</source>
<translation>Marcador nuevo</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="463"/>
<location filename="../../widgets.py" line="537"/>
<source>Edit</source>
<translation>Editar</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="466"/>
<location filename="../../widgets.py" line="540"/>
<source>Delete</source>
<translation>Eliminar</translation>
</message>
<message>
<location filename="../../widgets.py" line="127"/>
<source>Annotations</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../widgets.py" line="143"/>
<source>Note</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>TableProxyModel</name>
<message>
<location filename="../../lector/toolbars.py" line="417"/>
<location filename="../../models.py" line="72"/>
<source>Title</source>
<translation>Título</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="418"/>
<location filename="../../models.py" line="73"/>
<source>Author</source>
<translation>Autor</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="419"/>
<location filename="../../models.py" line="74"/>
<source>Year</source>
<translation>Año</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="421"/>
<location filename="../../models.py" line="75"/>
<source>Last Read</source>
<translation>Última lectura</translation>
</message>
<message>
<location filename="../../lector/models.py" line="77"/>
<location filename="../../models.py" line="76"/>
<source>Tags</source>
<translation>Etiquetas</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="420"/>
<location filename="../../toolbars.py" line="419"/>
<source>Newest</source>
<translation>Más recientes</translation>
<translation type="obsolete">Más recientes</translation>
</message>
</context>
</TS>

View File

@@ -3,120 +3,135 @@
<context>
<name>BookToolBar</name>
<message>
<location filename="../../lector/toolbars.py" line="45"/>
<location filename="../../toolbars.py" line="42"/>
<source>View settings</source>
<translation>Options</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="49"/>
<location filename="../../toolbars.py" line="48"/>
<source>Fullscreen</source>
<translation>Plein écran</translation>
<translation type="obsolete">Plein écran</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="53"/>
<location filename="../../toolbars.py" line="50"/>
<source>Add bookmark</source>
<translation>Ajouter un marque page</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="57"/>
<location filename="../../toolbars.py" line="56"/>
<source>Bookmarks</source>
<translation>Marque-pages</translation>
<translation type="obsolete">Marque-pages</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="62"/>
<location filename="../../toolbars.py" line="66"/>
<source>Reset profile</source>
<translation>Réinitialiser le profil</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="83"/>
<location filename="../../toolbars.py" line="91"/>
<source>Font size</source>
<translation>Taille de la police</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="87"/>
<location filename="../../toolbars.py" line="95"/>
<source>Increase padding</source>
<translation>Augmenter la marge</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="92"/>
<location filename="../../toolbars.py" line="100"/>
<source>Decrease padding</source>
<translation>Diminuer la marge</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="98"/>
<location filename="../../toolbars.py" line="106"/>
<source>Increase line spacing</source>
<translation>Augmenter l&apos;espacement des lignes</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="103"/>
<location filename="../../toolbars.py" line="111"/>
<source>Decrease line spacing</source>
<translation>Diminuer l&apos;espacement des lignes</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="109"/>
<location filename="../../toolbars.py" line="117"/>
<source>Left align text</source>
<translation>Aligner le texte à gauche</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="116"/>
<location filename="../../toolbars.py" line="124"/>
<source>Right align text</source>
<translation>Aligner le texte à droite</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="123"/>
<location filename="../../toolbars.py" line="131"/>
<source>Center align text</source>
<translation>Centrer le texte</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="130"/>
<location filename="../../toolbars.py" line="138"/>
<source>Justify text</source>
<translation>Justifier le texte</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="233"/>
<location filename="../../toolbars.py" line="241"/>
<source>Background color</source>
<translation>Couleur d&apos;arrière-plan</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="202"/>
<location filename="../../toolbars.py" line="210"/>
<source>Zoom in</source>
<translation>Zoom avant</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="207"/>
<location filename="../../toolbars.py" line="215"/>
<source>Zoom Out</source>
<translation>Zoom arrière</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="213"/>
<location filename="../../toolbars.py" line="221"/>
<source>Fit Width</source>
<translation>Ajuster à la largeur</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="219"/>
<location filename="../../toolbars.py" line="227"/>
<source>Best Fit</source>
<translation>Meilleur ajustement</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="225"/>
<location filename="../../toolbars.py" line="233"/>
<source>Original size</source>
<translation>Taille d&apos;origine</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="260"/>
<location filename="../../toolbars.py" line="268"/>
<source>Search...</source>
<translation>Rechercher</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="269"/>
<location filename="../../toolbars.py" line="277"/>
<source>Table of Contents</source>
<translation>Sommaire</translation>
</message>
<message>
<location filename="../../toolbars.py" line="54"/>
<source>Bookmarks (Ctrl + B)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../toolbars.py" line="62"/>
<source>Fullscreen (F11)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../toolbars.py" line="46"/>
<source>Annotations</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>DefinitionsUI</name>
<message>
<location filename="../../lector/definitionsdialog.py" line="117"/>
<location filename="../../definitionsdialog.py" line="125"/>
<source>No definitions found in</source>
<translation>Aucune définitions trouvées dans</translation>
</message>
@@ -139,62 +154,62 @@
<translation>Lire la prononciation de la racine</translation>
</message>
<message>
<location filename="../settingswindow.py" line="117"/>
<location filename="../settingswindow.py" line="305"/>
<source>Settings</source>
<translation>Options</translation>
</message>
<message>
<location filename="../settingswindow.py" line="118"/>
<location filename="../settingswindow.py" line="306"/>
<source>Library</source>
<translation>Bibliothèque</translation>
</message>
<message>
<location filename="../settingswindow.py" line="119"/>
<source>Switches</source>
<translation>Options</translation>
<translation type="obsolete">Options</translation>
</message>
<message>
<location filename="../settingswindow.py" line="120"/>
<location filename="../settingswindow.py" line="314"/>
<source>Startup: Refresh library</source>
<translation>Au démarrage: Rafraîchir la bibliothèque</translation>
</message>
<message>
<location filename="../settingswindow.py" line="121"/>
<location filename="../settingswindow.py" line="315"/>
<source>Remember open files</source>
<translation>Se souvenir des fichiers ouverts</translation>
</message>
<message>
<location filename="../settingswindow.py" line="125"/>
<location filename="../settingswindow.py" line="319"/>
<source>Generate tags from files</source>
<translation>Générer des étiquettes à partir des fichiers</translation>
</message>
<message>
<location filename="../settingswindow.py" line="128"/>
<source>Dictionary:</source>
<translation>Dictionnaire:</translation>
<translation type="obsolete">Dictionnaire:</translation>
</message>
<message>
<location filename="../settingswindow.py" line="124"/>
<location filename="../settingswindow.py" line="316"/>
<source>Cover shadows</source>
<translation>Ombres des couverture</translation>
</message>
<message>
<location filename="../settingswindow.py" line="122"/>
<location filename="../settingswindow.py" line="317"/>
<source>Enabling reduces startup time and memory usage</source>
<translation>Si activé, réduit le temps de chargement et l&apos;utilisation de la mémoire</translation>
</message>
<message>
<location filename="../settingswindow.py" line="123"/>
<location filename="../settingswindow.py" line="318"/>
<source>Load covers only when needed</source>
<translation>Charger les couvertures seulement quand nécessaire</translation>
</message>
<message>
<location filename="../settingswindow.py" line="126"/>
<location filename="../settingswindow.py" line="325"/>
<source>Greatly reduces page transition time at the cost of more memory</source>
<translation>Réduit grandement le temps de transition des pages contre plus d&apos;utilisation de la mémoire</translation>
</message>
<message>
<location filename="../settingswindow.py" line="127"/>
<location filename="../settingswindow.py" line="326"/>
<source>Cache comic / pdf pages</source>
<translation>Mettre en cache les pages de bande dessinée / pdf</translation>
</message>
@@ -204,34 +219,34 @@
<translation type="obsolete">Redémarrer pour voir les modifications</translation>
</message>
<message>
<location filename="../settingswindow.py" line="133"/>
<location filename="../settingswindow.py" line="309"/>
<source>Icon theme: </source>
<translation>Thème d&apos;icones: </translation>
</message>
<message>
<location filename="../settingswindow.py" line="135"/>
<source>Dar&amp;k</source>
<translation>Som&amp;bre</translation>
<translation type="obsolete">Som&amp;bre</translation>
</message>
<message>
<location filename="../settingswindow.py" line="137"/>
<source>&amp;Light</source>
<translation>C&amp;lair</translation>
<translation type="obsolete">C&amp;lair</translation>
</message>
<message>
<location filename="../settingswindow.py" line="138"/>
<location filename="../settingswindow.py" line="336"/>
<source>Scan Library</source>
<translation>Analyser la bibliothèque</translation>
</message>
<message>
<location filename="../settingswindow.py" line="139"/>
<location filename="../settingswindow.py" line="337"/>
<source>Close</source>
<translation>Fermer</translation>
</message>
<message>
<location filename="../settingswindow.py" line="140"/>
<source>About</source>
<translation>À propos</translation>
<translation type="obsolete">À propos</translation>
</message>
<message>
<location filename="../metadata.py" line="88"/>
@@ -279,41 +294,111 @@
<translation>Annuler</translation>
</message>
<message>
<location filename="../settingswindow.py" line="129"/>
<location filename="../settingswindow.py" line="322"/>
<source>Horizontal scrolling with Alt + Scroll
Reopen book to see changes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="131"/>
<location filename="../settingswindow.py" line="324"/>
<source>Hide scrollbars when reading</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="136"/>
<location filename="../settingswindow.py" line="312"/>
<source>Restart application to see changes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="311"/>
<source>&amp;Dark</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="313"/>
<source>L&amp;ight</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="321"/>
<source>Reading</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="307"/>
<source>Consider book read at percent</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="327"/>
<source>Dictionary language</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="328"/>
<source>Scroll speed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="334"/>
<source>Text</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="329"/>
<source>New</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="330"/>
<source>Delete</source>
<translation type="unfinished">Supprimer</translation>
</message>
<message>
<location filename="../settingswindow.py" line="331"/>
<source>Edit</source>
<translation type="unfinished">Modifier</translation>
</message>
<message>
<location filename="../settingswindow.py" line="332"/>
<source>Move Up</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="333"/>
<source>Move Down</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="335"/>
<source>Image</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="320"/>
<source>Shrink long book titles</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Library</name>
<message>
<location filename="../../lector/library.py" line="130"/>
<location filename="../../library.py" line="133"/>
<source>Author</source>
<translation>Auteur</translation>
</message>
<message>
<location filename="../../lector/library.py" line="131"/>
<location filename="../../library.py" line="134"/>
<source>Year</source>
<translation>Année</translation>
</message>
<message>
<location filename="../../lector/library.py" line="282"/>
<location filename="../../library.py" line="292"/>
<source>manually added</source>
<translation>manuellement ajouté</translation>
</message>
<message>
<location filename="../../lector/library.py" line="209"/>
<location filename="../../library.py" line="215"/>
<source> books</source>
<translation type="unfinished"></translation>
</message>
@@ -321,148 +406,191 @@ Reopen book to see changes</source>
<context>
<name>LibraryToolBar</name>
<message>
<location filename="../../lector/toolbars.py" line="349"/>
<location filename="../../toolbars.py" line="360"/>
<source>Add book</source>
<translation>Ajouter un livre</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="353"/>
<location filename="../../toolbars.py" line="364"/>
<source>Delete book</source>
<translation>Supprimer un livre</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="357"/>
<location filename="../../toolbars.py" line="368"/>
<source>Library background color</source>
<translation>Couleur d&apos;arrière-plan de la bibliothèque</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="362"/>
<location filename="../../toolbars.py" line="373"/>
<source>Settings</source>
<translation>Options</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="368"/>
<location filename="../../toolbars.py" line="379"/>
<source>View as covers</source>
<translation>Vue par couvertures</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="373"/>
<location filename="../../toolbars.py" line="384"/>
<source>View as table</source>
<translation>Vue par table</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="383"/>
<location filename="../../toolbars.py" line="399"/>
<source>Filter library</source>
<translation>Filtrer la bibliothèque</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="410"/>
<location filename="../../toolbars.py" line="427"/>
<source>Search for Title, Author, Tags...</source>
<translation>Rechercher par Titre, Auteur, Étiquettes</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="430"/>
<location filename="../../toolbars.py" line="449"/>
<source>Sort by</source>
<translation>Trier par</translation>
</message>
<message>
<location filename="../../toolbars.py" line="390"/>
<source>Scan Library</source>
<translation type="unfinished">Analyser la bibliothèque</translation>
</message>
<message>
<location filename="../../toolbars.py" line="434"/>
<source>Title</source>
<translation type="unfinished">Titre</translation>
</message>
<message>
<location filename="../../toolbars.py" line="435"/>
<source>Author</source>
<translation type="unfinished">Auteur</translation>
</message>
<message>
<location filename="../../toolbars.py" line="436"/>
<source>Year</source>
<translation type="unfinished">Année</translation>
</message>
<message>
<location filename="../../toolbars.py" line="437"/>
<source>Newest</source>
<translation type="unfinished">Nouveau</translation>
</message>
<message>
<location filename="../../toolbars.py" line="438"/>
<source>Last Read</source>
<translation type="unfinished">Lu pour la dernière fois</translation>
</message>
<message>
<location filename="../../toolbars.py" line="439"/>
<source>Progress</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../mainwindow.py" line="95"/>
<location filename="../mainwindow.py" line="67"/>
<source>Lector</source>
<translation>Lector</translation>
</message>
<message>
<location filename="../mainwindow.py" line="96"/>
<location filename="../mainwindow.py" line="68"/>
<source>Library</source>
<translation>Bibliothèque</translation>
</message>
</context>
<context>
<name>Main_BookToolBarUI</name>
<message>
<location filename="../../toolbars.py" line="58"/>
<source>Toggle distraction free mode (Ctrl + D)</source>
<translation type="unfinished">Basculer en mode sans distraction (Ctrl + D)</translation>
</message>
</context>
<context>
<name>Main_UI</name>
<message>
<location filename="../../lector/__main__.py" line="114"/>
<location filename="../../__main__.py" line="119"/>
<source>Toggle distraction free mode (Ctrl + D)</source>
<translation>Basculer en mode sans distraction (Ctrl + D)</translation>
<translation type="obsolete">Basculer en mode sans distraction (Ctrl + D)</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="211"/>
<location filename="../../__main__.py" line="216"/>
<source>Scan library</source>
<translation>Analyser la bibliothèque</translation>
<translation type="obsolete">Analyser la bibliothèque</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="463"/>
<location filename="../../__main__.py" line="471"/>
<source>Add books to database</source>
<translation>Ajouter des livres à la base de données</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="464"/>
<location filename="../../__main__.py" line="472"/>
<source>eBooks</source>
<translation>eBooks</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="477"/>
<location filename="../../__main__.py" line="486"/>
<source>Adding books...</source>
<translation>Ajout des livres</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="540"/>
<location filename="../../__main__.py" line="549"/>
<source>Confirm deletion</source>
<translation>Confirmez la suppression</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="553"/>
<location filename="../../__main__.py" line="562"/>
<source>Save changes and start library scan</source>
<translation>Enregistrer les modifications et démarrer l&apos;analyse de la bibliothèque</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="601"/>
<location filename="../../__main__.py" line="618"/>
<source> Books</source>
<translation> Livres</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="1028"/>
<location filename="../../__main__.py" line="762"/>
<source>Start reading</source>
<translation>Commencer à lire</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="1034"/>
<location filename="../../__main__.py" line="768"/>
<source>Edit</source>
<translation>Modifier</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="1038"/>
<location filename="../../__main__.py" line="772"/>
<source>Delete</source>
<translation>Supprimer</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="1041"/>
<location filename="../../__main__.py" line="775"/>
<source>Mark read</source>
<translation>Marquer comme lu</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="1044"/>
<location filename="../../__main__.py" line="778"/>
<source>Mark unread</source>
<translation>Marquer comme non-lu</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="1144"/>
<location filename="../../__main__.py" line="878"/>
<source>Manually Added</source>
<translation>Manuellement ajouté</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="747"/>
<location filename="../../widgets.py" line="747"/>
<source>Save page as...</source>
<translation type="unfinished">Enregistrerla page sous</translation>
<translation type="obsolete">Enregistrerla page sous</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="748"/>
<location filename="../../widgets.py" line="748"/>
<source>Images</source>
<translation type="unfinished">Images</translation>
<translation type="obsolete">Images</translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="563"/>
<location filename="../../__main__.py" line="575"/>
<source> books</source>
<translation type="unfinished"></translation>
</message>
@@ -470,12 +598,12 @@ Reopen book to see changes</source>
<context>
<name>MetadataUI</name>
<message>
<location filename="../../lector/metadatadialog.py" line="101"/>
<location filename="../../metadatadialog.py" line="102"/>
<source>Author</source>
<translation>Auteur</translation>
</message>
<message>
<location filename="../../lector/metadatadialog.py" line="102"/>
<location filename="../../metadatadialog.py" line="103"/>
<source>Year</source>
<translation>Année</translation>
</message>
@@ -483,12 +611,12 @@ Reopen book to see changes</source>
<context>
<name>PliantQGraphicsScene</name>
<message>
<location filename="../../lector/widgets.py" line="1002"/>
<location filename="../../widgets.py" line="647"/>
<source>Select new cover</source>
<translation>Choisissez une nouvelle couverture</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="1003"/>
<location filename="../../widgets.py" line="648"/>
<source>Images</source>
<translation>Images</translation>
</message>
@@ -496,181 +624,181 @@ Reopen book to see changes</source>
<context>
<name>PliantQGraphicsView</name>
<message>
<location filename="../../lector/widgets.py" line="695"/>
<location filename="../../widgets.py" line="695"/>
<source>Save page as...</source>
<translation>Enregistrerla page sous</translation>
<translation type="obsolete">Enregistrerla page sous</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="721"/>
<location filename="../../widgets.py" line="721"/>
<source>Zoom in (+)</source>
<translation>Zoom avant (+)</translation>
<translation type="obsolete">Zoom avant (+)</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="725"/>
<location filename="../../widgets.py" line="725"/>
<source>Zoom out (-)</source>
<translation>Zoom arrière (-)</translation>
<translation type="obsolete">Zoom arrière (-)</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="729"/>
<location filename="../../widgets.py" line="729"/>
<source>Fit width (W)</source>
<translation>Ajuster à la largeur (W)</translation>
<translation type="obsolete">Ajuster à la largeur (W)</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="733"/>
<location filename="../../widgets.py" line="733"/>
<source>Best fit (B)</source>
<translation>Meilleur ajustement (B)</translation>
<translation type="obsolete">Meilleur ajustement (B)</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="737"/>
<location filename="../../widgets.py" line="737"/>
<source>Original size (O)</source>
<translation>Taille d&apos;origine (O)</translation>
<translation type="obsolete">Taille d&apos;origine (O)</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="685"/>
<source>Toggle distraction free mode</source>
<translation type="obsolete">Basculer en mode sans distraction</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="702"/>
<source>Exit fullscreen</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="707"/>
<source>Distraction Free mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="710"/>
<source>Exit Distraction Free mode</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>PliantQTextBrowser</name>
<message>
<location filename="../../lector/widgets.py" line="848"/>
<location filename="../../widgets.py" line="848"/>
<source>Define</source>
<translation>Définir</translation>
<translation type="obsolete">Définir</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="853"/>
<location filename="../../widgets.py" line="853"/>
<source>Search</source>
<translation>Rechercher</translation>
<translation type="obsolete">Rechercher</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="827"/>
<source>Toggle distraction free mode</source>
<translation type="obsolete">Basculer en mode sans distraction</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="860"/>
<source>Exit fullscreen</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="865"/>
<source>Distraction Free mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="868"/>
<source>Exit Distraction Free mode</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SettingsUI</name>
<message>
<location filename="../../lector/settingsdialog.py" line="58"/>
<location filename="../../settingsdialog.py" line="62"/>
<source>English</source>
<translation>Anglais</translation>
</message>
<message>
<location filename="../../lector/settingsdialog.py" line="59"/>
<location filename="../../settingsdialog.py" line="63"/>
<source>Spanish</source>
<translation>Espagnol</translation>
</message>
<message>
<location filename="../../lector/settingsdialog.py" line="60"/>
<location filename="../../settingsdialog.py" line="64"/>
<source>Hindi</source>
<translation>Hindi</translation>
</message>
<message>
<location filename="../../lector/settingsdialog.py" line="73"/>
<location filename="../../settingsdialog.py" line="77"/>
<source>Save changes and start library scan</source>
<translation>Enregistrer les modifications et démarrer l&apos;analyse de la bibliothèque</translation>
</message>
<message>
<location filename="../../lector/settingsdialog.py" line="213"/>
<location filename="../../settingsdialog.py" line="280"/>
<source>Library scan in progress...</source>
<translation>Analyse de la bibliothèque en cours</translation>
</message>
<message>
<location filename="../../lector/settingsdialog.py" line="217"/>
<location filename="../../settingsdialog.py" line="284"/>
<source>Checking library folders</source>
<translation>Vérification des dossiers de la bibliothèque</translation>
</message>
<message>
<location filename="../../lector/settingsdialog.py" line="232"/>
<location filename="../../settingsdialog.py" line="300"/>
<source>Parsing files</source>
<translation>Lecture des fichiers</translation>
</message>
<message>
<location filename="../../settingsdialog.py" line="116"/>
<source>Library</source>
<translation type="unfinished">Bibliothèque</translation>
</message>
<message>
<location filename="../../settingsdialog.py" line="117"/>
<source>Switches</source>
<translation type="unfinished">Options</translation>
</message>
<message>
<location filename="../../settingsdialog.py" line="119"/>
<source>About</source>
<translation type="unfinished">À propos</translation>
</message>
<message>
<location filename="../../settingsdialog.py" line="118"/>
<source>Annotations</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Tab</name>
<message>
<location filename="../../lector/widgets.py" line="130"/>
<location filename="../../widgets.py" line="154"/>
<source>Bookmarks</source>
<translation>Marque-pages</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="391"/>
<location filename="../../widgets.py" line="458"/>
<source>New bookmark</source>
<translation>Nouveau marque-page</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="463"/>
<location filename="../../widgets.py" line="537"/>
<source>Edit</source>
<translation>Modifier</translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="466"/>
<location filename="../../widgets.py" line="540"/>
<source>Delete</source>
<translation>Supprimer</translation>
</message>
<message>
<location filename="../../widgets.py" line="127"/>
<source>Annotations</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../widgets.py" line="143"/>
<source>Note</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>TableProxyModel</name>
<message>
<location filename="../../lector/toolbars.py" line="417"/>
<location filename="../../models.py" line="72"/>
<source>Title</source>
<translation>Titre</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="418"/>
<location filename="../../models.py" line="73"/>
<source>Author</source>
<translation>Auteur</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="419"/>
<location filename="../../models.py" line="74"/>
<source>Year</source>
<translation>Année</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="421"/>
<location filename="../../models.py" line="75"/>
<source>Last Read</source>
<translation>Lu pour la dernière fois</translation>
</message>
<message>
<location filename="../../lector/models.py" line="77"/>
<location filename="../../models.py" line="76"/>
<source>Tags</source>
<translation>Étiquettes</translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="420"/>
<location filename="../../toolbars.py" line="419"/>
<source>Newest</source>
<translation>Nouveau</translation>
<translation type="obsolete">Nouveau</translation>
</message>
</context>
</TS>

View File

@@ -0,0 +1,734 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS><TS version="2.0" language="zh_CN" sourcelanguage="">
<context>
<name>BookToolBar</name>
<message>
<location filename="../../toolbars.py" line="42"/>
<source>View settings</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="50"/>
<source>Add bookmark</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="66"/>
<source>Reset profile</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="91"/>
<source>Font size</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="95"/>
<source>Increase padding</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="100"/>
<source>Decrease padding</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="106"/>
<source>Increase line spacing</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="111"/>
<source>Decrease line spacing</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="117"/>
<source>Left align text</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="124"/>
<source>Right align text</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="131"/>
<source>Center align text</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="138"/>
<source>Justify text</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="241"/>
<source>Background color</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="210"/>
<source>Zoom in</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="215"/>
<source>Zoom Out</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="221"/>
<source>Fit Width</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="227"/>
<source>Best Fit</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="233"/>
<source>Original size</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="268"/>
<source>Search...</source>
<translation>...</translation>
</message>
<message>
<location filename="../../toolbars.py" line="277"/>
<source>Table of Contents</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="54"/>
<source>Bookmarks (Ctrl + B)</source>
<translation> (Ctrl + B)</translation>
</message>
<message>
<location filename="../../toolbars.py" line="62"/>
<source>Fullscreen (F11)</source>
<translation> (F11)</translation>
</message>
<message>
<location filename="../../toolbars.py" line="46"/>
<source>Annotations</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>DefinitionsUI</name>
<message>
<location filename="../../definitionsdialog.py" line="125"/>
<source>No definitions found in</source>
<translation></translation>
</message>
</context>
<context>
<name>Dialog</name>
<message>
<location filename="../definitions.py" line="65"/>
<source>Dialog</source>
<translation></translation>
</message>
<message>
<location filename="../definitions.py" line="66"/>
<source>WERDS</source>
<translation>WERDS</translation>
</message>
<message>
<location filename="../definitions.py" line="67"/>
<source>Play pronunciation of root word</source>
<translation></translation>
</message>
<message>
<location filename="../settingswindow.py" line="305"/>
<source>Settings</source>
<translation></translation>
</message>
<message>
<location filename="../settingswindow.py" line="306"/>
<source>Library</source>
<translation></translation>
</message>
<message>
<location filename="../settingswindow.py" line="314"/>
<source>Startup: Refresh library</source>
<translation></translation>
</message>
<message>
<location filename="../settingswindow.py" line="315"/>
<source>Remember open files</source>
<translation></translation>
</message>
<message>
<location filename="../settingswindow.py" line="319"/>
<source>Generate tags from files</source>
<translation></translation>
</message>
<message>
<location filename="../settingswindow.py" line="316"/>
<source>Cover shadows</source>
<translation></translation>
</message>
<message>
<location filename="../settingswindow.py" line="317"/>
<source>Enabling reduces startup time and memory usage</source>
<translation></translation>
</message>
<message>
<location filename="../settingswindow.py" line="318"/>
<source>Load covers only when needed</source>
<translation></translation>
</message>
<message>
<location filename="../settingswindow.py" line="325"/>
<source>Greatly reduces page transition time at the cost of more memory</source>
<translation></translation>
</message>
<message>
<location filename="../settingswindow.py" line="326"/>
<source>Cache comic / pdf pages</source>
<translation> / pdf </translation>
</message>
<message>
<location filename="../settingswindow.py" line="309"/>
<source>Icon theme: </source>
<translation></translation>
</message>
<message>
<location filename="../settingswindow.py" line="336"/>
<source>Scan Library</source>
<translation></translation>
</message>
<message>
<location filename="../settingswindow.py" line="337"/>
<source>Close</source>
<translation></translation>
</message>
<message>
<location filename="../metadata.py" line="88"/>
<source>Edit metadata</source>
<translation></translation>
</message>
<message>
<location filename="../metadata.py" line="89"/>
<source>Cover (click to change)</source>
<translation></translation>
</message>
<message>
<location filename="../metadata.py" line="91"/>
<source>Title</source>
<translation></translation>
</message>
<message>
<location filename="../metadata.py" line="93"/>
<source>Author</source>
<translation></translation>
</message>
<message>
<location filename="../metadata.py" line="95"/>
<source>Year</source>
<translation></translation>
</message>
<message>
<location filename="../metadata.py" line="96"/>
<source>Tags (comma separated)</source>
<translation></translation>
</message>
<message>
<location filename="../metadata.py" line="97"/>
<source>Tags</source>
<translation></translation>
</message>
<message>
<location filename="../metadata.py" line="98"/>
<source>OK</source>
<translation></translation>
</message>
<message>
<location filename="../metadata.py" line="99"/>
<source>Cancel</source>
<translation></translation>
</message>
<message>
<location filename="../settingswindow.py" line="322"/>
<source>Horizontal scrolling with Alt + Scroll
Reopen book to see changes</source>
<translation> Alt + Scroll
</translation>
</message>
<message>
<location filename="../settingswindow.py" line="324"/>
<source>Hide scrollbars when reading</source>
<translation></translation>
</message>
<message>
<location filename="../settingswindow.py" line="312"/>
<source>Restart application to see changes</source>
<translation></translation>
</message>
<message>
<location filename="../settingswindow.py" line="311"/>
<source>&amp;Dark</source>
<translation>&amp;</translation>
</message>
<message>
<location filename="../settingswindow.py" line="313"/>
<source>L&amp;ight</source>
<translation></translation>
</message>
<message>
<location filename="../settingswindow.py" line="321"/>
<source>Reading</source>
<translation></translation>
</message>
<message>
<location filename="../settingswindow.py" line="307"/>
<source>Consider book read at percent</source>
<translation></translation>
</message>
<message>
<location filename="../settingswindow.py" line="327"/>
<source>Dictionary language</source>
<translation></translation>
</message>
<message>
<location filename="../settingswindow.py" line="328"/>
<source>Scroll speed</source>
<translation></translation>
</message>
<message>
<location filename="../settingswindow.py" line="327"/>
<source>+</source>
<translation type="obsolete">+</translation>
</message>
<message>
<location filename="../settingswindow.py" line="328"/>
<source>-</source>
<translation type="obsolete">-</translation>
</message>
<message encoding="UTF-8">
<location filename="../settingswindow.py" line="329"/>
<source></source>
<translation type="obsolete"></translation>
</message>
<message encoding="UTF-8">
<location filename="../settingswindow.py" line="330"/>
<source></source>
<translation type="obsolete"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="331"/>
<source>Foreground</source>
<translation type="obsolete"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="332"/>
<source>Highlight</source>
<translation type="obsolete"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="333"/>
<source>Bold</source>
<translation type="obsolete"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="334"/>
<source>Italic</source>
<translation type="obsolete"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="335"/>
<source>Underline</source>
<translation type="obsolete">线</translation>
</message>
<message>
<location filename="../settingswindow.py" line="334"/>
<source>Text</source>
<translation></translation>
</message>
<message>
<location filename="../settingswindow.py" line="337"/>
<source>Comic/PDF</source>
<translation type="obsolete"> / PDF</translation>
</message>
<message>
<location filename="../settingswindow.py" line="320"/>
<source>Shrink long book titles</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="329"/>
<source>New</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="330"/>
<source>Delete</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="331"/>
<source>Edit</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="332"/>
<source>Move Up</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="333"/>
<source>Move Down</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="335"/>
<source>Image</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Library</name>
<message>
<location filename="../../library.py" line="133"/>
<source>Author</source>
<translation></translation>
</message>
<message>
<location filename="../../library.py" line="134"/>
<source>Year</source>
<translation></translation>
</message>
<message>
<location filename="../../library.py" line="292"/>
<source>manually added</source>
<translation></translation>
</message>
<message>
<location filename="../../library.py" line="215"/>
<source> books</source>
<translation> </translation>
</message>
</context>
<context>
<name>LibraryToolBar</name>
<message>
<location filename="../../toolbars.py" line="360"/>
<source>Add book</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="364"/>
<source>Delete book</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="368"/>
<source>Library background color</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="373"/>
<source>Settings</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="379"/>
<source>View as covers</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="384"/>
<source>View as table</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="399"/>
<source>Filter library</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="427"/>
<source>Search for Title, Author, Tags...</source>
<translation>...</translation>
</message>
<message>
<location filename="../../toolbars.py" line="449"/>
<source>Sort by</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="390"/>
<source>Scan Library</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="434"/>
<source>Title</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="435"/>
<source>Author</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="436"/>
<source>Year</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="437"/>
<source>Newest</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="438"/>
<source>Last Read</source>
<translation></translation>
</message>
<message>
<location filename="../../toolbars.py" line="439"/>
<source>Progress</source>
<translation></translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../mainwindow.py" line="67"/>
<source>Lector</source>
<translation>Lector</translation>
</message>
<message>
<location filename="../mainwindow.py" line="68"/>
<source>Library</source>
<translation></translation>
</message>
</context>
<context>
<name>Main_BookToolBarUI</name>
<message>
<location filename="../../toolbars.py" line="58"/>
<source>Toggle distraction free mode (Ctrl + D)</source>
<translation> (Ctrl + D)</translation>
</message>
</context>
<context>
<name>Main_UI</name>
<message>
<location filename="../../__main__.py" line="471"/>
<source>Add books to database</source>
<translation></translation>
</message>
<message>
<location filename="../../__main__.py" line="472"/>
<source>eBooks</source>
<translation></translation>
</message>
<message>
<location filename="../../__main__.py" line="486"/>
<source>Adding books...</source>
<translation>...</translation>
</message>
<message>
<location filename="../../__main__.py" line="549"/>
<source>Confirm deletion</source>
<translation></translation>
</message>
<message>
<location filename="../../__main__.py" line="562"/>
<source>Save changes and start library scan</source>
<translation></translation>
</message>
<message>
<location filename="../../__main__.py" line="618"/>
<source> Books</source>
<translation> </translation>
</message>
<message>
<location filename="../../__main__.py" line="762"/>
<source>Start reading</source>
<translation></translation>
</message>
<message>
<location filename="../../__main__.py" line="768"/>
<source>Edit</source>
<translation></translation>
</message>
<message>
<location filename="../../__main__.py" line="772"/>
<source>Delete</source>
<translation></translation>
</message>
<message>
<location filename="../../__main__.py" line="775"/>
<source>Mark read</source>
<translation></translation>
</message>
<message>
<location filename="../../__main__.py" line="778"/>
<source>Mark unread</source>
<translation></translation>
</message>
<message>
<location filename="../../__main__.py" line="878"/>
<source>Manually Added</source>
<translation></translation>
</message>
<message>
<location filename="../../__main__.py" line="575"/>
<source> books</source>
<translation> </translation>
</message>
</context>
<context>
<name>MetadataUI</name>
<message>
<location filename="../../metadatadialog.py" line="102"/>
<source>Author</source>
<translation></translation>
</message>
<message>
<location filename="../../metadatadialog.py" line="103"/>
<source>Year</source>
<translation></translation>
</message>
</context>
<context>
<name>PliantQGraphicsScene</name>
<message>
<location filename="../../widgets.py" line="647"/>
<source>Select new cover</source>
<translation></translation>
</message>
<message>
<location filename="../../widgets.py" line="648"/>
<source>Images</source>
<translation></translation>
</message>
</context>
<context>
<name>SettingsUI</name>
<message>
<location filename="../../settingsdialog.py" line="62"/>
<source>English</source>
<translation></translation>
</message>
<message>
<location filename="../../settingsdialog.py" line="63"/>
<source>Spanish</source>
<translation>西</translation>
</message>
<message>
<location filename="../../settingsdialog.py" line="64"/>
<source>Hindi</source>
<translation></translation>
</message>
<message>
<location filename="../../settingsdialog.py" line="77"/>
<source>Save changes and start library scan</source>
<translation></translation>
</message>
<message>
<location filename="../../settingsdialog.py" line="280"/>
<source>Library scan in progress...</source>
<translation></translation>
</message>
<message>
<location filename="../../settingsdialog.py" line="284"/>
<source>Checking library folders</source>
<translation></translation>
</message>
<message>
<location filename="../../settingsdialog.py" line="300"/>
<source>Parsing files</source>
<translation></translation>
</message>
<message>
<location filename="../../settingsdialog.py" line="116"/>
<source>Library</source>
<translation></translation>
</message>
<message>
<location filename="../../settingsdialog.py" line="117"/>
<source>Switches</source>
<translation></translation>
</message>
<message>
<location filename="../../settingsdialog.py" line="119"/>
<source>About</source>
<translation></translation>
</message>
<message>
<location filename="../../settingsdialog.py" line="118"/>
<source>Annotations</source>
<translation></translation>
</message>
</context>
<context>
<name>Tab</name>
<message>
<location filename="../../widgets.py" line="154"/>
<source>Bookmarks</source>
<translation></translation>
</message>
<message>
<location filename="../../widgets.py" line="458"/>
<source>New bookmark</source>
<translation></translation>
</message>
<message>
<location filename="../../widgets.py" line="537"/>
<source>Edit</source>
<translation></translation>
</message>
<message>
<location filename="../../widgets.py" line="540"/>
<source>Delete</source>
<translation></translation>
</message>
<message>
<location filename="../../widgets.py" line="127"/>
<source>Annotations</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../widgets.py" line="143"/>
<source>Note</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>TableProxyModel</name>
<message>
<location filename="../../models.py" line="72"/>
<source>Title</source>
<translation></translation>
</message>
<message>
<location filename="../../models.py" line="73"/>
<source>Author</source>
<translation></translation>
</message>
<message>
<location filename="../../models.py" line="74"/>
<source>Year</source>
<translation></translation>
</message>
<message>
<location filename="../../models.py" line="75"/>
<source>Last Read</source>
<translation></translation>
</message>
<message>
<location filename="../../models.py" line="76"/>
<source>Tags</source>
<translation></translation>
</message>
</context>
</TS>

View File

@@ -3,120 +3,125 @@
<context>
<name>BookToolBar</name>
<message>
<location filename="../../lector/toolbars.py" line="45"/>
<location filename="../../toolbars.py" line="42"/>
<source>View settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="49"/>
<source>Fullscreen</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="53"/>
<location filename="../../toolbars.py" line="50"/>
<source>Add bookmark</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="57"/>
<source>Bookmarks</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="62"/>
<location filename="../../toolbars.py" line="66"/>
<source>Reset profile</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="83"/>
<location filename="../../toolbars.py" line="91"/>
<source>Font size</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="87"/>
<location filename="../../toolbars.py" line="95"/>
<source>Increase padding</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="92"/>
<location filename="../../toolbars.py" line="100"/>
<source>Decrease padding</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="98"/>
<location filename="../../toolbars.py" line="106"/>
<source>Increase line spacing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="103"/>
<location filename="../../toolbars.py" line="111"/>
<source>Decrease line spacing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="109"/>
<location filename="../../toolbars.py" line="117"/>
<source>Left align text</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="116"/>
<location filename="../../toolbars.py" line="124"/>
<source>Right align text</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="123"/>
<location filename="../../toolbars.py" line="131"/>
<source>Center align text</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="130"/>
<location filename="../../toolbars.py" line="138"/>
<source>Justify text</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="233"/>
<location filename="../../toolbars.py" line="241"/>
<source>Background color</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="202"/>
<location filename="../../toolbars.py" line="210"/>
<source>Zoom in</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="207"/>
<location filename="../../toolbars.py" line="215"/>
<source>Zoom Out</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="213"/>
<location filename="../../toolbars.py" line="221"/>
<source>Fit Width</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="219"/>
<location filename="../../toolbars.py" line="227"/>
<source>Best Fit</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="225"/>
<location filename="../../toolbars.py" line="233"/>
<source>Original size</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="260"/>
<location filename="../../toolbars.py" line="268"/>
<source>Search...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="269"/>
<location filename="../../toolbars.py" line="277"/>
<source>Table of Contents</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../toolbars.py" line="54"/>
<source>Bookmarks (Ctrl + B)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../toolbars.py" line="62"/>
<source>Fullscreen (F11)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../toolbars.py" line="46"/>
<source>Annotations</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>DefinitionsUI</name>
<message>
<location filename="../../lector/definitionsdialog.py" line="117"/>
<location filename="../../definitionsdialog.py" line="125"/>
<source>No definitions found in</source>
<translation type="unfinished"></translation>
</message>
@@ -139,95 +144,70 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="117"/>
<location filename="../settingswindow.py" line="305"/>
<source>Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="118"/>
<location filename="../settingswindow.py" line="306"/>
<source>Library</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="119"/>
<source>Switches</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="120"/>
<location filename="../settingswindow.py" line="314"/>
<source>Startup: Refresh library</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="121"/>
<location filename="../settingswindow.py" line="315"/>
<source>Remember open files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="125"/>
<location filename="../settingswindow.py" line="319"/>
<source>Generate tags from files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="128"/>
<source>Dictionary:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="124"/>
<location filename="../settingswindow.py" line="316"/>
<source>Cover shadows</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="122"/>
<location filename="../settingswindow.py" line="317"/>
<source>Enabling reduces startup time and memory usage</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="123"/>
<location filename="../settingswindow.py" line="318"/>
<source>Load covers only when needed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="126"/>
<location filename="../settingswindow.py" line="325"/>
<source>Greatly reduces page transition time at the cost of more memory</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="127"/>
<location filename="../settingswindow.py" line="326"/>
<source>Cache comic / pdf pages</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="133"/>
<location filename="../settingswindow.py" line="309"/>
<source>Icon theme: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="135"/>
<source>Dar&amp;k</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="137"/>
<source>&amp;Light</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="138"/>
<location filename="../settingswindow.py" line="336"/>
<source>Scan Library</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="139"/>
<location filename="../settingswindow.py" line="337"/>
<source>Close</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="140"/>
<source>About</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../metadata.py" line="88"/>
<source>Edit metadata</source>
@@ -274,41 +254,111 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="129"/>
<location filename="../settingswindow.py" line="322"/>
<source>Horizontal scrolling with Alt + Scroll
Reopen book to see changes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="131"/>
<location filename="../settingswindow.py" line="324"/>
<source>Hide scrollbars when reading</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="136"/>
<location filename="../settingswindow.py" line="312"/>
<source>Restart application to see changes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="311"/>
<source>&amp;Dark</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="313"/>
<source>L&amp;ight</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="321"/>
<source>Reading</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="307"/>
<source>Consider book read at percent</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="327"/>
<source>Dictionary language</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="328"/>
<source>Scroll speed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="334"/>
<source>Text</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="329"/>
<source>New</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="330"/>
<source>Delete</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="331"/>
<source>Edit</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="332"/>
<source>Move Up</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="333"/>
<source>Move Down</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="335"/>
<source>Image</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="320"/>
<source>Shrink long book titles</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Library</name>
<message>
<location filename="../../lector/library.py" line="130"/>
<location filename="../../library.py" line="133"/>
<source>Author</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/library.py" line="131"/>
<location filename="../../library.py" line="134"/>
<source>Year</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/library.py" line="282"/>
<location filename="../../library.py" line="292"/>
<source>manually added</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/library.py" line="209"/>
<location filename="../../library.py" line="215"/>
<source> books</source>
<translation type="unfinished"></translation>
</message>
@@ -316,148 +366,171 @@ Reopen book to see changes</source>
<context>
<name>LibraryToolBar</name>
<message>
<location filename="../../lector/toolbars.py" line="349"/>
<location filename="../../toolbars.py" line="360"/>
<source>Add book</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="353"/>
<location filename="../../toolbars.py" line="364"/>
<source>Delete book</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="357"/>
<location filename="../../toolbars.py" line="368"/>
<source>Library background color</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="362"/>
<location filename="../../toolbars.py" line="373"/>
<source>Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="368"/>
<location filename="../../toolbars.py" line="379"/>
<source>View as covers</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="373"/>
<location filename="../../toolbars.py" line="384"/>
<source>View as table</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="383"/>
<location filename="../../toolbars.py" line="399"/>
<source>Filter library</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="410"/>
<location filename="../../toolbars.py" line="427"/>
<source>Search for Title, Author, Tags...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="430"/>
<location filename="../../toolbars.py" line="449"/>
<source>Sort by</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../toolbars.py" line="390"/>
<source>Scan Library</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../toolbars.py" line="434"/>
<source>Title</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../toolbars.py" line="435"/>
<source>Author</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../toolbars.py" line="436"/>
<source>Year</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../toolbars.py" line="437"/>
<source>Newest</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../toolbars.py" line="438"/>
<source>Last Read</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../toolbars.py" line="439"/>
<source>Progress</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../mainwindow.py" line="95"/>
<location filename="../mainwindow.py" line="67"/>
<source>Lector</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.py" line="96"/>
<location filename="../mainwindow.py" line="68"/>
<source>Library</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Main_BookToolBarUI</name>
<message>
<location filename="../../toolbars.py" line="58"/>
<source>Toggle distraction free mode (Ctrl + D)</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Main_UI</name>
<message>
<location filename="../../lector/__main__.py" line="114"/>
<source>Toggle distraction free mode (Ctrl + D)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="211"/>
<source>Scan library</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="463"/>
<location filename="../../__main__.py" line="471"/>
<source>Add books to database</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="464"/>
<location filename="../../__main__.py" line="472"/>
<source>eBooks</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="477"/>
<location filename="../../__main__.py" line="486"/>
<source>Adding books...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="540"/>
<location filename="../../__main__.py" line="549"/>
<source>Confirm deletion</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="553"/>
<location filename="../../__main__.py" line="562"/>
<source>Save changes and start library scan</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="601"/>
<location filename="../../__main__.py" line="618"/>
<source> Books</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="1028"/>
<location filename="../../__main__.py" line="762"/>
<source>Start reading</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="1034"/>
<location filename="../../__main__.py" line="768"/>
<source>Edit</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="1038"/>
<location filename="../../__main__.py" line="772"/>
<source>Delete</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="1041"/>
<location filename="../../__main__.py" line="775"/>
<source>Mark read</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="1044"/>
<location filename="../../__main__.py" line="778"/>
<source>Mark unread</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="1144"/>
<location filename="../../__main__.py" line="878"/>
<source>Manually Added</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="747"/>
<source>Save page as...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="748"/>
<source>Images</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/__main__.py" line="563"/>
<location filename="../../__main__.py" line="575"/>
<source> books</source>
<translation type="unfinished"></translation>
</message>
@@ -465,12 +538,12 @@ Reopen book to see changes</source>
<context>
<name>MetadataUI</name>
<message>
<location filename="../../lector/metadatadialog.py" line="101"/>
<location filename="../../metadatadialog.py" line="102"/>
<source>Author</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/metadatadialog.py" line="102"/>
<location filename="../../metadatadialog.py" line="103"/>
<source>Year</source>
<translation type="unfinished"></translation>
</message>
@@ -478,184 +551,133 @@ Reopen book to see changes</source>
<context>
<name>PliantQGraphicsScene</name>
<message>
<location filename="../../lector/widgets.py" line="1002"/>
<location filename="../../widgets.py" line="647"/>
<source>Select new cover</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="1003"/>
<location filename="../../widgets.py" line="648"/>
<source>Images</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>PliantQGraphicsView</name>
<message>
<location filename="../../lector/widgets.py" line="695"/>
<source>Save page as...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="721"/>
<source>Zoom in (+)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="725"/>
<source>Zoom out (-)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="729"/>
<source>Fit width (W)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="733"/>
<source>Best fit (B)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="737"/>
<source>Original size (O)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="702"/>
<source>Exit fullscreen</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="707"/>
<source>Distraction Free mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="710"/>
<source>Exit Distraction Free mode</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>PliantQTextBrowser</name>
<message>
<location filename="../../lector/widgets.py" line="848"/>
<source>Define</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="853"/>
<source>Search</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="860"/>
<source>Exit fullscreen</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="865"/>
<source>Distraction Free mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="868"/>
<source>Exit Distraction Free mode</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SettingsUI</name>
<message>
<location filename="../../lector/settingsdialog.py" line="58"/>
<location filename="../../settingsdialog.py" line="62"/>
<source>English</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/settingsdialog.py" line="59"/>
<location filename="../../settingsdialog.py" line="63"/>
<source>Spanish</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/settingsdialog.py" line="60"/>
<location filename="../../settingsdialog.py" line="64"/>
<source>Hindi</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/settingsdialog.py" line="73"/>
<location filename="../../settingsdialog.py" line="77"/>
<source>Save changes and start library scan</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/settingsdialog.py" line="213"/>
<location filename="../../settingsdialog.py" line="280"/>
<source>Library scan in progress...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/settingsdialog.py" line="217"/>
<location filename="../../settingsdialog.py" line="284"/>
<source>Checking library folders</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/settingsdialog.py" line="232"/>
<location filename="../../settingsdialog.py" line="300"/>
<source>Parsing files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../settingsdialog.py" line="116"/>
<source>Library</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../settingsdialog.py" line="117"/>
<source>Switches</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../settingsdialog.py" line="119"/>
<source>About</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../settingsdialog.py" line="118"/>
<source>Annotations</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Tab</name>
<message>
<location filename="../../lector/widgets.py" line="130"/>
<location filename="../../widgets.py" line="154"/>
<source>Bookmarks</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="391"/>
<location filename="../../widgets.py" line="458"/>
<source>New bookmark</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="463"/>
<location filename="../../widgets.py" line="537"/>
<source>Edit</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/widgets.py" line="466"/>
<location filename="../../widgets.py" line="540"/>
<source>Delete</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../widgets.py" line="127"/>
<source>Annotations</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../widgets.py" line="143"/>
<source>Note</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>TableProxyModel</name>
<message>
<location filename="../../lector/toolbars.py" line="417"/>
<location filename="../../models.py" line="72"/>
<source>Title</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="418"/>
<location filename="../../models.py" line="73"/>
<source>Author</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="419"/>
<location filename="../../models.py" line="74"/>
<source>Year</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="421"/>
<location filename="../../models.py" line="75"/>
<source>Last Read</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/models.py" line="77"/>
<location filename="../../models.py" line="76"/>
<source>Tags</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="420"/>
<source>Newest</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

View File

@@ -1,7 +1,23 @@
#!/usr/bin/env python3
# This file is a part of Lector, a Qt based ebook reader
# Copyright (C) 2017-2018 BasioMeusPuga
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Keep in mind that all integer / boolean settings are returned as strings
import os
from ast import literal_eval
from PyQt5 import QtCore, QtGui
@@ -103,6 +119,10 @@ class Settings:
'cachingEnabled', 'True').capitalize())
self.parent.settings['hide_scrollbars'] = literal_eval(self.settings.value(
'hideScrollBars', 'False').capitalize())
self.parent.settings['scroll_speed'] = int(self.settings.value('scrollSpeed', 7))
self.parent.settings['consider_read_at'] = int(self.settings.value('considerReadAt', 95))
self.parent.settings['attenuate_titles'] = literal_eval(self.settings.value(
'attenuateTitles', 'False').capitalize())
self.settings.endGroup()
self.settings.beginGroup('dialogSettings')
@@ -110,6 +130,13 @@ class Settings:
'dialogBackground', QtGui.QColor().fromRgb(0, 0, 0))
self.settings.endGroup()
self.settings.beginGroup('annotations')
self.parent.settings['annotations'] = self.settings.value(
'annotationList', list())
if self.parent.settings['annotations'] is None:
self.parent.settings['annotations'] = list()
self.settings.endGroup()
def save_settings(self):
print('Saving settings...')
current_settings = self.parent.settings
@@ -165,16 +192,23 @@ class Settings:
self.settings.endGroup()
self.settings.beginGroup('settingsSwitches')
self.settings.setValue('rememberFiles', current_settings['remember_files'])
self.settings.setValue('coverShadows', current_settings['cover_shadows'])
self.settings.setValue('autoTags', current_settings['auto_tags'])
self.settings.setValue('scanLibraryAtStart', current_settings['scan_library'])
self.settings.setValue('performCulling', current_settings['perform_culling'])
self.settings.setValue('dictionaryLanguage', current_settings['dictionary_language'])
self.settings.setValue('cachingEnabled', current_settings['caching_enabled'])
self.settings.setValue('hideScrollBars', current_settings['hide_scrollbars'])
self.settings.setValue('rememberFiles', str(current_settings['remember_files']))
self.settings.setValue('coverShadows', str(current_settings['cover_shadows']))
self.settings.setValue('autoTags', str(current_settings['auto_tags']))
self.settings.setValue('scanLibraryAtStart', str(current_settings['scan_library']))
self.settings.setValue('performCulling', str(current_settings['perform_culling']))
self.settings.setValue('dictionaryLanguage', str(current_settings['dictionary_language']))
self.settings.setValue('cachingEnabled', str(current_settings['caching_enabled']))
self.settings.setValue('hideScrollBars', str(current_settings['hide_scrollbars']))
self.settings.setValue('attenuateTitles', str(current_settings['attenuate_titles']))
self.settings.setValue('scrollSpeed', current_settings['scroll_speed'])
self.settings.setValue('considerReadAt', current_settings['consider_read_at'])
self.settings.endGroup()
self.settings.beginGroup('dialogSettings')
self.settings.setValue('dialogBackground', current_settings['dialog_background'])
self.settings.endGroup()
self.settings.beginGroup('annotations')
self.settings.setValue('annotationList', current_settings['annotations'])
self.settings.endGroup()

View File

@@ -1,7 +1,5 @@
#!/usr/bin/env python3
# This file is a part of Lector, a Qt based ebook reader
# Copyright (C) 2017 BasioMeusPuga
# Copyright (C) 2017-2018 BasioMeusPuga
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -22,27 +20,34 @@
import os
import copy
import pathlib
from PyQt5 import QtWidgets, QtCore
from PyQt5 import QtWidgets, QtCore, QtGui
from lector import database
from lector.annotations import AnnotationsUI
from lector.models import MostExcellentFileSystemModel
from lector.threaded import BackGroundBookSearch, BackGroundBookAddition
from lector.resources import settingswindow
from lector.settings import Settings
class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog):
def __init__(self, parent=None):
super(SettingsUI, self).__init__()
self.setupUi(self)
self.verticalLayout_4.setContentsMargins(0, 0, 0, 0)
self._translate = QtCore.QCoreApplication.translate
self.parent = parent
self.database_path = self.parent.database_path
self.main_window = parent
self.database_path = self.main_window.database_path
self.image_factory = self.main_window.QImageFactory
self.resize(self.parent.settings['settings_dialog_size'])
self.move(self.parent.settings['settings_dialog_position'])
# The annotation dialog will use the settings dialog as its parent
self.annotationsDialog = AnnotationsUI(self)
self.resize(self.main_window.settings['settings_dialog_size'])
self.move(self.main_window.settings['settings_dialog_position'])
self.aboutBox.setVisible(False)
install_dir = os.path.realpath(__file__)
install_dir = pathlib.Path(install_dir).parents[1]
aboutfile_path = os.path.join(install_dir, 'lector', 'resources', 'about.html')
@@ -51,7 +56,7 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog):
self.paths = None
self.thread = None
self.filesystem_model = None
self.filesystemModel = None
self.tag_data_copy = None
english_string = self._translate('SettingsUI', 'English')
@@ -60,7 +65,7 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog):
languages = [english_string, spanish_string, hindi_string]
self.languageBox.addItems(languages)
current_language = self.parent.settings['dictionary_language']
current_language = self.main_window.settings['dictionary_language']
if current_language == 'en':
self.languageBox.setCurrentIndex(0)
elif current_language == 'es':
@@ -73,10 +78,9 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog):
self._translate('SettingsUI', 'Save changes and start library scan'))
self.okButton.clicked.connect(self.start_library_scan)
self.cancelButton.clicked.connect(self.cancel_pressed)
self.aboutButton.clicked.connect(self.about_pressed)
# Radio buttons
if self.parent.settings['icon_theme'] == 'DarkIcons':
if self.main_window.settings['icon_theme'] == 'DarkIcons':
self.darkIconsRadio.setChecked(True)
else:
self.lightIconsRadio.setChecked(True)
@@ -84,13 +88,16 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog):
self.lightIconsRadio.clicked.connect(self.change_icon_theme)
# Check boxes
self.autoTags.setChecked(self.parent.settings['auto_tags'])
self.coverShadows.setChecked(self.parent.settings['cover_shadows'])
self.refreshLibrary.setChecked(self.parent.settings['scan_library'])
self.fileRemember.setChecked(self.parent.settings['remember_files'])
self.performCulling.setChecked(self.parent.settings['perform_culling'])
self.cachingEnabled.setChecked(self.parent.settings['caching_enabled'])
self.hideScrollBars.setChecked(self.parent.settings['hide_scrollbars'])
self.autoTags.setChecked(self.main_window.settings['auto_tags'])
self.coverShadows.setChecked(self.main_window.settings['cover_shadows'])
self.refreshLibrary.setChecked(self.main_window.settings['scan_library'])
self.fileRemember.setChecked(self.main_window.settings['remember_files'])
self.performCulling.setChecked(self.main_window.settings['perform_culling'])
self.cachingEnabled.setChecked(self.main_window.settings['caching_enabled'])
self.hideScrollBars.setChecked(self.main_window.settings['hide_scrollbars'])
self.attenuateTitles.setChecked(self.main_window.settings['attenuate_titles'])
self.scrollSpeedSlider.setValue(self.main_window.settings['scroll_speed'])
self.readAtPercent.setValue(self.main_window.settings['consider_read_at'])
self.autoTags.clicked.connect(self.manage_checkboxes)
self.coverShadows.clicked.connect(self.manage_checkboxes)
@@ -99,10 +106,71 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog):
self.performCulling.clicked.connect(self.manage_checkboxes)
self.cachingEnabled.clicked.connect(self.manage_checkboxes)
self.hideScrollBars.clicked.connect(self.manage_checkboxes)
self.attenuateTitles.clicked.connect(self.manage_checkboxes)
self.scrollSpeedSlider.valueChanged.connect(self.change_scroll_speed)
self.readAtPercent.valueChanged.connect(self.change_read_at)
# Generate the QStandardItemModel for the listView
self.listModel = QtGui.QStandardItemModel()
library_string = self._translate('SettingsUI', 'Library')
switches_string = self._translate('SettingsUI', 'Switches')
annotations_string = self._translate('SettingsUI', 'Annotations')
about_string = self._translate('SettingsUI', 'About')
list_options = [
library_string, switches_string, annotations_string, about_string]
icon_dict = {
0: 'view-readermode',
1: 'switches',
2: 'annotate',
3: 'about'}
for count, i in enumerate(list_options):
item = QtGui.QStandardItem()
item.setText(i)
this_icon = icon_dict[count]
item.setIcon(
self.main_window.QImageFactory.get_image(this_icon))
self.listModel.appendRow(item)
self.listView.setModel(self.listModel)
self.listView.clicked.connect(self.page_switch)
# Annotation related buttons
# Icon names
self.newAnnotation.setIcon(self.image_factory.get_image('add'))
self.deleteAnnotation.setIcon(self.image_factory.get_image('remove'))
self.editAnnotation.setIcon(self.image_factory.get_image('edit-rename'))
self.moveUp.setIcon(self.image_factory.get_image('arrow-up'))
self.moveDown.setIcon(self.image_factory.get_image('arrow-down'))
# Icon sizes
self.newAnnotation.setIconSize(QtCore.QSize(24, 24))
self.deleteAnnotation.setIconSize(QtCore.QSize(24, 24))
self.editAnnotation.setIconSize(QtCore.QSize(24, 24))
self.moveUp.setIconSize(QtCore.QSize(24, 24))
self.moveDown.setIconSize(QtCore.QSize(24, 24))
self.annotationsList.clicked.connect(self.load_annotation)
self.annotationsList.doubleClicked.connect(self.editAnnotation.click)
self.newAnnotation.clicked.connect(self.add_annotation)
self.deleteAnnotation.clicked.connect(self.delete_annotation)
self.editAnnotation.clicked.connect(self.load_annotation)
self.moveUp.clicked.connect(self.move_annotation)
self.moveDown.clicked.connect(self.move_annotation)
# Generate annotation settings
self.annotationModel = QtGui.QStandardItemModel()
self.generate_annotations()
# Generate the filesystem treeView
self.generate_tree()
# Hide the image annotation tab
# TODO
# Maybe get off your lazy ass and write something for this
self.tabWidget.tabBar().setVisible(False)
def generate_tree(self):
# Fetch all directories in the database
paths = database.DatabaseFunctions(
@@ -112,10 +180,10 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog):
{'Path': ''},
'LIKE')
self.parent.generate_library_filter_menu(paths)
self.main_window.generate_library_filter_menu(paths)
directory_data = {}
if not paths:
print('Database returned no paths for settings...')
print('Database: No paths for settings...')
else:
# Convert to the dictionary format that is
# to be fed into the QFileSystemModel
@@ -125,9 +193,9 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog):
'tags': i[2],
'check_state': i[3]}
self.filesystem_model = MostExcellentFileSystemModel(directory_data)
self.filesystem_model.setFilter(QtCore.QDir.NoDotAndDotDot | QtCore.QDir.Dirs)
self.treeView.setModel(self.filesystem_model)
self.filesystemModel = MostExcellentFileSystemModel(directory_data)
self.filesystemModel.setFilter(QtCore.QDir.NoDotAndDotDot | QtCore.QDir.Dirs)
self.treeView.setModel(self.filesystemModel)
# TODO
# This here might break on them pestilent non unixy OSes
@@ -135,7 +203,7 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog):
root_directory = QtCore.QDir().rootPath()
self.treeView.setRootIndex(
self.filesystem_model.setRootPath(root_directory))
self.filesystemModel.setRootPath(root_directory))
# Set the treeView and QFileSystemModel to its desired state
selected_paths = [
@@ -157,10 +225,10 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog):
expand_paths.remove(root_directory)
for i in expand_paths:
this_index = self.filesystem_model.index(i)
this_index = self.filesystemModel.index(i)
self.treeView.expand(this_index)
header_sizes = self.parent.settings['settings_dialog_headers']
header_sizes = self.main_window.settings['settings_dialog_headers']
if header_sizes:
for count, i in enumerate((0, 4)):
self.treeView.setColumnWidth(i, int(header_sizes[count]))
@@ -178,7 +246,7 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog):
self.hide()
data_pairs = []
for i in self.filesystem_model.tag_data.items():
for i in self.filesystemModel.tag_data.items():
data_pairs.append([
i[0], i[1]['name'], i[1]['tags'], i[1]['check_state']
])
@@ -196,24 +264,24 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog):
database.DatabaseFunctions(
self.database_path).delete_from_database('*', '*')
self.parent.lib_ref.generate_model('build')
self.parent.lib_ref.generate_proxymodels()
self.parent.generate_library_filter_menu()
self.main_window.lib_ref.generate_model('build')
self.main_window.lib_ref.generate_proxymodels()
self.main_window.generate_library_filter_menu()
return
# Update the main window library filter menu
self.parent.generate_library_filter_menu(data_pairs)
self.parent.set_library_filter()
self.main_window.generate_library_filter_menu(data_pairs)
self.main_window.set_library_filter()
# Disallow rechecking until the first check completes
self.okButton.setEnabled(False)
self.parent.reloadLibrary.setEnabled(False)
self.main_window.libraryToolBar.reloadLibraryButton.setEnabled(False)
self.okButton.setToolTip(
self._translate('SettingsUI', 'Library scan in progress...'))
# Traverse directories looking for files
self.parent.statusMessage.setText(
self.main_window.statusMessage.setText(
self._translate('SettingsUI', 'Checking library folders'))
self.thread = BackGroundBookSearch(data_pairs)
self.thread.finished.connect(self.finished_iterating)
@@ -223,22 +291,30 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog):
# The books the search thread has found
# are now in self.thread.valid_files
if not self.thread.valid_files:
self.parent.move_on()
self.main_window.move_on()
return
# Hey, messaging is important, okay?
self.parent.sorterProgress.setVisible(True)
self.parent.statusMessage.setText(
self.main_window.statusBar.setVisible(True)
self.main_window.sorterProgress.setVisible(True)
self.main_window.statusMessage.setText(
self._translate('SettingsUI', 'Parsing files'))
# We now create a new thread to put those files into the database
self.thread = BackGroundBookAddition(
self.thread.valid_files, self.database_path, 'automatic', self.parent)
self.thread.finished.connect(self.parent.move_on)
self.thread.valid_files, self.database_path, 'automatic', self.main_window)
self.thread.finished.connect(self.main_window.move_on)
self.thread.start()
def page_switch(self, index):
self.stackedWidget.setCurrentIndex(index.row())
if index.row() == 0:
self.okButton.setVisible(True)
else:
self.okButton.setVisible(False)
def cancel_pressed(self):
self.filesystem_model.tag_data = copy.deepcopy(self.tag_data_copy)
self.filesystemModel.tag_data = copy.deepcopy(self.tag_data_copy)
self.hide()
def hideEvent(self, event):
@@ -246,35 +322,46 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog):
event.accept()
def showEvent(self, event):
self.tag_data_copy = copy.deepcopy(self.filesystem_model.tag_data)
self.format_preview()
self.tag_data_copy = copy.deepcopy(self.filesystemModel.tag_data)
event.accept()
def no_more_settings(self):
self.parent.libraryToolBar.settingsButton.setChecked(False)
self.aboutBox.hide()
self.treeView.show()
self.main_window.libraryToolBar.settingsButton.setChecked(False)
self.gather_annotations()
Settings(self.main_window).save_settings()
Settings(self.main_window).read_settings()
self.main_window.settings['last_open_tab'] = None # Needed to allow focus change
# to newly opened book
self.resizeEvent()
def resizeEvent(self, event=None):
self.parent.settings['settings_dialog_size'] = self.size()
self.parent.settings['settings_dialog_position'] = self.pos()
self.main_window.settings['settings_dialog_size'] = self.size()
self.main_window.settings['settings_dialog_position'] = self.pos()
table_headers = []
for i in [0, 4]:
table_headers.append(self.treeView.columnWidth(i))
self.parent.settings['settings_dialog_headers'] = table_headers
self.main_window.settings['settings_dialog_headers'] = table_headers
def change_icon_theme(self):
if self.sender() == self.darkIconsRadio:
self.parent.settings['icon_theme'] = 'DarkIcons'
self.main_window.settings['icon_theme'] = 'DarkIcons'
else:
self.parent.settings['icon_theme'] = 'LightIcons'
self.main_window.settings['icon_theme'] = 'LightIcons'
def change_dictionary_language(self, event):
language_dict = {
0: 'en',
1: 'es',
2: 'hi'}
self.parent.settings['dictionary_language'] = language_dict[self.languageBox.currentIndex()]
self.main_window.settings[
'dictionary_language'] = language_dict[self.languageBox.currentIndex()]
def change_scroll_speed(self, event=None):
self.main_window.settings['scroll_speed'] = self.scrollSpeedSlider.value()
def change_read_at(self, event=None):
self.main_window.settings['consider_read_at'] = self.readAtPercent.value()
def manage_checkboxes(self, event=None):
sender = self.sender().objectName()
@@ -286,13 +373,108 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog):
'fileRemember': 'remember_files',
'performCulling': 'perform_culling',
'cachingEnabled': 'caching_enabled',
'hideScrollBars': 'hide_scrollbars'}
'hideScrollBars': 'hide_scrollbars',
'attenuateTitles': 'attenuate_titles'}
self.parent.settings[sender_dict[sender]] = not self.parent.settings[sender_dict[sender]]
self.main_window.settings[
sender_dict[sender]] = not self.main_window.settings[sender_dict[sender]]
if not self.performCulling.isChecked():
self.parent.load_all_covers()
self.main_window.cover_functions.load_all_covers()
def about_pressed(self):
self.treeView.setVisible(not self.treeView.isVisible())
self.aboutBox.setVisible(not self.aboutBox.isVisible())
def generate_annotations(self):
saved_annotations = self.main_window.settings['annotations']
for i in saved_annotations:
item = QtGui.QStandardItem()
item.setText(i['name'])
item.setData(i, QtCore.Qt.UserRole)
self.annotationModel.appendRow(item)
self.annotationsList.setModel(self.annotationModel)
def format_preview(self):
# Needed to clear the preview of annotation ickiness
cursor = QtGui.QTextCursor()
self.previewView.setTextCursor(cursor)
self.previewView.setText('Vidistine nuper imagines moventes bonas?')
profile_index = self.main_window.bookToolBar.profileBox.currentIndex()
current_profile = self.main_window.bookToolBar.profileBox.itemData(
profile_index, QtCore.Qt.UserRole)
if not current_profile:
return
font = current_profile['font']
self.foreground = current_profile['foreground']
background = current_profile['background']
font_size = current_profile['font_size']
self.previewView.setStyleSheet(
"QTextEdit {{font-family: {0}; font-size: {1}px; color: {2}; background-color: {3}}}".format(
font, font_size, self.foreground.name(), background.name()))
block_format = QtGui.QTextBlockFormat()
block_format.setAlignment(QtCore.Qt.AlignVCenter | QtCore.Qt.AlignHCenter)
cursor = self.previewView.textCursor()
while True:
old_position = cursor.position()
cursor.mergeBlockFormat(block_format)
cursor.movePosition(QtGui.QTextCursor.NextBlock, 0, 1)
new_position = cursor.position()
if old_position == new_position:
break
def add_annotation(self):
self.annotationsDialog.show_dialog('add')
def delete_annotation(self):
selected_index = self.annotationsList.currentIndex()
if not selected_index.isValid():
return
self.annotationModel.removeRow(
self.annotationsList.currentIndex().row())
self.format_preview()
self.annotationsList.clearSelection()
def load_annotation(self):
selected_index = self.annotationsList.currentIndex()
if not selected_index.isValid():
return
if self.sender() == self.annotationsList:
self.annotationsDialog.show_dialog('preview', selected_index)
elif self.sender() == self.editAnnotation:
self.annotationsDialog.show_dialog('edit', selected_index)
def move_annotation(self):
current_row = self.annotationsList.currentIndex().row()
if self.sender() == self.moveUp:
new_row = current_row - 1
if new_row < 0:
return
elif self.sender() == self.moveDown:
new_row = current_row + 1
if new_row == self.annotationModel.rowCount():
return
row_out = self.annotationModel.takeRow(current_row)
self.annotationModel.insertRow(new_row, row_out)
new_index = self.annotationModel.index(new_row, 0)
self.annotationsList.setCurrentIndex(new_index)
def gather_annotations(self):
annotations_out = []
for i in range(self.annotationModel.rowCount()):
annotation_item = self.annotationModel.item(i, 0)
annotation_data = annotation_item.data(QtCore.Qt.UserRole)
annotations_out.append(annotation_data)
self.main_window.settings['annotations'] = annotations_out

View File

@@ -1,7 +1,5 @@
#!/usr/bin/env python3
# This file is a part of Lector, a Qt based ebook reader
# Copyright (C) 2017 BasioMeusPuga
# Copyright (C) 2017-2018 BasioMeusPuga
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -17,7 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# INSTRUCTIONS
# Every parser is supposed to have the following methods, even if they return None:
# Every parser is supposed to have the following methods. None returns are not allowed.
# read_book()
# get_title()
# get_author()
@@ -35,22 +33,26 @@
import io
import os
import sys
import time
import pickle
import hashlib
import threading
from multiprocessing import Pool, Manager
from PyQt5 import QtCore, QtGui
# The multiprocessing module does not work correctly on Windows
if sys.platform.startswith('win'):
from multiprocessing.dummy import Pool, Manager
else:
from multiprocessing import Pool, Manager
from PyQt5 import QtCore, QtGui
from lector import database
from lector.parsers.pdf import ParsePDF
from lector.parsers.epub import ParseEPUB
from lector.parsers.mobi import ParseMOBI
from lector.parsers.comicbooks import ParseCOMIC
sorter = {
'pdf': ParsePDF,
'epub': ParseEPUB,
'mobi': ParseMOBI,
'azw': ParseMOBI,
@@ -60,6 +62,13 @@ sorter = {
'cbz': ParseCOMIC,
'cbr': ParseCOMIC}
# The following imports are for optional dependencies
try:
from lector.parsers.pdf import ParsePDF
sorter['pdf'] = ParsePDF
except ImportError:
print('python-poppler-qt5 is not installed. Pdf files will not work.')
available_parsers = [i for i in sorter]
progressbar = None # This is populated by __main__
progress_emitter = None # This is to be made into a global variable
@@ -118,7 +127,8 @@ class BookSorter:
def database_entry_for_book(self, file_hash):
database_return = database.DatabaseFunctions(
self.database_path).fetch_data(
('Title', 'Author', 'Year', 'ISBN', 'Tags', 'Position', 'Bookmarks'),
('Title', 'Author', 'Year', 'ISBN', 'Tags',
'Position', 'Bookmarks', 'CoverImage', 'Annotations'),
'books',
{'Hash': file_hash},
'EQUALS')[0]
@@ -126,7 +136,7 @@ class BookSorter:
book_data = []
for count, i in enumerate(database_return):
if count in (5, 6):
if count in (5, 6, 8): # Position, Bookmarks, and Annotations are pickled
if i:
book_data.append(pickle.loads(i))
else:
@@ -175,7 +185,6 @@ class BookSorter:
book_ref.read_book()
if book_ref.book:
this_book = {}
this_book[file_md5] = {
'hash': file_md5,
@@ -186,13 +195,8 @@ class BookSorter:
# Reduce the size of the incoming image
# if one is found
title = book_ref.get_title()
author = book_ref.get_author()
if not author:
author = 'Unknown'
year = book_ref.get_year()
isbn = book_ref.get_isbn()
tags = None
@@ -214,8 +218,7 @@ class BookSorter:
# get_contents() returns a tuple. Index 1 is a collection of
# special settings that depend on the kind of data being parsed.
# Currently, this includes:
# Only images included images_only BOOL Specify only paths to images
# File will not be cached on exit
# Only images included images_only BOOL Book contains only images
content = all_content[0]
images_only = all_content[1]['images_only']
@@ -231,11 +234,15 @@ class BookSorter:
tags = book_data[4]
position = book_data[5]
bookmarks = book_data[6]
cover = book_data[7]
annotations = book_data[8]
this_book[file_md5]['position'] = position
this_book[file_md5]['bookmarks'] = bookmarks
this_book[file_md5]['content'] = content
this_book[file_md5]['images_only'] = images_only
this_book[file_md5]['cover'] = cover
this_book[file_md5]['annotations'] = annotations
this_book[file_md5]['title'] = title
this_book[file_md5]['author'] = author

View File

@@ -1,7 +1,5 @@
#!/usr/bin/env python3
# This file is a part of Lector, a Qt based ebook reader
# Copyright (C) 2017 BasioMeusPuga
# Copyright (C) 2017-2018 BasioMeusPuga
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -18,6 +16,7 @@
import os
import pathlib
from multiprocessing.dummy import Pool
from PyQt5 import QtCore, QtGui
@@ -37,7 +36,8 @@ class BackGroundTabUpdate(QtCore.QThread):
database_dict = {
'Position': i['position'],
'LastAccessed': i['last_accessed'],
'Bookmarks': i['bookmarks']}
'Bookmarks': i['bookmarks'],
'Annotations': i['annotations']}
database.DatabaseFunctions(self.database_path).modify_metadata(
database_dict, book_hash)
@@ -129,6 +129,10 @@ class BackGroundCacheRefill(QtCore.QThread):
def __init__(self, image_cache, remove_value, filetype, book, all_pages, parent=None):
super(BackGroundCacheRefill, self).__init__(parent)
# TODO
# Return with only the first image in case of a cache miss
# Rebuilding the entire n image cache takes considerably longer
self.image_cache = image_cache
self.remove_value = remove_value
self.filetype = filetype

View File

@@ -1,7 +1,5 @@
#!usr/bin/env python3
# This file is a part of Lector, a Qt based ebook reader
# Copyright (C) 2018 BasioMeusPuga
# Copyright (C) 2017-2018 BasioMeusPuga
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -45,9 +43,9 @@ class BookToolBar(QtWidgets.QToolBar):
image_factory.get_image('gtk-select-font'),
self._translate('BookToolBar', 'View settings'),
self)
self.fullscreenButton = QtWidgets.QAction(
image_factory.get_image('view-fullscreen'),
self._translate('BookToolBar', 'Fullscreen'),
self.annotationButton = QtWidgets.QAction(
image_factory.get_image('annotate'),
self._translate('BookToolBar', 'Annotations'),
self)
self.addBookmarkButton = QtWidgets.QAction(
image_factory.get_image('bookmark-new'),
@@ -55,9 +53,16 @@ class BookToolBar(QtWidgets.QToolBar):
self)
self.bookmarkButton = QtWidgets.QAction(
image_factory.get_image('bookmarks'),
self._translate('BookToolBar', 'Bookmarks'),
self._translate('BookToolBar', 'Bookmarks (Ctrl + B)'),
self)
self.distractionFreeButton = QtWidgets.QAction(
image_factory.get_image('visibility'),
self._translate('Main_BookToolBarUI', 'Toggle distraction free mode (Ctrl + D)'),
self)
self.fullscreenButton = QtWidgets.QAction(
image_factory.get_image('view-fullscreen'),
self._translate('BookToolBar', 'Fullscreen (F11)'),
self)
self.bookmarkButton.setObjectName('bookmarkButton')
self.resetProfile = QtWidgets.QAction(
image_factory.get_image('reload'),
self._translate('BookToolBar', 'Reset profile'),
@@ -68,10 +73,14 @@ class BookToolBar(QtWidgets.QToolBar):
self.fontButton.setCheckable(True)
self.fontButton.triggered.connect(self.toggle_font_settings)
self.addSeparator()
self.addAction(self.annotationButton)
self.annotationButton.setCheckable(True)
self.addSeparator()
self.addAction(self.addBookmarkButton)
self.addAction(self.bookmarkButton)
self.bookmarkButton.setCheckable(True)
self.addSeparator()
self.addAction(self.distractionFreeButton)
self.addAction(self.fullscreenButton)
# Font modification
@@ -277,8 +286,10 @@ class BookToolBar(QtWidgets.QToolBar):
self.searchBarAction = self.addWidget(self.searchBar)
self.bookActions = [
self.annotationButton,
self.addBookmarkButton,
self.bookmarkButton,
self.distractionFreeButton,
self.fullscreenButton,
self.tocBoxAction,
self.searchBarAction]
@@ -317,6 +328,7 @@ class BookToolBar(QtWidgets.QToolBar):
i.setVisible(False)
def customize_view_off(self):
self.fontButton.setChecked(False)
for i in self.fontActions:
i.setVisible(False)
@@ -375,6 +387,11 @@ class LibraryToolBar(QtWidgets.QToolBar):
self)
self.tableViewButton.setCheckable(True)
self.reloadLibraryButton = QtWidgets.QAction(
image_factory.get_image('reload'),
self._translate('LibraryToolBar', 'Scan Library'),
self)
self.libraryFilterButton = QtWidgets.QToolButton(self)
self.libraryFilterButton.setIcon(image_factory.get_image('view-readermode'))
self.libraryFilterButton.setText(
@@ -395,6 +412,7 @@ class LibraryToolBar(QtWidgets.QToolBar):
self.addAction(self.coverViewButton)
self.addAction(self.tableViewButton)
self.addSeparator()
self.addAction(self.reloadLibraryButton)
self.addWidget(self.libraryFilterButton)
self.addSeparator()
self.addAction(self.colorButton)
@@ -413,13 +431,15 @@ class LibraryToolBar(QtWidgets.QToolBar):
self.searchBar.setObjectName('searchBar')
# Sorter
title_string = self._translate('TableProxyModel', 'Title')
author_string = self._translate('TableProxyModel', 'Author')
year_string = self._translate('TableProxyModel', 'Year')
newest_string = self._translate('TableProxyModel', 'Newest')
lastread_string = self._translate('TableProxyModel', 'Last Read')
title_string = self._translate('LibraryToolBar', 'Title')
author_string = self._translate('LibraryToolBar', 'Author')
year_string = self._translate('LibraryToolBar', 'Year')
newest_string = self._translate('LibraryToolBar', 'Newest')
lastread_string = self._translate('LibraryToolBar', 'Last Read')
progress_string = self._translate('LibraryToolBar', 'Progress')
sorting_choices = [
title_string, author_string, year_string, newest_string, lastread_string]
title_string, author_string, year_string,
newest_string, lastread_string, progress_string]
self.sortingBox = FixedComboBox(self)
self.sortingBox.addItems(sorting_choices)

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,7 @@ from setuptools import setup, find_packages
HERE = path.abspath(path.dirname(__file__))
MAJOR_VERSION = '0'
MINOR_VERSION = '3'
MINOR_VERSION = '4'
MICRO_VERSION = '0'
VERSION = "{}.{}.{}".format(MAJOR_VERSION, MINOR_VERSION, MICRO_VERSION)
@@ -13,10 +13,8 @@ VERSION = "{}.{}.{}".format(MAJOR_VERSION, MINOR_VERSION, MICRO_VERSION)
with codecs.open(path.join(HERE, 'README.md'), encoding='utf-8') as f:
LONG_DESC = f.read()
INSTALL_DEPS = ['requests',
'beautifulsoup4']
TEST_DEPS = ['pytest',
'unittest2']
INSTALL_DEPS = ['beautifulsoup4']
TEST_DEPS = []
DEV_DEPS = []
setup(