示例#1
0
 def setModel(self, model):
     QTableView.setModel(self, model)
     if model:
         if model.parent() is None:
             model.setParent(self)
         model.dataChanged.connect(self._handle_data_changed)
         self._update_cell_spans()
示例#2
0
    def initialise (self, univers):
        model = QStandardItemModel (3,1)
    
        i = 0
        for faction in univers.faction_list :
            item = QStandardItem(faction.name)
            item.setFlags(QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled);
            item.setData(QtCore.Qt.Unchecked, QtCore.Qt.CheckStateRole);

            model.setItem(i, 0, item)
            i = i + 1

        combo = QComboBox()
        combo.setModel(model)

        list_v = QListView()
        list_v.setModel(model)

        table = QTableView()
        table.setModel(model)

        container = QWidget()
        containerLayout = QVBoxLayout()
        container.setLayout(containerLayout)
        containerLayout.addWidget(combo)
        containerLayout.addWidget(list_v)
        containerLayout.addWidget(table)
示例#3
0
 def init_results_widget(self):
     results_widget = QTabWidget(self)
     results_widget.setTabsClosable(False)
     table_view = QTableView(self)
     table_view.setModel(self.model)
     table_view.sizePolicy().setVerticalPolicy(
         QSizePolicy.MinimumExpanding)
     results_widget.addTab(table_view, 'Data')
     log = QTextEdit(self)
     log.setReadOnly(True)
     self.model.executed.connect(log.append)
     results_widget.addTab(log, 'Events')
     return results_widget
示例#4
0
    def build_results_widget(self):
        # Initialize QTabWidget to display table view and log
        # in differnt unclosable tabs
        results_widget = QTabWidget(self)
        results_widget.setTabsClosable(False)

        # Add table view
        table_view = QTableView(self)
        table_view.setModel(self.model)
        table_view.sizePolicy().setVerticalPolicy(QSizePolicy.MinimumExpanding)
        results_widget.addTab(table_view, UI.QUERY_RESULTS_DATA_TAB_TEXT)

        # Att log view
        log = QTextEdit(self)
        log.setReadOnly(True)
        self.model.executed.connect(log.append)
        results_widget.addTab(log, UI.QUERY_RESULTS_EVENTS_TAB_TEXT)
        return results_widget
示例#5
0
    def init_results_widget(self):
        # Initialize QTabWidget to display table view and log
        # in differnt unclosable tabs
        results_widget = QTabWidget(self)
        results_widget.setTabsClosable(False)

        # Add table view
        table_view = QTableView(self)
        table_view.setModel(self.model)
        table_view.sizePolicy().setVerticalPolicy(
            QSizePolicy.MinimumExpanding)
        results_widget.addTab(table_view, 'Data')

        # Att log view
        log = QTextEdit(self)
        log.setReadOnly(True)
        self.model.executed.connect(log.append)
        results_widget.addTab(log, 'Events')
        return results_widget
