mstuttgart/pynocchio

View on GitHub
pynocchio/main_window_model.py

Summary

Maintainability
F
3 days
Test Coverage
import logging

from PyQt5 import QtCore, QtGui

from .bookmark import Bookmark, TemporaryBookmark
from .bookmark_database_manager import BookmarkManager
from .comic import Comic
from .comic_file_loader_factory import ComicLoaderFactory
from .comic_page_handler import ComicPageHandlerDoublePage
from .comic_page_handler_factory import ComicPageHandlerFactory
from .comic_path_filter import ComicPathFilter
from .exception import NoDataFindException
from .settings_manager import SettingsManager
from .utility import get_base_name, get_dir_name, is_file, is_dir

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)


class MainWindowModel(QtCore.QObject):
    _ORIGINAL_FIT = 'action_original_fit'
    _VERTICAL_FIT = 'action_vertical_fit'
    _HORIZONTAL_FIT = 'action_horizontal_fit'
    _BEST_FIT = 'action_best_fit'
    _PAGE_FIT = 'action_page_fit'

    load_progress = QtCore.pyqtSignal(int)
    load_done = QtCore.pyqtSignal()

    def __init__(self):
        super().__init__()
        self.comic = None
        self.comic_page_handler = None
        self.settings_manager = SettingsManager()
        self.rotate_angle = 0
        self.scroll_area_size = None
        self.scroll_bar_size = None
        self.fit_type = self.load_view_adjust(MainWindowModel._ORIGINAL_FIT)
        self.resize_always = True
        self.current_directory = self.load_current_directory()

        ext_list = ["*.cbr", "*.cbz", "*.rar", "*.zip", "*.tar", "*.cbt"]

        self.comic_file_filter = ComicPathFilter(ext_list)

    def save_recent_files(self, recent_files_list):
        self.settings_manager.save_recent_files(recent_files_list)

    def load_recent_files(self):
        return self.settings_manager.load_recent_files()

    def load_view_adjust(self, default_object_name):
        return self.settings_manager.load_view_adjust(default_object_name)

    def load_current_directory(self):
        return self.settings_manager.load_current_directory()

    def load(self, filename, initial_page=None):
        logger.info('Loading %s at %i', filename,
                    0 if initial_page is None else initial_page)

        loader = ComicLoaderFactory.create_loader(filename)
        loader.progress.connect(self.load_progressbar_value)

        try:
            loader.load(filename)
        except NoDataFindException as exc:
            from pynocchio.comic import Page
            logger.exception('Error in load comic! %s', exc)
            q_file = QtCore.QFile(":/icons/not_cover.png")
            q_file.open(QtCore.QIODevice.ReadOnly)
            loader.data.append(Page(q_file.readAll(), 'exit_red_1.png', 0))

        page = initial_page if initial_page is not None \
            else loader.initial_page

        # Memorize last page on comic
        if self.comic:
            if not self.is_first_page() and not self.is_last_page():
                self.add_bookmark(table=TemporaryBookmark)
            else:
                self.remove_bookmark(table=TemporaryBookmark)

        self.comic = Comic(get_base_name(filename),
                           get_dir_name(filename))

        self.comic.pages = loader.data
        self.comic_page_handler = ComicPageHandlerFactory.create_handler(
            False, self.comic, index=page)
        self.current_directory = get_dir_name(filename)

        if is_dir(filename) or type(loader).__name__ == 'ComicImageLoader':
            self.comic_file_filter.parse(filename, isdir=True)
        elif is_file(filename):
            self.comic_file_filter.parse(self.current_directory)

    def save_current_page_image(self, file_name):
        self.get_current_page().save(file_name)

    def next_page(self):
        return self.comic_page_handler.go_next_page()

    def previous_page(self):
        return self.comic_page_handler.go_previous_page()

    def first_page(self):
        self.comic_page_handler.go_first_page()

    def last_page(self):
        self.comic_page_handler.go_last_page()

    def previous_comic(self):
        return self.comic_file_filter.get_previous_comic(self.comic.name)

    def next_comic(self):
        return self.comic_file_filter.get_next_comic(self.comic.name)

    def rotate_left(self):
        self.rotate_angle = (self.rotate_angle - 90) % 360

    def rotate_right(self):
        self.rotate_angle = (self.rotate_angle + 90) % 360

    def get_comic_name(self):
        return self.comic.name

    def get_comic_path(self):
        return self.comic.path

    def get_comic_title(self):
        return self.comic.name

    def get_current_page(self):
        try:
            pix_map = self.comic_page_handler.get_current_page_image()
        except AttributeError:
            return None
        else:
            pix_map = self._rotate_page(pix_map)
            pix_map = self._resize_page(pix_map)
            return pix_map

    def get_current_page_title(self):
        return self.comic_page_handler.get_current_page().title

    def set_current_page_index(self, idx):
        self.comic_page_handler.current_page_index = idx

    def get_current_page_index(self):
        return self.comic_page_handler.current_page_index

    def get_current_page_number(self):
        return self.comic_page_handler.get_current_page().number

    def get_number_of_pages(self):
        return len(self.comic.pages)

    def is_first_page(self):
        return self.comic_page_handler.current_page_index == 0

    def is_last_page(self):
        return self.comic_page_handler.current_page_index + 1 == \
            len(self.comic.pages)

    def is_first_comic(self):
        return self.comic_file_filter.is_first_comic(self.comic.name)

    def is_last_comic(self):
        return self.comic_file_filter.is_last_comic(self.comic.name)

    def _rotate_page(self, pix_map):
        if self.rotate_angle != 0:
            trans = QtGui.QTransform().rotate(self.rotate_angle)
            pix_map = QtGui.QPixmap(pix_map.transformed(trans))
        return pix_map

    def _resize_page(self, pix_map):

        width = pix_map.width()
        height = pix_map.height()

        h = self.scroll_area_size.height()
        w = self.scroll_area_size.width()

        if self.fit_type == MainWindowModel._VERTICAL_FIT:
            f = h / height
            if int(f*width) > w:
                h -= self.scroll_bar_size
                f = h / height
                if int(f*width) < w:
                    f = w / width
                    h = int(f*height)
            if self.resize_always or h < height:
                pix_map = pix_map.scaledToHeight(
                    h, QtCore.Qt.SmoothTransformation)

        elif self.fit_type == MainWindowModel._HORIZONTAL_FIT:
            f = w / width
            if int(f*height) > h:
                w -= self.scroll_bar_size
                f = w / width
                if int(f*height) < h:
                    f = h / height
                    w = int(f*width)
            if self.resize_always or w < width:
                pix_map = pix_map.scaledToWidth(
                    w, QtCore.Qt.SmoothTransformation)

        elif self.fit_type == MainWindowModel._BEST_FIT:
            w *= 0.8
            if self.resize_always or w < width:
                pix_map = pix_map.scaledToWidth(
                    w, QtCore.Qt.SmoothTransformation)

        elif self.fit_type == MainWindowModel._PAGE_FIT:
            if self.resize_always or w < width or h < height:
                pix_map = pix_map.scaled(
                    w, h,
                    QtCore.Qt.KeepAspectRatio,
                    QtCore.Qt.SmoothTransformation)

        pix_map.original_width = width
        pix_map.original_height = height

        return pix_map

    def original_fit(self):
        self.fit_type = MainWindowModel._ORIGINAL_FIT

    def vertical_fit(self):
        self.fit_type = MainWindowModel._VERTICAL_FIT

    def horizontal_fit(self):
        self.fit_type = MainWindowModel._HORIZONTAL_FIT

    def best_fit(self):
        self.fit_type = MainWindowModel._BEST_FIT

    def page_fit(self):
        self.fit_type = MainWindowModel._PAGE_FIT

    def double_page_mode(self, checked):
        index = self.comic_page_handler.current_page_index
        self.comic_page_handler = ComicPageHandlerFactory.create_handler(
            checked, self.comic, index=index)

    def manga_page_mode(self, checked):
        if isinstance(self.comic_page_handler, ComicPageHandlerDoublePage):
            self.comic_page_handler.inverse = checked

    @QtCore.pyqtSlot(int)
    def load_progressbar_value(self, percent):
        self.load_progress.emit(percent)

    @QtCore.pyqtSlot()
    def load_progressbar_done(self):
        self.load_done.emit()

    def save_settings(self):
        self.settings_manager.save_toggles(self.parent.ui)
        self.settings_manager.save_window(self.parent)
        self.settings_manager.save_view_adjust(self.fit_type)
        self.settings_manager.save_current_directory(self.current_directory)

    @staticmethod
    def get_bookmark_list(qty):
        return BookmarkManager.get_bookmarks(qty)

    def is_bookmark(self):
        return BookmarkManager.is_bookmark(self.comic.path)

    @staticmethod
    def get_bookmark_from_path(path, table=Bookmark):
        return BookmarkManager.get_bookmark_by_path(path, table=table)

    def add_bookmark(self, table=Bookmark):

        if self.comic:
            BookmarkManager.add_bookmark(
                self.comic.name, self.comic.path,
                self.comic_page_handler.get_current_page().number,
                data=self.comic_page_handler.get_current_page().data,
                table=table)

    def remove_bookmark(self, path=False, table=Bookmark):
        path = self.comic.path if not path else path
        BookmarkManager.remove_bookmark(path, table=table)

    def load_window(self, size, position):
        return (self.settings_manager.load_window_size(size),
                self.settings_manager.load_window_position(position),
                self.settings_manager.load_window_state())

    def load_toggles(self):
        return self.settings_manager.load_toggles()