diff --git a/lector/__main__.py b/lector/__main__.py index ad564b7..3f3d4d8 100755 --- a/lector/__main__.py +++ b/lector/__main__.py @@ -34,7 +34,7 @@ from PyQt5 import QtWidgets, QtGui, QtCore from lector import database from lector import sorter from lector.toolbars import LibraryToolBar, BookToolBar -from lector.widgets import Tab +from lector.widgets import Tab, DragDropListView, DragDropTableView from lector.delegates import LibraryDelegate from lector.threaded import BackGroundTabUpdate, BackGroundBookAddition, BackGroundBookDeletion from lector.library import Library @@ -62,6 +62,13 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow): # Initialize translation function self._translate = QtCore.QCoreApplication.translate + # Create library widgets + self.listView = DragDropListView(self, self.listPage) + self.gridLayout_4.addWidget(self.listView, 0, 0, 1, 1) + + self.tableView = DragDropTableView(self, self.tablePage) + self.gridLayout_3.addWidget(self.tableView, 0, 0, 1, 1) + # Empty variables that will be infested soon self.settings = {} self.thread = None # Background Thread @@ -318,24 +325,104 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow): my_args = cl_parser.positionalArguments() if my_args: file_list = [QtCore.QFileInfo(i).absoluteFilePath() for i in my_args] - books = sorter.BookSorter( - file_list, - ('addition', 'manual'), - self.database_path, - self.settings['auto_tags'], - self.temp_dir.path()) + self.process_post_hoc_files(file_list, True) - parsed_books = books.initiate_threads() - if not parsed_books: - return + def process_post_hoc_files(self, file_list, open_files_after_processing): + # Takes care of both dragged and dropped files + # As well as files sent as command line arguments + books = sorter.BookSorter( + file_list, + ('addition', 'manual'), + self.database_path, + self.settings['auto_tags'], + self.temp_dir.path()) - database.DatabaseFunctions(self.database_path).add_to_database(parsed_books) - self.lib_ref.generate_model('addition', parsed_books, True) + parsed_books = books.initiate_threads() + if not parsed_books: + return - file_dict = {QtCore.QFileInfo(i).absoluteFilePath(): None for i in my_args} + database.DatabaseFunctions(self.database_path).add_to_database(parsed_books) + self.lib_ref.generate_model('addition', parsed_books, True) + + file_dict = {i: None for i in file_list} + if open_files_after_processing: self.open_files(file_dict) - self.move_on() + self.move_on() + + def open_files(self, path_hash_dictionary): + # file_paths is expected to be a dictionary + # This allows for threading file opening + # Which should speed up multiple file opening + # especially @ application start + + file_paths = [i for i in path_hash_dictionary] + + for filename in path_hash_dictionary.items(): + + file_md5 = filename[1] + if not file_md5: + try: + with open(filename[0], 'rb') as current_book: + first_bytes = current_book.read(1024 * 32) # First 32KB of the file + file_md5 = hashlib.md5(first_bytes).hexdigest() + except FileNotFoundError: + return + + # Remove any already open files + # Set focus to last file in case only one is open + for i in range(1, self.tabWidget.count()): + tab_metadata = self.tabWidget.widget(i).metadata + if tab_metadata['hash'] == file_md5: + file_paths.remove(filename[0]) + if not file_paths: + self.tabWidget.setCurrentIndex(i) + return + + if not file_paths: + return + + def finishing_touches(): + self.profile_functions.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() + + # TODO + # Notification feedback in case all books return nothing + + if not contents: + return + + for i in contents: + # New tabs are created here + # Initial position adjustment is carried out by the tab itself + file_data = contents[i] + Tab(file_data, self) + + if self.settings['last_open_tab'] == 'library': + self.tabWidget.setCurrentIndex(0) + self.listView.setFocus() + self.settings['last_open_tab'] = None + return + + for i in range(1, self.tabWidget.count()): + this_path = self.tabWidget.widget(i).metadata['path'] + if self.settings['last_open_tab'] == this_path: + self.tabWidget.setCurrentIndex(i) + self.settings['last_open_tab'] = None + finishing_touches() + return + + self.tabWidget.setCurrentIndex(self.tabWidget.count() - 1) + finishing_touches() def start_culling_timer(self): if self.settings['perform_culling']: @@ -626,80 +713,6 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow): self.open_files(path) - def open_files(self, path_hash_dictionary): - # file_paths is expected to be a dictionary - # This allows for threading file opening - # Which should speed up multiple file opening - # especially @ application start - - file_paths = [i for i in path_hash_dictionary] - - for filename in path_hash_dictionary.items(): - - file_md5 = filename[1] - if not file_md5: - try: - with open(filename[0], 'rb') as current_book: - first_bytes = current_book.read(1024 * 32) # First 32KB of the file - file_md5 = hashlib.md5(first_bytes).hexdigest() - except FileNotFoundError: - return - - # Remove any already open files - # Set focus to last file in case only one is open - for i in range(1, self.tabWidget.count()): - tab_metadata = self.tabWidget.widget(i).metadata - if tab_metadata['hash'] == file_md5: - file_paths.remove(filename[0]) - if not file_paths: - self.tabWidget.setCurrentIndex(i) - return - - if not file_paths: - return - - def finishing_touches(): - self.profile_functions.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() - - # TODO - # Notification feedback in case all books return nothing - - if not contents: - return - - for i in contents: - # New tabs are created here - # Initial position adjustment is carried out by the tab itself - file_data = contents[i] - Tab(file_data, self) - - if self.settings['last_open_tab'] == 'library': - self.tabWidget.setCurrentIndex(0) - self.listView.setFocus() - self.settings['last_open_tab'] = None - return - - for i in range(1, self.tabWidget.count()): - this_path = self.tabWidget.widget(i).metadata['path'] - if self.settings['last_open_tab'] == this_path: - self.tabWidget.setCurrentIndex(i) - self.settings['last_open_tab'] = None - finishing_touches() - return - - self.tabWidget.setCurrentIndex(self.tabWidget.count() - 1) - finishing_touches() - def statusbar_visibility(self): if self.sender() == self.libraryToolBar.searchBar: if self.libraryToolBar.searchBar.text() == '': diff --git a/lector/resources/mainwindow.py b/lector/resources/mainwindow.py index 6df390e..83d3a6a 100644 --- a/lector/resources/mainwindow.py +++ b/lector/resources/mainwindow.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'raw/main.ui' # -# Created by: PyQt5 UI code generator 5.9.2 +# Created by: PyQt5 UI code generator 5.10.1 # # WARNING! All changes made in this file will be lost! @@ -35,20 +35,6 @@ class Ui_MainWindow(object): self.gridLayout_4.setContentsMargins(0, 0, 0, 0) self.gridLayout_4.setSpacing(0) self.gridLayout_4.setObjectName("gridLayout_4") - self.listView = QtWidgets.QListView(self.listPage) - self.listView.setFrameShape(QtWidgets.QFrame.NoFrame) - self.listView.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) - self.listView.setProperty("showDropIndicator", False) - self.listView.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) - self.listView.setMovement(QtWidgets.QListView.Static) - self.listView.setProperty("isWrapping", True) - self.listView.setResizeMode(QtWidgets.QListView.Fixed) - self.listView.setLayoutMode(QtWidgets.QListView.SinglePass) - self.listView.setViewMode(QtWidgets.QListView.IconMode) - self.listView.setUniformItemSizes(True) - self.listView.setWordWrap(True) - self.listView.setObjectName("listView") - self.gridLayout_4.addWidget(self.listView, 0, 0, 1, 1) self.stackedWidget.addWidget(self.listPage) self.tablePage = QtWidgets.QWidget() self.tablePage.setObjectName("tablePage") @@ -56,20 +42,6 @@ class Ui_MainWindow(object): self.gridLayout_3.setContentsMargins(0, 0, 0, 0) self.gridLayout_3.setSpacing(0) self.gridLayout_3.setObjectName("gridLayout_3") - self.tableView = QtWidgets.QTableView(self.tablePage) - self.tableView.setFrameShape(QtWidgets.QFrame.Box) - self.tableView.setFrameShadow(QtWidgets.QFrame.Plain) - self.tableView.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContentsOnFirstShow) - self.tableView.setEditTriggers(QtWidgets.QAbstractItemView.DoubleClicked|QtWidgets.QAbstractItemView.EditKeyPressed|QtWidgets.QAbstractItemView.SelectedClicked) - self.tableView.setAlternatingRowColors(True) - self.tableView.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) - self.tableView.setGridStyle(QtCore.Qt.NoPen) - self.tableView.setSortingEnabled(True) - self.tableView.setWordWrap(False) - self.tableView.setObjectName("tableView") - self.tableView.horizontalHeader().setVisible(True) - self.tableView.verticalHeader().setVisible(False) - self.gridLayout_3.addWidget(self.tableView, 0, 0, 1, 1) self.stackedWidget.addWidget(self.tablePage) self.gridLayout_2.addWidget(self.stackedWidget, 0, 0, 1, 1) self.tabWidget.addTab(self.tab, "") diff --git a/lector/resources/raw/main.ui b/lector/resources/raw/main.ui index a284e88..137d8d4 100644 --- a/lector/resources/raw/main.ui +++ b/lector/resources/raw/main.ui @@ -55,46 +55,6 @@ 0 - - - - QFrame::NoFrame - - - QAbstractItemView::NoEditTriggers - - - false - - - QAbstractItemView::ExtendedSelection - - - QListView::Static - - - true - - - QListView::Fixed - - - QListView::SinglePass - - - 0 - - - QListView::IconMode - - - true - - - true - - - @@ -114,43 +74,6 @@ 0 - - - - QFrame::Box - - - QFrame::Plain - - - QAbstractScrollArea::AdjustToContentsOnFirstShow - - - QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked - - - true - - - QAbstractItemView::SelectRows - - - Qt::NoPen - - - true - - - false - - - false - - - false - - - diff --git a/lector/widgets.py b/lector/widgets.py index e563606..51cd6eb 100644 --- a/lector/widgets.py +++ b/lector/widgets.py @@ -666,3 +666,81 @@ class PliantQGraphicsScene(QtWidgets.QGraphicsScene): self.parent.load_cover(cover_pixmap, True) self.parent.show() + + +class DragDropListView(QtWidgets.QListView): + # This is the library listview + def __init__(self, main_window, parent): + super(DragDropListView, self).__init__(parent) + self.main_window = main_window + self.setAcceptDrops(True) + self.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove) + self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) + self.setResizeMode(QtWidgets.QListView.Fixed) + self.setLayoutMode(QtWidgets.QListView.SinglePass) + self.setViewMode(QtWidgets.QListView.IconMode) + self.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.setProperty("showDropIndicator", False) + self.setProperty("isWrapping", True) + self.setFrameShape(QtWidgets.QFrame.NoFrame) + self.setUniformItemSizes(True) + self.setWordWrap(True) + self.setObjectName("listView") + + def dragEnterEvent(self, event): + if event.mimeData().hasUrls(): + event.acceptProposedAction() + else: + super(DragDropListView, self).dragEnterEvent(event) + + def dragMoveEvent(self, event): + super(DragDropListView, self).dragMoveEvent(event) + + def dropEvent(self, event): + if event.mimeData().hasUrls(): + file_list = [url.path() for url in event.mimeData().urls()] + self.main_window.process_post_hoc_files(file_list, False) + event.acceptProposedAction() + else: + super(DragDropListView, self).dropEvent(event) + + +class DragDropTableView(QtWidgets.QTableView): + # This is the library tableview + def __init__(self, main_window, parent): + super(DragDropTableView, self).__init__(parent) + self.main_window = main_window + self.setAcceptDrops(True) + self.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove) + self.setFrameShape(QtWidgets.QFrame.Box) + self.setFrameShadow(QtWidgets.QFrame.Plain) + self.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContentsOnFirstShow) + self.setEditTriggers( + QtWidgets.QAbstractItemView.DoubleClicked | + QtWidgets.QAbstractItemView.EditKeyPressed | + QtWidgets.QAbstractItemView.SelectedClicked) + self.setAlternatingRowColors(True) + self.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.setGridStyle(QtCore.Qt.NoPen) + self.setSortingEnabled(True) + self.setWordWrap(False) + self.setObjectName("tableView") + self.horizontalHeader().setVisible(True) + self.verticalHeader().setVisible(False) + + def dragEnterEvent(self, event): + if event.mimeData().hasUrls(): + event.acceptProposedAction() + else: + super(DragDropTableView, self).dragEnterEvent(event) + + def dragMoveEvent(self, event): + super(DragDropTableView, self).dragMoveEvent(event) + + def dropEvent(self, event): + if event.mimeData().hasUrls(): + file_list = [url.path() for url in event.mimeData().urls()] + self.main_window.process_post_hoc_files(file_list, False) + event.acceptProposedAction() + else: + super(DragDropTableView, self).dropEvent(event)