示例#6
0
class OpdsDialog(QDialog):
    def __init__(self, gui, icon, do_user_config):
        QDialog.__init__(self, gui)
        self.gui = gui
        self.do_user_config = do_user_config

        self.db = gui.current_db.new_api

        # The model for the book list
        self.model = OpdsBooksModel(None, self.dummy_books(), self.db)
        self.searchproxymodel = QSortFilterProxyModel(self)
        self.searchproxymodel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.searchproxymodel.setFilterKeyColumn(-1)
        self.searchproxymodel.setSourceModel(self.model)

        self.layout = QGridLayout()
        self.setLayout(self.layout)

        self.setWindowTitle("OPDS Client")
        self.setWindowIcon(icon)

        labelColumnWidths = []

        self.opdsUrlLabel = QLabel("OPDS URL: ")
        self.layout.addWidget(self.opdsUrlLabel, 0, 0)
        labelColumnWidths.append(self.layout.itemAtPosition(0, 0).sizeHint().width())

        config.convertSingleStringOpdsUrlPreferenceToListOfStringsPreference()
        self.opdsUrlEditor = QComboBox(self)
        self.opdsUrlEditor.activated.connect(self.opdsUrlEditorActivated)
        self.opdsUrlEditor.addItems(prefs["opds_url"])
        self.opdsUrlEditor.setEditable(True)
        self.opdsUrlEditor.setInsertPolicy(QComboBox.InsertAtTop)
        self.layout.addWidget(self.opdsUrlEditor, 0, 1, 1, 3)
        self.opdsUrlLabel.setBuddy(self.opdsUrlEditor)

        buttonColumnNumber = 7
        buttonColumnWidths = []
        self.about_button = QPushButton("About", self)
        self.about_button.setAutoDefault(False)
        self.about_button.clicked.connect(self.about)
        self.layout.addWidget(self.about_button, 0, buttonColumnNumber)
        buttonColumnWidths.append(
            self.layout.itemAtPosition(0, buttonColumnNumber).sizeHint().width()
        )

        # Initially download the catalogs found in the root catalog of the URL
        # selected at startup.  Fail quietly on failing to open the URL
        catalogsTuple = self.model.downloadOpdsRootCatalog(
            self.gui, self.opdsUrlEditor.currentText(), False
        )
        print(catalogsTuple)
        firstCatalogTitle = catalogsTuple[0]
        self.currentOpdsCatalogs = catalogsTuple[1]  # A dictionary of title->feedURL

        self.opdsCatalogSelectorLabel = QLabel("OPDS Catalog:")
        self.layout.addWidget(self.opdsCatalogSelectorLabel, 1, 0)
        labelColumnWidths.append(self.layout.itemAtPosition(1, 0).sizeHint().width())

        self.opdsCatalogSelector = QComboBox(self)
        self.opdsCatalogSelector.setEditable(False)
        self.opdsCatalogSelectorModel = QStringListModel(self.currentOpdsCatalogs.keys())
        self.opdsCatalogSelector.setModel(self.opdsCatalogSelectorModel)
        self.opdsCatalogSelector.setCurrentText(firstCatalogTitle)
        self.layout.addWidget(self.opdsCatalogSelector, 1, 1, 1, 3)

        self.download_opds_button = QPushButton("Download OPDS", self)
        self.download_opds_button.setAutoDefault(False)
        self.download_opds_button.clicked.connect(self.download_opds)
        self.layout.addWidget(self.download_opds_button, 1, buttonColumnNumber)
        buttonColumnWidths.append(
            self.layout.itemAtPosition(1, buttonColumnNumber).sizeHint().width()
        )

        # Search GUI
        self.searchEditor = QLineEdit(self)
        self.searchEditor.returnPressed.connect(self.searchBookList)
        self.layout.addWidget(self.searchEditor, 2, buttonColumnNumber - 2, 1, 2)

        self.searchButton = QPushButton("Search", self)
        self.searchButton.setAutoDefault(False)
        self.searchButton.clicked.connect(self.searchBookList)
        self.layout.addWidget(self.searchButton, 2, buttonColumnNumber)
        buttonColumnWidths.append(
            self.layout.itemAtPosition(2, buttonColumnNumber).sizeHint().width()
        )

        # The main book list
        self.library_view = QTableView(self)
        self.library_view.setAlternatingRowColors(True)
        self.library_view.setModel(self.searchproxymodel)
        self.library_view.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
        self.library_view.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
        self.library_view.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch)
        self.library_view.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.resizeAllLibraryViewLinesToHeaderHeight()
        self.library_view.resizeColumnsToContents()
        self.layout.addWidget(self.library_view, 3, 0, 3, buttonColumnNumber + 1)

        self.hideNewsCheckbox = QCheckBox("Hide Newspapers", self)
        self.hideNewsCheckbox.clicked.connect(self.setHideNewspapers)
        self.hideNewsCheckbox.setChecked(prefs["hideNewspapers"])
        self.layout.addWidget(self.hideNewsCheckbox, 6, 0, 1, 3)

        self.hideBooksAlreadyInLibraryCheckbox = QCheckBox("Hide books already in library", self)
        self.hideBooksAlreadyInLibraryCheckbox.clicked.connect(self.setHideBooksAlreadyInLibrary)
        self.hideBooksAlreadyInLibraryCheckbox.setChecked(prefs["hideBooksAlreadyInLibrary"])
        self.layout.addWidget(self.hideBooksAlreadyInLibraryCheckbox, 7, 0, 1, 3)

        # Let the checkbox initial state control the filtering
        self.model.setFilterBooksThatAreNewspapers(self.hideNewsCheckbox.isChecked())
        self.model.setFilterBooksThatAreAlreadyInLibrary(
            self.hideBooksAlreadyInLibraryCheckbox.isChecked()
        )

        self.downloadButton = QPushButton("Download selected books", self)
        self.downloadButton.setAutoDefault(False)
        self.downloadButton.clicked.connect(self.downloadSelectedBooks)
        self.layout.addWidget(self.downloadButton, 6, buttonColumnNumber)
        buttonColumnWidths.append(
            self.layout.itemAtPosition(6, buttonColumnNumber).sizeHint().width()
        )

        self.fixTimestampButton = QPushButton("Fix timestamps of selection", self)
        self.fixTimestampButton.setAutoDefault(False)
        self.fixTimestampButton.clicked.connect(self.fixBookTimestamps)
        self.layout.addWidget(self.fixTimestampButton, 7, buttonColumnNumber)
        buttonColumnWidths.append(
            self.layout.itemAtPosition(7, buttonColumnNumber).sizeHint().width()
        )

        # Make all columns of the grid layout the same width as the button column
        buttonColumnWidth = max(buttonColumnWidths)
        for columnNumber in range(0, buttonColumnNumber):
            self.layout.setColumnMinimumWidth(columnNumber, buttonColumnWidth)

        # Make sure the first column isn't wider than the labels it holds
        labelColumnWidth = max(labelColumnWidths)
        self.layout.setColumnMinimumWidth(0, labelColumnWidth)

        self.resize(self.sizeHint())

    def opdsUrlEditorActivated(self, text):
        prefs["opds_url"] = config.saveOpdsUrlCombobox(self.opdsUrlEditor)
        catalogsTuple = self.model.downloadOpdsRootCatalog(
            self.gui, self.opdsUrlEditor.currentText(), True
        )
        firstCatalogTitle = catalogsTuple[0]
        self.currentOpdsCatalogs = catalogsTuple[1]  # A dictionary of title->feedURL
        self.opdsCatalogSelectorModel.setStringList(self.currentOpdsCatalogs.keys())
        self.opdsCatalogSelector.setCurrentText(firstCatalogTitle)

    def setHideNewspapers(self, checked):
        prefs["hideNewspapers"] = checked
        self.model.setFilterBooksThatAreNewspapers(checked)
        self.resizeAllLibraryViewLinesToHeaderHeight()

    def setHideBooksAlreadyInLibrary(self, checked):
        prefs["hideBooksAlreadyInLibrary"] = checked
        self.model.setFilterBooksThatAreAlreadyInLibrary(checked)
        self.resizeAllLibraryViewLinesToHeaderHeight()

    def searchBookList(self):
        searchString = self.searchEditor.text()
        print("starting book list search for: %s" % searchString)
        self.searchproxymodel.setFilterFixedString(searchString)

    def about(self):
        text = get_resources("about.txt")
        QMessageBox.about(self, "About the OPDS Client plugin", text.decode("utf-8"))

    def download_opds(self):
        opdsCatalogUrl = self.currentOpdsCatalogs.get(self.opdsCatalogSelector.currentText(), None)
        if opdsCatalogUrl is None:
            # Just give up quietly
            return
        self.model.downloadOpdsCatalog(self.gui, opdsCatalogUrl)
        if self.model.isCalibreOpdsServer():
            self.model.downloadMetadataUsingCalibreRestApi(self.opdsUrlEditor.currentText())
        self.library_view.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
        self.library_view.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
        self.library_view.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch)
        self.resizeAllLibraryViewLinesToHeaderHeight()
        self.resize(self.sizeHint())

    def config(self):
        self.do_user_config(parent=self)

    def downloadSelectedBooks(self):
        selectionmodel = self.library_view.selectionModel()
        if selectionmodel.hasSelection():
            rows = selectionmodel.selectedRows()
            for row in reversed(rows):
                book = row.data(Qt.UserRole)
                self.downloadBook(book)

    def downloadBook(self, book):
        if len(book.links) > 0:
            self.gui.download_ebook(book.links[0])

    def fixBookTimestamps(self):
        selectionmodel = self.library_view.selectionModel()
        if selectionmodel.hasSelection():
            rows = selectionmodel.selectedRows()
            for row in reversed(rows):
                book = row.data(Qt.UserRole)
                self.fixBookTimestamp(book)

    def fixBookTimestamp(self, book):
        bookTimestamp = book.timestamp
        identicalBookIds = self.findIdenticalBooksForBooksWithMultipleAuthors(book)
        bookIdToValMap = {}
        for identicalBookId in identicalBookIds:
            bookIdToValMap[identicalBookId] = bookTimestamp
        if len(bookIdToValMap) < 1:
            print("Failed to set timestamp of book: %s" % book)
        self.db.set_field("timestamp", bookIdToValMap)

    def findIdenticalBooksForBooksWithMultipleAuthors(self, book):
        authorsList = book.authors
        if len(authorsList) < 2:
            return self.db.find_identical_books(book)
        # Try matching the authors one by one
        identicalBookIds = set()
        for author in authorsList:
            singleAuthorBook = Metadata(book.title, [author])
            singleAuthorIdenticalBookIds = self.db.find_identical_books(singleAuthorBook)
            identicalBookIds = identicalBookIds.union(singleAuthorIdenticalBookIds)
        return identicalBookIds

    def dummy_books(self):
        dummy_author = " " * 40
        dummy_title = " " * 60
        books_list = []
        for line in range(1, 10):
            book = DynamicBook()
            book.author = dummy_author
            book.title = dummy_title
            book.updated = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S+00:00")
            book.id = ""
            books_list.append(book)
        return books_list

    def resizeAllLibraryViewLinesToHeaderHeight(self):
        rowHeight = self.library_view.horizontalHeader().height()
        for rowNumber in range(0, self.library_view.model().rowCount()):
            self.library_view.setRowHeight(rowNumber, rowHeight)
