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/library.py \
lector/toolbars.py \ lector/toolbars.py \
lector/settingsdialog.py \ lector/settingsdialog.py \
resources/definitions.py \ lector/resources/definitions.py \
resources/settingswindow.py \ lector/resources/settingswindow.py \
resources/metadata.py \ lector/resources/metadata.py \
resources/mainwindow.py lector/resources/mainwindow.py
TRANSLATIONS += resources/translations/Lector_es.ts \ TRANSLATIONS += lector/resources/translations/Lector_es.ts \
resources/translations/Lector_fr.ts \ lector/resources/translations/Lector_fr.ts \
resources/translations/Lector_de.ts \ lector/resources/translations/Lector_de.ts \
resources/translations/SAMPLE.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 | | Qt5 | 5.10.1 |
| Python | 3.6 | | Python | 3.6 |
| PyQt5 | 5.10.1 | | PyQt5 | 5.10.1 |
| python-requests | 2.18.4 |
| python-beautifulsoup4 | 4.6.0 | | python-beautifulsoup4 | 4.6.0 |
| poppler-qt5 | 0.61.1 | | poppler-qt5 | 0.61.1 |
| python-poppler-qt5 | 0.24.2 | | 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/) * [Gentoo (unofficial)](https://bitbucket.org/szymonsz/gen2-overlay/src/master/app-text/lector/)
## Translations ## 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. 2. Pick the language you wish to translate to.
3. Translate relevant strings. 3. Translate relevant strings.
4. Try to resist the urge to include profanity. 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. 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 ## Screenshots

22
TODO
View File

@@ -1,8 +1,8 @@
TODO TODO
General: General:
✓ Internationalization ✓ Internationalization
Application icon Application icon
.desktop file .desktop file
Options: Options:
✓ Automatic library management ✓ Automatic library management
✓ Recursive file addition ✓ Recursive file addition
@@ -29,6 +29,7 @@ TODO
✓ Information dialog widget ✓ Information dialog widget
✓ Allow editing of database data through the UI + for Bookmarks ✓ Allow editing of database data through the UI + for Bookmarks
✓ Include (action) icons with the applications ✓ Include (action) icons with the applications
✓ Drag and drop support for the library
Set focus to newly added file Set focus to newly added file
Reading: Reading:
✓ Drop down for TOC ✓ Drop down for TOC
@@ -57,8 +58,15 @@ TODO
✓ Paragraph indentation ✓ Paragraph indentation
✓ Comic view keyboard shortcuts ✓ Comic view keyboard shortcuts
✓ Comic view context menu ✓ 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 Adjust key navigation according to viewport dimensions
Search document using QTextCursor? Search document using QTextCursor
Filetypes: Filetypes:
✓ pdf support ✓ pdf support
Parse TOC Parse TOC
@@ -72,28 +80,28 @@ TODO
Other: Other:
✓ Define every widget in code ✓ Define every widget in code
Bugs: Bugs:
Slider position change might be acting up
Deselecting all directories in the settings dialog also filters out manually added books 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: Secondary:
Annotations
Graphical themes Graphical themes
Change focus rectangle dimensions Change focus rectangle dimensions
Tab reordering Tab reordering
Universal Ctrl + Tab
Allow tabs to detach and form their own windows Allow tabs to detach and form their own windows
Goodreads API: Ratings, Read, Recommendations Goodreads API: Ratings, Read, Recommendations
Get ISBN using python-isbnlib Get ISBN using python-isbnlib
Pagination Pagination
Use embedded fonts + CSS Use embedded fonts + CSS
Scrolling: Smooth / By Line Scrolling: Smooth / By Line
Spacebar should not cut off lines at the top
Shift to logging instead of print statements Shift to logging instead of print statements
txt, doc, chm, djvu, fb2 support txt, doc, chm, djvu, fb2 support
Include icons for filetype emblems Include icons for filetype emblems
Drag and drop support for the library
Comic view modes Comic view modes
Continuous paging Continuous paging
Double pages Double pages
Ignore a / the / numbers for sorting purposes Ignore a / the / numbers for sorting purposes
? Add only one file type if multiple are present ? Add only one file type if multiple are present
? Create emblem per filetype ? 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 sys
import hashlib import hashlib
import pathlib import pathlib
from PyQt5 import QtWidgets, QtGui, QtCore
# This allows for the program to be launched from the # This allows for the program to be launched from the
# dir where it's been copied instead of needing to be # 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] install_dir = pathlib.Path(install_dir).parents[1]
sys.path.append(str(install_dir)) sys.path.append(str(install_dir))
from PyQt5 import QtWidgets, QtGui, QtCore
from lector import database from lector import database
from lector import sorter from lector import sorter
from lector.toolbars import LibraryToolBar, BookToolBar 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.delegates import LibraryDelegate
from lector.threaded import BackGroundTabUpdate, BackGroundBookAddition, BackGroundBookDeletion from lector.threaded import BackGroundTabUpdate, BackGroundBookAddition, BackGroundBookDeletion
from lector.library import Library from lector.library import Library
from lector.guifunctions import QImageFactory from lector.guifunctions import QImageFactory, CoverLoadingAndCulling, ViewProfileModification
from lector.settings import Settings from lector.settings import Settings
from lector.settingsdialog import SettingsUI from lector.settingsdialog import SettingsUI
from lector.metadatadialog import MetadataUI from lector.metadatadialog import MetadataUI
from lector.definitionsdialog import DefinitionsUI from lector.definitionsdialog import DefinitionsUI
from lector.resources import mainwindow, resources from lector.resources import mainwindow, resources
@@ -62,6 +62,13 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
# Initialize translation function # Initialize translation function
self._translate = QtCore.QCoreApplication.translate 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 # Empty variables that will be infested soon
self.settings = {} self.settings = {}
self.thread = None # Background Thread self.thread = None # Background Thread
@@ -71,6 +78,7 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
self.comic_profile = {} self.comic_profile = {}
self.database_path = None self.database_path = None
self.active_library_filters = [] self.active_library_filters = []
self.active_bookmark_docks = []
# Initialize application # Initialize application
Settings(self).read_settings() # This should populate all variables that need Settings(self).read_settings() # This should populate all variables that need
@@ -86,9 +94,13 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
# Widget declarations # Widget declarations
self.libraryFilterMenu = QtWidgets.QMenu() self.libraryFilterMenu = QtWidgets.QMenu()
self.statusMessage = QtWidgets.QLabel() self.statusMessage = QtWidgets.QLabel()
self.distractionFreeToggle = QtWidgets.QToolButton()
# self.reloadLibrary = QtWidgets.QToolButton() # Reference variables
self.reloadLibrary = QtWidgets.QPushButton() 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 # Create the database in case it doesn't exist
database.DatabaseInit(self.database_path) database.DatabaseInit(self.database_path)
@@ -102,6 +114,9 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
# Initialize definition view dialog # Initialize definition view dialog
self.definitionDialog = DefinitionsUI(self) self.definitionDialog = DefinitionsUI(self)
# Make the statusbar invisible by default
self.statusBar.setVisible(False)
# Statusbar widgets # Statusbar widgets
self.statusMessage.setObjectName('statusMessage') self.statusMessage.setObjectName('statusMessage')
self.statusBar.addPermanentWidget(self.statusMessage) self.statusBar.addPermanentWidget(self.statusMessage)
@@ -113,25 +128,23 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
self.statusBar.addWidget(self.sorterProgress) self.statusBar.addWidget(self.sorterProgress)
self.sorterProgress.setVisible(False) 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 # Application wide temporary directory
self.temp_dir = QtCore.QTemporaryDir() 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 # Init the culling timer
self.culling_timer = QtCore.QTimer() self.culling_timer = QtCore.QTimer()
self.culling_timer.setSingleShot(True) 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 # Initialize profile modification functions
self.lib_ref = Library(self) self.profile_functions = ViewProfileModification(self)
# Toolbar display # Toolbar display
# Maybe make this a persistent option # 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.deleteButton.triggered.connect(self.delete_books)
self.libraryToolBar.coverViewButton.triggered.connect(self.switch_library_view) self.libraryToolBar.coverViewButton.triggered.connect(self.switch_library_view)
self.libraryToolBar.tableViewButton.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.colorButton.triggered.connect(self.get_color)
self.libraryToolBar.settingsButton.triggered.connect(self.show_settings) self.libraryToolBar.settingsButton.triggered.connect(self.show_settings)
self.libraryToolBar.searchBar.textChanged.connect(self.lib_ref.update_proxymodels) self.libraryToolBar.searchBar.textChanged.connect(self.lib_ref.update_proxymodels)
self.libraryToolBar.sortingBox.activated.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.libraryFilterButton.setPopupMode(QtWidgets.QToolButton.InstantPopup)
self.libraryToolBar.searchBar.textChanged.connect(self.statusbar_visibility)
self.addToolBar(self.libraryToolBar) self.addToolBar(self.libraryToolBar)
if self.settings['current_view'] == 0: if self.settings['current_view'] == 0:
@@ -155,13 +171,16 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
self.libraryToolBar.tableViewButton.trigger() self.libraryToolBar.tableViewButton.trigger()
# Book toolbar # Book toolbar
self.bookToolBar.annotationButton.triggered.connect(self.toggle_dock_widgets)
self.bookToolBar.addBookmarkButton.triggered.connect(self.add_bookmark) 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) self.bookToolBar.fullscreenButton.triggered.connect(self.set_fullscreen)
for count, i in enumerate(self.display_profiles): for count, i in enumerate(self.display_profiles):
self.bookToolBar.profileBox.setItemData(count, i, QtCore.Qt.UserRole) 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.profileBox.setCurrentIndex(self.current_profile_index)
self.bookToolBar.fontBox.currentFontChanged.connect(self.modify_font) 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.lineSpacingDown.triggered.connect(self.modify_font)
self.bookToolBar.paddingUp.triggered.connect(self.modify_font) self.bookToolBar.paddingUp.triggered.connect(self.modify_font)
self.bookToolBar.paddingDown.triggered.connect(self.modify_font) self.bookToolBar.paddingDown.triggered.connect(self.modify_font)
self.bookToolBar.resetProfile.triggered.connect(self.reset_profile) self.bookToolBar.resetProfile.triggered.connect(
self.profile_functions.reset_profile)
self.alignment_dict = {
'left': self.bookToolBar.alignLeft,
'right': self.bookToolBar.alignRight,
'center': self.bookToolBar.alignCenter,
'justify': self.bookToolBar.alignJustify}
profile_index = self.bookToolBar.profileBox.currentIndex() profile_index = self.bookToolBar.profileBox.currentIndex()
current_profile = self.bookToolBar.profileBox.itemData( current_profile = self.bookToolBar.profileBox.itemData(
@@ -209,16 +223,11 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
self.available_parsers = '*.' + ' *.'.join(sorter.available_parsers) self.available_parsers = '*.' + ' *.'.join(sorter.available_parsers)
print('Available parsers: ' + self.available_parsers) print('Available parsers: ' + self.available_parsers)
# The library refresh button on the Library tab # The Library tab gets no button
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)
self.tabWidget.tabBar().setTabButton( self.tabWidget.tabBar().setTabButton(
0, QtWidgets.QTabBar.RightSide, self.reloadLibrary) 0, QtWidgets.QTabBar.RightSide, None)
self.tabWidget.tabCloseRequested.connect(self.tab_close) self.tabWidget.tabCloseRequested.connect(self.tab_close)
self.tabWidget.setTabBarAutoHide(True)
# Init display models # Init display models
self.lib_ref.generate_model('build') 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.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.listView.customContextMenuRequested.connect(self.generate_library_context_menu) self.listView.customContextMenuRequested.connect(self.generate_library_context_menu)
self.listView.verticalScrollBar().valueChanged.connect(self.start_culling_timer) self.listView.verticalScrollBar().valueChanged.connect(self.start_culling_timer)
self.listView.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
self.listView.setAcceptDrops(True)
self.listView.setStyleSheet( self.listView.setStyleSheet(
"QListView {{background-color: {0}}}".format( "QListView {{background-color: {0}}}".format(
@@ -260,10 +271,10 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
if self.settings['main_window_headers']: if self.settings['main_window_headers']:
for count, i in enumerate(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(count, int(i))
self.tableView.horizontalHeader().resizeSection(5, 1) self.tableView.horizontalHeader().resizeSection(5, 30)
self.tableView.horizontalHeader().setStretchLastSection(True) self.tableView.horizontalHeader().setStretchLastSection(False)
self.tableView.horizontalHeader().sectionClicked.connect( 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.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.tableView.customContextMenuRequested.connect( self.tableView.customContextMenuRequested.connect(
self.generate_library_context_menu) self.generate_library_context_menu)
@@ -314,6 +325,11 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
my_args = cl_parser.positionalArguments() my_args = cl_parser.positionalArguments()
if my_args: if my_args:
file_list = [QtCore.QFileInfo(i).absoluteFilePath() for i in my_args] file_list = [QtCore.QFileInfo(i).absoluteFilePath() for i in my_args]
self.process_post_hoc_files(file_list, True)
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( books = sorter.BookSorter(
file_list, file_list,
('addition', 'manual'), ('addition', 'manual'),
@@ -328,103 +344,90 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
database.DatabaseFunctions(self.database_path).add_to_database(parsed_books) database.DatabaseFunctions(self.database_path).add_to_database(parsed_books)
self.lib_ref.generate_model('addition', parsed_books, True) self.lib_ref.generate_model('addition', parsed_books, True)
file_dict = {QtCore.QFileInfo(i).absoluteFilePath(): None for i in my_args} file_dict = {i: None for i in file_list}
if open_files_after_processing:
self.open_files(file_dict) self.open_files(file_dict)
self.move_on() self.move_on()
def cull_covers(self, event=None): def open_files(self, path_hash_dictionary):
blank_pixmap = QtGui.QPixmap() # file_paths is expected to be a dictionary
blank_pixmap.load(':/images/blank.png') # Keep this. Removing it causes the # This allows for threading file opening
# listView to go blank on a resize # Which should speed up multiple file opening
# especially @ application start
all_indexes = set() file_paths = [i for i in path_hash_dictionary]
for i in range(self.lib_ref.item_proxy_model.rowCount()):
all_indexes.add(self.lib_ref.item_proxy_model.index(i, 0))
y_range = list(range(0, self.listView.viewport().height(), 100)) for filename in path_hash_dictionary.items():
y_range.extend((-20, self.listView.viewport().height() + 20))
x_range = range(0, self.listView.viewport().width(), 80)
visible_indexes = set() file_md5 = filename[1]
for i in y_range: if not file_md5:
for j in x_range: try:
this_index = self.listView.indexAt(QtCore.QPoint(j, i)) with open(filename[0], 'rb') as current_book:
visible_indexes.add(this_index) 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 # Remove any already open files
for i in invisible_indexes: # Set focus to last file in case only one is open
model_index = self.lib_ref.item_proxy_model.mapToSource(i) for i in range(1, self.tabWidget.count()):
this_item = self.lib_ref.view_model.item(model_index.row()) 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: if not file_paths:
this_item.setIcon(QtGui.QIcon(blank_pixmap)) return
this_item.setData(False, QtCore.Qt.UserRole + 8)
hash_index_dict = {} def finishing_touches():
hash_list = [] self.profile_functions.format_contentView()
for i in visible_indexes: self.start_culling_timer()
model_index = self.lib_ref.item_proxy_model.mapToSource(i)
book_hash = self.lib_ref.view_model.data( print('Attempting to open: ' + ', '.join(file_paths))
model_index, QtCore.Qt.UserRole + 6)
cover_displayed = self.lib_ref.view_model.data(
model_index, QtCore.Qt.UserRole + 8)
if book_hash and not cover_displayed: contents = sorter.BookSorter(
hash_list.append(book_hash) file_paths,
hash_index_dict[book_hash] = model_index ('reading', None),
self.database_path,
True,
self.temp_dir.path()).initiate_threads()
all_covers = database.DatabaseFunctions( # TODO
self.database_path).fetch_covers_only(hash_list) # Notification feedback in case all books return nothing
for i in all_covers: if not contents:
book_hash = i[0] return
cover = i[1]
model_index = hash_index_dict[book_hash]
book_item = self.lib_ref.view_model.item(model_index.row()) for i in contents:
self.cover_loader(book_item, cover) # 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): def start_culling_timer(self):
if self.settings['perform_culling']: if self.settings['perform_culling']:
self.culling_timer.start(30) 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): def add_bookmark(self):
if self.tabWidget.currentIndex() != 0: if self.tabWidget.currentIndex() != 0:
self.tabWidget.widget(self.tabWidget.currentIndex()).add_bookmark() self.tabWidget.widget(self.tabWidget.currentIndex()).add_bookmark()
@@ -475,9 +478,10 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
return return
self.settingsDialog.okButton.setEnabled(False) 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.settings['last_open_path'] = os.path.dirname(opened_files[0][0])
self.statusBar.setVisible(True)
self.sorterProgress.setVisible(True) self.sorterProgress.setVisible(True)
self.statusMessage.setText(self._translate('Main_UI', 'Adding books...')) self.statusMessage.setText(self._translate('Main_UI', 'Adding books...'))
self.thread = BackGroundBookAddition( self.thread = BackGroundBookAddition(
@@ -489,14 +493,14 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
selected_indexes = None selected_indexes = None
if library_widget == self.listView: 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()) self.listView.selectionModel().selection())
selected_indexes = [i.indexes()[0] for i in selected_books] selected_indexes = [i.indexes()[0] for i in selected_books]
elif library_widget == self.tableView: elif library_widget == self.tableView:
selected_books = self.tableView.selectionModel().selectedRows() selected_books = self.tableView.selectionModel().selectedRows()
selected_indexes = [ 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 return selected_indexes
@@ -522,12 +526,12 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
# Persistent model indexes are required beause deletion mutates the model # Persistent model indexes are required beause deletion mutates the model
# Generate and delete by persistent index # Generate and delete by persistent index
delete_hashes = [ delete_hashes = [
self.lib_ref.view_model.data( self.lib_ref.libraryModel.data(
i, QtCore.Qt.UserRole + 6) for i in selected_indexes] i, QtCore.Qt.UserRole + 6) for i in selected_indexes]
persistent_indexes = [QtCore.QPersistentModelIndex(i) for i in selected_indexes] persistent_indexes = [QtCore.QPersistentModelIndex(i) for i in selected_indexes]
for i in persistent_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 # Update the database in the background
self.thread = BackGroundBookDeletion( self.thread = BackGroundBookDeletion(
@@ -557,20 +561,23 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
self.settingsDialog.okButton.setEnabled(True) self.settingsDialog.okButton.setEnabled(True)
self.settingsDialog.okButton.setToolTip( self.settingsDialog.okButton.setToolTip(
self._translate('Main_UI', 'Save changes and start library scan')) 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.setVisible(False)
self.sorterProgress.setValue(0) self.sorterProgress.setValue(0)
if self.libraryToolBar.searchBar.text() == '':
self.statusBar.setVisible(False)
self.lib_ref.update_proxymodels() self.lib_ref.update_proxymodels()
self.lib_ref.generate_library_tags() self.lib_ref.generate_library_tags()
self.statusMessage.setText( self.statusMessage.setText(
str(self.lib_ref.item_proxy_model.rowCount()) + str(self.lib_ref.itemProxyModel.rowCount()) +
self._translate('Main_UI', ' books')) self._translate('Main_UI', ' books'))
if not self.settings['perform_culling']: if not self.settings['perform_culling']:
self.load_all_covers() self.cover_functions.load_all_covers()
def switch_library_view(self): def switch_library_view(self):
if self.libraryToolBar.coverViewButton.isChecked(): if self.libraryToolBar.coverViewButton.isChecked():
@@ -592,6 +599,11 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
self.current_tab = self.tabWidget.currentIndex() 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: if self.tabWidget.currentIndex() == 0:
self.resizeEvent() self.resizeEvent()
@@ -600,11 +612,11 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
self.bookToolBar.hide() self.bookToolBar.hide()
self.libraryToolBar.show() self.libraryToolBar.show()
if self.lib_ref.item_proxy_model: if self.lib_ref.itemProxyModel:
# Making the proxy model available doesn't affect # Making the proxy model available doesn't affect
# memory utilization at all. Bleh. # memory utilization at all. Bleh.
self.statusMessage.setText( self.statusMessage.setText(
str(self.lib_ref.item_proxy_model.rowCount()) + str(self.lib_ref.itemProxyModel.rowCount()) +
self._translate('Main_UI', ' Books')) self._translate('Main_UI', ' Books'))
else: else:
@@ -631,10 +643,10 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
self.bookToolBar.tocBox.setCurrentIndex( self.bookToolBar.tocBox.setCurrentIndex(
current_position['current_chapter'] - 1) current_position['current_chapter'] - 1)
if not current_metadata['images_only']: if not current_metadata['images_only']:
current_tab.set_scroll_value(False) current_tab.hiddenButton.animateClick(25)
self.bookToolBar.tocBox.blockSignals(False) self.bookToolBar.tocBox.blockSignals(False)
self.format_contentView() self.profile_functions.format_contentView()
self.statusMessage.setText( self.statusMessage.setText(
current_author + ' - ' + current_title) current_author + ' - ' + current_title)
@@ -660,361 +672,53 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
def set_toc_position(self, event=None): def set_toc_position(self, event=None):
current_tab = self.tabWidget.widget(self.tabWidget.currentIndex()) 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[ current_tab.metadata[
'position']['current_chapter'] = event + 1 'position']['current_chapter'] = event + 1
current_tab.metadata[ current_tab.metadata[
'position']['is_read'] = False '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 # Go on to change the value of the Table of Contents box
current_tab.change_chapter_tocBox() current_tab.change_chapter_tocBox()
self.format_contentView() current_tab.contentView.record_position()
self.profile_functions.format_contentView()
def set_fullscreen(self): def set_fullscreen(self):
current_tab = self.tabWidget.currentIndex() current_tab = self.tabWidget.currentIndex()
current_tab_widget = self.tabWidget.widget(current_tab) current_tab_widget = self.tabWidget.widget(current_tab)
current_tab_widget.go_fullscreen() current_tab_widget.go_fullscreen()
def toggle_dock_widget(self): def toggle_dock_widgets(self):
sender = self.sender().objectName() sender = self.sender()
current_tab = self.tabWidget.currentIndex() current_tab = self.tabWidget.currentIndex()
current_tab_widget = self.tabWidget.widget(current_tab) current_tab_widget = self.tabWidget.widget(current_tab)
# TODO if sender == self.bookToolBar.bookmarkButton:
# Extend this to other context related functions
# Make this fullscreenable
if sender == 'bookmarkButton':
current_tab_widget.toggle_bookmarks() current_tab_widget.toggle_bookmarks()
if sender == self.bookToolBar.annotationButton:
current_tab_widget.toggle_annotations()
def library_doubleclick(self, index): def library_doubleclick(self, index):
sender = self.sender().objectName() sender = self.sender().objectName()
if sender == 'listView': if sender == 'listView':
source_index = self.lib_ref.item_proxy_model.mapToSource(index) source_index = self.lib_ref.itemProxyModel.mapToSource(index)
elif sender == 'tableView': 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) metadata = item.data(QtCore.Qt.UserRole + 3)
path = {metadata['path']: metadata['hash']} path = {metadata['path']: metadata['hash']}
self.open_files(path) self.open_files(path)
def open_files(self, path_hash_dictionary): def statusbar_visibility(self):
# file_paths is expected to be a dictionary if self.sender() == self.libraryToolBar.searchBar:
# This allows for threading file opening if self.libraryToolBar.searchBar.text() == '':
# Which should speed up multiple file opening self.statusBar.setVisible(False)
# 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
else: else:
return current_color self.statusBar.setVisible(True)
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()
def show_settings(self): def show_settings(self):
if not self.settingsDialog.isVisible(): if not self.settingsDialog.isVisible():
@@ -1022,12 +726,34 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
else: else:
self.settingsDialog.hide() 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): def generate_library_context_menu(self, position):
index = self.sender().indexAt(position) index = self.sender().indexAt(position)
if not index.isValid(): if not index.isValid():
return 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 # and NOT of the proxy models
selected_indexes = self.get_selection(self.sender()) selected_indexes = self.get_selection(self.sender())
@@ -1058,28 +784,28 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
if action == openAction: if action == openAction:
books_to_open = {} books_to_open = {}
for i in selected_indexes: 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'] books_to_open[metadata['path']] = metadata['hash']
self.open_files(books_to_open) self.open_files(books_to_open)
if action == editAction: if action == editAction:
edit_book = selected_indexes[0] edit_book = selected_indexes[0]
metadata = self.lib_ref.view_model.data( metadata = self.lib_ref.libraryModel.data(
edit_book, QtCore.Qt.UserRole + 3) 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) edit_book, QtCore.Qt.UserRole + 8)
# Loads a cover in case culling is enabled and the table view is visible # Loads a cover in case culling is enabled and the table view is visible
if not is_cover_loaded: 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) 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( book_cover = database.DatabaseFunctions(
self.database_path).fetch_covers_only([book_hash])[0][1] 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'] title = metadata['title']
author = metadata['author'] author = metadata['author']
year = str(metadata['year']) year = str(metadata['year'])
@@ -1095,8 +821,8 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
if action == readAction or action == unreadAction: if action == readAction or action == unreadAction:
for i in selected_indexes: 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)
book_hash = self.lib_ref.view_model.data(i, QtCore.Qt.UserRole + 6) book_hash = self.lib_ref.libraryModel.data(i, QtCore.Qt.UserRole + 6)
position = metadata['position'] position = metadata['position']
if position: if position:
@@ -1118,11 +844,11 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
last_accessed_time = None last_accessed_time = None
if action == readAction: if action == readAction:
last_accessed_time = QtCore.QDateTime().currentDateTime() 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.libraryModel.setData(i, metadata, QtCore.Qt.UserRole + 3)
self.lib_ref.view_model.setData(i, position_perc, QtCore.Qt.UserRole + 7) self.lib_ref.libraryModel.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, last_accessed_time, QtCore.Qt.UserRole + 12)
self.lib_ref.update_proxymodels() self.lib_ref.update_proxymodels()
database_dict = { database_dict = {
@@ -1189,10 +915,9 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
def toggle_distraction_free(self): def toggle_distraction_free(self):
self.settings['show_bars'] = not self.settings['show_bars'] self.settings['show_bars'] = not self.settings['show_bars']
self.statusBar.setVisible( if self.tabWidget.count() > 1:
not self.statusBar.isVisible())
self.tabWidget.tabBar().setVisible( self.tabWidget.tabBar().setVisible(
not self.tabWidget.tabBar().isVisible()) self.settings['show_bars'])
current_tab = self.tabWidget.currentIndex() current_tab = self.tabWidget.currentIndex()
if current_tab == 0: if current_tab == 0:
@@ -1213,6 +938,11 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
self.settingsDialog.hide() self.settingsDialog.hide()
self.definitionDialog.hide() self.definitionDialog.hide()
self.temp_dir.remove() 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'] = [] self.settings['last_open_books'] = []
if self.tabWidget.count() > 1: 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 # 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 # 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 # it under the terms of the GNU General Public License as published by
@@ -19,6 +17,7 @@
import os import os
import pickle import pickle
import sqlite3 import sqlite3
from PyQt5 import QtCore from PyQt5 import QtCore
@@ -41,7 +40,8 @@ class DatabaseInit:
'LastAccessed': 'BLOB', 'LastAccessed': 'BLOB',
'Bookmarks': 'BLOB', 'Bookmarks': 'BLOB',
'CoverImage': 'BLOB', 'CoverImage': 'BLOB',
'Addition': 'TEXT'} 'Addition': 'TEXT',
'Annotations': 'BLOB'}
self.directories_table_columns = { self.directories_table_columns = {
'id': 'INTEGER PRIMARY KEY', 'id': 'INTEGER PRIMARY KEY',
@@ -51,7 +51,7 @@ class DatabaseInit:
'CheckState': 'INTEGER'} 'CheckState': 'INTEGER'}
if os.path.exists(self.database_path): if os.path.exists(self.database_path):
self.check_database() self.check_columns()
else: else:
self.create_database() self.create_database()
@@ -70,7 +70,7 @@ class DatabaseInit:
self.database.commit() self.database.commit()
self.database.close() self.database.close()
def check_database(self): def check_columns(self):
self.database = sqlite3.connect(self.database_path) self.database = sqlite3.connect(self.database_path)
database_return = self.database.execute("PRAGMA table_info(books)").fetchall() database_return = self.database.execute("PRAGMA table_info(books)").fetchall()
@@ -81,13 +81,12 @@ class DatabaseInit:
for i in self.books_table_columns.items(): for i in self.books_table_columns.items():
if i[0] not in database_columns: if i[0] not in database_columns:
commit_required = True 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]}" sql_command = f"ALTER TABLE books ADD COLUMN {i[0]} {i[1]}"
self.database.execute(sql_command) self.database.execute(sql_command)
if commit_required: if commit_required:
self.database.commit() self.database.commit()
self.database.close()
class DatabaseFunctions: class DatabaseFunctions:
@@ -220,7 +219,7 @@ class DatabaseFunctions:
def modify_metadata(self, metadata_dict, book_hash): def modify_metadata(self, metadata_dict, book_hash):
def generate_binary(column, data): def generate_binary(column, data):
if column in ('Position', 'LastAccessed', 'Bookmarks'): if column in ('Position', 'LastAccessed', 'Bookmarks', 'Annotations'):
return sqlite3.Binary(pickle.dumps(data)) return sqlite3.Binary(pickle.dumps(data))
elif column == 'CoverImage': elif column == 'CoverImage':
return sqlite3.Binary(data) 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 # 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 # 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 # 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 # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # 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 PyQt5 import QtWidgets, QtCore, QtGui, QtMultimedia
from lector.resources import definitions from lector.resources import definitions
@@ -37,8 +38,12 @@ class DefinitionsUI(QtWidgets.QDialog, definitions.Ui_Dialog):
radius = 15 radius = 15
path = QtGui.QPainterPath() path = QtGui.QPainterPath()
path.addRoundedRect(QtCore.QRectF(self.rect()), radius, radius) path.addRoundedRect(QtCore.QRectF(self.rect()), radius, radius)
try:
mask = QtGui.QRegion(path.toFillPolygon().toPolygon()) mask = QtGui.QRegion(path.toFillPolygon().toPolygon())
self.setMask(mask) self.setMask(mask)
except TypeError: # Required for older versions of Qt
pass
self.definitionView.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.definitionView.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
@@ -52,21 +57,24 @@ class DefinitionsUI(QtWidgets.QDialog, definitions.Ui_Dialog):
self.okButton.clicked.connect(self.hide) self.okButton.clicked.connect(self.hide)
self.pronounceButton.clicked.connect(self.play_pronunciation) self.pronounceButton.clicked.connect(self.play_pronunciation)
self.dialogBackground.clicked.connect(self.color_background)
def api_call(self, url, word): def api_call(self, url, word):
language = self.parent.settings['dictionary_language'] language = self.parent.settings['dictionary_language']
url = url + language + '/' + word.lower() url = url + language + '/' + word.lower()
r = requests.get( req = urllib.request.Request(url)
url, req.add_header('app_id', self.app_id)
headers={'app_id': self.app_id, 'app_key': self.app_key}) req.add_header('app_key', self.app_key)
if r.status_code != 200: try:
print('A firm nope on the dictionary finding thing') 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 None
return r.json()
def find_definition(self, word): def find_definition(self, word):
word_root_json = self.api_call(self.root_url, word) word_root_json = self.api_call(self.root_url, word)
if not word_root_json: 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) definition_json = self.api_call(self.define_url, word_root)
if not definition_json: if not definition_json:
self.set_text(word, None, None, True)
return return
definitions = {} definitions = {}
@@ -137,7 +146,8 @@ class DefinitionsUI(QtWidgets.QDialog, definitions.Ui_Dialog):
background = self.parent.settings['dialog_background'] background = self.parent.settings['dialog_background']
else: else:
self.previous_position = self.pos() self.previous_position = self.pos()
background = self.parent.get_color() self.parent.get_color()
background = self.parent.settings['dialog_background']
self.setStyleSheet( self.setStyleSheet(
"QDialog {{background-color: {0}}}".format(background.name())) "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 # 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 # 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 # 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) option = option.__class__(option)
file_exists = index.data(QtCore.Qt.UserRole + 5) file_exists = index.data(QtCore.Qt.UserRole + 5)
metadata = index.data(QtCore.Qt.UserRole + 3) position_percent = index.data(QtCore.Qt.UserRole + 7)
position = metadata['position']
if position:
is_read = position['is_read']
# The shadow pixmap currently is set to 420 x 600 # The shadow pixmap currently is set to 420 x 600
# Only draw the cover shadow in case the setting is enabled # Only draw the cover shadow in case the setting is enabled
@@ -55,36 +49,29 @@ class LibraryDelegate(QtWidgets.QStyledItemDelegate):
if not file_exists: if not file_exists:
painter.setOpacity(.7) painter.setOpacity(.7)
QtWidgets.QStyledItemDelegate.paint(self, painter, option, index) 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 x_draw = option.rect.bottomRight().x() - 30
y_draw = option.rect.bottomRight().y() - 35 y_draw = option.rect.bottomRight().y() - 35
painter.drawPixmap(x_draw, y_draw, read_icon) painter.drawPixmap(x_draw, y_draw, read_icon)
painter.setOpacity(1)
return return
QtWidgets.QStyledItemDelegate.paint(self, painter, option, index) 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( 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 x_draw = option.rect.bottomRight().x() - 30
y_draw = option.rect.bottomRight().y() - 35 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): class BookmarkDelegate(QtWidgets.QStyledItemDelegate):
def __init__(self, parent=None): def __init__(self, main_window, parent=None):
super(BookmarkDelegate, self).__init__(parent) super(BookmarkDelegate, self).__init__()
self.main_window = main_window
self.parent = parent self.parent = parent
def sizeHint(self, *args): def sizeHint(self, *args):
@@ -98,7 +85,7 @@ class BookmarkDelegate(QtWidgets.QStyledItemDelegate):
option = option.__class__(option) option = option.__class__(option)
chapter_index = index.data(QtCore.Qt.UserRole) 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: if len(chapter_name) > 25:
chapter_name = 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( return_list.append(
(chapter_titles[count - 1], bs_obj_string)) (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 = BeautifulSoup(xml_string, 'lxml')
bs_obj_string = str(bs_obj).replace('"&gt;', '', 1) + ('<br/>' * 8) 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 # 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 # 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 # 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 # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # 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 from lector.resources import resources
@@ -30,3 +31,316 @@ class QImageFactory:
this_qicon = QtGui.QIcon(icon_path) this_qicon = QtGui.QIcon(icon_path)
return this_qicon 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 # 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 # 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 # it under the terms of the GNU General Public License as published by
@@ -19,26 +17,28 @@
import os import os
import pickle import pickle
import pathlib import pathlib
from PyQt5 import QtGui, QtCore from PyQt5 import QtGui, QtCore
from lector import database from lector import database
from lector.models import TableProxyModel, ItemProxyModel from lector.models import TableProxyModel, ItemProxyModel
class Library: class Library:
def __init__(self, parent): def __init__(self, parent):
self.parent = parent self.main_window = parent
self.view_model = None self.libraryModel = None
self.item_proxy_model = None self.itemProxyModel = None
self.table_proxy_model = None self.tableProxyModel = None
self._translate = QtCore.QCoreApplication.translate self._translate = QtCore.QCoreApplication.translate
def generate_model(self, mode, parsed_books=None, is_database_ready=True): def generate_model(self, mode, parsed_books=None, is_database_ready=True):
if mode == 'build': if mode == 'build':
self.view_model = QtGui.QStandardItemModel() self.libraryModel = QtGui.QStandardItemModel()
self.view_model.setColumnCount(10) self.libraryModel.setColumnCount(10)
books = database.DatabaseFunctions( books = database.DatabaseFunctions(
self.parent.database_path).fetch_data( self.main_window.database_path).fetch_data(
('Title', 'Author', 'Year', 'DateAdded', 'Path', ('Title', 'Author', 'Year', 'DateAdded', 'Path',
'Position', 'ISBN', 'Tags', 'Hash', 'LastAccessed', 'Position', 'ISBN', 'Tags', 'Hash', 'LastAccessed',
'Addition'), 'Addition'),
@@ -51,7 +51,7 @@ class Library:
return return
elif mode == 'addition': 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 # Because any additional books have already been added to the
# database using background threads # database using background threads
@@ -99,18 +99,22 @@ class Library:
if position: if position:
position = pickle.loads(position) position = pickle.loads(position)
if position['is_read']: if position['is_read']:
position_perc = 100 position_perc = 1
else: else:
try: try:
position_perc = ( position_perc = (
position['current_chapter'] * 100 / position['total_chapters']) position['current_block'] / position['total_blocks'])
except (KeyError, ZeroDivisionError):
try:
position_perc = (
position['current_chapter'] / position['total_chapters'])
except KeyError: except KeyError:
position_perc = None position_perc = None
try: try:
file_exists = os.path.exists(path) file_exists = os.path.exists(path)
except UnicodeEncodeError: except UnicodeEncodeError:
print('Error with unicode encoding in the library module') print('Library: Unicode encoding error')
all_metadata = { all_metadata = {
'title': title, 'title': title,
@@ -156,57 +160,60 @@ class Library:
item.setData(False, QtCore.Qt.UserRole + 8) # Is the cover being displayed? item.setData(False, QtCore.Qt.UserRole + 8) # Is the cover being displayed?
item.setData(date_added, QtCore.Qt.UserRole + 9) item.setData(date_added, QtCore.Qt.UserRole + 9)
item.setData(last_accessed, QtCore.Qt.UserRole + 12) item.setData(last_accessed, QtCore.Qt.UserRole + 12)
item.setData(path, QtCore.Qt.UserRole + 13)
item.setIcon(QtGui.QIcon(img_pixmap)) 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 # The is_database_ready boolean is required when a new thread sends
# books here for model generation. # books here for model generation.
if not self.parent.settings['perform_culling'] and is_database_ready: if not self.main_window.settings['perform_culling'] and is_database_ready:
self.parent.load_all_covers() self.main_window.cover_functions.load_all_covers()
def generate_proxymodels(self): def generate_proxymodels(self):
self.item_proxy_model = ItemProxyModel() self.itemProxyModel = ItemProxyModel()
self.item_proxy_model.setSourceModel(self.view_model) self.itemProxyModel.setSourceModel(self.libraryModel)
self.item_proxy_model.setSortCaseSensitivity(False) self.itemProxyModel.setSortCaseSensitivity(False)
s = QtCore.QSize(160, 250) # Set icon sizing here s = QtCore.QSize(160, 250) # Set icon sizing here
self.parent.listView.setIconSize(s) self.main_window.listView.setIconSize(s)
self.parent.listView.setModel(self.item_proxy_model) self.main_window.listView.setModel(self.itemProxyModel)
self.table_proxy_model = TableProxyModel( self.tableProxyModel = TableProxyModel(
self.parent.temp_dir.path(), self.parent.tableView.horizontalHeader()) self.main_window.temp_dir.path(),
self.table_proxy_model.setSourceModel(self.view_model) self.main_window.tableView.horizontalHeader(),
self.table_proxy_model.setSortCaseSensitivity(False) self.main_window.settings['consider_read_at'])
self.parent.tableView.setModel(self.table_proxy_model) self.tableProxyModel.setSourceModel(self.libraryModel)
self.tableProxyModel.setSortCaseSensitivity(False)
self.main_window.tableView.setModel(self.tableProxyModel)
self.update_proxymodels() self.update_proxymodels()
def update_proxymodels(self): def update_proxymodels(self):
# Table proxy model # Table proxy model
self.table_proxy_model.invalidateFilter() self.tableProxyModel.invalidateFilter()
self.table_proxy_model.setFilterParams( self.tableProxyModel.setFilterParams(
self.parent.libraryToolBar.searchBar.text(), self.main_window.libraryToolBar.searchBar.text(),
self.parent.active_library_filters, self.main_window.active_library_filters,
0) # This doesn't need to know the sorting box position 0) # This doesn't need to know the sorting box position
self.table_proxy_model.setFilterFixedString( self.tableProxyModel.setFilterFixedString(
self.parent.libraryToolBar.searchBar.text()) self.main_window.libraryToolBar.searchBar.text())
# ^^^ This isn't needed, but it forces a model update every time the # ^^^ 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. # text in the line edit changes. So I guess it is needed.
self.table_proxy_model.sort_table_columns( self.tableProxyModel.sort_table_columns(
self.parent.tableView.horizontalHeader().sortIndicatorSection()) self.main_window.tableView.horizontalHeader().sortIndicatorSection())
self.table_proxy_model.sort_table_columns() self.tableProxyModel.sort_table_columns()
# Item proxy model # Item proxy model
self.item_proxy_model.invalidateFilter() self.itemProxyModel.invalidateFilter()
self.item_proxy_model.setFilterParams( self.itemProxyModel.setFilterParams(
self.parent.libraryToolBar.searchBar.text(), self.main_window.libraryToolBar.searchBar.text(),
self.parent.active_library_filters, self.main_window.active_library_filters,
self.parent.libraryToolBar.sortingBox.currentIndex()) self.main_window.libraryToolBar.sortingBox.currentIndex())
self.item_proxy_model.setFilterFixedString( self.itemProxyModel.setFilterFixedString(
self.parent.libraryToolBar.searchBar.text()) self.main_window.libraryToolBar.searchBar.text())
self.parent.statusMessage.setText( self.main_window.statusMessage.setText(
str(self.item_proxy_model.rowCount()) + str(self.itemProxyModel.rowCount()) +
self._translate('Library', ' books')) self._translate('Library', ' books'))
# TODO # TODO
@@ -221,23 +228,25 @@ class Library:
1: 1, 1: 1,
2: 2, 2: 2,
3: 9, 3: 9,
4: 12} 4: 12,
5: 7}
# Sorting according to roles and the drop down in the library toolbar # Sorting according to roles and the drop down in the library toolbar
self.item_proxy_model.setSortRole( self.itemProxyModel.setSortRole(
QtCore.Qt.UserRole + sort_roles[self.parent.libraryToolBar.sortingBox.currentIndex()]) QtCore.Qt.UserRole +
sort_roles[self.main_window.libraryToolBar.sortingBox.currentIndex()])
# This can be expanded to other fields by appending to the list # This can be expanded to other fields by appending to the list
sort_order = QtCore.Qt.AscendingOrder 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 sort_order = QtCore.Qt.DescendingOrder
self.item_proxy_model.sort(0, sort_order) self.itemProxyModel.sort(0, sort_order)
self.parent.start_culling_timer() self.main_window.start_culling_timer()
def generate_library_tags(self): def generate_library_tags(self):
db_library_directories = database.DatabaseFunctions( db_library_directories = database.DatabaseFunctions(
self.parent.database_path).fetch_data( self.main_window.database_path).fetch_data(
('Path', 'Name', 'Tags'), ('Path', 'Name', 'Tags'),
'directories', # This checks the directories table NOT the book one 'directories', # This checks the directories table NOT the book one
{'Path': ''}, {'Path': ''},
@@ -249,7 +258,7 @@ class Library:
else: else:
db_library_directories = database.DatabaseFunctions( db_library_directories = database.DatabaseFunctions(
self.parent.database_path).fetch_data( self.main_window.database_path).fetch_data(
('Path',), ('Path',),
'books', # THIS CHECKS THE BOOKS TABLE 'books', # THIS CHECKS THE BOOKS TABLE
{'Path': ''}, {'Path': ''},
@@ -285,8 +294,8 @@ class Library:
# Generate tags for the QStandardItemModel # Generate tags for the QStandardItemModel
# This isn't triggered for an empty view model # This isn't triggered for an empty view model
for i in range(self.view_model.rowCount()): for i in range(self.libraryModel.rowCount()):
this_item = self.view_model.item(i, 0) this_item = self.libraryModel.item(i, 0)
all_metadata = this_item.data(QtCore.Qt.UserRole + 3) all_metadata = this_item.data(QtCore.Qt.UserRole + 3)
directory_name, directory_tags = get_tags(all_metadata) directory_name, directory_tags = get_tags(all_metadata)
@@ -301,8 +310,8 @@ class Library:
invalid_paths = [] invalid_paths = []
deletable_persistent_indexes = [] deletable_persistent_indexes = []
for i in range(self.view_model.rowCount()): for i in range(self.libraryModel.rowCount()):
item = self.view_model.item(i) item = self.libraryModel.item(i)
item_metadata = item.data(QtCore.Qt.UserRole + 3) item_metadata = item.data(QtCore.Qt.UserRole + 3)
book_path = item_metadata['path'] book_path = item_metadata['path']
@@ -321,8 +330,8 @@ class Library:
if deletable_persistent_indexes: if deletable_persistent_indexes:
for i in 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 # Remove invalid paths from the database as well
database.DatabaseFunctions( 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 # 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 # 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 # 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 radius = 15
path = QtGui.QPainterPath() path = QtGui.QPainterPath()
path.addRoundedRect(QtCore.QRectF(self.rect()), radius, radius) path.addRoundedRect(QtCore.QRectF(self.rect()), radius, radius)
try:
mask = QtGui.QRegion(path.toFillPolygon().toPolygon()) mask = QtGui.QRegion(path.toFillPolygon().toPolygon())
self.setMask(mask) self.setMask(mask)
except TypeError: # Required for older versions of Qt
pass
self.parent = parent self.parent = parent
self.database_path = self.parent.database_path self.database_path = self.parent.database_path
@@ -86,7 +88,7 @@ class MetadataUI(QtWidgets.QDialog, metadata.Ui_Dialog):
self.coverView.setScene(graphics_scene) self.coverView.setScene(graphics_scene)
def ok_pressed(self, event=None): 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() title = self.titleLine.text()
author = self.authorLine.text() author = self.authorLine.text()
@@ -116,7 +118,7 @@ class MetadataUI(QtWidgets.QDialog, metadata.Ui_Dialog):
if self.cover_for_database: if self.cover_for_database:
database_dict['CoverImage'] = 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) book_item, self.cover_for_database)
self.parent.lib_ref.update_proxymodels() self.parent.lib_ref.update_proxymodels()
@@ -148,7 +150,8 @@ class MetadataUI(QtWidgets.QDialog, metadata.Ui_Dialog):
background = self.parent.settings['dialog_background'] background = self.parent.settings['dialog_background']
else: else:
self.previous_position = self.pos() self.previous_position = self.pos()
background = self.parent.get_color() self.parent.get_color()
background = self.parent.settings['dialog_background']
self.setStyleSheet( self.setStyleSheet(
"QDialog {{background-color: {0}}}".format(background.name())) "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 # 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 # 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 # 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): 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) super(TableProxyModel, self).__init__(parent)
self.tableViewHeader = tableViewHeader self.tableViewHeader = tableViewHeader
self.consider_read_at = consider_read_at
self._translate = QtCore.QCoreApplication.translate self._translate = QtCore.QCoreApplication.translate
title_string = self._translate('TableProxyModel', 'Title') title_string = self._translate('TableProxyModel', 'Title')
@@ -101,6 +100,7 @@ class TableProxyModel(QtCore.QSortFilterProxyModel):
return self.header_data[column] return self.header_data[column]
except IndexError: except IndexError:
print('Table proxy model: Can\'t find header for column', column) print('Table proxy model: Can\'t find header for column', column)
# The column will be called IndexError. Not a typo.
return 'IndexError' return 'IndexError'
def flags(self, index): def flags(self, index):
@@ -121,32 +121,16 @@ class TableProxyModel(QtCore.QSortFilterProxyModel):
return_pixmap = None return_pixmap = None
file_exists = item.data(QtCore.Qt.UserRole + 5) file_exists = item.data(QtCore.Qt.UserRole + 5)
metadata = item.data(QtCore.Qt.UserRole + 3) position_percent = item.data(QtCore.Qt.UserRole + 7)
position = metadata['position']
if position:
is_read = position['is_read']
if not file_exists: if not file_exists:
return pie_chart.pixmapper( return pie_chart.pixmapper(
-1, None, None, QtCore.Qt.SizeHintRole + 10) -1, None, None, QtCore.Qt.SizeHintRole + 10)
if position: if position_percent:
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
return_pixmap = pie_chart.pixmapper( 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) QtCore.Qt.SizeHintRole + 10)
return return_pixmap return return_pixmap
@@ -214,14 +198,20 @@ class ProxyModelsCommonFunctions:
title = model.data(this_index, QtCore.Qt.UserRole) title = model.data(this_index, QtCore.Qt.UserRole)
author = model.data(this_index, QtCore.Qt.UserRole + 1) author = model.data(this_index, QtCore.Qt.UserRole + 1)
tags = model.data(this_index, QtCore.Qt.UserRole + 4) 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_name = model.data(this_index, QtCore.Qt.UserRole + 10)
directory_tags = model.data(this_index, QtCore.Qt.UserRole + 11) directory_tags = model.data(this_index, QtCore.Qt.UserRole + 11)
last_accessed = model.data(this_index, QtCore.Qt.UserRole + 12) 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 # Hide untouched files when sorting by last accessed
if self.parent_model.sorting_box_position == 4 and not last_accessed: if self.parent_model.sorting_box_position == 4 and not last_accessed:
return False 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 self.parent_model.active_library_filters:
if directory_name not in self.parent_model.active_library_filters: if directory_name not in self.parent_model.active_library_filters:
return False return False
@@ -233,7 +223,9 @@ class ProxyModelsCommonFunctions:
else: else:
valid_data = [ valid_data = [
i.lower() for i in ( 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: for i in valid_data:
if self.parent_model.filter_text.lower() in i: if self.parent_model.filter_text.lower() in i:
return True return True

View File

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

View File

@@ -18,15 +18,12 @@
import io import io
import os import os
from PyQt5 import QtCore from PyQt5 import QtCore
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
proceed = True
try:
import popplerqt5 import popplerqt5
except ImportError:
print('python-poppler-qt5 is not installed. Pdf files will not work.')
proceed = False
class ParsePDF: class ParsePDF:
def __init__(self, filename, *args): def __init__(self, filename, *args):
@@ -35,9 +32,6 @@ class ParsePDF:
self.metadata = None self.metadata = None
def read_book(self): def read_book(self):
if not proceed:
return
self.book = popplerqt5.Poppler.Document.load(self.filename) self.book = popplerqt5.Poppler.Document.load(self.filename)
if not self.book: if not self.book:
return return
@@ -61,8 +55,8 @@ class ParsePDF:
def get_year(self): def get_year(self):
try: try:
year = self.metadata.find('MetadataDate').text year = self.metadata.find('MetadataDate').text
return year.replace('\n', '') return int(year.replace('\n', '')[:4])
except AttributeError: except (AttributeError, ValueError):
return 9999 return 9999
def get_cover_image(self): def get_cover_image(self):
@@ -70,9 +64,12 @@ class ParsePDF:
popplerqt5.Poppler.Document.Antialiasing popplerqt5.Poppler.Document.Antialiasing
and popplerqt5.Poppler.Document.TextAntialiasing) and popplerqt5.Poppler.Document.TextAntialiasing)
try:
cover_page = self.book.page(0) cover_page = self.book.page(0)
cover_image = cover_page.renderToImage(300, 300) cover_image = cover_page.renderToImage(300, 300)
return resize_image(cover_image) return resize_image(cover_image)
except AttributeError:
return None
def get_isbn(self): def get_isbn(self):
return None 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' # 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! # 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.setContentsMargins(0, 0, 0, 0)
self.gridLayout_4.setSpacing(0) self.gridLayout_4.setSpacing(0)
self.gridLayout_4.setObjectName("gridLayout_4") 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.stackedWidget.addWidget(self.listPage)
self.tablePage = QtWidgets.QWidget() self.tablePage = QtWidgets.QWidget()
self.tablePage.setObjectName("tablePage") self.tablePage.setObjectName("tablePage")
@@ -56,20 +42,6 @@ class Ui_MainWindow(object):
self.gridLayout_3.setContentsMargins(0, 0, 0, 0) self.gridLayout_3.setContentsMargins(0, 0, 0, 0)
self.gridLayout_3.setSpacing(0) self.gridLayout_3.setSpacing(0)
self.gridLayout_3.setObjectName("gridLayout_3") 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.stackedWidget.addWidget(self.tablePage)
self.gridLayout_2.addWidget(self.stackedWidget, 0, 0, 1, 1) self.gridLayout_2.addWidget(self.stackedWidget, 0, 0, 1, 1)
self.tabWidget.addTab(self.tab, "") self.tabWidget.addTab(self.tab, "")

View File

@@ -94,26 +94,26 @@ def generate_pie(progress_percent, temp_dir=None):
return lSvg 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 current_chapter of -1 implies the files does not exist
# A chapter number == Total chapters implies the file is unread # position_percent and consider_read_at are expected as a <1 decimal value
return_pixmap = None
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_pixmap = QtGui.QIcon(':/images/error.svg').pixmap(size)
return return_pixmap 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) return_pixmap = QtGui.QIcon(':/images/checkmark.svg').pixmap(size)
else: else:
# TODO # TODO
# See if saving the svg to disk can be avoided # 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 # Maybe make the alignment a little more uniform across emblems
progress_percent = int(current_chapter * 100 / total_chapters) generate_pie(int(position_percent * 100), temp_dir)
generate_pie(progress_percent, temp_dir)
svg_path = os.path.join(temp_dir, 'lector_progress.svg') svg_path = os.path.join(temp_dir, 'lector_progress.svg')
return_pixmap = QtGui.QIcon(svg_path).pixmap(size - 4) ## The -4 looks more proportional 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"> <property name="spacing">
<number>0</number> <number>0</number>
</property> </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> </layout>
</widget> </widget>
<widget class="QWidget" name="tablePage"> <widget class="QWidget" name="tablePage">
@@ -114,43 +74,6 @@
<property name="spacing"> <property name="spacing">
<number>0</number> <number>0</number>
</property> </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> </layout>
</widget> </widget>
</widget> </widget>

View File

@@ -1,5 +1,20 @@
<RCC> <RCC>
<qresource prefix="images"> <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>Lector.png</file>
<file>DarkIcons/tableofcontents.svg</file> <file>DarkIcons/tableofcontents.svg</file>
<file>LightIcons/tableofcontents.svg</file> <file>LightIcons/tableofcontents.svg</file>
@@ -78,5 +93,6 @@
<file>translations_bin/Lector_es.qm</file> <file>translations_bin/Lector_es.qm</file>
<file>translations_bin/Lector_de.qm</file> <file>translations_bin/Lector_de.qm</file>
<file>translations_bin/Lector_fr.qm</file> <file>translations_bin/Lector_fr.qm</file>
<file>translations_bin/Lector_zh.qm</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@@ -6,110 +6,56 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>1216</width> <width>1119</width>
<height>658</height> <height>612</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Settings</string> <string>Settings</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_3"> <layout class="QGridLayout" name="gridLayout">
<item row="0" column="0"> <item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_2"> <widget class="QListView" name="listView">
<item> <property name="sizePolicy">
<widget class="QGroupBox" name="groupBox_2"> <sizepolicy hsizetype="Maximum" vsizetype="Expanding">
<property name="title"> <horstretch>0</horstretch>
<string>Library</string> <verstretch>0</verstretch>
</sizepolicy>
</property> </property>
<layout class="QGridLayout" name="gridLayout_2"> <property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QStackedWidget" name="stackedWidget">
<widget class="QWidget" name="treeViewPage">
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="0"> <item row="0" column="0">
<widget class="QTreeView" name="treeView"/> <widget class="QTreeView" name="treeView"/>
</item> </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> </layout>
</widget> </widget>
</item> <widget class="QWidget" name="switchPage">
<item> <layout class="QGridLayout" name="gridLayout_2">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Switches</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0"> <item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_4"> <widget class="QGroupBox" name="groupBox">
<item> <property name="title">
<widget class="QCheckBox" name="refreshLibrary"> <string>Library</string>
<property name="text">
<string>Startup: Refresh library</string>
</property> </property>
</widget> <layout class="QGridLayout" name="gridLayout_4">
</item> <item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item> <item>
<widget class="QCheckBox" name="fileRemember"> <layout class="QHBoxLayout" name="horizontalLayout_13">
<property name="text">
<string>Remember open files</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QCheckBox" name="performCulling"> <layout class="QHBoxLayout" name="horizontalLayout_14">
<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> <item>
<widget class="QCheckBox" name="coverShadows"> <widget class="QLabel" name="readAtLabel">
<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"> <property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred"> <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch> <horstretch>0</horstretch>
@@ -117,7 +63,7 @@
</sizepolicy> </sizepolicy>
</property> </property>
<property name="text"> <property name="text">
<string>Dictionary:</string> <string>Consider book read at percent</string>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
@@ -125,23 +71,19 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QComboBox" name="languageBox"/> <widget class="QSpinBox" name="readAtPercent">
<property name="minimum">
<number>90</number>
</property>
<property name="value">
<number>95</number>
</property>
</widget>
</item> </item>
</layout> </layout>
</item> </item>
<item> <item>
<widget class="QCheckBox" name="hideScrollBars"> <layout class="QHBoxLayout" name="horizontalLayout_7">
<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> <item>
<widget class="QLabel" name="label"> <widget class="QLabel" name="label">
<property name="toolTip"> <property name="toolTip">
@@ -158,7 +100,7 @@ Reopen book to see changes</string>
<string>Restart application to see changes</string> <string>Restart application to see changes</string>
</property> </property>
<property name="text"> <property name="text">
<string>Dar&amp;k</string> <string>&amp;Dark</string>
</property> </property>
</widget> </widget>
</item> </item>
@@ -168,7 +110,7 @@ Reopen book to see changes</string>
<string>Restart application to see changes</string> <string>Restart application to see changes</string>
</property> </property>
<property name="text"> <property name="text">
<string>&amp;Light</string> <string>L&amp;ight</string>
</property> </property>
</widget> </widget>
</item> </item>
@@ -176,13 +118,454 @@ Reopen book to see changes</string>
</item> </item>
</layout> </layout>
</item> </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> </layout>
</widget> </widget>
</item> </item>
</layout> </layout>
</item> </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"> <item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_2"> <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>
<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> <item>
<widget class="QPushButton" name="okButton"> <widget class="QPushButton" name="okButton">
<property name="text"> <property name="text">
@@ -197,15 +580,7 @@ Reopen book to see changes</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> </layout>
<widget class="QPushButton" name="aboutButton">
<property name="text">
<string>About</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item> </item>
</layout> </layout>
</item> </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): class Ui_Dialog(object):
def setupUi(self, Dialog): def setupUi(self, Dialog):
Dialog.setObjectName("Dialog") Dialog.setObjectName("Dialog")
Dialog.resize(1216, 658) Dialog.resize(1119, 612)
self.gridLayout_3 = QtWidgets.QGridLayout(Dialog) self.gridLayout = 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)
self.gridLayout.setObjectName("gridLayout") 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 = QtWidgets.QVBoxLayout()
self.verticalLayout.setObjectName("verticalLayout") 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 = QtWidgets.QHBoxLayout()
self.horizontalLayout_4.setObjectName("horizontalLayout_4") self.horizontalLayout_4.setObjectName("horizontalLayout_4")
self.refreshLibrary = QtWidgets.QCheckBox(self.groupBox) self.refreshLibrary = QtWidgets.QCheckBox(self.groupBox)
@@ -43,28 +87,47 @@ class Ui_Dialog(object):
self.fileRemember = QtWidgets.QCheckBox(self.groupBox) self.fileRemember = QtWidgets.QCheckBox(self.groupBox)
self.fileRemember.setObjectName("fileRemember") self.fileRemember.setObjectName("fileRemember")
self.horizontalLayout_4.addWidget(self.fileRemember) self.horizontalLayout_4.addWidget(self.fileRemember)
self.performCulling = QtWidgets.QCheckBox(self.groupBox) self.verticalLayout_2.addLayout(self.horizontalLayout_4)
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.horizontalLayout_3 = QtWidgets.QHBoxLayout() self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
self.horizontalLayout_3.setObjectName("horizontalLayout_3") 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 = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0) sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0) sizePolicy.setVerticalStretch(0)
@@ -72,70 +135,204 @@ class Ui_Dialog(object):
self.languageLabel.setSizePolicy(sizePolicy) self.languageLabel.setSizePolicy(sizePolicy)
self.languageLabel.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) self.languageLabel.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
self.languageLabel.setObjectName("languageLabel") self.languageLabel.setObjectName("languageLabel")
self.horizontalLayout_3.addWidget(self.languageLabel) self.horizontalLayout_5.addWidget(self.languageLabel)
self.languageBox = QtWidgets.QComboBox(self.groupBox) self.languageBox = QtWidgets.QComboBox(self.groupBox_2)
self.languageBox.setObjectName("languageBox") self.languageBox.setObjectName("languageBox")
self.horizontalLayout_3.addWidget(self.languageBox) self.horizontalLayout_5.addWidget(self.languageBox)
self.horizontalLayout_6.addLayout(self.horizontalLayout_3) self.horizontalLayout_8.addLayout(self.horizontalLayout_5)
self.hideScrollBars = QtWidgets.QCheckBox(self.groupBox) self.horizontalLayout = QtWidgets.QHBoxLayout()
self.hideScrollBars.setObjectName("hideScrollBars") self.horizontalLayout.setObjectName("horizontalLayout")
self.horizontalLayout_6.addWidget(self.hideScrollBars) self.scrollSpeedLabel = QtWidgets.QLabel(self.groupBox_2)
self.horizontalLayout_5 = QtWidgets.QHBoxLayout() sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred)
self.horizontalLayout_5.setObjectName("horizontalLayout_5") sizePolicy.setHorizontalStretch(0)
self.label = QtWidgets.QLabel(self.groupBox) sizePolicy.setVerticalStretch(0)
self.label.setObjectName("label") sizePolicy.setHeightForWidth(self.scrollSpeedLabel.sizePolicy().hasHeightForWidth())
self.horizontalLayout_5.addWidget(self.label) self.scrollSpeedLabel.setSizePolicy(sizePolicy)
self.darkIconsRadio = QtWidgets.QRadioButton(self.groupBox) self.scrollSpeedLabel.setObjectName("scrollSpeedLabel")
self.darkIconsRadio.setObjectName("darkIconsRadio") self.horizontalLayout.addWidget(self.scrollSpeedLabel)
self.horizontalLayout_5.addWidget(self.darkIconsRadio) self.scrollSpeedSlider = QtWidgets.QSlider(self.groupBox_2)
self.lightIconsRadio = QtWidgets.QRadioButton(self.groupBox) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
self.lightIconsRadio.setObjectName("lightIconsRadio") sizePolicy.setHorizontalStretch(0)
self.horizontalLayout_5.addWidget(self.lightIconsRadio) sizePolicy.setVerticalStretch(0)
self.horizontalLayout_6.addLayout(self.horizontalLayout_5) sizePolicy.setHeightForWidth(self.scrollSpeedSlider.sizePolicy().hasHeightForWidth())
self.gridLayout.addLayout(self.horizontalLayout_6, 2, 0, 1, 1) self.scrollSpeedSlider.setSizePolicy(sizePolicy)
self.verticalLayout_2.addWidget(self.groupBox) self.scrollSpeedSlider.setMinimum(3)
self.gridLayout_3.addLayout(self.verticalLayout_2, 0, 0, 1, 1) 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 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setObjectName("horizontalLayout_2") 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 = QtWidgets.QPushButton(Dialog)
self.okButton.setObjectName("okButton") self.okButton.setObjectName("okButton")
self.horizontalLayout_2.addWidget(self.okButton) self.horizontalLayout_10.addWidget(self.okButton)
self.cancelButton = QtWidgets.QPushButton(Dialog) self.cancelButton = QtWidgets.QPushButton(Dialog)
self.cancelButton.setObjectName("cancelButton") self.cancelButton.setObjectName("cancelButton")
self.horizontalLayout_2.addWidget(self.cancelButton) self.horizontalLayout_10.addWidget(self.cancelButton)
self.aboutButton = QtWidgets.QPushButton(Dialog) self.verticalLayout_4.addLayout(self.horizontalLayout_10)
self.aboutButton.setCheckable(True) self.gridLayout.addLayout(self.verticalLayout_4, 0, 1, 1, 1)
self.aboutButton.setObjectName("aboutButton")
self.horizontalLayout_2.addWidget(self.aboutButton)
self.gridLayout_3.addLayout(self.horizontalLayout_2, 1, 0, 1, 1)
self.retranslateUi(Dialog) self.retranslateUi(Dialog)
self.tabWidget.setCurrentIndex(0)
QtCore.QMetaObject.connectSlotsByName(Dialog) QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog): def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate _translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Settings")) Dialog.setWindowTitle(_translate("Dialog", "Settings"))
self.groupBox_2.setTitle(_translate("Dialog", "Library")) self.groupBox.setTitle(_translate("Dialog", "Library"))
self.groupBox.setTitle(_translate("Dialog", "Switches")) self.readAtLabel.setText(_translate("Dialog", "Consider book read at percent"))
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.label.setToolTip(_translate("Dialog", "Restart application to see changes")) self.label.setToolTip(_translate("Dialog", "Restart application to see changes"))
self.label.setText(_translate("Dialog", "Icon theme: ")) self.label.setText(_translate("Dialog", "Icon theme: "))
self.darkIconsRadio.setToolTip(_translate("Dialog", "Restart application to see changes")) 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.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.okButton.setText(_translate("Dialog", "Scan Library"))
self.cancelButton.setText(_translate("Dialog", "Close")) self.cancelButton.setText(_translate("Dialog", "Close"))
self.aboutButton.setText(_translate("Dialog", "About"))

View File

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

View File

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

View File

@@ -3,120 +3,135 @@
<context> <context>
<name>BookToolBar</name> <name>BookToolBar</name>
<message> <message>
<location filename="../../lector/toolbars.py" line="45"/> <location filename="../../toolbars.py" line="42"/>
<source>View settings</source> <source>View settings</source>
<translation>Options</translation> <translation>Options</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="49"/> <location filename="../../toolbars.py" line="48"/>
<source>Fullscreen</source> <source>Fullscreen</source>
<translation>Plein écran</translation> <translation type="obsolete">Plein écran</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="53"/> <location filename="../../toolbars.py" line="50"/>
<source>Add bookmark</source> <source>Add bookmark</source>
<translation>Ajouter un marque page</translation> <translation>Ajouter un marque page</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="57"/> <location filename="../../toolbars.py" line="56"/>
<source>Bookmarks</source> <source>Bookmarks</source>
<translation>Marque-pages</translation> <translation type="obsolete">Marque-pages</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="62"/> <location filename="../../toolbars.py" line="66"/>
<source>Reset profile</source> <source>Reset profile</source>
<translation>Réinitialiser le profil</translation> <translation>Réinitialiser le profil</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="83"/> <location filename="../../toolbars.py" line="91"/>
<source>Font size</source> <source>Font size</source>
<translation>Taille de la police</translation> <translation>Taille de la police</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="87"/> <location filename="../../toolbars.py" line="95"/>
<source>Increase padding</source> <source>Increase padding</source>
<translation>Augmenter la marge</translation> <translation>Augmenter la marge</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="92"/> <location filename="../../toolbars.py" line="100"/>
<source>Decrease padding</source> <source>Decrease padding</source>
<translation>Diminuer la marge</translation> <translation>Diminuer la marge</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="98"/> <location filename="../../toolbars.py" line="106"/>
<source>Increase line spacing</source> <source>Increase line spacing</source>
<translation>Augmenter l&apos;espacement des lignes</translation> <translation>Augmenter l&apos;espacement des lignes</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="103"/> <location filename="../../toolbars.py" line="111"/>
<source>Decrease line spacing</source> <source>Decrease line spacing</source>
<translation>Diminuer l&apos;espacement des lignes</translation> <translation>Diminuer l&apos;espacement des lignes</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="109"/> <location filename="../../toolbars.py" line="117"/>
<source>Left align text</source> <source>Left align text</source>
<translation>Aligner le texte à gauche</translation> <translation>Aligner le texte à gauche</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="116"/> <location filename="../../toolbars.py" line="124"/>
<source>Right align text</source> <source>Right align text</source>
<translation>Aligner le texte à droite</translation> <translation>Aligner le texte à droite</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="123"/> <location filename="../../toolbars.py" line="131"/>
<source>Center align text</source> <source>Center align text</source>
<translation>Centrer le texte</translation> <translation>Centrer le texte</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="130"/> <location filename="../../toolbars.py" line="138"/>
<source>Justify text</source> <source>Justify text</source>
<translation>Justifier le texte</translation> <translation>Justifier le texte</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="233"/> <location filename="../../toolbars.py" line="241"/>
<source>Background color</source> <source>Background color</source>
<translation>Couleur d&apos;arrière-plan</translation> <translation>Couleur d&apos;arrière-plan</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="202"/> <location filename="../../toolbars.py" line="210"/>
<source>Zoom in</source> <source>Zoom in</source>
<translation>Zoom avant</translation> <translation>Zoom avant</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="207"/> <location filename="../../toolbars.py" line="215"/>
<source>Zoom Out</source> <source>Zoom Out</source>
<translation>Zoom arrière</translation> <translation>Zoom arrière</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="213"/> <location filename="../../toolbars.py" line="221"/>
<source>Fit Width</source> <source>Fit Width</source>
<translation>Ajuster à la largeur</translation> <translation>Ajuster à la largeur</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="219"/> <location filename="../../toolbars.py" line="227"/>
<source>Best Fit</source> <source>Best Fit</source>
<translation>Meilleur ajustement</translation> <translation>Meilleur ajustement</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="225"/> <location filename="../../toolbars.py" line="233"/>
<source>Original size</source> <source>Original size</source>
<translation>Taille d&apos;origine</translation> <translation>Taille d&apos;origine</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="260"/> <location filename="../../toolbars.py" line="268"/>
<source>Search...</source> <source>Search...</source>
<translation>Rechercher</translation> <translation>Rechercher</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="269"/> <location filename="../../toolbars.py" line="277"/>
<source>Table of Contents</source> <source>Table of Contents</source>
<translation>Sommaire</translation> <translation>Sommaire</translation>
</message> </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>
<context> <context>
<name>DefinitionsUI</name> <name>DefinitionsUI</name>
<message> <message>
<location filename="../../lector/definitionsdialog.py" line="117"/> <location filename="../../definitionsdialog.py" line="125"/>
<source>No definitions found in</source> <source>No definitions found in</source>
<translation>Aucune définitions trouvées dans</translation> <translation>Aucune définitions trouvées dans</translation>
</message> </message>
@@ -139,62 +154,62 @@
<translation>Lire la prononciation de la racine</translation> <translation>Lire la prononciation de la racine</translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="117"/> <location filename="../settingswindow.py" line="305"/>
<source>Settings</source> <source>Settings</source>
<translation>Options</translation> <translation>Options</translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="118"/> <location filename="../settingswindow.py" line="306"/>
<source>Library</source> <source>Library</source>
<translation>Bibliothèque</translation> <translation>Bibliothèque</translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="119"/> <location filename="../settingswindow.py" line="119"/>
<source>Switches</source> <source>Switches</source>
<translation>Options</translation> <translation type="obsolete">Options</translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="120"/> <location filename="../settingswindow.py" line="314"/>
<source>Startup: Refresh library</source> <source>Startup: Refresh library</source>
<translation>Au démarrage: Rafraîchir la bibliothèque</translation> <translation>Au démarrage: Rafraîchir la bibliothèque</translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="121"/> <location filename="../settingswindow.py" line="315"/>
<source>Remember open files</source> <source>Remember open files</source>
<translation>Se souvenir des fichiers ouverts</translation> <translation>Se souvenir des fichiers ouverts</translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="125"/> <location filename="../settingswindow.py" line="319"/>
<source>Generate tags from files</source> <source>Generate tags from files</source>
<translation>Générer des étiquettes à partir des fichiers</translation> <translation>Générer des étiquettes à partir des fichiers</translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="128"/> <location filename="../settingswindow.py" line="128"/>
<source>Dictionary:</source> <source>Dictionary:</source>
<translation>Dictionnaire:</translation> <translation type="obsolete">Dictionnaire:</translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="124"/> <location filename="../settingswindow.py" line="316"/>
<source>Cover shadows</source> <source>Cover shadows</source>
<translation>Ombres des couverture</translation> <translation>Ombres des couverture</translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="122"/> <location filename="../settingswindow.py" line="317"/>
<source>Enabling reduces startup time and memory usage</source> <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> <translation>Si activé, réduit le temps de chargement et l&apos;utilisation de la mémoire</translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="123"/> <location filename="../settingswindow.py" line="318"/>
<source>Load covers only when needed</source> <source>Load covers only when needed</source>
<translation>Charger les couvertures seulement quand nécessaire</translation> <translation>Charger les couvertures seulement quand nécessaire</translation>
</message> </message>
<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> <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> <translation>Réduit grandement le temps de transition des pages contre plus d&apos;utilisation de la mémoire</translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="127"/> <location filename="../settingswindow.py" line="326"/>
<source>Cache comic / pdf pages</source> <source>Cache comic / pdf pages</source>
<translation>Mettre en cache les pages de bande dessinée / pdf</translation> <translation>Mettre en cache les pages de bande dessinée / pdf</translation>
</message> </message>
@@ -204,34 +219,34 @@
<translation type="obsolete">Redémarrer pour voir les modifications</translation> <translation type="obsolete">Redémarrer pour voir les modifications</translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="133"/> <location filename="../settingswindow.py" line="309"/>
<source>Icon theme: </source> <source>Icon theme: </source>
<translation>Thème d&apos;icones: </translation> <translation>Thème d&apos;icones: </translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="135"/> <location filename="../settingswindow.py" line="135"/>
<source>Dar&amp;k</source> <source>Dar&amp;k</source>
<translation>Som&amp;bre</translation> <translation type="obsolete">Som&amp;bre</translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="137"/> <location filename="../settingswindow.py" line="137"/>
<source>&amp;Light</source> <source>&amp;Light</source>
<translation>C&amp;lair</translation> <translation type="obsolete">C&amp;lair</translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="138"/> <location filename="../settingswindow.py" line="336"/>
<source>Scan Library</source> <source>Scan Library</source>
<translation>Analyser la bibliothèque</translation> <translation>Analyser la bibliothèque</translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="139"/> <location filename="../settingswindow.py" line="337"/>
<source>Close</source> <source>Close</source>
<translation>Fermer</translation> <translation>Fermer</translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="140"/> <location filename="../settingswindow.py" line="140"/>
<source>About</source> <source>About</source>
<translation>À propos</translation> <translation type="obsolete">À propos</translation>
</message> </message>
<message> <message>
<location filename="../metadata.py" line="88"/> <location filename="../metadata.py" line="88"/>
@@ -279,41 +294,111 @@
<translation>Annuler</translation> <translation>Annuler</translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="129"/> <location filename="../settingswindow.py" line="322"/>
<source>Horizontal scrolling with Alt + Scroll <source>Horizontal scrolling with Alt + Scroll
Reopen book to see changes</source> Reopen book to see changes</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="131"/> <location filename="../settingswindow.py" line="324"/>
<source>Hide scrollbars when reading</source> <source>Hide scrollbars when reading</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="136"/> <location filename="../settingswindow.py" line="312"/>
<source>Restart application to see changes</source> <source>Restart application to see changes</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </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>
<context> <context>
<name>Library</name> <name>Library</name>
<message> <message>
<location filename="../../lector/library.py" line="130"/> <location filename="../../library.py" line="133"/>
<source>Author</source> <source>Author</source>
<translation>Auteur</translation> <translation>Auteur</translation>
</message> </message>
<message> <message>
<location filename="../../lector/library.py" line="131"/> <location filename="../../library.py" line="134"/>
<source>Year</source> <source>Year</source>
<translation>Année</translation> <translation>Année</translation>
</message> </message>
<message> <message>
<location filename="../../lector/library.py" line="282"/> <location filename="../../library.py" line="292"/>
<source>manually added</source> <source>manually added</source>
<translation>manuellement ajouté</translation> <translation>manuellement ajouté</translation>
</message> </message>
<message> <message>
<location filename="../../lector/library.py" line="209"/> <location filename="../../library.py" line="215"/>
<source> books</source> <source> books</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@@ -321,148 +406,191 @@ Reopen book to see changes</source>
<context> <context>
<name>LibraryToolBar</name> <name>LibraryToolBar</name>
<message> <message>
<location filename="../../lector/toolbars.py" line="349"/> <location filename="../../toolbars.py" line="360"/>
<source>Add book</source> <source>Add book</source>
<translation>Ajouter un livre</translation> <translation>Ajouter un livre</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="353"/> <location filename="../../toolbars.py" line="364"/>
<source>Delete book</source> <source>Delete book</source>
<translation>Supprimer un livre</translation> <translation>Supprimer un livre</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="357"/> <location filename="../../toolbars.py" line="368"/>
<source>Library background color</source> <source>Library background color</source>
<translation>Couleur d&apos;arrière-plan de la bibliothèque</translation> <translation>Couleur d&apos;arrière-plan de la bibliothèque</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="362"/> <location filename="../../toolbars.py" line="373"/>
<source>Settings</source> <source>Settings</source>
<translation>Options</translation> <translation>Options</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="368"/> <location filename="../../toolbars.py" line="379"/>
<source>View as covers</source> <source>View as covers</source>
<translation>Vue par couvertures</translation> <translation>Vue par couvertures</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="373"/> <location filename="../../toolbars.py" line="384"/>
<source>View as table</source> <source>View as table</source>
<translation>Vue par table</translation> <translation>Vue par table</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="383"/> <location filename="../../toolbars.py" line="399"/>
<source>Filter library</source> <source>Filter library</source>
<translation>Filtrer la bibliothèque</translation> <translation>Filtrer la bibliothèque</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="410"/> <location filename="../../toolbars.py" line="427"/>
<source>Search for Title, Author, Tags...</source> <source>Search for Title, Author, Tags...</source>
<translation>Rechercher par Titre, Auteur, Étiquettes</translation> <translation>Rechercher par Titre, Auteur, Étiquettes</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="430"/> <location filename="../../toolbars.py" line="449"/>
<source>Sort by</source> <source>Sort by</source>
<translation>Trier par</translation> <translation>Trier par</translation>
</message> </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>
<context> <context>
<name>MainWindow</name> <name>MainWindow</name>
<message> <message>
<location filename="../mainwindow.py" line="95"/> <location filename="../mainwindow.py" line="67"/>
<source>Lector</source> <source>Lector</source>
<translation>Lector</translation> <translation>Lector</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.py" line="96"/> <location filename="../mainwindow.py" line="68"/>
<source>Library</source> <source>Library</source>
<translation>Bibliothèque</translation> <translation>Bibliothèque</translation>
</message> </message>
</context> </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> <context>
<name>Main_UI</name> <name>Main_UI</name>
<message> <message>
<location filename="../../lector/__main__.py" line="114"/> <location filename="../../__main__.py" line="119"/>
<source>Toggle distraction free mode (Ctrl + D)</source> <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>
<message> <message>
<location filename="../../lector/__main__.py" line="211"/> <location filename="../../__main__.py" line="216"/>
<source>Scan library</source> <source>Scan library</source>
<translation>Analyser la bibliothèque</translation> <translation type="obsolete">Analyser la bibliothèque</translation>
</message> </message>
<message> <message>
<location filename="../../lector/__main__.py" line="463"/> <location filename="../../__main__.py" line="471"/>
<source>Add books to database</source> <source>Add books to database</source>
<translation>Ajouter des livres à la base de données</translation> <translation>Ajouter des livres à la base de données</translation>
</message> </message>
<message> <message>
<location filename="../../lector/__main__.py" line="464"/> <location filename="../../__main__.py" line="472"/>
<source>eBooks</source> <source>eBooks</source>
<translation>eBooks</translation> <translation>eBooks</translation>
</message> </message>
<message> <message>
<location filename="../../lector/__main__.py" line="477"/> <location filename="../../__main__.py" line="486"/>
<source>Adding books...</source> <source>Adding books...</source>
<translation>Ajout des livres</translation> <translation>Ajout des livres</translation>
</message> </message>
<message> <message>
<location filename="../../lector/__main__.py" line="540"/> <location filename="../../__main__.py" line="549"/>
<source>Confirm deletion</source> <source>Confirm deletion</source>
<translation>Confirmez la suppression</translation> <translation>Confirmez la suppression</translation>
</message> </message>
<message> <message>
<location filename="../../lector/__main__.py" line="553"/> <location filename="../../__main__.py" line="562"/>
<source>Save changes and start library scan</source> <source>Save changes and start library scan</source>
<translation>Enregistrer les modifications et démarrer l&apos;analyse de la bibliothèque</translation> <translation>Enregistrer les modifications et démarrer l&apos;analyse de la bibliothèque</translation>
</message> </message>
<message> <message>
<location filename="../../lector/__main__.py" line="601"/> <location filename="../../__main__.py" line="618"/>
<source> Books</source> <source> Books</source>
<translation> Livres</translation> <translation> Livres</translation>
</message> </message>
<message> <message>
<location filename="../../lector/__main__.py" line="1028"/> <location filename="../../__main__.py" line="762"/>
<source>Start reading</source> <source>Start reading</source>
<translation>Commencer à lire</translation> <translation>Commencer à lire</translation>
</message> </message>
<message> <message>
<location filename="../../lector/__main__.py" line="1034"/> <location filename="../../__main__.py" line="768"/>
<source>Edit</source> <source>Edit</source>
<translation>Modifier</translation> <translation>Modifier</translation>
</message> </message>
<message> <message>
<location filename="../../lector/__main__.py" line="1038"/> <location filename="../../__main__.py" line="772"/>
<source>Delete</source> <source>Delete</source>
<translation>Supprimer</translation> <translation>Supprimer</translation>
</message> </message>
<message> <message>
<location filename="../../lector/__main__.py" line="1041"/> <location filename="../../__main__.py" line="775"/>
<source>Mark read</source> <source>Mark read</source>
<translation>Marquer comme lu</translation> <translation>Marquer comme lu</translation>
</message> </message>
<message> <message>
<location filename="../../lector/__main__.py" line="1044"/> <location filename="../../__main__.py" line="778"/>
<source>Mark unread</source> <source>Mark unread</source>
<translation>Marquer comme non-lu</translation> <translation>Marquer comme non-lu</translation>
</message> </message>
<message> <message>
<location filename="../../lector/__main__.py" line="1144"/> <location filename="../../__main__.py" line="878"/>
<source>Manually Added</source> <source>Manually Added</source>
<translation>Manuellement ajouté</translation> <translation>Manuellement ajouté</translation>
</message> </message>
<message> <message>
<location filename="../../lector/widgets.py" line="747"/> <location filename="../../widgets.py" line="747"/>
<source>Save page as...</source> <source>Save page as...</source>
<translation type="unfinished">Enregistrerla page sous</translation> <translation type="obsolete">Enregistrerla page sous</translation>
</message> </message>
<message> <message>
<location filename="../../lector/widgets.py" line="748"/> <location filename="../../widgets.py" line="748"/>
<source>Images</source> <source>Images</source>
<translation type="unfinished">Images</translation> <translation type="obsolete">Images</translation>
</message> </message>
<message> <message>
<location filename="../../lector/__main__.py" line="563"/> <location filename="../../__main__.py" line="575"/>
<source> books</source> <source> books</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@@ -470,12 +598,12 @@ Reopen book to see changes</source>
<context> <context>
<name>MetadataUI</name> <name>MetadataUI</name>
<message> <message>
<location filename="../../lector/metadatadialog.py" line="101"/> <location filename="../../metadatadialog.py" line="102"/>
<source>Author</source> <source>Author</source>
<translation>Auteur</translation> <translation>Auteur</translation>
</message> </message>
<message> <message>
<location filename="../../lector/metadatadialog.py" line="102"/> <location filename="../../metadatadialog.py" line="103"/>
<source>Year</source> <source>Year</source>
<translation>Année</translation> <translation>Année</translation>
</message> </message>
@@ -483,12 +611,12 @@ Reopen book to see changes</source>
<context> <context>
<name>PliantQGraphicsScene</name> <name>PliantQGraphicsScene</name>
<message> <message>
<location filename="../../lector/widgets.py" line="1002"/> <location filename="../../widgets.py" line="647"/>
<source>Select new cover</source> <source>Select new cover</source>
<translation>Choisissez une nouvelle couverture</translation> <translation>Choisissez une nouvelle couverture</translation>
</message> </message>
<message> <message>
<location filename="../../lector/widgets.py" line="1003"/> <location filename="../../widgets.py" line="648"/>
<source>Images</source> <source>Images</source>
<translation>Images</translation> <translation>Images</translation>
</message> </message>
@@ -496,181 +624,181 @@ Reopen book to see changes</source>
<context> <context>
<name>PliantQGraphicsView</name> <name>PliantQGraphicsView</name>
<message> <message>
<location filename="../../lector/widgets.py" line="695"/> <location filename="../../widgets.py" line="695"/>
<source>Save page as...</source> <source>Save page as...</source>
<translation>Enregistrerla page sous</translation> <translation type="obsolete">Enregistrerla page sous</translation>
</message> </message>
<message> <message>
<location filename="../../lector/widgets.py" line="721"/> <location filename="../../widgets.py" line="721"/>
<source>Zoom in (+)</source> <source>Zoom in (+)</source>
<translation>Zoom avant (+)</translation> <translation type="obsolete">Zoom avant (+)</translation>
</message> </message>
<message> <message>
<location filename="../../lector/widgets.py" line="725"/> <location filename="../../widgets.py" line="725"/>
<source>Zoom out (-)</source> <source>Zoom out (-)</source>
<translation>Zoom arrière (-)</translation> <translation type="obsolete">Zoom arrière (-)</translation>
</message> </message>
<message> <message>
<location filename="../../lector/widgets.py" line="729"/> <location filename="../../widgets.py" line="729"/>
<source>Fit width (W)</source> <source>Fit width (W)</source>
<translation>Ajuster à la largeur (W)</translation> <translation type="obsolete">Ajuster à la largeur (W)</translation>
</message> </message>
<message> <message>
<location filename="../../lector/widgets.py" line="733"/> <location filename="../../widgets.py" line="733"/>
<source>Best fit (B)</source> <source>Best fit (B)</source>
<translation>Meilleur ajustement (B)</translation> <translation type="obsolete">Meilleur ajustement (B)</translation>
</message> </message>
<message> <message>
<location filename="../../lector/widgets.py" line="737"/> <location filename="../../widgets.py" line="737"/>
<source>Original size (O)</source> <source>Original size (O)</source>
<translation>Taille d&apos;origine (O)</translation> <translation type="obsolete">Taille d&apos;origine (O)</translation>
</message> </message>
<message> <message>
<location filename="../../lector/widgets.py" line="685"/> <location filename="../../lector/widgets.py" line="685"/>
<source>Toggle distraction free mode</source> <source>Toggle distraction free mode</source>
<translation type="obsolete">Basculer en mode sans distraction</translation> <translation type="obsolete">Basculer en mode sans distraction</translation>
</message> </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>
<context> <context>
<name>PliantQTextBrowser</name> <name>PliantQTextBrowser</name>
<message> <message>
<location filename="../../lector/widgets.py" line="848"/> <location filename="../../widgets.py" line="848"/>
<source>Define</source> <source>Define</source>
<translation>Définir</translation> <translation type="obsolete">Définir</translation>
</message> </message>
<message> <message>
<location filename="../../lector/widgets.py" line="853"/> <location filename="../../widgets.py" line="853"/>
<source>Search</source> <source>Search</source>
<translation>Rechercher</translation> <translation type="obsolete">Rechercher</translation>
</message> </message>
<message> <message>
<location filename="../../lector/widgets.py" line="827"/> <location filename="../../lector/widgets.py" line="827"/>
<source>Toggle distraction free mode</source> <source>Toggle distraction free mode</source>
<translation type="obsolete">Basculer en mode sans distraction</translation> <translation type="obsolete">Basculer en mode sans distraction</translation>
</message> </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>
<context> <context>
<name>SettingsUI</name> <name>SettingsUI</name>
<message> <message>
<location filename="../../lector/settingsdialog.py" line="58"/> <location filename="../../settingsdialog.py" line="62"/>
<source>English</source> <source>English</source>
<translation>Anglais</translation> <translation>Anglais</translation>
</message> </message>
<message> <message>
<location filename="../../lector/settingsdialog.py" line="59"/> <location filename="../../settingsdialog.py" line="63"/>
<source>Spanish</source> <source>Spanish</source>
<translation>Espagnol</translation> <translation>Espagnol</translation>
</message> </message>
<message> <message>
<location filename="../../lector/settingsdialog.py" line="60"/> <location filename="../../settingsdialog.py" line="64"/>
<source>Hindi</source> <source>Hindi</source>
<translation>Hindi</translation> <translation>Hindi</translation>
</message> </message>
<message> <message>
<location filename="../../lector/settingsdialog.py" line="73"/> <location filename="../../settingsdialog.py" line="77"/>
<source>Save changes and start library scan</source> <source>Save changes and start library scan</source>
<translation>Enregistrer les modifications et démarrer l&apos;analyse de la bibliothèque</translation> <translation>Enregistrer les modifications et démarrer l&apos;analyse de la bibliothèque</translation>
</message> </message>
<message> <message>
<location filename="../../lector/settingsdialog.py" line="213"/> <location filename="../../settingsdialog.py" line="280"/>
<source>Library scan in progress...</source> <source>Library scan in progress...</source>
<translation>Analyse de la bibliothèque en cours</translation> <translation>Analyse de la bibliothèque en cours</translation>
</message> </message>
<message> <message>
<location filename="../../lector/settingsdialog.py" line="217"/> <location filename="../../settingsdialog.py" line="284"/>
<source>Checking library folders</source> <source>Checking library folders</source>
<translation>Vérification des dossiers de la bibliothèque</translation> <translation>Vérification des dossiers de la bibliothèque</translation>
</message> </message>
<message> <message>
<location filename="../../lector/settingsdialog.py" line="232"/> <location filename="../../settingsdialog.py" line="300"/>
<source>Parsing files</source> <source>Parsing files</source>
<translation>Lecture des fichiers</translation> <translation>Lecture des fichiers</translation>
</message> </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>
<context> <context>
<name>Tab</name> <name>Tab</name>
<message> <message>
<location filename="../../lector/widgets.py" line="130"/> <location filename="../../widgets.py" line="154"/>
<source>Bookmarks</source> <source>Bookmarks</source>
<translation>Marque-pages</translation> <translation>Marque-pages</translation>
</message> </message>
<message> <message>
<location filename="../../lector/widgets.py" line="391"/> <location filename="../../widgets.py" line="458"/>
<source>New bookmark</source> <source>New bookmark</source>
<translation>Nouveau marque-page</translation> <translation>Nouveau marque-page</translation>
</message> </message>
<message> <message>
<location filename="../../lector/widgets.py" line="463"/> <location filename="../../widgets.py" line="537"/>
<source>Edit</source> <source>Edit</source>
<translation>Modifier</translation> <translation>Modifier</translation>
</message> </message>
<message> <message>
<location filename="../../lector/widgets.py" line="466"/> <location filename="../../widgets.py" line="540"/>
<source>Delete</source> <source>Delete</source>
<translation>Supprimer</translation> <translation>Supprimer</translation>
</message> </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>
<context> <context>
<name>TableProxyModel</name> <name>TableProxyModel</name>
<message> <message>
<location filename="../../lector/toolbars.py" line="417"/> <location filename="../../models.py" line="72"/>
<source>Title</source> <source>Title</source>
<translation>Titre</translation> <translation>Titre</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="418"/> <location filename="../../models.py" line="73"/>
<source>Author</source> <source>Author</source>
<translation>Auteur</translation> <translation>Auteur</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="419"/> <location filename="../../models.py" line="74"/>
<source>Year</source> <source>Year</source>
<translation>Année</translation> <translation>Année</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="421"/> <location filename="../../models.py" line="75"/>
<source>Last Read</source> <source>Last Read</source>
<translation>Lu pour la dernière fois</translation> <translation>Lu pour la dernière fois</translation>
</message> </message>
<message> <message>
<location filename="../../lector/models.py" line="77"/> <location filename="../../models.py" line="76"/>
<source>Tags</source> <source>Tags</source>
<translation>Étiquettes</translation> <translation>Étiquettes</translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="420"/> <location filename="../../toolbars.py" line="419"/>
<source>Newest</source> <source>Newest</source>
<translation>Nouveau</translation> <translation type="obsolete">Nouveau</translation>
</message> </message>
</context> </context>
</TS> </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> <context>
<name>BookToolBar</name> <name>BookToolBar</name>
<message> <message>
<location filename="../../lector/toolbars.py" line="45"/> <location filename="../../toolbars.py" line="42"/>
<source>View settings</source> <source>View settings</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="49"/> <location filename="../../toolbars.py" line="50"/>
<source>Fullscreen</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="53"/>
<source>Add bookmark</source> <source>Add bookmark</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="57"/> <location filename="../../toolbars.py" line="66"/>
<source>Bookmarks</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../lector/toolbars.py" line="62"/>
<source>Reset profile</source> <source>Reset profile</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="83"/> <location filename="../../toolbars.py" line="91"/>
<source>Font size</source> <source>Font size</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="87"/> <location filename="../../toolbars.py" line="95"/>
<source>Increase padding</source> <source>Increase padding</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="92"/> <location filename="../../toolbars.py" line="100"/>
<source>Decrease padding</source> <source>Decrease padding</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="98"/> <location filename="../../toolbars.py" line="106"/>
<source>Increase line spacing</source> <source>Increase line spacing</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="103"/> <location filename="../../toolbars.py" line="111"/>
<source>Decrease line spacing</source> <source>Decrease line spacing</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="109"/> <location filename="../../toolbars.py" line="117"/>
<source>Left align text</source> <source>Left align text</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="116"/> <location filename="../../toolbars.py" line="124"/>
<source>Right align text</source> <source>Right align text</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="123"/> <location filename="../../toolbars.py" line="131"/>
<source>Center align text</source> <source>Center align text</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="130"/> <location filename="../../toolbars.py" line="138"/>
<source>Justify text</source> <source>Justify text</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="233"/> <location filename="../../toolbars.py" line="241"/>
<source>Background color</source> <source>Background color</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="202"/> <location filename="../../toolbars.py" line="210"/>
<source>Zoom in</source> <source>Zoom in</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="207"/> <location filename="../../toolbars.py" line="215"/>
<source>Zoom Out</source> <source>Zoom Out</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="213"/> <location filename="../../toolbars.py" line="221"/>
<source>Fit Width</source> <source>Fit Width</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="219"/> <location filename="../../toolbars.py" line="227"/>
<source>Best Fit</source> <source>Best Fit</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="225"/> <location filename="../../toolbars.py" line="233"/>
<source>Original size</source> <source>Original size</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="260"/> <location filename="../../toolbars.py" line="268"/>
<source>Search...</source> <source>Search...</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="269"/> <location filename="../../toolbars.py" line="277"/>
<source>Table of Contents</source> <source>Table of Contents</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </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>
<context> <context>
<name>DefinitionsUI</name> <name>DefinitionsUI</name>
<message> <message>
<location filename="../../lector/definitionsdialog.py" line="117"/> <location filename="../../definitionsdialog.py" line="125"/>
<source>No definitions found in</source> <source>No definitions found in</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@@ -139,95 +144,70 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="117"/> <location filename="../settingswindow.py" line="305"/>
<source>Settings</source> <source>Settings</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="118"/> <location filename="../settingswindow.py" line="306"/>
<source>Library</source> <source>Library</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="119"/> <location filename="../settingswindow.py" line="314"/>
<source>Switches</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="120"/>
<source>Startup: Refresh library</source> <source>Startup: Refresh library</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="121"/> <location filename="../settingswindow.py" line="315"/>
<source>Remember open files</source> <source>Remember open files</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="125"/> <location filename="../settingswindow.py" line="319"/>
<source>Generate tags from files</source> <source>Generate tags from files</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="128"/> <location filename="../settingswindow.py" line="316"/>
<source>Dictionary:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingswindow.py" line="124"/>
<source>Cover shadows</source> <source>Cover shadows</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="122"/> <location filename="../settingswindow.py" line="317"/>
<source>Enabling reduces startup time and memory usage</source> <source>Enabling reduces startup time and memory usage</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="123"/> <location filename="../settingswindow.py" line="318"/>
<source>Load covers only when needed</source> <source>Load covers only when needed</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<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> <source>Greatly reduces page transition time at the cost of more memory</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="127"/> <location filename="../settingswindow.py" line="326"/>
<source>Cache comic / pdf pages</source> <source>Cache comic / pdf pages</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="133"/> <location filename="../settingswindow.py" line="309"/>
<source>Icon theme: </source> <source>Icon theme: </source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="135"/> <location filename="../settingswindow.py" line="336"/>
<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"/>
<source>Scan Library</source> <source>Scan Library</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="139"/> <location filename="../settingswindow.py" line="337"/>
<source>Close</source> <source>Close</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<location filename="../settingswindow.py" line="140"/>
<source>About</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<location filename="../metadata.py" line="88"/> <location filename="../metadata.py" line="88"/>
<source>Edit metadata</source> <source>Edit metadata</source>
@@ -274,41 +254,111 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="129"/> <location filename="../settingswindow.py" line="322"/>
<source>Horizontal scrolling with Alt + Scroll <source>Horizontal scrolling with Alt + Scroll
Reopen book to see changes</source> Reopen book to see changes</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="131"/> <location filename="../settingswindow.py" line="324"/>
<source>Hide scrollbars when reading</source> <source>Hide scrollbars when reading</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../settingswindow.py" line="136"/> <location filename="../settingswindow.py" line="312"/>
<source>Restart application to see changes</source> <source>Restart application to see changes</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </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>
<context> <context>
<name>Library</name> <name>Library</name>
<message> <message>
<location filename="../../lector/library.py" line="130"/> <location filename="../../library.py" line="133"/>
<source>Author</source> <source>Author</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/library.py" line="131"/> <location filename="../../library.py" line="134"/>
<source>Year</source> <source>Year</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/library.py" line="282"/> <location filename="../../library.py" line="292"/>
<source>manually added</source> <source>manually added</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/library.py" line="209"/> <location filename="../../library.py" line="215"/>
<source> books</source> <source> books</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@@ -316,148 +366,171 @@ Reopen book to see changes</source>
<context> <context>
<name>LibraryToolBar</name> <name>LibraryToolBar</name>
<message> <message>
<location filename="../../lector/toolbars.py" line="349"/> <location filename="../../toolbars.py" line="360"/>
<source>Add book</source> <source>Add book</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="353"/> <location filename="../../toolbars.py" line="364"/>
<source>Delete book</source> <source>Delete book</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="357"/> <location filename="../../toolbars.py" line="368"/>
<source>Library background color</source> <source>Library background color</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="362"/> <location filename="../../toolbars.py" line="373"/>
<source>Settings</source> <source>Settings</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="368"/> <location filename="../../toolbars.py" line="379"/>
<source>View as covers</source> <source>View as covers</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="373"/> <location filename="../../toolbars.py" line="384"/>
<source>View as table</source> <source>View as table</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="383"/> <location filename="../../toolbars.py" line="399"/>
<source>Filter library</source> <source>Filter library</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="410"/> <location filename="../../toolbars.py" line="427"/>
<source>Search for Title, Author, Tags...</source> <source>Search for Title, Author, Tags...</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="430"/> <location filename="../../toolbars.py" line="449"/>
<source>Sort by</source> <source>Sort by</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </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>
<context> <context>
<name>MainWindow</name> <name>MainWindow</name>
<message> <message>
<location filename="../mainwindow.py" line="95"/> <location filename="../mainwindow.py" line="67"/>
<source>Lector</source> <source>Lector</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.py" line="96"/> <location filename="../mainwindow.py" line="68"/>
<source>Library</source> <source>Library</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </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> <context>
<name>Main_UI</name> <name>Main_UI</name>
<message> <message>
<location filename="../../lector/__main__.py" line="114"/> <location filename="../../__main__.py" line="471"/>
<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"/>
<source>Add books to database</source> <source>Add books to database</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/__main__.py" line="464"/> <location filename="../../__main__.py" line="472"/>
<source>eBooks</source> <source>eBooks</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/__main__.py" line="477"/> <location filename="../../__main__.py" line="486"/>
<source>Adding books...</source> <source>Adding books...</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/__main__.py" line="540"/> <location filename="../../__main__.py" line="549"/>
<source>Confirm deletion</source> <source>Confirm deletion</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/__main__.py" line="553"/> <location filename="../../__main__.py" line="562"/>
<source>Save changes and start library scan</source> <source>Save changes and start library scan</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/__main__.py" line="601"/> <location filename="../../__main__.py" line="618"/>
<source> Books</source> <source> Books</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/__main__.py" line="1028"/> <location filename="../../__main__.py" line="762"/>
<source>Start reading</source> <source>Start reading</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/__main__.py" line="1034"/> <location filename="../../__main__.py" line="768"/>
<source>Edit</source> <source>Edit</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/__main__.py" line="1038"/> <location filename="../../__main__.py" line="772"/>
<source>Delete</source> <source>Delete</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/__main__.py" line="1041"/> <location filename="../../__main__.py" line="775"/>
<source>Mark read</source> <source>Mark read</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/__main__.py" line="1044"/> <location filename="../../__main__.py" line="778"/>
<source>Mark unread</source> <source>Mark unread</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/__main__.py" line="1144"/> <location filename="../../__main__.py" line="878"/>
<source>Manually Added</source> <source>Manually Added</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/widgets.py" line="747"/> <location filename="../../__main__.py" line="575"/>
<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"/>
<source> books</source> <source> books</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@@ -465,12 +538,12 @@ Reopen book to see changes</source>
<context> <context>
<name>MetadataUI</name> <name>MetadataUI</name>
<message> <message>
<location filename="../../lector/metadatadialog.py" line="101"/> <location filename="../../metadatadialog.py" line="102"/>
<source>Author</source> <source>Author</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/metadatadialog.py" line="102"/> <location filename="../../metadatadialog.py" line="103"/>
<source>Year</source> <source>Year</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@@ -478,184 +551,133 @@ Reopen book to see changes</source>
<context> <context>
<name>PliantQGraphicsScene</name> <name>PliantQGraphicsScene</name>
<message> <message>
<location filename="../../lector/widgets.py" line="1002"/> <location filename="../../widgets.py" line="647"/>
<source>Select new cover</source> <source>Select new cover</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/widgets.py" line="1003"/> <location filename="../../widgets.py" line="648"/>
<source>Images</source> <source>Images</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </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> <context>
<name>SettingsUI</name> <name>SettingsUI</name>
<message> <message>
<location filename="../../lector/settingsdialog.py" line="58"/> <location filename="../../settingsdialog.py" line="62"/>
<source>English</source> <source>English</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/settingsdialog.py" line="59"/> <location filename="../../settingsdialog.py" line="63"/>
<source>Spanish</source> <source>Spanish</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/settingsdialog.py" line="60"/> <location filename="../../settingsdialog.py" line="64"/>
<source>Hindi</source> <source>Hindi</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/settingsdialog.py" line="73"/> <location filename="../../settingsdialog.py" line="77"/>
<source>Save changes and start library scan</source> <source>Save changes and start library scan</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/settingsdialog.py" line="213"/> <location filename="../../settingsdialog.py" line="280"/>
<source>Library scan in progress...</source> <source>Library scan in progress...</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/settingsdialog.py" line="217"/> <location filename="../../settingsdialog.py" line="284"/>
<source>Checking library folders</source> <source>Checking library folders</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/settingsdialog.py" line="232"/> <location filename="../../settingsdialog.py" line="300"/>
<source>Parsing files</source> <source>Parsing files</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </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>
<context> <context>
<name>Tab</name> <name>Tab</name>
<message> <message>
<location filename="../../lector/widgets.py" line="130"/> <location filename="../../widgets.py" line="154"/>
<source>Bookmarks</source> <source>Bookmarks</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/widgets.py" line="391"/> <location filename="../../widgets.py" line="458"/>
<source>New bookmark</source> <source>New bookmark</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/widgets.py" line="463"/> <location filename="../../widgets.py" line="537"/>
<source>Edit</source> <source>Edit</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/widgets.py" line="466"/> <location filename="../../widgets.py" line="540"/>
<source>Delete</source> <source>Delete</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </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>
<context> <context>
<name>TableProxyModel</name> <name>TableProxyModel</name>
<message> <message>
<location filename="../../lector/toolbars.py" line="417"/> <location filename="../../models.py" line="72"/>
<source>Title</source> <source>Title</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="418"/> <location filename="../../models.py" line="73"/>
<source>Author</source> <source>Author</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="419"/> <location filename="../../models.py" line="74"/>
<source>Year</source> <source>Year</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/toolbars.py" line="421"/> <location filename="../../models.py" line="75"/>
<source>Last Read</source> <source>Last Read</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../lector/models.py" line="77"/> <location filename="../../models.py" line="76"/>
<source>Tags</source> <source>Tags</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<location filename="../../lector/toolbars.py" line="420"/>
<source>Newest</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
</TS> </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 # Keep in mind that all integer / boolean settings are returned as strings
import os import os
from ast import literal_eval from ast import literal_eval
from PyQt5 import QtCore, QtGui from PyQt5 import QtCore, QtGui
@@ -103,6 +119,10 @@ class Settings:
'cachingEnabled', 'True').capitalize()) 'cachingEnabled', 'True').capitalize())
self.parent.settings['hide_scrollbars'] = literal_eval(self.settings.value( self.parent.settings['hide_scrollbars'] = literal_eval(self.settings.value(
'hideScrollBars', 'False').capitalize()) '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.endGroup()
self.settings.beginGroup('dialogSettings') self.settings.beginGroup('dialogSettings')
@@ -110,6 +130,13 @@ class Settings:
'dialogBackground', QtGui.QColor().fromRgb(0, 0, 0)) 'dialogBackground', QtGui.QColor().fromRgb(0, 0, 0))
self.settings.endGroup() 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): def save_settings(self):
print('Saving settings...') print('Saving settings...')
current_settings = self.parent.settings current_settings = self.parent.settings
@@ -165,16 +192,23 @@ class Settings:
self.settings.endGroup() self.settings.endGroup()
self.settings.beginGroup('settingsSwitches') self.settings.beginGroup('settingsSwitches')
self.settings.setValue('rememberFiles', current_settings['remember_files']) self.settings.setValue('rememberFiles', str(current_settings['remember_files']))
self.settings.setValue('coverShadows', current_settings['cover_shadows']) self.settings.setValue('coverShadows', str(current_settings['cover_shadows']))
self.settings.setValue('autoTags', current_settings['auto_tags']) self.settings.setValue('autoTags', str(current_settings['auto_tags']))
self.settings.setValue('scanLibraryAtStart', current_settings['scan_library']) self.settings.setValue('scanLibraryAtStart', str(current_settings['scan_library']))
self.settings.setValue('performCulling', current_settings['perform_culling']) self.settings.setValue('performCulling', str(current_settings['perform_culling']))
self.settings.setValue('dictionaryLanguage', current_settings['dictionary_language']) self.settings.setValue('dictionaryLanguage', str(current_settings['dictionary_language']))
self.settings.setValue('cachingEnabled', current_settings['caching_enabled']) self.settings.setValue('cachingEnabled', str(current_settings['caching_enabled']))
self.settings.setValue('hideScrollBars', current_settings['hide_scrollbars']) 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.endGroup()
self.settings.beginGroup('dialogSettings') self.settings.beginGroup('dialogSettings')
self.settings.setValue('dialogBackground', current_settings['dialog_background']) self.settings.setValue('dialogBackground', current_settings['dialog_background'])
self.settings.endGroup() 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 # 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 # 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 # it under the terms of the GNU General Public License as published by
@@ -22,27 +20,34 @@
import os import os
import copy import copy
import pathlib import pathlib
from PyQt5 import QtWidgets, QtCore
from PyQt5 import QtWidgets, QtCore, QtGui
from lector import database from lector import database
from lector.annotations import AnnotationsUI
from lector.models import MostExcellentFileSystemModel from lector.models import MostExcellentFileSystemModel
from lector.threaded import BackGroundBookSearch, BackGroundBookAddition from lector.threaded import BackGroundBookSearch, BackGroundBookAddition
from lector.resources import settingswindow from lector.resources import settingswindow
from lector.settings import Settings
class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog): class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog):
def __init__(self, parent=None): def __init__(self, parent=None):
super(SettingsUI, self).__init__() super(SettingsUI, self).__init__()
self.setupUi(self) self.setupUi(self)
self.verticalLayout_4.setContentsMargins(0, 0, 0, 0)
self._translate = QtCore.QCoreApplication.translate self._translate = QtCore.QCoreApplication.translate
self.parent = parent self.main_window = parent
self.database_path = self.parent.database_path self.database_path = self.main_window.database_path
self.image_factory = self.main_window.QImageFactory
self.resize(self.parent.settings['settings_dialog_size']) # The annotation dialog will use the settings dialog as its parent
self.move(self.parent.settings['settings_dialog_position']) 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 = os.path.realpath(__file__)
install_dir = pathlib.Path(install_dir).parents[1] install_dir = pathlib.Path(install_dir).parents[1]
aboutfile_path = os.path.join(install_dir, 'lector', 'resources', 'about.html') 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.paths = None
self.thread = None self.thread = None
self.filesystem_model = None self.filesystemModel = None
self.tag_data_copy = None self.tag_data_copy = None
english_string = self._translate('SettingsUI', 'English') english_string = self._translate('SettingsUI', 'English')
@@ -60,7 +65,7 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog):
languages = [english_string, spanish_string, hindi_string] languages = [english_string, spanish_string, hindi_string]
self.languageBox.addItems(languages) self.languageBox.addItems(languages)
current_language = self.parent.settings['dictionary_language'] current_language = self.main_window.settings['dictionary_language']
if current_language == 'en': if current_language == 'en':
self.languageBox.setCurrentIndex(0) self.languageBox.setCurrentIndex(0)
elif current_language == 'es': 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._translate('SettingsUI', 'Save changes and start library scan'))
self.okButton.clicked.connect(self.start_library_scan) self.okButton.clicked.connect(self.start_library_scan)
self.cancelButton.clicked.connect(self.cancel_pressed) self.cancelButton.clicked.connect(self.cancel_pressed)
self.aboutButton.clicked.connect(self.about_pressed)
# Radio buttons # Radio buttons
if self.parent.settings['icon_theme'] == 'DarkIcons': if self.main_window.settings['icon_theme'] == 'DarkIcons':
self.darkIconsRadio.setChecked(True) self.darkIconsRadio.setChecked(True)
else: else:
self.lightIconsRadio.setChecked(True) self.lightIconsRadio.setChecked(True)
@@ -84,13 +88,16 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog):
self.lightIconsRadio.clicked.connect(self.change_icon_theme) self.lightIconsRadio.clicked.connect(self.change_icon_theme)
# Check boxes # Check boxes
self.autoTags.setChecked(self.parent.settings['auto_tags']) self.autoTags.setChecked(self.main_window.settings['auto_tags'])
self.coverShadows.setChecked(self.parent.settings['cover_shadows']) self.coverShadows.setChecked(self.main_window.settings['cover_shadows'])
self.refreshLibrary.setChecked(self.parent.settings['scan_library']) self.refreshLibrary.setChecked(self.main_window.settings['scan_library'])
self.fileRemember.setChecked(self.parent.settings['remember_files']) self.fileRemember.setChecked(self.main_window.settings['remember_files'])
self.performCulling.setChecked(self.parent.settings['perform_culling']) self.performCulling.setChecked(self.main_window.settings['perform_culling'])
self.cachingEnabled.setChecked(self.parent.settings['caching_enabled']) self.cachingEnabled.setChecked(self.main_window.settings['caching_enabled'])
self.hideScrollBars.setChecked(self.parent.settings['hide_scrollbars']) 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.autoTags.clicked.connect(self.manage_checkboxes)
self.coverShadows.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.performCulling.clicked.connect(self.manage_checkboxes)
self.cachingEnabled.clicked.connect(self.manage_checkboxes) self.cachingEnabled.clicked.connect(self.manage_checkboxes)
self.hideScrollBars.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 # Generate the filesystem treeView
self.generate_tree() 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): def generate_tree(self):
# Fetch all directories in the database # Fetch all directories in the database
paths = database.DatabaseFunctions( paths = database.DatabaseFunctions(
@@ -112,10 +180,10 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog):
{'Path': ''}, {'Path': ''},
'LIKE') 'LIKE')
self.parent.generate_library_filter_menu(paths) self.main_window.generate_library_filter_menu(paths)
directory_data = {} directory_data = {}
if not paths: if not paths:
print('Database returned no paths for settings...') print('Database: No paths for settings...')
else: else:
# Convert to the dictionary format that is # Convert to the dictionary format that is
# to be fed into the QFileSystemModel # to be fed into the QFileSystemModel
@@ -125,9 +193,9 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog):
'tags': i[2], 'tags': i[2],
'check_state': i[3]} 'check_state': i[3]}
self.filesystem_model = MostExcellentFileSystemModel(directory_data) self.filesystemModel = MostExcellentFileSystemModel(directory_data)
self.filesystem_model.setFilter(QtCore.QDir.NoDotAndDotDot | QtCore.QDir.Dirs) self.filesystemModel.setFilter(QtCore.QDir.NoDotAndDotDot | QtCore.QDir.Dirs)
self.treeView.setModel(self.filesystem_model) self.treeView.setModel(self.filesystemModel)
# TODO # TODO
# This here might break on them pestilent non unixy OSes # 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() root_directory = QtCore.QDir().rootPath()
self.treeView.setRootIndex( self.treeView.setRootIndex(
self.filesystem_model.setRootPath(root_directory)) self.filesystemModel.setRootPath(root_directory))
# Set the treeView and QFileSystemModel to its desired state # Set the treeView and QFileSystemModel to its desired state
selected_paths = [ selected_paths = [
@@ -157,10 +225,10 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog):
expand_paths.remove(root_directory) expand_paths.remove(root_directory)
for i in expand_paths: for i in expand_paths:
this_index = self.filesystem_model.index(i) this_index = self.filesystemModel.index(i)
self.treeView.expand(this_index) 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: if header_sizes:
for count, i in enumerate((0, 4)): for count, i in enumerate((0, 4)):
self.treeView.setColumnWidth(i, int(header_sizes[count])) self.treeView.setColumnWidth(i, int(header_sizes[count]))
@@ -178,7 +246,7 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog):
self.hide() self.hide()
data_pairs = [] data_pairs = []
for i in self.filesystem_model.tag_data.items(): for i in self.filesystemModel.tag_data.items():
data_pairs.append([ data_pairs.append([
i[0], i[1]['name'], i[1]['tags'], i[1]['check_state'] 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( database.DatabaseFunctions(
self.database_path).delete_from_database('*', '*') self.database_path).delete_from_database('*', '*')
self.parent.lib_ref.generate_model('build') self.main_window.lib_ref.generate_model('build')
self.parent.lib_ref.generate_proxymodels() self.main_window.lib_ref.generate_proxymodels()
self.parent.generate_library_filter_menu() self.main_window.generate_library_filter_menu()
return return
# Update the main window library filter menu # Update the main window library filter menu
self.parent.generate_library_filter_menu(data_pairs) self.main_window.generate_library_filter_menu(data_pairs)
self.parent.set_library_filter() self.main_window.set_library_filter()
# Disallow rechecking until the first check completes # Disallow rechecking until the first check completes
self.okButton.setEnabled(False) self.okButton.setEnabled(False)
self.parent.reloadLibrary.setEnabled(False) self.main_window.libraryToolBar.reloadLibraryButton.setEnabled(False)
self.okButton.setToolTip( self.okButton.setToolTip(
self._translate('SettingsUI', 'Library scan in progress...')) self._translate('SettingsUI', 'Library scan in progress...'))
# Traverse directories looking for files # Traverse directories looking for files
self.parent.statusMessage.setText( self.main_window.statusMessage.setText(
self._translate('SettingsUI', 'Checking library folders')) self._translate('SettingsUI', 'Checking library folders'))
self.thread = BackGroundBookSearch(data_pairs) self.thread = BackGroundBookSearch(data_pairs)
self.thread.finished.connect(self.finished_iterating) 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 # The books the search thread has found
# are now in self.thread.valid_files # are now in self.thread.valid_files
if not self.thread.valid_files: if not self.thread.valid_files:
self.parent.move_on() self.main_window.move_on()
return return
# Hey, messaging is important, okay? # Hey, messaging is important, okay?
self.parent.sorterProgress.setVisible(True) self.main_window.statusBar.setVisible(True)
self.parent.statusMessage.setText( self.main_window.sorterProgress.setVisible(True)
self.main_window.statusMessage.setText(
self._translate('SettingsUI', 'Parsing files')) self._translate('SettingsUI', 'Parsing files'))
# We now create a new thread to put those files into the database # We now create a new thread to put those files into the database
self.thread = BackGroundBookAddition( self.thread = BackGroundBookAddition(
self.thread.valid_files, self.database_path, 'automatic', self.parent) self.thread.valid_files, self.database_path, 'automatic', self.main_window)
self.thread.finished.connect(self.parent.move_on) self.thread.finished.connect(self.main_window.move_on)
self.thread.start() 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): 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() self.hide()
def hideEvent(self, event): def hideEvent(self, event):
@@ -246,35 +322,46 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog):
event.accept() event.accept()
def showEvent(self, event): 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() event.accept()
def no_more_settings(self): def no_more_settings(self):
self.parent.libraryToolBar.settingsButton.setChecked(False) self.main_window.libraryToolBar.settingsButton.setChecked(False)
self.aboutBox.hide() self.gather_annotations()
self.treeView.show() 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() self.resizeEvent()
def resizeEvent(self, event=None): def resizeEvent(self, event=None):
self.parent.settings['settings_dialog_size'] = self.size() self.main_window.settings['settings_dialog_size'] = self.size()
self.parent.settings['settings_dialog_position'] = self.pos() self.main_window.settings['settings_dialog_position'] = self.pos()
table_headers = [] table_headers = []
for i in [0, 4]: for i in [0, 4]:
table_headers.append(self.treeView.columnWidth(i)) 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): def change_icon_theme(self):
if self.sender() == self.darkIconsRadio: if self.sender() == self.darkIconsRadio:
self.parent.settings['icon_theme'] = 'DarkIcons' self.main_window.settings['icon_theme'] = 'DarkIcons'
else: else:
self.parent.settings['icon_theme'] = 'LightIcons' self.main_window.settings['icon_theme'] = 'LightIcons'
def change_dictionary_language(self, event): def change_dictionary_language(self, event):
language_dict = { language_dict = {
0: 'en', 0: 'en',
1: 'es', 1: 'es',
2: 'hi'} 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): def manage_checkboxes(self, event=None):
sender = self.sender().objectName() sender = self.sender().objectName()
@@ -286,13 +373,108 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog):
'fileRemember': 'remember_files', 'fileRemember': 'remember_files',
'performCulling': 'perform_culling', 'performCulling': 'perform_culling',
'cachingEnabled': 'caching_enabled', '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(): if not self.performCulling.isChecked():
self.parent.load_all_covers() self.main_window.cover_functions.load_all_covers()
def about_pressed(self): def generate_annotations(self):
self.treeView.setVisible(not self.treeView.isVisible()) saved_annotations = self.main_window.settings['annotations']
self.aboutBox.setVisible(not self.aboutBox.isVisible())
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 # 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 # 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 # 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/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# INSTRUCTIONS # 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() # read_book()
# get_title() # get_title()
# get_author() # get_author()
@@ -35,22 +33,26 @@
import io import io
import os import os
import sys
import time import time
import pickle import pickle
import hashlib import hashlib
import threading 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 import database
from lector.parsers.pdf import ParsePDF
from lector.parsers.epub import ParseEPUB from lector.parsers.epub import ParseEPUB
from lector.parsers.mobi import ParseMOBI from lector.parsers.mobi import ParseMOBI
from lector.parsers.comicbooks import ParseCOMIC from lector.parsers.comicbooks import ParseCOMIC
sorter = { sorter = {
'pdf': ParsePDF,
'epub': ParseEPUB, 'epub': ParseEPUB,
'mobi': ParseMOBI, 'mobi': ParseMOBI,
'azw': ParseMOBI, 'azw': ParseMOBI,
@@ -60,6 +62,13 @@ sorter = {
'cbz': ParseCOMIC, 'cbz': ParseCOMIC,
'cbr': 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] available_parsers = [i for i in sorter]
progressbar = None # This is populated by __main__ progressbar = None # This is populated by __main__
progress_emitter = None # This is to be made into a global variable 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): def database_entry_for_book(self, file_hash):
database_return = database.DatabaseFunctions( database_return = database.DatabaseFunctions(
self.database_path).fetch_data( self.database_path).fetch_data(
('Title', 'Author', 'Year', 'ISBN', 'Tags', 'Position', 'Bookmarks'), ('Title', 'Author', 'Year', 'ISBN', 'Tags',
'Position', 'Bookmarks', 'CoverImage', 'Annotations'),
'books', 'books',
{'Hash': file_hash}, {'Hash': file_hash},
'EQUALS')[0] 'EQUALS')[0]
@@ -126,7 +136,7 @@ class BookSorter:
book_data = [] book_data = []
for count, i in enumerate(database_return): 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: if i:
book_data.append(pickle.loads(i)) book_data.append(pickle.loads(i))
else: else:
@@ -175,7 +185,6 @@ class BookSorter:
book_ref.read_book() book_ref.read_book()
if book_ref.book: if book_ref.book:
this_book = {} this_book = {}
this_book[file_md5] = { this_book[file_md5] = {
'hash': file_md5, 'hash': file_md5,
@@ -186,13 +195,8 @@ class BookSorter:
# Reduce the size of the incoming image # Reduce the size of the incoming image
# if one is found # if one is found
title = book_ref.get_title() title = book_ref.get_title()
author = book_ref.get_author() author = book_ref.get_author()
if not author:
author = 'Unknown'
year = book_ref.get_year() year = book_ref.get_year()
isbn = book_ref.get_isbn() isbn = book_ref.get_isbn()
tags = None tags = None
@@ -214,8 +218,7 @@ class BookSorter:
# get_contents() returns a tuple. Index 1 is a collection of # get_contents() returns a tuple. Index 1 is a collection of
# special settings that depend on the kind of data being parsed. # special settings that depend on the kind of data being parsed.
# Currently, this includes: # Currently, this includes:
# Only images included images_only BOOL Specify only paths to images # Only images included images_only BOOL Book contains only images
# File will not be cached on exit
content = all_content[0] content = all_content[0]
images_only = all_content[1]['images_only'] images_only = all_content[1]['images_only']
@@ -231,11 +234,15 @@ class BookSorter:
tags = book_data[4] tags = book_data[4]
position = book_data[5] position = book_data[5]
bookmarks = book_data[6] bookmarks = book_data[6]
cover = book_data[7]
annotations = book_data[8]
this_book[file_md5]['position'] = position this_book[file_md5]['position'] = position
this_book[file_md5]['bookmarks'] = bookmarks this_book[file_md5]['bookmarks'] = bookmarks
this_book[file_md5]['content'] = content this_book[file_md5]['content'] = content
this_book[file_md5]['images_only'] = images_only 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]['title'] = title
this_book[file_md5]['author'] = author 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 # 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 # 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 # it under the terms of the GNU General Public License as published by
@@ -18,6 +16,7 @@
import os import os
import pathlib import pathlib
from multiprocessing.dummy import Pool from multiprocessing.dummy import Pool
from PyQt5 import QtCore, QtGui from PyQt5 import QtCore, QtGui
@@ -37,7 +36,8 @@ class BackGroundTabUpdate(QtCore.QThread):
database_dict = { database_dict = {
'Position': i['position'], 'Position': i['position'],
'LastAccessed': i['last_accessed'], 'LastAccessed': i['last_accessed'],
'Bookmarks': i['bookmarks']} 'Bookmarks': i['bookmarks'],
'Annotations': i['annotations']}
database.DatabaseFunctions(self.database_path).modify_metadata( database.DatabaseFunctions(self.database_path).modify_metadata(
database_dict, book_hash) 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): def __init__(self, image_cache, remove_value, filetype, book, all_pages, parent=None):
super(BackGroundCacheRefill, self).__init__(parent) 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.image_cache = image_cache
self.remove_value = remove_value self.remove_value = remove_value
self.filetype = filetype 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 # 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 # 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 # 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'), image_factory.get_image('gtk-select-font'),
self._translate('BookToolBar', 'View settings'), self._translate('BookToolBar', 'View settings'),
self) self)
self.fullscreenButton = QtWidgets.QAction( self.annotationButton = QtWidgets.QAction(
image_factory.get_image('view-fullscreen'), image_factory.get_image('annotate'),
self._translate('BookToolBar', 'Fullscreen'), self._translate('BookToolBar', 'Annotations'),
self) self)
self.addBookmarkButton = QtWidgets.QAction( self.addBookmarkButton = QtWidgets.QAction(
image_factory.get_image('bookmark-new'), image_factory.get_image('bookmark-new'),
@@ -55,9 +53,16 @@ class BookToolBar(QtWidgets.QToolBar):
self) self)
self.bookmarkButton = QtWidgets.QAction( self.bookmarkButton = QtWidgets.QAction(
image_factory.get_image('bookmarks'), 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)
self.bookmarkButton.setObjectName('bookmarkButton')
self.resetProfile = QtWidgets.QAction( self.resetProfile = QtWidgets.QAction(
image_factory.get_image('reload'), image_factory.get_image('reload'),
self._translate('BookToolBar', 'Reset profile'), self._translate('BookToolBar', 'Reset profile'),
@@ -68,10 +73,14 @@ class BookToolBar(QtWidgets.QToolBar):
self.fontButton.setCheckable(True) self.fontButton.setCheckable(True)
self.fontButton.triggered.connect(self.toggle_font_settings) self.fontButton.triggered.connect(self.toggle_font_settings)
self.addSeparator() self.addSeparator()
self.addAction(self.annotationButton)
self.annotationButton.setCheckable(True)
self.addSeparator()
self.addAction(self.addBookmarkButton) self.addAction(self.addBookmarkButton)
self.addAction(self.bookmarkButton) self.addAction(self.bookmarkButton)
self.bookmarkButton.setCheckable(True) self.bookmarkButton.setCheckable(True)
self.addSeparator() self.addSeparator()
self.addAction(self.distractionFreeButton)
self.addAction(self.fullscreenButton) self.addAction(self.fullscreenButton)
# Font modification # Font modification
@@ -277,8 +286,10 @@ class BookToolBar(QtWidgets.QToolBar):
self.searchBarAction = self.addWidget(self.searchBar) self.searchBarAction = self.addWidget(self.searchBar)
self.bookActions = [ self.bookActions = [
self.annotationButton,
self.addBookmarkButton, self.addBookmarkButton,
self.bookmarkButton, self.bookmarkButton,
self.distractionFreeButton,
self.fullscreenButton, self.fullscreenButton,
self.tocBoxAction, self.tocBoxAction,
self.searchBarAction] self.searchBarAction]
@@ -317,6 +328,7 @@ class BookToolBar(QtWidgets.QToolBar):
i.setVisible(False) i.setVisible(False)
def customize_view_off(self): def customize_view_off(self):
self.fontButton.setChecked(False)
for i in self.fontActions: for i in self.fontActions:
i.setVisible(False) i.setVisible(False)
@@ -375,6 +387,11 @@ class LibraryToolBar(QtWidgets.QToolBar):
self) self)
self.tableViewButton.setCheckable(True) 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 = QtWidgets.QToolButton(self)
self.libraryFilterButton.setIcon(image_factory.get_image('view-readermode')) self.libraryFilterButton.setIcon(image_factory.get_image('view-readermode'))
self.libraryFilterButton.setText( self.libraryFilterButton.setText(
@@ -395,6 +412,7 @@ class LibraryToolBar(QtWidgets.QToolBar):
self.addAction(self.coverViewButton) self.addAction(self.coverViewButton)
self.addAction(self.tableViewButton) self.addAction(self.tableViewButton)
self.addSeparator() self.addSeparator()
self.addAction(self.reloadLibraryButton)
self.addWidget(self.libraryFilterButton) self.addWidget(self.libraryFilterButton)
self.addSeparator() self.addSeparator()
self.addAction(self.colorButton) self.addAction(self.colorButton)
@@ -413,13 +431,15 @@ class LibraryToolBar(QtWidgets.QToolBar):
self.searchBar.setObjectName('searchBar') self.searchBar.setObjectName('searchBar')
# Sorter # Sorter
title_string = self._translate('TableProxyModel', 'Title') title_string = self._translate('LibraryToolBar', 'Title')
author_string = self._translate('TableProxyModel', 'Author') author_string = self._translate('LibraryToolBar', 'Author')
year_string = self._translate('TableProxyModel', 'Year') year_string = self._translate('LibraryToolBar', 'Year')
newest_string = self._translate('TableProxyModel', 'Newest') newest_string = self._translate('LibraryToolBar', 'Newest')
lastread_string = self._translate('TableProxyModel', 'Last Read') lastread_string = self._translate('LibraryToolBar', 'Last Read')
progress_string = self._translate('LibraryToolBar', 'Progress')
sorting_choices = [ 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 = FixedComboBox(self)
self.sortingBox.addItems(sorting_choices) 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__)) HERE = path.abspath(path.dirname(__file__))
MAJOR_VERSION = '0' MAJOR_VERSION = '0'
MINOR_VERSION = '3' MINOR_VERSION = '4'
MICRO_VERSION = '0' MICRO_VERSION = '0'
VERSION = "{}.{}.{}".format(MAJOR_VERSION, MINOR_VERSION, MICRO_VERSION) 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: with codecs.open(path.join(HERE, 'README.md'), encoding='utf-8') as f:
LONG_DESC = f.read() LONG_DESC = f.read()
INSTALL_DEPS = ['requests', INSTALL_DEPS = ['beautifulsoup4']
'beautifulsoup4'] TEST_DEPS = []
TEST_DEPS = ['pytest',
'unittest2']
DEV_DEPS = [] DEV_DEPS = []
setup( setup(