class AnnotatedBooksDialog(SizePersistedDialog):
    '''
    This dialog is shown when the user fetches or imports books
    self.fetch_single_annotations controls checkmark display, behavior of fetch button
    '''
    if isosx:
        FONT = QFont('Monaco', 11)
    elif iswindows:
        FONT = QFont('Lucida Console', 9)
    elif islinux:
        FONT = QFont('Monospace', 9)
        FONT.setStyleHint(QFont.TypeWriter)

    def __init__(self, parent, book_list, get_annotations_as_HTML, source):
        self.opts = parent.opts
        self.parent = parent
        self.get_annotations_as_HTML = get_annotations_as_HTML
        self.show_confidence_colors = self.opts.prefs.get(
            'annotated_books_dialog_show_confidence_as_bg_color', True)
        self.source = source

        #         QDialog.__init__(self, parent=self.opts.gui)
        SizePersistedDialog.__init__(
            self, self.opts.gui,
            'Annotations plugin:import annotations dialog')
        self.setWindowTitle(_('Import Annotations'))
        self.setWindowIcon(self.opts.icon)
        self.l = QVBoxLayout(self)
        self.setLayout(self.l)
        self.perfect_width = 0

        from calibre_plugins.annotations.appearance import default_timestamp
        friendly_timestamp_format = plugin_prefs.get(
            'appearance_timestamp_format', default_timestamp)

        # Are we collecting News clippings?
        collect_news_clippings = self.opts.prefs.get(
            'cfg_news_clippings_checkbox', False)
        news_clippings_destination = self.opts.prefs.get(
            'cfg_news_clippings_lineEdit', None)

        # Populate the table data
        self.tabledata = []
        for book_data in book_list:
            enabled = QCheckBox()
            enabled.setChecked(True)

            # last_annotation sorts by timestamp
            last_annotation = SortableTableWidgetItem(
                strftime(friendly_timestamp_format,
                         localtime(book_data['last_update'])),
                book_data['last_update'])

            # reader_app sorts case-insensitive
            reader_app = SortableTableWidgetItem(
                book_data['reader_app'], book_data['reader_app'].upper())

            # title, author sort by title_sort, author_sort
            if not book_data['title_sort']:
                book_data['title_sort'] = book_data['title']
            title = SortableTableWidgetItem(book_data['title'],
                                            book_data['title_sort'].upper())

            if not book_data['author_sort']:
                book_data['author_sort'] = book_data['author']
            author = SortableTableWidgetItem(book_data['author'],
                                             book_data['author_sort'].upper())

            genres = book_data['genre'].split(', ')
            if 'News' in genres and collect_news_clippings:
                cid = get_clippings_cid(self, news_clippings_destination)
                confidence = 5
            else:
                cid, confidence = parent.generate_confidence(book_data)

            # List order matches self.annotations_header
            this_book = [
                book_data['uuid'], book_data['book_id'], book_data['genre'],
                enabled, reader_app, title, author, last_annotation,
                book_data['annotations'], confidence
            ]
            self.tabledata.append(this_book)

        self.tv = QTableView(self)
        self.l.addWidget(self.tv)
        self.annotations_header = [
            'uuid', 'book_id', 'genre', '',
            _('Reader App'),
            _('Title'),
            _('Author'),
            _('Last Annotation'),
            _('Annotations'),
            _('Confidence')
        ]
        self.ENABLED_COL = 3
        self.READER_APP_COL = 4
        self.TITLE_COL = 5
        self.AUTHOR_COL = 6
        self.LAST_ANNOTATION_COL = 7
        self.CONFIDENCE_COL = 9
        columns_to_center = [8]
        self.tm = MarkupTableModel(self, columns_to_center=columns_to_center)
        self.tv.setModel(self.tm)
        self.tv.setShowGrid(False)
        self.tv.setFont(self.FONT)
        self.tvSelectionModel = self.tv.selectionModel()
        self.tv.setAlternatingRowColors(not self.show_confidence_colors)
        self.tv.setShowGrid(False)
        self.tv.setWordWrap(False)
        self.tv.setSelectionBehavior(self.tv.SelectRows)

        # Connect signals
        self.tv.doubleClicked.connect(self.getTableRowDoubleClick)
        self.tv.horizontalHeader().sectionClicked.connect(
            self.capture_sort_column)

        # Hide the vertical self.header
        self.tv.verticalHeader().setVisible(False)

        # Hide uuid, book_id, genre, confidence
        self.tv.hideColumn(self.annotations_header.index('uuid'))
        self.tv.hideColumn(self.annotations_header.index('book_id'))
        self.tv.hideColumn(self.annotations_header.index('genre'))
        #         self.tv.hideColumn(self.annotations_header.index(_('Confidence')))
        self.tv.hideColumn(self.CONFIDENCE_COL)

        # Set horizontal self.header props
        self.tv.horizontalHeader().setStretchLastSection(True)

        narrow_columns = [
            _('Last Annotation'),
            _('Reader App'),
            _('Annotations')
        ]
        extra_width = 10
        breathing_space = 20

        # Set column width to fit contents
        self.tv.resizeColumnsToContents()
        perfect_width = 10 + (len(narrow_columns) * extra_width)
        for i in range(3, 8):
            perfect_width += self.tv.columnWidth(i) + breathing_space
        self.tv.setMinimumSize(perfect_width, 100)
        self.perfect_width = perfect_width

        # Add some width to narrow columns
        for nc in narrow_columns:
            cw = self.tv.columnWidth(self.annotations_header.index(nc))
            self.tv.setColumnWidth(self.annotations_header.index(nc),
                                   cw + extra_width)

        # Set row height
        fm = QFontMetrics(self.FONT)
        nrows = len(self.tabledata)
        for row in xrange(nrows):
            self.tv.setRowHeight(row, fm.height() + 4)

        self.tv.setSortingEnabled(True)
        sort_column = self.opts.prefs.get('annotated_books_dialog_sort_column',
                                          self.CONFIDENCE_COL)
        sort_order = self.opts.prefs.get('annotated_books_dialog_sort_order',
                                         Qt.DescendingOrder)
        self.tv.sortByColumn(sort_column, sort_order)

        # ~~~~~~~~ Create the ButtonBox ~~~~~~~~
        self.dialogButtonBox = QDialogButtonBox(QDialogButtonBox.Cancel
                                                | QDialogButtonBox.Help)
        self.dialogButtonBox.setOrientation(Qt.Horizontal)
        self.import_button = self.dialogButtonBox.addButton(
            self.dialogButtonBox.Ok)
        self.import_button.setText(_('Import Annotations'))

        # Action buttons
        self.toggle_checkmarks_button = self.dialogButtonBox.addButton(
            _('Clear All'), QDialogButtonBox.ActionRole)
        self.toggle_checkmarks_button.setObjectName('toggle_checkmarks_button')

        scb_text = _('Show match status')
        if self.show_confidence_colors:
            scb_text = _("Hide match status")
        self.show_confidence_button = self.dialogButtonBox.addButton(
            scb_text, QDialogButtonBox.ActionRole)
        self.show_confidence_button.setObjectName('confidence_button')
        if self.show_confidence_colors:
            self.show_confidence_button.setIcon(
                get_icon('images/matches_hide.png'))
        else:
            self.show_confidence_button.setIcon(
                get_icon('images/matches_show.png'))

        self.preview_button = self.dialogButtonBox.addButton(
            _('Preview'), QDialogButtonBox.ActionRole)
        self.preview_button.setObjectName('preview_button')

        self.dialogButtonBox.clicked.connect(
            self.show_annotated_books_dialog_clicked)
        self.l.addWidget(self.dialogButtonBox)

        # Cause our dialog size to be restored from prefs or created on first usage
        self.resize_dialog()

    def capture_sort_column(self, sort_column):
        sort_order = self.tv.horizontalHeader().sortIndicatorOrder()
        self.opts.prefs.set('annotated_books_dialog_sort_column', sort_column)
        self.opts.prefs.set('annotated_books_dialog_sort_order', sort_order)

    def fetch_selected_annotations(self):
        '''
        Invoked by 'Import annotations' button in show_annotated_books_dialog()
        Populate a list of books by Reader App:
        { 'iBooks': [{'title':, 'author':, 'uuid'}, ...],
          'Marvin': [{'title':, 'author':, 'uuid'}, ...] }
        '''
        self.selected_books = {}

        for i in range(len(self.tabledata)):
            self.tv.selectRow(i)
            enabled = bool(self.tm.arraydata[i][self.ENABLED_COL].checkState())
            if not enabled:
                continue

            reader_app = str(self.tm.arraydata[i][self.READER_APP_COL].text())
            if not reader_app in self.selected_books:
                self.selected_books[reader_app] = []

            author = str(self.tm.arraydata[i][self.AUTHOR_COL].text())
            book_id = self.tm.arraydata[i][self.annotations_header.index(
                'book_id')]
            genre = self.tm.arraydata[i][self.annotations_header.index(
                'genre')]
            title = str(self.tm.arraydata[i][self.TITLE_COL].text())
            uuid = self.tm.arraydata[i][self.annotations_header.index('uuid')]

            book_mi = BookStruct()
            book_mi.author = author
            book_mi.book_id = book_id
            book_mi.genre = genre
            book_mi.reader_app = reader_app
            book_mi.title = title
            book_mi.uuid = uuid
            self.selected_books[reader_app].append(book_mi)

    def getTableRowDoubleClick(self, index):
        self.preview_annotations()

    def preview_annotations(self):
        """
        The listed annotations are in annotations.db.
        AnnotationsDB:annotations_to_HTML() needs title, book_id, reader_app
        """
        i = self.tvSelectionModel.currentIndex().row()
        reader_app = str(self.tm.arraydata[i][self.READER_APP_COL].text())
        title = str(self.tm.arraydata[i][self.TITLE_COL].text())

        book_mi = BookStruct()
        book_mi.book_id = self.tm.arraydata[i][self.annotations_header.index(
            'book_id')]
        book_mi.reader_app = reader_app
        book_mi.title = title

        # Render annotations from db
        annotations_db = ReaderApp.generate_annotations_db_name(
            reader_app, self.source)
        annotations = self.get_annotations_as_HTML(annotations_db, book_mi)

        PreviewDialog(book_mi, annotations, parent=self.opts.gui).exec_()

    def show_annotated_books_dialog_clicked(self, button):
        '''
        BUTTON_ROLES = ['AcceptRole', 'RejectRole', 'DestructiveRole', 'ActionRole',
                        'HelpRole', 'YesRole', 'NoRole', 'ApplyRole', 'ResetRole']
        '''
        if self.dialogButtonBox.buttonRole(
                button) == QDialogButtonBox.AcceptRole:
            self.fetch_selected_annotations()
            self.accept()
        elif self.dialogButtonBox.buttonRole(
                button) == QDialogButtonBox.ActionRole:
            if button.objectName() == 'confidence_button':
                self.toggle_confidence_colors()
            elif button.objectName() == 'preview_button':
                self.preview_annotations()
            elif button.objectName() == 'toggle_checkmarks_button':
                self.toggle_checkmarks()
        elif self.dialogButtonBox.buttonRole(
                button) == QDialogButtonBox.HelpRole:
            self.show_help()
        elif self.dialogButtonBox.buttonRole(
                button) == QDialogButtonBox.RejectRole:
            self.close()

    def show_help(self):
        '''
        Display help file
        '''
        hv = HelpView(self,
                      self.opts.icon,
                      self.opts.prefs,
                      html=get_resources('help/import_annotations.html'),
                      title=_("Import Annotations"))
        hv.show()

    def size_hint(self):
        return QtCore.QSize(self.perfect_width, self.height())

    def start_confidence_scan(self):
        self.annotated_books_scanner.start()

    def toggle_checkmarks(self):
        button_text = str(self.toggle_checkmarks_button.text())
        if button_text == _('Clear All'):
            for i in range(len(self.tabledata)):
                self.tm.arraydata[i][self.ENABLED_COL].setCheckState(False)
            self.toggle_checkmarks_button.setText(_('Set All'))
        else:
            for i in range(len(self.tabledata)):
                self.tm.arraydata[i][self.ENABLED_COL].setCheckState(True)
            self.toggle_checkmarks_button.setText(_('Clear All'))
        self.tm.refresh(self.show_confidence_colors)

    def toggle_confidence_colors(self):
        self.show_confidence_colors = not self.show_confidence_colors
        self.opts.prefs.set(
            'annotated_books_dialog_show_confidence_as_bg_color',
            self.show_confidence_colors)
        if self.show_confidence_colors:
            self.show_confidence_button.setText(_("Hide match status"))
            self.show_confidence_button.setIcon(
                get_icon('images/matches_hide.png'))
            self.tv.sortByColumn(self.CONFIDENCE_COL, Qt.DescendingOrder)
            self.capture_sort_column(self.CONFIDENCE_COL)
        else:
            self.show_confidence_button.setText(_("Show match status"))
            self.show_confidence_button.setIcon(
                get_icon('images/matches_show.png'))
        self.tv.setAlternatingRowColors(not self.show_confidence_colors)
        self.tm.refresh(self.show_confidence_colors)
class AnnotatedBooksDialog(SizePersistedDialog):
    '''
    This dialog is shown when the user fetches or imports books
    self.fetch_single_annotations controls checkmark display, behavior of fetch button
    '''
    if isosx:
        FONT = QFont('Monaco', 11)
    elif iswindows:
        FONT = QFont('Lucida Console', 9)
    elif islinux:
        FONT = QFont('Monospace', 9)
        FONT.setStyleHint(QFont.TypeWriter)

    def __init__(self, parent, book_list, get_annotations_as_HTML, source):
        self.opts = parent.opts
        self.parent = parent
        self.get_annotations_as_HTML = get_annotations_as_HTML
        self.show_confidence_colors = self.opts.prefs.get('annotated_books_dialog_show_confidence_as_bg_color', True)
        self.source = source

#         QDialog.__init__(self, parent=self.opts.gui)
        SizePersistedDialog.__init__(self, self.opts.gui, 'Annotations plugin:import annotations dialog')
        self.setWindowTitle(u'Import Annotations')
        self.setWindowIcon(self.opts.icon)
        self.l = QVBoxLayout(self)
        self.setLayout(self.l)
        self.perfect_width = 0

        from calibre_plugins.annotations.appearance import default_timestamp
        friendly_timestamp_format = plugin_prefs.get('appearance_timestamp_format', default_timestamp)

        # Are we collecting News clippings?
        collect_news_clippings = self.opts.prefs.get('cfg_news_clippings_checkbox', False)
        news_clippings_destination = self.opts.prefs.get('cfg_news_clippings_lineEdit', None)

        # Populate the table data
        self.tabledata = []
        for book_data in book_list:
            enabled = QCheckBox()
            enabled.setChecked(True)

            # last_annotation sorts by timestamp
            last_annotation = SortableTableWidgetItem(
                strftime(friendly_timestamp_format,
                         localtime(book_data['last_update'])),
                book_data['last_update'])

            # reader_app sorts case-insensitive
            reader_app = SortableTableWidgetItem(
                book_data['reader_app'],
                book_data['reader_app'].upper())

            # title, author sort by title_sort, author_sort
            if not book_data['title_sort']:
                book_data['title_sort'] = book_data['title']
            title = SortableTableWidgetItem(
                book_data['title'],
                book_data['title_sort'].upper())

            if not book_data['author_sort']:
                book_data['author_sort'] = book_data['author']
            author = SortableTableWidgetItem(
                book_data['author'],
                book_data['author_sort'].upper())

            genres = book_data['genre'].split(', ')
            if 'News' in genres and collect_news_clippings:
                cid = get_clippings_cid(self, news_clippings_destination)
                confidence = 5
            else:
                cid, confidence = parent.generate_confidence(book_data)

            # List order matches self.annotations_header
            this_book = [
                book_data['uuid'],
                book_data['book_id'],
                book_data['genre'],
                enabled,
                reader_app,
                title,
                author,
                last_annotation,
                book_data['annotations'],
                confidence]
            self.tabledata.append(this_book)

        self.tv = QTableView(self)
        self.l.addWidget(self.tv)
        self.annotations_header = ['uuid', 'book_id', 'genre', '', 'Reader App', 'Title',
                                   'Author', 'Last Annotation', 'Annotations', 'Confidence']
        self.ENABLED_COL = 3
        self.READER_APP_COL = 4
        self.TITLE_COL = 5
        self.AUTHOR_COL = 6
        self.LAST_ANNOTATION_COL = 7
        self.CONFIDENCE_COL = 9
        columns_to_center = [8]
        self.tm = MarkupTableModel(self, columns_to_center=columns_to_center)
        self.tv.setModel(self.tm)
        self.tv.setShowGrid(False)
        self.tv.setFont(self.FONT)
        self.tvSelectionModel = self.tv.selectionModel()
        self.tv.setAlternatingRowColors(not self.show_confidence_colors)
        self.tv.setShowGrid(False)
        self.tv.setWordWrap(False)
        self.tv.setSelectionBehavior(self.tv.SelectRows)

        # Connect signals
        self.tv.doubleClicked.connect(self.getTableRowDoubleClick)
        self.tv.horizontalHeader().sectionClicked.connect(self.capture_sort_column)

        # Hide the vertical self.header
        self.tv.verticalHeader().setVisible(False)

        # Hide uuid, book_id, genre, confidence
        self.tv.hideColumn(self.annotations_header.index('uuid'))
        self.tv.hideColumn(self.annotations_header.index('book_id'))
        self.tv.hideColumn(self.annotations_header.index('genre'))
        self.tv.hideColumn(self.annotations_header.index('Confidence'))

        # Set horizontal self.header props
        self.tv.horizontalHeader().setStretchLastSection(True)

        narrow_columns = ['Last Annotation', 'Reader App', 'Annotations']
        extra_width = 10
        breathing_space = 20

        # Set column width to fit contents
        self.tv.resizeColumnsToContents()
        perfect_width = 10 + (len(narrow_columns) * extra_width)
        for i in range(3, 8):
            perfect_width += self.tv.columnWidth(i) + breathing_space
        self.tv.setMinimumSize(perfect_width, 100)
        self.perfect_width = perfect_width

        # Add some width to narrow columns
        for nc in narrow_columns:
            cw = self.tv.columnWidth(self.annotations_header.index(nc))
            self.tv.setColumnWidth(self.annotations_header.index(nc), cw + extra_width)

        # Set row height
        fm = QFontMetrics(self.FONT)
        nrows = len(self.tabledata)
        for row in xrange(nrows):
            self.tv.setRowHeight(row, fm.height() + 4)

        self.tv.setSortingEnabled(True)
        sort_column = self.opts.prefs.get('annotated_books_dialog_sort_column',
                                          self.annotations_header.index('Confidence'))
        sort_order = self.opts.prefs.get('annotated_books_dialog_sort_order',
                                         Qt.DescendingOrder)
        self.tv.sortByColumn(sort_column, sort_order)

        # ~~~~~~~~ Create the ButtonBox ~~~~~~~~
        self.dialogButtonBox = QDialogButtonBox(QDialogButtonBox.Cancel | QDialogButtonBox.Help)
        self.dialogButtonBox.setOrientation(Qt.Horizontal)
        self.import_button = self.dialogButtonBox.addButton(self.dialogButtonBox.Ok)
        self.import_button.setText('Import Annotations')

        # Action buttons
        self.toggle_checkmarks_button = self.dialogButtonBox.addButton('Clear All', QDialogButtonBox.ActionRole)
        self.toggle_checkmarks_button.setObjectName('toggle_checkmarks_button')

        scb_text = 'Show match status'
        if self.show_confidence_colors:
            scb_text = "Hide match status"
        self.show_confidence_button = self.dialogButtonBox.addButton(scb_text, QDialogButtonBox.ActionRole)
        self.show_confidence_button.setObjectName('confidence_button')
        if self.show_confidence_colors:
            self.show_confidence_button.setIcon(get_icon('images/matches_hide.png'))
        else:
            self.show_confidence_button.setIcon(get_icon('images/matches_show.png'))

        self.preview_button = self.dialogButtonBox.addButton('Preview', QDialogButtonBox.ActionRole)
        self.preview_button.setObjectName('preview_button')

        self.dialogButtonBox.clicked.connect(self.show_annotated_books_dialog_clicked)
        self.l.addWidget(self.dialogButtonBox)

        # Cause our dialog size to be restored from prefs or created on first usage
        self.resize_dialog()

    def capture_sort_column(self, sort_column):
        sort_order = self.tv.horizontalHeader().sortIndicatorOrder()
        self.opts.prefs.set('annotated_books_dialog_sort_column', sort_column)
        self.opts.prefs.set('annotated_books_dialog_sort_order', sort_order)

    def fetch_selected_annotations(self):
        '''
        Invoked by 'Import annotations' button in show_annotated_books_dialog()
        Populate a list of books by Reader App:
        { 'iBooks': [{'title':, 'author':, 'uuid'}, ...],
          'Marvin': [{'title':, 'author':, 'uuid'}, ...] }
        '''
        self.selected_books = {}

        for i in range(len(self.tabledata)):
            self.tv.selectRow(i)
            enabled = bool(self.tm.arraydata[i][self.ENABLED_COL].checkState())
            if not enabled:
                continue

            reader_app = str(self.tm.arraydata[i][self.annotations_header.index('Reader App')].text())
            if not reader_app in self.selected_books:
                self.selected_books[reader_app] = []

            author = str(self.tm.arraydata[i][self.annotations_header.index('Author')].text())
            book_id = self.tm.arraydata[i][self.annotations_header.index('book_id')]
            genre = self.tm.arraydata[i][self.annotations_header.index('genre')]
            title = str(self.tm.arraydata[i][self.annotations_header.index('Title')].text())
            uuid = self.tm.arraydata[i][self.annotations_header.index('uuid')]

            book_mi = BookStruct()
            book_mi.author = author
            book_mi.book_id = book_id
            book_mi.genre = genre
            book_mi.reader_app = reader_app
            book_mi.title = title
            book_mi.uuid = uuid
            self.selected_books[reader_app].append(book_mi)

    def getTableRowDoubleClick(self, index):
        self.preview_annotations()

    def preview_annotations(self):
        """
        The listed annotations are in annotations.db.
        AnnotationsDB:annotations_to_HTML() needs title, book_id, reader_app
        """
        i = self.tvSelectionModel.currentIndex().row()
        reader_app = str(self.tm.arraydata[i][self.annotations_header.index('Reader App')].text())
        title = str(self.tm.arraydata[i][self.annotations_header.index('Title')].text())

        book_mi = BookStruct()
        book_mi.book_id = self.tm.arraydata[i][self.annotations_header.index('book_id')]
        book_mi.reader_app = reader_app
        book_mi.title = title

        # Render annotations from db
        annotations_db = ReaderApp.generate_annotations_db_name(reader_app, self.source)
        annotations = self.get_annotations_as_HTML(annotations_db, book_mi)

        PreviewDialog(book_mi, annotations, parent=self.opts.gui).exec_()

    def show_annotated_books_dialog_clicked(self, button):
        '''
        BUTTON_ROLES = ['AcceptRole', 'RejectRole', 'DestructiveRole', 'ActionRole',
                        'HelpRole', 'YesRole', 'NoRole', 'ApplyRole', 'ResetRole']
        '''
        if self.dialogButtonBox.buttonRole(button) == QDialogButtonBox.AcceptRole:
            self.fetch_selected_annotations()
            self.accept()
        elif self.dialogButtonBox.buttonRole(button) == QDialogButtonBox.ActionRole:
            if button.objectName() == 'confidence_button':
                self.toggle_confidence_colors()
            elif button.objectName() == 'preview_button':
                self.preview_annotations()
            elif button.objectName() == 'toggle_checkmarks_button':
                self.toggle_checkmarks()
        elif self.dialogButtonBox.buttonRole(button) == QDialogButtonBox.HelpRole:
            self.show_help()
        elif self.dialogButtonBox.buttonRole(button) == QDialogButtonBox.RejectRole:
            self.close()

    def show_help(self):
        '''
        Display help file
        '''
        hv = HelpView(self, self.opts.icon, self.opts.prefs,
                      html=get_resources('help/import_annotations.html'), title="Import Annotations")
        hv.show()

    def size_hint(self):
        return QtCore.QSize(self.perfect_width, self.height())

    def start_confidence_scan(self):
        self.annotated_books_scanner.start()

    def toggle_checkmarks(self):
        button_text = str(self.toggle_checkmarks_button.text())
        if button_text == 'Clear All':
            for i in range(len(self.tabledata)):
                self.tm.arraydata[i][self.ENABLED_COL].setCheckState(False)
            self.toggle_checkmarks_button.setText(' Set All ')
        else:
            for i in range(len(self.tabledata)):
                self.tm.arraydata[i][self.ENABLED_COL].setCheckState(True)
            self.toggle_checkmarks_button.setText('Clear All')
        self.tm.refresh(self.show_confidence_colors)

    def toggle_confidence_colors(self):
        self.show_confidence_colors = not self.show_confidence_colors
        self.opts.prefs.set('annotated_books_dialog_show_confidence_as_bg_color', self.show_confidence_colors)
        if self.show_confidence_colors:
            self.show_confidence_button.setText("Hide match status")
            self.show_confidence_button.setIcon(get_icon('images/matches_hide.png'))
            self.tv.sortByColumn(self.annotations_header.index('Confidence'), Qt.DescendingOrder)
            self.capture_sort_column(self.annotations_header.index('Confidence'))
        else:
            self.show_confidence_button.setText("Show match status")
            self.show_confidence_button.setIcon(get_icon('images/matches_show.png'))
        self.tv.setAlternatingRowColors(not self.show_confidence_colors)
        self.tm.refresh(self.show_confidence_colors)
示例#9
0
class OpdsDialog(QDialog):

    def __init__(self, gui, icon, do_user_config):
        QDialog.__init__(self, gui)
        self.gui = gui
        self.do_user_config = do_user_config

        self.db = gui.current_db.new_api

        # The model for the book list
        self.model = OpdsBooksModel(None, self.dummy_books(), self.db)
        self.searchproxymodel = QSortFilterProxyModel(self)
        self.searchproxymodel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.searchproxymodel.setFilterKeyColumn(-1)
        self.searchproxymodel.setSourceModel(self.model)

        self.layout = QGridLayout()
        self.setLayout(self.layout)

        self.setWindowTitle('OPDS Client')
        self.setWindowIcon(icon)

        labelColumnWidths = []

        self.opdsUrlLabel = QLabel('OPDS URL: ')
        self.layout.addWidget(self.opdsUrlLabel, 0, 0)
        labelColumnWidths.append(self.layout.itemAtPosition(0, 0).sizeHint().width())

        config.convertSingleStringOpdsUrlPreferenceToListOfStringsPreference()
        self.opdsUrlEditor = QComboBox(self)
        self.opdsUrlEditor.activated.connect(self.opdsUrlEditorActivated)
        self.opdsUrlEditor.addItems(prefs['opds_url'])
        self.opdsUrlEditor.setEditable(True)
        self.opdsUrlEditor.setInsertPolicy(QComboBox.InsertAtTop)
        self.layout.addWidget(self.opdsUrlEditor, 0, 1, 1, 3)
        self.opdsUrlLabel.setBuddy(self.opdsUrlEditor)

        buttonColumnNumber = 7
        buttonColumnWidths = []
        self.about_button = QPushButton('About', self)
        self.about_button.setAutoDefault(False)
        self.about_button.clicked.connect(self.about)
        self.layout.addWidget(self.about_button, 0, buttonColumnNumber)
        buttonColumnWidths.append(self.layout.itemAtPosition(0, buttonColumnNumber).sizeHint().width()) 

        # Initially download the catalogs found in the root catalog of the URL
        # selected at startup.  Fail quietly on failing to open the URL
        catalogsTuple = self.model.downloadOpdsRootCatalog(self.gui, self.opdsUrlEditor.currentText(), False)
        print catalogsTuple
        firstCatalogTitle = catalogsTuple[0]
        self.currentOpdsCatalogs = catalogsTuple[1] # A dictionary of title->feedURL

        self.opdsCatalogSelectorLabel = QLabel('OPDS Catalog:')
        self.layout.addWidget(self.opdsCatalogSelectorLabel, 1, 0)
        labelColumnWidths.append(self.layout.itemAtPosition(1, 0).sizeHint().width())

        self.opdsCatalogSelector = QComboBox(self)
        self.opdsCatalogSelector.setEditable(False)
        self.opdsCatalogSelectorModel = QStringListModel(self.currentOpdsCatalogs.keys())
        self.opdsCatalogSelector.setModel(self.opdsCatalogSelectorModel)
        self.opdsCatalogSelector.setCurrentText(firstCatalogTitle)
        self.layout.addWidget(self.opdsCatalogSelector, 1, 1, 1, 3)

        self.download_opds_button = QPushButton('Download OPDS', self)
        self.download_opds_button.setAutoDefault(False)
        self.download_opds_button.clicked.connect(self.download_opds)
        self.layout.addWidget(self.download_opds_button, 1, buttonColumnNumber)
        buttonColumnWidths.append(self.layout.itemAtPosition(1, buttonColumnNumber).sizeHint().width()) 

        # Search GUI
        self.searchEditor = QLineEdit(self)
        self.searchEditor.returnPressed.connect(self.searchBookList)
        self.layout.addWidget(self.searchEditor, 2, buttonColumnNumber - 2, 1, 2)

        self.searchButton = QPushButton('Search', self)
        self.searchButton.setAutoDefault(False)
        self.searchButton.clicked.connect(self.searchBookList)
        self.layout.addWidget(self.searchButton, 2, buttonColumnNumber)
        buttonColumnWidths.append(self.layout.itemAtPosition(2, buttonColumnNumber).sizeHint().width())

        # The main book list
        self.library_view = QTableView(self)
        self.library_view.setAlternatingRowColors(True)
        self.library_view.setModel(self.searchproxymodel)
        self.library_view.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
        self.library_view.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
        self.library_view.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch)
        self.library_view.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.resizeAllLibraryViewLinesToHeaderHeight()
        self.library_view.resizeColumnsToContents()
        self.layout.addWidget(self.library_view, 3, 0, 3, buttonColumnNumber + 1)

        self.hideNewsCheckbox = QCheckBox('Hide Newspapers', self)
        self.hideNewsCheckbox.clicked.connect(self.setHideNewspapers)
        self.hideNewsCheckbox.setChecked(prefs['hideNewspapers'])
        self.layout.addWidget(self.hideNewsCheckbox, 6, 0, 1, 3)

        self.hideBooksAlreadyInLibraryCheckbox = QCheckBox('Hide books already in library', self)
        self.hideBooksAlreadyInLibraryCheckbox.clicked.connect(self.setHideBooksAlreadyInLibrary)
        self.hideBooksAlreadyInLibraryCheckbox.setChecked(prefs['hideBooksAlreadyInLibrary'])
        self.layout.addWidget(self.hideBooksAlreadyInLibraryCheckbox, 7, 0, 1, 3)

        # Let the checkbox initial state control the filtering
        self.model.setFilterBooksThatAreNewspapers(self.hideNewsCheckbox.isChecked())
        self.model.setFilterBooksThatAreAlreadyInLibrary(self.hideBooksAlreadyInLibraryCheckbox.isChecked())

        self.downloadButton = QPushButton('Download selected books', self)
        self.downloadButton.setAutoDefault(False)
        self.downloadButton.clicked.connect(self.downloadSelectedBooks)
        self.layout.addWidget(self.downloadButton, 6, buttonColumnNumber)
        buttonColumnWidths.append(self.layout.itemAtPosition(6, buttonColumnNumber).sizeHint().width()) 

        self.fixTimestampButton = QPushButton('Fix timestamps of selection', self)
        self.fixTimestampButton.setAutoDefault(False)
        self.fixTimestampButton.clicked.connect(self.fixBookTimestamps)
        self.layout.addWidget(self.fixTimestampButton, 7, buttonColumnNumber)
        buttonColumnWidths.append(self.layout.itemAtPosition(7, buttonColumnNumber).sizeHint().width()) 

        # Make all columns of the grid layout the same width as the button column
        buttonColumnWidth = max(buttonColumnWidths)
        for columnNumber in range(0, buttonColumnNumber):
            self.layout.setColumnMinimumWidth(columnNumber, buttonColumnWidth)

        # Make sure the first column isn't wider than the labels it holds
        labelColumnWidth = max(labelColumnWidths)
        self.layout.setColumnMinimumWidth(0, labelColumnWidth)

        self.resize(self.sizeHint())

    def opdsUrlEditorActivated(self, text):
        prefs['opds_url'] = config.saveOpdsUrlCombobox(self.opdsUrlEditor)
        catalogsTuple = self.model.downloadOpdsRootCatalog(self.gui, self.opdsUrlEditor.currentText(), True)
        firstCatalogTitle = catalogsTuple[0]
        self.currentOpdsCatalogs = catalogsTuple[1] # A dictionary of title->feedURL
        self.opdsCatalogSelectorModel.setStringList(self.currentOpdsCatalogs.keys())
        self.opdsCatalogSelector.setCurrentText(firstCatalogTitle)

    def setHideNewspapers(self, checked):
        prefs['hideNewspapers'] = checked
        self.model.setFilterBooksThatAreNewspapers(checked)
        self.resizeAllLibraryViewLinesToHeaderHeight()

    def setHideBooksAlreadyInLibrary(self, checked):
        prefs['hideBooksAlreadyInLibrary'] = checked
        self.model.setFilterBooksThatAreAlreadyInLibrary(checked)
        self.resizeAllLibraryViewLinesToHeaderHeight()

    def searchBookList(self):
        searchString = self.searchEditor.text()
        print "starting book list search for: %s" % searchString
        self.searchproxymodel.setFilterFixedString(searchString)

    def about(self):
        text = get_resources('about.txt')
        QMessageBox.about(self, 'About the OPDS Client plugin', text.decode('utf-8'))

    def download_opds(self):
        opdsCatalogUrl = self.currentOpdsCatalogs.get(self.opdsCatalogSelector.currentText(), None)
        if opdsCatalogUrl is None:
            # Just give up quietly
            return
        self.model.downloadOpdsCatalog(self.gui, opdsCatalogUrl)
        if self.model.isCalibreOpdsServer():
            self.model.downloadMetadataUsingCalibreRestApi(self.opdsUrlEditor.currentText())
        self.library_view.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
        self.library_view.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
        self.library_view.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch)
        self.resizeAllLibraryViewLinesToHeaderHeight()
        self.resize(self.sizeHint())

    def config(self):
        self.do_user_config(parent=self)

    def downloadSelectedBooks(self):
        selectionmodel = self.library_view.selectionModel()
        if selectionmodel.hasSelection():
            rows = selectionmodel.selectedRows()
            for row in reversed(rows):
                book = row.data(Qt.UserRole)
                self.downloadBook(book)

    def downloadBook(self, book):
        if len(book.links) > 0:
            self.gui.download_ebook(book.links[0])

    def fixBookTimestamps(self):
        selectionmodel = self.library_view.selectionModel()
        if selectionmodel.hasSelection():
            rows = selectionmodel.selectedRows()
            for row in reversed(rows):
                book = row.data(Qt.UserRole)
                self.fixBookTimestamp(book)

    def fixBookTimestamp(self, book):
        bookTimestamp = book.timestamp
        identicalBookIds = self.findIdenticalBooksForBooksWithMultipleAuthors(book)
        bookIdToValMap = {}
        for identicalBookId in identicalBookIds:
            bookIdToValMap[identicalBookId] = bookTimestamp
        if len(bookIdToValMap) < 1:
            print "Failed to set timestamp of book: %s" % book
        self.db.set_field('timestamp', bookIdToValMap)

    def findIdenticalBooksForBooksWithMultipleAuthors(self, book):
        authorsList = book.authors
        if len(authorsList) < 2:
            return self.db.find_identical_books(book)
        # Try matching the authors one by one
        identicalBookIds = set()
        for author in authorsList:
            singleAuthorBook = Metadata(book.title, [author])
            singleAuthorIdenticalBookIds = self.db.find_identical_books(singleAuthorBook)
            identicalBookIds = identicalBookIds.union(singleAuthorIdenticalBookIds)
        return identicalBookIds

    def dummy_books(self):
        dummy_author = ' ' * 40
        dummy_title = ' ' * 60
        books_list = []
        for line in range (1, 10):
            book = DynamicBook()
            book.author = dummy_author
            book.title = dummy_title
            book.updated = datetime.datetime.now().strftime('%Y-%m-%dT%H:%M:%S+00:00')
            book.id = ''
            books_list.append(book)
        return books_list

    def resizeAllLibraryViewLinesToHeaderHeight(self):
        rowHeight = self.library_view.horizontalHeader().height()
        for rowNumber in range (0, self.library_view.model().rowCount()):
            self.library_view.setRowHeight(rowNumber, rowHeight)
示例#10
0
class FITSBrowse(QMainWindow):
    """ The main window of this GUI."""

    imdisp = None

    def __init__(self, parent=None):
        """ 
        """
        print("Skeet")

        super(FITSBrowse, self).__init__(parent)
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        self.setWindowTitle("FITSBrowse")

        self.current_directory = CurrentDirectory(
            "/data/lemi-archive-2016-04/20160427")
        self.model = FitsFileTableModel(self.current_directory)
        self.d_model = DirectoryListModel(self.current_directory)
        self.main_widget = QWidget(self)

        self.dir_text = "Current Directory: {0}".format(
            self.current_directory.cur_dir_path)
        self.cur_dir_label = QLabel(self.dir_text, self)

        self.listLabel = QLabel("&Directories")

        self.list_view = QListView()
        self.listLabel.setBuddy(self.list_view)
        self.list_view.setModel(self.d_model)
        self.list_view.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)

        self.list_view.setMinimumWidth(self.list_view.sizeHintForColumn(0))
        self.list_view.setMaximumWidth(self.list_view.sizeHintForColumn(0))

        self.list_view_sm = self.list_view.selectionModel()
        self.list_view.doubleClicked.connect(self.change_directory)

        self.table_view = QTableView()
        self.table_view.setModel(self.model)
        self.table_view.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        self.table_view_sm = self.table_view.selectionModel()
        self.table_view.doubleClicked.connect(self.display_image)

        list_vbox = QVBoxLayout()
        list_vbox.addWidget(self.listLabel)
        list_vbox.addWidget(self.list_view)
        self.list_widget = QWidget()
        self.list_widget.setLayout(list_vbox)

        #self.list_view.size

        main_layout = QHBoxLayout()
        main_layout.addWidget(self.list_widget)
        main_layout.addWidget(self.table_view)

        button_layout = QHBoxLayout()
        quit_button = QPushButton('Quit', self)
        quit_button.setToolTip('This button quits FITSBrowse')
        quit_button.clicked.connect(QApplication.instance().quit)
        button_layout.addStretch()
        button_layout.addWidget(quit_button)

        sep_line = QFrame()
        sep_line.setFrameShape(QFrame.HLine)

        super_layout = QVBoxLayout(self.main_widget)
        super_layout.addWidget(self.cur_dir_label)
        super_layout.addWidget(sep_line)
        super_layout.addLayout(main_layout)
        super_layout.addLayout(button_layout)

        self.setCentralWidget(self.main_widget)
        QtCore.QTimer.singleShot(0, self.initialLoad)
        x = self.table_view.frameSize()
        x = x.width()
        self.table_view.setMinimumWidth(x)
        self.main_widget.setMinimumHeight(500)

    def initialLoad(self):
        for column in (1, 2, 3, 4, 5, 6, 7):
            self.table_view.resizeColumnToContents(column)

    def display_image(self):
        indexes = self.table_view_sm.selectedIndexes()
        index = indexes[0]
        file_name = str(index.data())
        if (file_name.endswith("fits") or file_name.endswith("fit")):
            file_with_path = os.path.join(self.current_directory.cur_dir_path,
                                          file_name)
            self.im_disp = ImageAnalyzer(file_with_path, parent=self)

    def change_directory(self):
        indexes = self.list_view_sm.selectedRows()
        if (indexes != []):
            index = indexes[0]
            new_directory = str(index.data())
            current_path = self.current_directory.cur_dir_path
            if (new_directory == ".."):
                # Go up one directory
                if (current_path == "/"):
                    # Do nothing.
                    pass
                else:
                    self.current_directory = CurrentDirectory(
                        os.path.dirname(current_path))
            else:
                # Go down into the selected directory.
                self.current_directory = CurrentDirectory(
                    os.path.join(current_path, new_directory))
            print("change directory, new directory is:",
                  self.current_directory.cur_dir_path)
            self.model = FitsFileTableModel(self.current_directory)
            self.d_model = DirectoryListModel(self.current_directory)

            self.dir_text = "Current Directory: {0}".format(
                self.current_directory.cur_dir_path)
            self.cur_dir_label.setText(self.dir_text)

            self.list_view.setModel(self.d_model)
            self.list_view_sm = self.list_view.selectionModel()
            self.list_view.update()
            self.list_view.setMinimumWidth(self.list_view.sizeHintForColumn(0))
            self.list_view.setMaximumWidth(self.list_view.sizeHintForColumn(0))

            self.table_view.setModel(self.model)
            self.table_view_sm = self.table_view.selectionModel()
            self.table_view.update()
            QtCore.QTimer.singleShot(0, self.initialLoad)
            x = self.table_view.frameSize()
            x = x.width()
            self.table_view.setMinimumWidth(x)
        else:
            print("no directory selected")