Exemplo n.º 1
0
class RecipeWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.recipe_title = ""

        self.conn = QSqlDatabase.addDatabase("QSQLITE")
        self.conn.setDatabaseName("recipes.db")

        self.initUI()

    def initUI(self):
        """
        PURPOSE
        -----
        To pass create all QWidgets to be displayed on our window.
        All class instances are changed dynamically, i.e. title, author, etc.
        All non-class instances are static widgets that will not be moved

        OUTPUT
        -----
        Nothing
        """
        self.setWindowTitle("Recipe Application")

        self.title = QLabel(self)
        self.title.setWordWrap(True)  # Enables word wrap for specific label
        self.title.setFont(QFont('Arial', 20, QFont.Bold))
        self.title.setAlignment(Qt.AlignCenter)
        self.title.setFixedWidth(600)
        self.title.move(150, 10)

        author_label = QLabel("Author: ", self)
        author_label.move(45, 120)
        author_label.setFont(QFont('Arial', 10, QFont.Bold))

        self.author = QLabel(self)
        self.author.move(95, 120)
        self.author.setFixedWidth(165)
        self.author.setFont(QFont('Arial', 10))

        cuisine_label = QLabel("Cuisine: ", self)
        cuisine_label.move(265, 120)
        cuisine_label.setFont(QFont('Arial', 10, QFont.Bold))

        self.cuisine = QLabel(self)
        self.cuisine.move(320, 120)
        self.cuisine.setFixedWidth(160)
        self.cuisine.setFont(QFont('Arial', 10))

        tag_label = QLabel("Tags: ", self)
        tag_label.move(485, 120)
        tag_label.setFont(QFont('Arial', 10, QFont.Bold))

        self.tags = QLabel(self)
        self.tags.setFixedWidth(330)
        self.tags.setWordWrap(True)
        self.tags.move(525, 115)
        self.tags.setFont(QFont('Arial', 10))

        ingredients_label = QLabel("Ingredients: ", self)
        ingredients_label.setFont(QFont('Arial', 10, QFont.Bold))
        ingredients_label.move(45, 170)

        self.ingredients = QTextEdit(self)
        self.ingredients.setReadOnly(True)
        self.ingredients.setFixedWidth(200)
        self.ingredients.setFixedHeight(300)
        self.ingredients.move(30, 200)
        self.ingredients.setFont(QFont('Arial', 10))

        recipe_label = QLabel("Recipe Procedure: ", self)
        recipe_label.setFont(QFont('Arial', 10, QFont.Bold))
        recipe_label.move(265, 170)

        self.recipe = QTextEdit(self)
        self.recipe.setReadOnly(True)
        self.recipe.setFixedWidth(610)
        self.recipe.setFixedHeight(300)
        self.recipe.move(250, 200)
        self.recipe.setFont(QFont('Arial', 10))

        website_url_label = QLabel("If you'd like to see full details of this recipe click here: ", self)
        website_url_label.setFont(QFont('Arial', 10, QFont.Bold))
        website_url_label.move(35, 540)

        self.website_url = QLabel(self)
        self.website_url.setOpenExternalLinks(True)  # Allows us to click on hyperlink
        self.website_url.setFixedWidth(500)
        self.website_url.setWordWrap(True)  # Set word wrap
        self.website_url.move(385, 540)
        self.website_url.setFont(QFont('Arial', 10))

        self.title_view_label = QLabel("Below are potentially some related recipes! :", self)
        self.title_view_label.setFont(QFont('Arial', 10))

    def obtain_recipe(self):
        """
        PURPOSE
        -----
        To obtain all information pertaining to the recipe clicked on by user, i.e. title, author, cuisine, etc. and
        create a model to store that information

        OUTPUT
        -----
        The model with the stored information
        """
        recipe_info_cmd = \
            f"""
        SELECT R.`Recipe Title`, R.Author, R.Cuisine, R.Ingredients, R.`Recipe Procedure`, R.Tags, R.'Website URL'
        FROM recipes R
        WHERE R.`Recipe Title` = "{self.recipe_title}"
        """
        # Query to get title, author, ingredients, and recipe procedure from desired recipe title
        recipe_query = QSqlQuery(self.conn)  # Same process as the title_query
        recipe_query.prepare(recipe_info_cmd)
        recipe_query.exec_()

        recipe_model = QSqlQueryModel()
        recipe_model.setQuery(recipe_query)

        return recipe_model

    def view_recipe(self, model):
        """
        PURPOSE
        -----
        To obtain all information pertaining to the recipe clicked on by user, i.e. title, author, cuisine, etc. from
        the model parameter and set the information to our widgets create in the initUI() function declared previously

        Then takes the tags from said recipe to view other recipes with one of its tags in view_related_recipes()

        INPUT
        -----
        model: QSqlQueryModel() containing recipe information

        OUTPUT
        -----
        Calls view_related_recipes() with array of tag values
        """

        # All values taken from QSqlQuery returned in obtain_recipe() function
        recipe_title = model.record(0).value(0)  # Recipe title
        recipe_author = model.record(0).value(1)  # Recipe author
        recipe_cuisine = model.record(0).value(2)  # Recipe cuisine
        recipe_ingredients = model.record(0).value(3)  # Recipe ingredients
        recipe_steps = model.record(0).value(4)  # Recipe steps
        recipe_tags = model.record(0).value(5)  # Recipe tags
        recipe_website = model.record(0).value(6)  # Recipe website

        self.setGeometry(0, 0, 900, 780)  # Set our window size
        self.setFixedSize(self.width(), self.height())

        # Everything done below is pretty self explanatory; create label/textedit, populate, move, etc.
        self.title.setText(recipe_title)
        self.title.repaint()

        self.author.setText(recipe_author)
        self.author.repaint()

        self.cuisine.setText(recipe_cuisine)
        self.cuisine.repaint()

        self.tags.setText(recipe_tags)
        self.tags.repaint()

        self.ingredients.setText(recipe_ingredients)
        self.ingredients.repaint()

        self.recipe.setText(recipe_steps)
        self.recipe.repaint()

        self.website_url.setText('<a href="' + recipe_website + '/">' + recipe_title + '</a>')  # Creates hyperlink
        self.website_url.repaint()

        self.view_related_recipes(recipe_tags.split(","))

    def view_related_recipes(self, tag_list):
        """
        PURPOSE
        -----
        To create a QTableView() with all recipes with like-tags of the already shown recipe

        INPUT
        -----
        tag_list: list containing tag information

        OUTPUT
        -----
        Displays full window containing recipe information + related recipes
        """

        recipe_query = ""  # Empty string to construct our query
        for elements in tag_list:
            # Here we construct our query through a for-loop
            # There shouldn't be many elements in our array in the first place, so no worries of efficiency
            recipe_query += f"Tags LIKE '%" + elements + "%' OR "

        recipe_query = recipe_query[:len(recipe_query) - 4]  # to remove last OR + extra space

        cmd = \
            f"""
            SELECT `Recipe Title` FROM recipes R WHERE {recipe_query}
            """
        title_query = QSqlQuery(self.conn)  # Establish our query, prepare, and execute it
        title_query.prepare(cmd)
        title_query.exec_()

        title_model = QSqlQueryModel()  # Adds our queried information into a read-only model
        title_model.setQuery(title_query)

        # Adds information from out query model to a QTableView to be seen
        self.title_view = QTableView(self)
        self.title_view.setModel(title_model)
        self.title_view.resizeColumnToContents(0)  # Modifying sizing of our QTableView

        new_title_width = self.title_view.columnWidth(0) + 45

        self.title_view_label.move(int((self.width() - new_title_width) / 2), 580)

        self.title_view.resize(new_title_width, 130)
        self.title_view.move(int((self.width() - new_title_width) / 2), 605)

        self.title_view.doubleClicked.connect(lambda: self.pass_info(
            self.title_view.selectionModel().currentIndex()))  # Allow users to go to new related recipe

        self.show()

    def pass_info(self, index):
        """
        PURPOSE
        -----
        To pass related recipe information in next window

        INPUT
        -----
        index: The index of the row+col selected by the user when they double click the recipe view

        OUTPUT
        -----
        calls function within RecipeWindow object we create in __init()__
        """
        # Get current indexed position from click
        cell_val = index.sibling(index.row(), index.column()).data()  # Get cell value from the cell itself
        self.recipe_title = cell_val
        self.title_view.hide()
        self.hide()
        self.view_recipe(self.obtain_recipe())
Exemplo n.º 2
0
class FreezeTableWidget(QTableView):
    def __init__(self, model):
        super(FreezeTableWidget, self).__init__()
        self.setModel(model)
        self.frozenTableView = QTableView(self)
        self.init()
        self.horizontalHeader().sectionResized.connect(self.updateSectionWidth)
        self.verticalHeader().sectionResized.connect(self.updateSectionHeight)
        self.frozenTableView.verticalScrollBar().valueChanged.connect(
            self.verticalScrollBar().setValue)
        self.verticalScrollBar().valueChanged.connect(
            self.frozenTableView.verticalScrollBar().setValue)

    def init(self):
        self.frozenTableView.setModel(self.model())
        self.frozenTableView.setFocusPolicy(Qt.NoFocus)
        self.frozenTableView.verticalHeader().hide()
        self.frozenTableView.horizontalHeader().setSectionResizeMode(
            QHeaderView.Fixed)
        self.viewport().stackUnder(self.frozenTableView)

        self.frozenTableView.setStyleSheet('''
            QTableView { border: none;
                         background-color: #8EDE21;
                         selection-background-color: #999;
            }''')  # for demo purposes

        self.frozenTableView.setSelectionModel(self.selectionModel())
        for col in range(1, self.model().columnCount()):
            self.frozenTableView.setColumnHidden(col, True)
        self.frozenTableView.setColumnWidth(0, self.columnWidth(0))
        self.frozenTableView.setHorizontalScrollBarPolicy(
            Qt.ScrollBarAlwaysOff)
        self.frozenTableView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.frozenTableView.show()
        self.updateFrozenTableGeometry()
        self.setHorizontalScrollMode(self.ScrollPerPixel)
        self.setVerticalScrollMode(self.ScrollPerPixel)
        self.frozenTableView.setVerticalScrollMode(self.ScrollPerPixel)

    def updateSectionWidth(self, logicalIndex, oldSize, newSize):
        if self.logicalIndex == 0:
            self.frozenTableView.setColumnWidth(0, newSize)
            self.updateFrozenTableGeometry()

    def updateSectionHeight(self, logicalIndex, oldSize, newSize):
        self.frozenTableView.setRowHeight(logicalIndex, newSize)

    def resizeEvent(self, event):
        super(FreezeTableWidget, self).resizeEvent(event)
        self.updateFrozenTableGeometry()

    def moveCursor(self, cursorAction, modifiers):
        current = super(FreezeTableWidget,
                        self).moveCursor(cursorAction, modifiers)
        if (cursorAction == self.MoveLeft and self.current.column() > 0
                and self.visualRect(current).topLeft().x() <
                self.frozenTableView.columnWidth(0)):
            newValue = (self.horizontalScrollBar().value() +
                        self.visualRect(current).topLeft().x() -
                        self.frozenTableView.columnWidth(0))
            self.horizontalScrollBar().setValue(newValue)
        return current

    def scrollTo(self, index, hint):
        if index.column() > 0:
            super(FreezeTableWidget, self).scrollTo(index, hint)

    def updateFrozenTableGeometry(self):
        self.frozenTableView.setGeometry(
            self.verticalHeader().width() + self.frameWidth(),
            self.frameWidth(), self.columnWidth(0),
            self.viewport().height() + self.horizontalHeader().height())
Exemplo n.º 3
0
class RecipeTitleWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.search_text = ""
        self.search_category = ""

        self.title_view = QTableView(self)

        self.recipe_window = RecipeWindow()

        # Create connection with SQlite3 language
        self.conn = QSqlDatabase.addDatabase("QSQLITE")
        self.conn.setDatabaseName("recipes.db")

    def recipe_search(self):
        """
        PURPOSE
        -----
        To search and display the recipes from the desired query from the user using sqlite3 on a table-view

        OUTPUT
        -----
        Displays a table of rows containing recipe titles that the user can double click on to view information about it

        """
        self.conn.open() # Open our connection to database
        self.setWindowTitle("Recipe Application")

        if len(self.search_text.strip(' ')) == 0: # If the query is empty, throw an error message
            error_dialog = QErrorMessage()
            error_dialog.showMessage(
                f"It seems you haven't input anything to search for the {self.search_category.lower()}'s associated recipes! Please try again.")
            error_dialog.exec_()
        else: # Otherwise we proceed as normally

            self.search_list = self.search_text.split(',')  # Create an array of desired ingredients

            recipe_query = ""  # Empty string to construct our query
            for elements in self.search_list:
                # Here we construct our query through a for-loop
                # There shouldn't be many elements in our array in the first place, so no worries of efficiency
                recipe_query += f"`{self.search_category}` LIKE '%" + elements + "%' AND "

            if len(recipe_query) > 5:  # On the off chance that there is nothing input into the text box, throw error
                recipe_query = recipe_query[:len(recipe_query) - 5]  # to remove last AND

            cmd = \
                f"""
                SELECT `Recipe Title` FROM recipes R WHERE {recipe_query}
                """

            title_query = QSqlQuery(self.conn)  # Establish our query, prepare, and execute it
            title_query.prepare(cmd)
            title_query.exec_()

            title_model = QSqlQueryModel()  # Adds our queried information into a read-only model
            title_model.setQuery(title_query)

            if title_model.rowCount() == 0: # If no recipes return, throw error message saying there exists no recipe
                                            # with their desired information
                empty_error_dialog = QErrorMessage()
                empty_error_dialog.showMessage(
                    f"It appears that there are no recipes pertaining to your search. Please try again!")
                empty_error_dialog.exec_()
            else:
                # Adds information from out query model to a QTableView to be seen
                self.title_view.setModel(title_model)
                self.title_view.setWindowTitle("Recipe List")

                self.title_view.doubleClicked.connect(lambda: self.pass_info(self.title_view.selectionModel().currentIndex()))
                # Adds functionality of view_recipe when double clicking cell

                self.title_view.setMaximumHeight(500) # Set max height of table + window
                self.setMaximumHeight(500)

                self.title_view.resizeColumnToContents(0) # Sets size of column to contents, i.e. longest recipe title

                # Each cell is ~ 30 pixels, so we make our window slightly smaller than the rows can fit if it
                # is less than 16 cells (which populates ~ 500 pixel height) to keep width consistent w/ scroll bar
                # and to make sure we have no empty space in our window
                self.title_view.resize(self.title_view.columnWidth(0) + 40, 25*title_model.rowCount())
                self.resize(self.title_view.columnWidth(0) + 40, 25*title_model.rowCount())
                self.title_view.show()
                self.show()

    def pass_info(self, index):  # Get current indexed position from click
        """
        PURPOSE
        -----
        To pass recipe information in next window, 'RecipeWindow'

        INPUT
        -----
        index: The index of the row+col selected by the user when they double click the recipe view

        OUTPUT
        -----
        calls function within RecipeWindow object we create in __init()__
        """

        cell_val = index.sibling(index.row(), index.column()).data()  # Get cell value from the cell itself
        self.recipe_window.recipe_title = cell_val # Sets information in RecipeWindow object

        self.title_view.hide()
        self.hide() # Hides our current window
        self.recipe_window.view_recipe(self.recipe_window.obtain_recipe())
Exemplo n.º 4
0
class FreezeTableMixin:
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self._frozen_table = QTableView(self)
        self._frozen_table.verticalHeader().hide()
        self._frozen_table.setFocusPolicy(Qt.NoFocus)
        self._frozen_table.setStyleSheet('''
        QTableView {
            border: none;
            background-color: palette(dark);
            alternate-background-color: palette(mid);
            color: palette(base);
        }
        ''')
        self._frozen_table.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self._frozen_table.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self._frozen_table.horizontalHeader().setStretchLastSection(True)
        self._frozen_table.horizontalHeader().setSortIndicator(
            -1, Qt.AscendingOrder)

        self.viewport().stackUnder(self._frozen_table)

        self._frozen_table.verticalHeader().setDefaultSectionSize(
            self.verticalHeader().defaultSectionSize())
        self._frozen_table.hide()

        self.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel)
        self.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel)
        self._frozen_table.setVerticalScrollMode(
            QAbstractItemView.ScrollPerPixel)

        # connect the headers and scrollbars of both tableviews together
        self.horizontalHeader().sectionResized.connect(
            self.updateFrozenSectionWidth)
        self._frozen_table.horizontalHeader().sectionResized.connect(
            self.updateTableSectionWidth)
        self.verticalHeader().sectionResized.connect(self.updateSectionHeight)
        self._frozen_table.verticalScrollBar().valueChanged.connect(
            self.verticalScrollBar().setValue)
        self.verticalScrollBar().valueChanged.connect(
            self._frozen_table.verticalScrollBar().setValue)

    def frozenTable(self):
        return self._frozen_table

    def setHorizontalHeader(self, header: QHeaderView) -> None:
        header.sectionResized.connect(self.updateFrozenSectionWidth)
        header.setSortIndicator(-1, Qt.AscendingOrder)
        super().setHorizontalHeader(header)
        header.stackUnder(self._frozen_table)

    def setFrozenTableHorizontalHeader(self, header: QHeaderView) -> None:
        header.sectionResized.connect(self.updateTableSectionWidth)
        header.setSortIndicator(-1, Qt.AscendingOrder)
        self._frozen_table.setHorizontalHeader(header)

    def setVerticalHeader(self, header: QHeaderView) -> None:
        header.sectionResized.connect(self.updateSectionHeight)
        self._frozen_table.verticalHeader().setDefaultSectionSize(
            header.defaultSectionSize())
        super().setVerticalHeader(header)

    def setModel(self, model: QAbstractItemModel) -> None:
        super().setModel(model)

        # Derive a proxy model from the model to limit number of columns
        frozen_model = RearrangeColumnsProxymodel(self)
        frozen_model.setSourceModel(self.model())
        self._frozen_table.setModel(frozen_model)

        link_selection_model = LinkItemSelectionModel(
            frozen_model, QAbstractItemView.selectionModel(self), self)
        self._frozen_table.setSelectionModel(link_selection_model)

    # noinspection PyUnusedLocal
    def updateFrozenSectionWidth(self, logical_index: int, old_size: int,
                                 new_size: int):
        model = self._frozen_table.model()
        if model is None:
            return

        proxy_logical_index = model.proxyColumnForSourceColumn(logical_index)
        if proxy_logical_index > 0:
            self._frozen_table.horizontalHeader().blockSignals(True)
            self._frozen_table.horizontalHeader().resizeSection(
                proxy_logical_index, new_size)
            self._frozen_table.horizontalHeader().blockSignals(False)
            self.updateFrozenTableGeometry()

    # noinspection PyUnusedLocal
    def updateTableSectionWidth(self, logical_index: int, old_size: int,
                                new_size: int):
        model = self._frozen_table.model()
        if model is None:
            return

        source_logical_index = model.sourceColumnForProxyColumn(logical_index)
        if source_logical_index > 0:
            self.setColumnWidth(source_logical_index, new_size)
            self.updateFrozenTableGeometry()

    # noinspection PyUnusedLocal
    def updateSectionHeight(self, logical_index: int, old_size: int,
                            new_size: int):
        self._frozen_table.setRowHeight(logical_index, new_size)

    def resizeEvent(self, event):
        QTableView.resizeEvent(self, event)
        self.updateFrozenTableGeometry()

    def scrollTo(
        self,
        index: QModelIndex,
        hint: QAbstractItemView.ScrollHint = QAbstractItemView.EnsureVisible
    ) -> None:
        if index.column() > 1:
            QTableView.scrollTo(self, index, hint)

    def setFrozenColumns(self, num_columns=None):
        if num_columns is not None:
            model = self._frozen_table.model()
            if model is None:
                return

            mapping = [
                self.horizontalHeader().logicalIndex(col)
                for col in range(num_columns)
            ]
            mapping = [col for col in mapping if not self.isColumnHidden(col)]
            model.setSourceColumns(mapping)

            # Synchronize section sizes between table and frozen table
            hh = self._frozen_table.horizontalHeader()
            for col in range(num_columns):
                logical_index = model.sourceColumnForProxyColumn(col)
                hh.resizeSection(col, self.columnWidth(logical_index))

            self._frozen_table.show()
            self.updateFrozenTableGeometry()
        else:
            self._frozen_table.hide()

    def updateFrozenTableGeometry(self):
        model = self._frozen_table.model()
        if model is None:
            return

        ax = ay = self.frameWidth()
        aw = sum(
            self.columnWidth(model.sourceColumnForProxyColumn(i))
            for i in range(model.columnCount()))
        ah = self.viewport().height() + self.horizontalHeader().height()
        if self.verticalHeader().isVisible():
            ax += self.verticalHeader().width()
        self._frozen_table.setGeometry(ax, ay, aw, ah)

    def moveCursor(self, cursorAction, modifiers):
        current = QTableView.moveCursor(self, cursorAction, modifiers)
        x = self.visualRect(current).topLeft().x()
        frozen_width = self._frozen_table.columnWidth(
            0) + self._frozen_table.columnWidth(1)
        if cursorAction == self.MoveLeft and current.column(
        ) > 1 and x < frozen_width:
            new_value = self.horizontalScrollBar().value() + x - frozen_width
            self.horizontalScrollBar().setValue(new_value)
        return current
Exemplo n.º 5
0
class TaggerDialog(QDialog):
    def __init__(self, args, **kwargs):
        super(TaggerDialog, self).__init__(**kwargs)

        self.reviewing = False
        self.args = args

        self.worker = TaggerWorker()
        self.thread = QThread()
        self.worker.moveToThread(self.thread)

        self.worker.on_error.connect(self.on_error)
        self.worker.on_review_ready.connect(self.on_review_ready)
        self.worker.on_stopped.connect(self.on_stopped)
        self.worker.on_progress.connect(self.on_progress)
        self.worker.on_updates_sent.connect(self.on_updates_sent)
        self.worker.on_mint_mfa.connect(self.on_mint_mfa)

        self.thread.started.connect(
            partial(self.worker.create_updates, args, self))
        self.thread.start()

        self.init_ui()

    def init_ui(self):
        self.setWindowTitle('Tagger is running...')
        self.setModal(True)
        self.v_layout = QVBoxLayout()
        self.setLayout(self.v_layout)

        self.label = QLabel()
        self.v_layout.addWidget(self.label)

        self.progress = 0
        self.progress_bar = QProgressBar()
        self.progress_bar.setRange(0, 0)
        self.v_layout.addWidget(self.progress_bar)

        self.button_bar = QHBoxLayout()
        self.v_layout.addLayout(self.button_bar)

        self.cancel_button = QPushButton('Cancel')
        self.button_bar.addWidget(self.cancel_button)
        self.cancel_button.clicked.connect(self.on_cancel)

    def on_error(self, msg):
        logger.error(msg)
        self.label.setText('Error: {}'.format(msg))
        self.label.setStyleSheet('QLabel { color: red; font-weight: bold; }')
        self.cancel_button.setText('Close')
        self.cancel_button.clicked.connect(self.close)

    def open_amazon_order_id(self, order_id):
        if order_id:
            QDesktopServices.openUrl(QUrl(amazon.get_invoice_url(order_id)))

    def on_activated(self, index):
        # Only handle clicks on the order_id cell.
        if index.column() != 5:
            return
        order_id = self.updates_table_model.data(index, Qt.DisplayRole)
        self.open_amazon_order_id(order_id)

    def on_double_click(self, index):
        if index.column() == 5:
            # Ignore double clicks on the order_id cell.
            return
        order_id_cell = self.updates_table_model.createIndex(index.row(), 5)
        order_id = self.updates_table_model.data(order_id_cell, Qt.DisplayRole)
        self.open_amazon_order_id(order_id)

    def on_review_ready(self, results):
        self.reviewing = True
        self.progress_bar.hide()

        self.label.setText('Select below which updates to send to Mint.')

        self.updates_table_model = MintUpdatesTableModel(results.updates)
        self.updates_table = QTableView()
        self.updates_table.doubleClicked.connect(self.on_double_click)
        self.updates_table.clicked.connect(self.on_activated)

        def resize():
            self.updates_table.resizeColumnsToContents()
            self.updates_table.resizeRowsToContents()
            min_width = sum(
                self.updates_table.columnWidth(i) for i in range(6))
            self.updates_table.setMinimumSize(min_width + 20, 600)

        self.updates_table.setSelectionMode(QAbstractItemView.SingleSelection)
        self.updates_table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.updates_table.setModel(self.updates_table_model)
        self.updates_table.setSortingEnabled(True)
        resize()
        self.updates_table_model.layoutChanged.connect(resize)

        self.v_layout.insertWidget(2, self.updates_table)

        unmatched_button = QPushButton('View Unmatched Amazon orders')
        self.button_bar.addWidget(unmatched_button)
        unmatched_button.clicked.connect(
            partial(self.on_open_unmatched, results.unmatched_orders))

        amazon_stats_button = QPushButton('Amazon Stats')
        self.button_bar.addWidget(amazon_stats_button)
        amazon_stats_button.clicked.connect(
            partial(self.on_open_amazon_stats, results.items, results.orders,
                    results.refunds))

        tagger_stats_button = QPushButton('Tagger Stats')
        self.button_bar.addWidget(tagger_stats_button)
        tagger_stats_button.clicked.connect(
            partial(self.on_open_tagger_stats, results.stats))

        self.confirm_button = QPushButton('Send to Mint')
        self.button_bar.addWidget(self.confirm_button)
        self.confirm_button.clicked.connect(self.on_send)

        self.setGeometry(50, 50, self.width(), self.height())

    def on_updates_sent(self, num_sent):
        self.label.setText(
            'All done! {} newly tagged Mint transactions'.format(num_sent))
        self.cancel_button.setText('Close')

    def on_open_unmatched(self, unmatched):
        self.unmatched_dialog = AmazonUnmatchedTableDialog(unmatched)
        self.unmatched_dialog.show()

    def on_open_amazon_stats(self, items, orders, refunds):
        self.amazon_stats_dialog = AmazonStatsDialog(items, orders, refunds)
        self.amazon_stats_dialog.show()

    def on_open_tagger_stats(self, stats):
        self.tagger_stats_dialog = TaggerStatsDialog(stats)
        self.tagger_stats_dialog.show()

    def on_send(self):
        self.progress_bar.show()
        updates = self.updates_table_model.get_selected_updates()

        self.confirm_button.hide()
        self.updates_table.hide()
        self.confirm_button.deleteLater()
        self.updates_table.deleteLater()
        self.adjustSize()

        QMetaObject.invokeMethod(self.worker, 'send_updates',
                                 Qt.QueuedConnection, Q_ARG(list, updates),
                                 Q_ARG(object, self.args))

    def on_stopped(self):
        self.close()

    def on_progress(self, msg, max, value):
        self.label.setText(msg)
        self.progress_bar.setRange(0, max)
        self.progress_bar.setValue(value)

    def on_cancel(self):
        if not self.reviewing:
            QMetaObject.invokeMethod(self.worker, 'stop', Qt.QueuedConnection)
        else:
            self.close()

    def on_mint_mfa(self):
        mfa_code, ok = QInputDialog().getText(self,
                                              'Please enter your Mint Code.',
                                              'Mint Code:')
        QMetaObject.invokeMethod(self.worker, 'mfa_code', Qt.QueuedConnection,
                                 Q_ARG(int, mfa_code))
Exemplo n.º 6
0
class DBViewer(QDialog):
    resized = pyqtSignal(object)

    def __init__(self, ctx, par, *args, **kwargs):
        super(DBViewer, self).__init__(*args, **kwargs)
        self.setAttribute(Qt.WA_DeleteOnClose)
        self.setWindowFlags(self.windowFlags() | Qt.WindowSystemMenuHint
                            | Qt.WindowMinMaxButtonsHint)
        self.ctx = ctx
        self.par = par
        self.layout = QVBoxLayout()
        self.query_model = QSqlQueryModel()

        self.toolbar = QToolBar()
        self.table_view = QTableView()
        self.table_view.setSelectionBehavior(QAbstractItemView.SelectRows)

        self.export_excel = QPushButton(
            self.ctx.export_icon,
            'Export to Excel',
        )
        self.refresh_btn = QPushButton("Refresh")
        self.close_btn = QPushButton("Close")
        self.delete_rows_btn = QPushButton("Delete Selected Row(s)")
        self.delete_rows_btn.setEnabled(False)

        self.initModel()
        self.initUI()
        self.sigConnect()

    def initUI(self):
        self.layout.setContentsMargins(11, 0, 11, 11)
        self.toolbar.addWidget(self.export_excel)
        self.layout.addWidget(self.toolbar)

        self.close_btn.setAutoDefault(True)
        self.close_btn.setDefault(True)
        self.refresh_btn.setAutoDefault(False)
        self.refresh_btn.setDefault(False)
        self.delete_rows_btn.setAutoDefault(False)
        self.delete_rows_btn.setDefault(False)
        self.export_excel.setAutoDefault(False)
        self.export_excel.setDefault(False)

        self.table_view.resizeColumnsToContents()
        self.layout.addWidget(self.table_view)

        hLayout = QHBoxLayout()
        hLayout.addWidget(self.delete_rows_btn)
        hLayout.addStretch()
        hLayout.addWidget(self.refresh_btn)
        hLayout.addWidget(self.close_btn)

        self.layout.addLayout(hLayout)
        self.setLayout(self.layout)

        self.setWindowTitle("Patients Record")
        wds = [
            self.table_view.columnWidth(c)
            for c in range(self.table_view.model().columnCount())
        ]
        self.resize(sum(wds) + 40, 600)
        rect = self.frameGeometry()
        rect.moveCenter(QDesktopWidget().availableGeometry().center())
        self.move(rect.topLeft().x(), rect.topLeft().y())

    def sigConnect(self):
        self.close_btn.clicked.connect(self.accept)
        self.refresh_btn.clicked.connect(self.on_refresh)
        self.delete_rows_btn.clicked.connect(self.on_delete_rows)
        self.export_excel.clicked.connect(self.on_export)
        self.resized.connect(self.on_window_resize)
        self.table_view.horizontalHeader().sectionResized.connect(
            self.on_column_resize)

    def initModel(self):
        self.table_model = QSqlTableModel(db=self.ctx.database.patient_db)
        self.table_model.setTable('patients')
        self.table_model.setEditStrategy(QSqlTableModel.OnFieldChange)
        self.table_model.select()
        self.table_view.setModel(self.table_model)
        self.table_view.selectionModel().selectionChanged.connect(
            self.on_rows_selected)

    def on_export(self):
        filename, _ = QFileDialog.getSaveFileName(self, "Export to Excel", "",
                                                  "Excel Workbook (*.xlsx)")
        if not filename:
            return
        workbook = Workbook(filename)
        worksheet = workbook.add_worksheet()
        bold = workbook.add_format({'bold': True})
        sql = "SELECT * FROM PATIENTS"
        self.query_model.setQuery(sql, self.ctx.database.patient_db)

        for row in range(self.query_model.rowCount() + 1):
            for col in range(self.query_model.record(row).count()):
                if row == 0:
                    worksheet.write(row, col,
                                    self.query_model.record().fieldName(col),
                                    bold)
                worksheet.write(row + 1, col,
                                self.query_model.record(row).value(col))
        workbook.close()
        QMessageBox.information(self, "Success",
                                "Records can be found in " + filename + " .")

    def on_refresh(self):
        self.initModel()

    def on_column_resize(self, id, oldsize, size):
        width = self.size().width()
        self.column_ratio[id] = size / width

    def on_window_resize(self, event):
        old_width = event.oldSize().width()
        width = event.size().width()
        if old_width == -1:
            self.column_ratio = [
                self.table_view.columnWidth(c) / width
                for c in range(self.table_view.model().columnCount())
            ]
        else:
            self.table_view.horizontalHeader().sectionResized.disconnect(
                self.on_column_resize)
            [
                self.table_view.setColumnWidth(c, r * width)
                for c, r in enumerate(self.column_ratio)
            ]
            self.table_view.horizontalHeader().sectionResized.connect(
                self.on_column_resize)

    def on_rows_selected(self):
        self.selected_rows = sorted(
            set(index.row() for index in self.table_view.selectedIndexes()))
        print(self.selected_rows)
        self.delete_rows_btn.setEnabled(len(self.selected_rows) != 0)

    def on_delete_rows(self):
        result = []
        for row in self.selected_rows:
            res = self.table_model.removeRow(row)
            result.append(res)
        if not all(result):
            print(self.table_model.lastError())
        self.ctx.records_count -= len(self.selected_rows)
        self.delete_rows_btn.setEnabled(False)
        self.on_refresh()
        self.par.info_panel.no_edit.setText(str(self.ctx.records_count + 1))

    def resizeEvent(self, event):
        self.resized.emit(event)
        return super(DBViewer, self).resizeEvent(event)
Exemplo n.º 7
0
class TableDemo(QWidget):
    def __init__(self, parent=None):
        super(TableDemo, self).__init__(parent)
        self.setWindowTitle('TableView Demo')
        self.resize(600, 500)

        modelVerticalTitleLabelList = ['A', 'B', 'C', 'D', 'E']
        modelHorizontalTitleLabelList = ['甲', '乙', '丙', '丁', '戊', '已']

        self.model = QStandardItemModel(5, 5)
        self.model.setHorizontalHeaderLabels(modelVerticalTitleLabelList)
        self.model.setVerticalHeaderLabels(modelHorizontalTitleLabelList)
        for i in range(5):
            for j in range(5):
                item = QStandardItem(str(i + j))
                self.model.setItem(i, j, item)

        self.tabletView = QTableView()
        self.tabletView.setModel(self.model)

        self.tabletView.horizontalHeader().setStretchLastSection(True)

        mainLayout = QVBoxLayout()
        mainLayout.addWidget(self.tabletView)

        self.testRowColumn()

        self.setLayout(mainLayout)

    def testRowColumn(self):
        # 用rowAt()和columnAt(),返回一个坐标在table中的行和列的序号
        x, y = 100, 200
        row_at_x = self.tabletView.rowAt(x)
        column_at_y = self.tabletView.columnAt(y)
        print('坐标(%d,%d)在表格中是第%d行,第%d列' %
              (x, y, row_at_x + 1, column_at_y + 1))
        # 如果(x,y)不在表格内,函数返回值是-1

        # setRowHeight,setColumnWidth:可以设置行高'列宽
        self.tabletView.setRowHeight(1, 50)
        self.tabletView.setColumnWidth(1, 150)
        # <int> columnWidth():返回指定列的宽度
        # <int> rowHeight():返回指定行的高度
        print('第(2,2)单元格的列宽,行高为为:%d,%d(像素)' %
              (self.tabletView.columnWidth(1), self.tabletView.rowHeight(1)))

        # setSpan():设定指定行和列的行跨度和列跨度
        self.tabletView.setSpan(2, 2, 2, 2)
        # <int> rowSpan():返回指定行的位置的行跨度
        # <int> columnSpan:返回指定(row,column)的列跨度
        print(
            '第(3,3)单元格的的行和列跨度为(%dx%d)' %
            (self.tabletView.columnSpan(2, 2), self.tabletView.rowSpan(2, 2)))

        # setCornerButtonEnable():设置是否启用左上角的按钮
        # 此按钮(用来全选整个表格),默认是启用的
        self.tabletView.setCornerButtonEnabled(False)  # 此时,左上角的按钮将不再起作用

    def contextMenuEvent(self, QContextMenuEvent):
        # 设置tableView的右键弹出菜单和菜单信号槽
        # 如何只在单元格内弹出右键菜单呢?现在在空白地方点击右键也会弹出菜单????????
        menu = QMenu(self)
        hideMenu = menu.addAction('&Hide')
        hideMenu.triggered.connect(self.hideCurrentColumn)

        # 设置显示所有被隐藏的列
        showhiddenColumnMenu = menu.addAction('显示隐藏列')
        showhiddenColumnMenu.triggered.connect(self.showAllHiddenColumns)

        menu.addSeparator()

        # 设置当前点击的列按照内容自适应列宽度
        resizeColumnToCtnsMenu = menu.addAction('宽度适应')
        resizeColumnToCtnsMenu.triggered.connect(
            lambda: self.tabletView.resizeColumnToContents(
                self.tabletView.currentIndex().column()))

        # 排序当前选择的列
        orderCurentColumnMenu = menu.addAction('排序')
        orderCurentColumnMenu.triggered.connect(self.orderCurrentColum)

        menu.exec_(QContextMenuEvent.globalPos())

    def hideCurrentColumn(self):
        print('第%d列被隐藏了!' % self.tabletView.currentIndex().column())
        self.tabletView.setColumnHidden(
            self.tabletView.currentIndex().column(), True)

    def showAllHiddenColumns(self):
        print('显示所有被隐藏的列')
        # 遍历所有的列,找到隐藏的列,设置其隐藏为False
        for i in range(self.model.columnCount()):
            if self.tabletView.isColumnHidden(i):
                self.tabletView.setColumnHidden(i, False)
                print('列%d已被重新显示' % (i + 1))

    def orderCurrentColum(self):
        self.tabletView.setSortingEnabled(True)
        self.tabletView.sortByColumn(self.tabletView.currentIndex().column(),
                                     Qt.AscendingOrder)
Exemplo n.º 8
0
class QuoteMonitor(QMainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)

        self.rowHeight = 30
        # self.colInsWidth = 200
        # self.colWidth = 100

        sshFile = "style.qss"
        # sshFile = "material.qss"
        with open(sshFile, "r") as f:
            self.setStyleSheet(f.read())

        self._defaultColWidths = {"instrument": 200}
        self._defaultColWidthOther = 100
        self.initUI()

        if g.state:
            print("set column width from state")
            columnsWidth = g.state["table"]["columnsWidth"]
            geometry = g.state["geometry"]

            left = geometry["left"]
            top = geometry["top"]
            width = geometry["width"]
            height = geometry["height"]

            self.setGeometry(left, top, width, height)

            for i, v in enumerate(columnsWidth):
                self.table.setColumnWidth(i, v)

    def initUI(self):

        self.table = QTableView()
        self.delegate = Delegate()
        if g.state:
            cols = g.state["table"]["columns"]
            for i, v in enumerate(cols):
                if v == "instrument":
                    g.colEditable = i
                    self.table.setItemDelegateForColumn(i, self.delegate)
                    break
        # self.table.verticalHeader().setSectionsMovable(True)
        self.table.horizontalHeader().setSectionsMovable(True)
        # self.table.horizontalHeader().sectionResized.connect(
        #         lambda a, b, c: self.resizeColumns(self.size(), self.size()))
        # self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.table.horizontalHeader().setStretchLastSection(True)
        self.table.setDragEnabled(True)
        self.table.setSelectionBehavior(self.table.SelectRows)
        self.table.setSelectionMode(self.table.SingleSelection)
        self.table.setDragDropMode(self.table.InternalMove)
        self.table.setDragDropOverwriteMode(False)
        self.table.setDropIndicatorShown(True)
        self.table.setAcceptDrops(True)
        self.table.setShowGrid(False)
        self.table.setAlternatingRowColors(True)
        self.table.setStyle(TableStyle())
        self.table.setMouseTracking(True)

        self.table.setContextMenuPolicy(Qt.CustomContextMenu)
        self.table.customContextMenuRequested.connect(self.showContextMenu)

        self.table.setModel(g.quoteModel)

        if not g.state:
            print("set column width from not state")
            accumWidth = 0
            for i in range(g.quoteModel.columnCount()):
                colName = g.quoteModel.columnName(i)
                colWidth = self._defaultColWidths.get(
                    colName, self._defaultColWidthOther)
                accumWidth += colWidth

                self.table.setColumnWidth(i, colWidth)

            self.resize(accumWidth + 20, 500)

        self.setCentralWidget(self.table)

        self.menubar = QMenuBar()

        self.fileMenu = self.menubar.addMenu("File")

        action = QAction("Preferences", self)
        self.fileMenu.addAction(action)
        self.fileMenu.triggered.connect(self.processtrigger)

        # menubar.setGeometry(300, 300, 300, 200)

        # mainLayout = QHBoxLayout()
        # mainLayout.addWidget(view)

        # self.setLayout(mainLayout)
        # self.setWindowTitle("Quote Monitor")

    # def showEvent(self, ev):
    #     self.appendedRowsIfNeeded()
    #     # self.setWidgetWidth()
    #     self.initColumnSizes()

    def showContextMenu(self, pos):
        self.contextMenu = QMenu(self)
        action = QAction("remove", self)
        action.triggered.connect(self.removeRow)
        self.contextMenu.addAction(action)
        self.contextMenu.exec(self.mapToGlobal(pos))

    def removeRow(self):
        item = self.table.currentIndex()
        row = item.row()
        g.quoteModel.removeRow(row)

    def processtrigger(self):
        self.dialog = Dialog(self)
        self.dialog.show()

    def appendedRowsIfNeeded(self):
        # L.debug("appended row if neened")
        self.height = QMainWindow.height(self)
        visibleRows = self.height / self.rowHeight
        rowsToAdd = ceil(visibleRows - g.quoteModel.rowCount())
        rowsToAdd = max(rowsToAdd, 0)

        for _ in range(rowsToAdd):
            g.quoteModel.appendRow()

    def initColumnSizes(self):
        numCols = g.quoteModel.columnCount()
        colWidth = round(self.width() / numCols)
        accumWidth = 0
        for i in range(numCols - 1):
            accumWidth += colWidth
            self.table.setColumnWidth(i, colWidth)
        self.table.setColumnWidth(numCols - 1, self.width() - accumWidth)

    # def resizeColumns(self, size, oldSize):
    #     numCols = g.quoteModel.columnCount()
    #     ratio = size.width() / oldSize.width()
    #     accumWidth = 0
    #     for i in range(numCols - 1):
    #         widthNow = round(self.table.columnWidth(i) * ratio)
    #         accumWidth += widthNow
    #         self.table.setColumnWidth(i, widthNow)
    #     self.table.setColumnWidth(numCols - 1, self.width() - accumWidth)

    def resizeEvent(self, ev):
        self.appendedRowsIfNeeded()
        # self.resizeColumns(ev.size(), ev.oldSize())

    def keyPressEvent(self, ev):
        if ev.key() == Qt.Key_Backspace:
            self.removeRow()

    def closeEvent(self, ev):
        self.saveApplicationState()
        writeToJSONFile(g.stateFile, g.state)

    # def sortIndicatorChanged(self, column=None, sortOrder=None):
    #     print("sortIndicatorChanged: column {}, sortOrder {}".format(column,
    #         sortOrder))

    def saveApplicationState(self):
        geom = self.geometry()
        columnsWidth = []
        header = []

        # for i in range(g.quoteModel.columnCount()):
        # print(g.quoteModel.headerData(i, Qt.Horizontal, Qt.DisplayRole))

        for i in range(g.quoteModel.columnCount()):
            idx = self.table.horizontalHeader().logicalIndex(i)
            header.insert(i, g.quoteModel.columnName(idx))
            width = self.table.columnWidth(idx)
            columnsWidth.insert(i, width)

        state = {}
        state["table"] = table = {}
        state["geometry"] = geometry = {}

        table["rows"] = g.quoteModel.getRows()
        table["columns"] = header
        table["data"] = {
            str(k): {
                "instrument": v["instrument"]
            }
            for k, v in g.quoteModel._data.items() if k
        }
        table["columnsWidth"] = columnsWidth

        geometry["left"] = geom.left()
        geometry["top"] = geom.top()
        geometry["width"] = geom.width()
        geometry["height"] = geom.height()

        g.state = state
Exemplo n.º 9
0
class FileManager(QWidget):
    def __init__(self, parent):
        QWidget.__init__(self)
        self.parent = parent
        self.name = 'File Manager'
        self.port = '9080'
        self.server = None

        drives = win32api.GetLogicalDriveStrings().split('\\\000')[:-1]
        self.logical_drives = drives + [d+'/' for d in drives]
        # create file manager tab
        self.file_manager_layout = QGridLayout(self)

        # create left manager (PC)
        self.left_up_btn = QPushButton()
        self.left_up_btn.setIcon(QIcon('images/up_btn.png'))
        self.left_up_btn.setFixedWidth(25)
        self.file_manager_layout.addWidget(self.left_up_btn, 0, 0, 1, 1)

        self.left_dir_path = QLineEdit(self.parent.expanduser_dir)
        self.file_manager_layout.addWidget(self.left_dir_path, 0, 1, 1, 8)

        self.left_go_to_btn = QPushButton()
        self.left_go_to_btn.setIcon(QIcon('images/right_btn.png'))
        self.left_go_to_btn.setFixedWidth(25)
        self.file_manager_layout.addWidget(self.left_go_to_btn, 0, 9, 1, 1)

        self.lefttableview = QTableView()
        self.lefttableview.setSelectionBehavior(QTableView.SelectRows)
        self.lefttableview.verticalHeader().hide()
        self.lefttableview.setShowGrid(False)
        self.lefttableview.contextMenuEvent = lambda event: self.left_context(event)

        self.left_file_model = QFileSystemModel()
        self.left_file_model.setFilter(QDir.AllEntries | QDir.NoDotAndDotDot)
        self.left_file_model.setRootPath(self.parent.expanduser_dir)
        self.left_file_model_path = self.parent.expanduser_dir
        self.lefttableview.setModel(self.left_file_model)
        self.lefttableview.setColumnWidth(0, 150)
        self.lefttableview.setRootIndex(self.left_file_model.index(self.parent.expanduser_dir))
        self.file_manager_layout.addWidget(self.lefttableview, 1, 0, 5, 10)

        # central buttons
        self.download_file_from_device_btn = QPushButton()
        self.download_file_from_device_btn.setIcon(QIcon('images/left_btn.png'))
        self.download_file_from_device_btn.setFixedWidth(30)
        self.download_file_from_device_btn.setEnabled(False)
        self.upload_file_to_device_btn = QPushButton()
        self.upload_file_to_device_btn.setIcon(QIcon('images/right_btn.png'))
        self.upload_file_to_device_btn.setFixedWidth(30)
        self.upload_file_to_device_btn.setEnabled(False)
        self.delete_file_btn = QPushButton()
        self.delete_file_btn.setIcon(QIcon('images/delete_btn.png'))
        self.delete_file_btn.setFixedWidth(30)
        self.file_manager_layout.addWidget(self.download_file_from_device_btn, 3, 10, 1, 1)
        self.file_manager_layout.addWidget(self.delete_file_btn, 4, 10, 1, 1)

        # create right manager (Device)
        self.right_up_btn = QPushButton()
        self.right_up_btn.setIcon(QIcon('images/up_btn.png'))
        self.right_up_btn.setFixedWidth(25)
        self.right_up_btn.setEnabled(False)
        self.file_manager_layout.addWidget(self.right_up_btn, 0, 11, 1, 1)

        self.add_folder_btn = QPushButton()
        self.add_folder_btn.setIcon(QIcon('images/folder_add.png'))
        self.add_folder_btn.setFixedWidth(25)
        self.add_folder_btn.setToolTip(_('Add new folder'))
        self.add_folder_btn.setEnabled(False)
        self.file_manager_layout.addWidget(self.add_folder_btn, 0, 12, 1, 1)

        self.right_dir_path = QLineEdit()
        self.file_manager_layout.addWidget(self.right_dir_path, 0, 13, 1, 7)

        self.right_update_btn = QPushButton()
        self.right_update_btn.setIcon(QIcon('images/update.png'))
        self.right_update_btn.setFixedWidth(25)
        self.file_manager_layout.addWidget(self.right_update_btn, 0, 20, 1, 1)

        self.righttableview = QTableView()
        self.righttableview.setSelectionBehavior(QTableView.SelectRows)
        self.righttableview.contextMenuEvent = lambda event: self.right_context(event)
        self.righttableview.verticalHeader().hide()
        self.righttableview.setShowGrid(False)
        self.right_file_model = QStandardItemModel()
        self.right_file_model_path = []
        self.right_active_dir = None
        self.righttableview.setModel(self.right_file_model)
        self.file_manager_layout.addWidget(self.righttableview, 1, 11, 5, 10)

        # auto sync
        self.timer = QTimer()
        self.timer.setInterval(10000)
        self.file_models_auto_sync = QCheckBox(_('Auto sync'))
        self.left_file_model_auto_sync_label = QLineEdit()
        self.left_file_model_auto_sync_label.setReadOnly(True)
        self.right_file_model_auto_sync_label = QLineEdit()
        self.right_file_model_auto_sync_label.setReadOnly(True)
        self.file_manager_layout.addWidget(self.file_models_auto_sync, 6, 9, 1, 3, alignment=Qt.AlignCenter)
        self.file_manager_layout.addWidget(self.left_file_model_auto_sync_label, 6, 0, 1, 9)
        self.file_manager_layout.addWidget(self.right_file_model_auto_sync_label, 6, 12, 1, 9)

        self.timer.timeout.connect(lambda: self.check_device_sync())
        self.lefttableview.clicked.connect(lambda idx: self.left_file_model_clicked(idx))
        self.lefttableview.doubleClicked.connect(lambda idx: self.left_file_model_doubleclicked(idx))
        self.left_up_btn.clicked.connect(lambda: self.left_file_model_up(self.left_file_model.index(self.left_dir_path.text())))
        self.left_go_to_btn.clicked.connect(lambda: self.left_file_model_go_to_dir())

        self.right_update_btn.clicked.connect(lambda: self.right_file_model_update())
        self.righttableview.doubleClicked.connect(lambda idx: self.right_file_model_doubleclicked(idx))
        self.right_up_btn.clicked.connect(lambda: self.right_file_model_up())
        self.add_folder_btn.clicked.connect(lambda: self.right_file_model_add_folder())
        self.righttableview.clicked.connect(lambda idx: self.right_file_model_clicked(idx))
        self.download_file_from_device_btn.clicked.connect(lambda: self.download_file_from_device())
        self.upload_file_to_device_btn.clicked.connect(lambda: self.upload_file_to_device())
        self.delete_file_btn.clicked.connect(lambda: self.delete_file_from_file_model())

        self.parent.settings_widget.signal_ip_changed.connect(lambda ip: self.change_ip(ip))

        self.parent.signal_language_changed.connect(lambda: self.retranslate())

    def retranslate(self):
        self.file_models_auto_sync.setText(_('Auto sync'))
        self.right_file_model.setHorizontalHeaderLabels([_('Name'), _('Size'), _('Changed date')])

    def change_ip(self, ip):
        self.server = ':'.join([ip, self.port])
        self.right_file_model_path = []
        self.right_file_model.clear()

    def left_file_model_clicked(self, idx):
        if os.path.isfile(self.left_file_model.filePath(idx)) and self.parent.geoshark_widget.device_on_connect:
            self.upload_file_to_device_btn.setEnabled(True)
        else:
            self.upload_file_to_device_btn.setEnabled(False)

    def left_file_model_doubleclicked(self, idx):
        self.left_up_btn.setEnabled(True)
        fileinfo = self.left_file_model.fileInfo(idx)
        if fileinfo.isDir():
            self.lefttableview.setRootIndex(idx)
            self.left_dir_path.setText(self.left_file_model.filePath(idx))
            self.left_file_model_path = self.left_file_model.filePath(idx)

    def left_file_model_up(self, idx):
        self.upload_file_to_device_btn.setEnabled(False)
        if self.left_dir_path.text() in self.logical_drives:
            self.left_file_model = QFileSystemModel()
            self.left_file_model.setFilter(QDir.AllEntries | QDir.NoDotAndDotDot)
            self.left_file_model.setRootPath('')
            self.lefttableview.setModel(self.left_file_model)
            self.left_dir_path.setText('My computer')
            self.left_up_btn.setEnabled(False)
        else:
            fileinfo = self.left_file_model.fileInfo(idx)
            dir = fileinfo.dir()
            self.left_dir_path.setText(dir.path())
            self.left_file_model_path = dir.path()
            self.lefttableview.setRootIndex(self.left_file_model.index(dir.absolutePath()))

    def left_file_model_go_to_dir(self):
        if os.path.isdir(self.left_dir_path.text()):
            self.left_file_model_path = self.left_dir_path.text()
            self.left_up_btn.setEnabled(True)
            self.upload_file_to_device_btn.setEnabled(False)
            self.left_file_model.setRootPath(self.left_dir_path.text())
            self.lefttableview.setRootIndex(self.left_file_model.index(self.left_dir_path.text()))

    def right_file_model_update(self):
        if not self.parent.geoshark_widget.device_on_connect:
            return
        url = 'http://{}/active_dir'.format(self.server)
        try:
            res = requests.get(url, timeout=5)
            if res.ok:
                self.right_active_dir = res.text
        except requests.exceptions.RequestException:
            pass

        file_list = self.get_folder_list()
        if file_list is None:
            return
        self.fill_right_file_model(file_list)
        self.download_file_from_device_btn.setEnabled(False)

    def get_folder_list(self, folder_path=None):
        if self.server is None:
            return
        if folder_path is None:
            folder_path = '/'.join(self.right_file_model_path)
        url = 'http://{}/data/{}'.format(self.server, folder_path)
        try:
            res = requests.get(url, timeout=1)
        except requests.exceptions.RequestException:
            show_error(_('GeoShark error'), _('GeoShark is not responding.'))
            return
        if res.ok:
            res = res.json()
            return res
        else:
            return None

    def check_device_sync(self):
        pc_path = self.left_file_model_auto_sync_label.text()
        device_path = self.right_file_model_auto_sync_label.text()
        if self.file_models_auto_sync.isChecked() and pc_path != '' and device_path != '':
            file_list = self.get_folder_list(self.right_file_model_auto_sync_label.text())
            left_list_of_files = os.listdir(self.left_file_model_auto_sync_label.text())
            for f in file_list:
                if f['name'] not in left_list_of_files or os.path.getsize('{}/{}'.format(pc_path, f['name'])) != f['size']:
                    self.download_file_from_device(device_path='{}/{}'.format(device_path, f['name']),
                                                   pc_path=pc_path)

    def fill_right_file_model(self, directory):
        self.add_folder_btn.setEnabled(True)
        if len(self.right_file_model_path) < 1:
            self.right_up_btn.setEnabled(False)
        else:
            self.right_up_btn.setEnabled(True)
            self.add_folder_btn.setEnabled(False)
        self.right_file_model.removeRows(0, self.right_file_model.rowCount())
        self.right_dir_path.setText('/'.join(self.right_file_model_path))
        self.right_file_model.setHorizontalHeaderLabels([_('Name'), _('Size'), _('Changed date')])
        for row, instance in enumerate(directory):
            if instance['name'] == self.right_active_dir:
                image = QIcon('images/directory_active.png')
            else:
                image = QIcon('images/{}.png'.format(instance['type']))
            item = QStandardItem(image, instance['name'])
            item.setData(instance['type'], 5)
            item.setEditable(False)
            self.right_file_model.setItem(row, 0, item)
            item = QStandardItem(str(instance['size']))
            item.setEditable(False)
            self.right_file_model.setItem(row, 1, item)
            item = QStandardItem(str(datetime.datetime.fromtimestamp(instance['changed']).strftime('%d.%m.%Y %H:%M')))
            item.setEditable(False)
            self.right_file_model.setItem(row, 2, item)

        self.righttableview.setColumnWidth(0, max(150, self.righttableview.columnWidth(0)))

    def left_context(self, event):
        context_menu = {}
        index = self.lefttableview.indexAt(event.pos())
        if index.row() == -1:
            return
        context_menu[_('Set active directory')] = lambda: self.set_pc_active_directory(self.left_file_model.filePath(index))
        context_menu[_('Remove element')] = lambda: self.delete_file_from_file_model(index)

        if not self.left_file_model.isDir(index):
            del context_menu[_('Set active directory')]

        menu = QMenu()

        actions = [QAction(a) for a in context_menu.keys()]
        menu.addActions(actions)
        action = menu.exec_(event.globalPos())
        if action:
            context_menu[action.text()]()

    def set_pc_active_directory(self, path):
        self.left_file_model_auto_sync_label.setText(path)
        self.parent.settings_widget.left_folder_tracked.setText(path)

    def right_context(self, event):
        context_menu = {}

        index = self.righttableview.indexAt(event.pos())
        if index.row() == -1:
            return
        item = self.right_file_model.itemFromIndex(index)
        item_row = item.row()

        context_menu[_('Set active directory')] = lambda: self.set_active_directory(item)
        context_menu[_('Remove element')] = lambda: self.delete_file_from_file_model(index)

        if self.right_file_model.item(item_row, 0).data(5) != 'directory':
            del context_menu[_('Set active directory')]

        menu = QMenu()

        actions = [QAction(a) for a in context_menu.keys()]
        menu.addActions(actions)
        action = menu.exec_(event.globalPos())
        if action:
            context_menu[action.text()]()

    def set_active_directory(self, item):
        if not self.parent.geoshark_widget.device_on_connect:
            return
        dirname = item.text()
        url = 'http://{}/active_dir'.format(self.server)
        try:
            res = requests.post(url=url, data=dirname, timeout=5)
        except requests.exceptions.RequestException:
            show_error(_('GeoShark error'), _('Can not set active directory.\nGeoShark is not responding.'))
            return
        if res.ok:
            self.right_file_model_update()
            self.set_active_path(dirname)
        elif res.status_code == 400:
            show_error(_('GeoShark error'), _('Request declined - request body specifies invalid path.'))
            return
        elif res.status_code == 409:
            show_error(_('GeoShark error'), _('Request declined - switching active directory is forbidden during active session.'))
            return
        else:
            print(res.status_code)
            return

    def set_active_path(self, dirname):
        path = '/'.join(self.right_file_model_path + [dirname])
        self.parent.settings_widget.right_folder_tracked.setText(path)
        self.right_file_model_auto_sync_label.setText(path)

    def right_file_model_clicked(self, idx):
        if not self.parent.geoshark_widget.device_on_connect:
            return
        if self.right_file_model.item(idx.row(), 0).data(5) == 'file':
            self.download_file_from_device_btn.setEnabled(True)
        else:
            self.download_file_from_device_btn.setEnabled(False)

    def right_file_model_doubleclicked(self, idx):
        if not self.parent.geoshark_widget.device_on_connect:
            return
        model_path = '/'.join(self.right_file_model_path)
        idx_name = self.right_file_model.item(idx.row(), 0).text()
        if model_path != '':
            dir = '{}/{}'.format(model_path, idx_name)
        else:
            dir = '{}'.format(idx_name)

        file_list = self.get_folder_list(dir)
        if file_list is None:
            return
        self.right_file_model_path = dir.split('/')
        self.fill_right_file_model(file_list)

    def right_file_model_up(self):
        if not self.parent.geoshark_widget.device_on_connect:
            return
        self.download_file_from_device_btn.setEnabled(False)
        up_dir = '/'.join(self.right_file_model_path[:-1])

        file_list = self.get_folder_list(up_dir)
        if file_list is None:
            return
        if up_dir == '':
            self.right_file_model_path = []
        else:
            self.right_file_model_path = up_dir.split('/')
        self.fill_right_file_model(file_list)

    def right_file_model_add_folder(self):
        if not self.parent.geoshark_widget.device_on_connect:
            return
        row = self.right_file_model.rowCount()
        item = QStandardItem(QIcon('images/folder.png'), 'New Directory')
        item.setData('directory', 5)
        item.setEditable(True)
        self.right_file_model.setItem(row, 0, item)
        item = QStandardItem(str(0.0))
        item.setEditable(False)
        self.right_file_model.setItem(row, 1, item)
        item = QStandardItem(str(datetime.datetime.today().strftime('%d.%m.%Y %H:%M')))
        item.setEditable(False)
        self.right_file_model.setItem(row, 2, item)

    def download_file_from_device(self, device_path=None, pc_path=None):
        if not self.parent.geoshark_widget.device_on_connect or self.server is None:
            return

        if not device_path:
            fileName = self.find_selected_idx()
            if fileName:
                fileName = fileName.data()
                device_path = '/'.join(self.right_file_model_path + [fileName])
            else:
                return

        right_file_model_filename = device_path.split('/')[-1]
        save_to_file = '{}/{}'.format(self.left_file_model_path, right_file_model_filename) \
            if not pc_path else '{}/{}'.format(pc_path, right_file_model_filename)
        if os.path.isfile(save_to_file):
            answer = show_warning_yes_no(_('File warning'), _('There is a file with the same name in PC.\n'
                                         'Do you want to rewrite <b>{}</b>?'.format(right_file_model_filename)))
            if answer == QMessageBox.No:
                return
        url = 'http://{}/data/{}'.format(self.server, device_path)
        try:
            b = bytearray()
            res = requests.get(url, timeout=5, stream=True)
            if res.ok:
                progress = QProgressBar()
                progress.setFormat(right_file_model_filename)
                self.file_manager_layout.addWidget(progress, 6, 12, 1, 9)
                total_length = int(res.headers.get('content-length'))
                len_b = 0
                for chunk in tee_to_bytearray(res, b):
                    len_b += len(chunk)
                    progress.setValue((len_b/total_length)*99)
                    QApplication.processEvents()
            else:
                return
        except:
            self.file_manager_layout.addWidget(self.right_file_model_auto_sync_label, 6, 12, 1, 9)
            show_error(_('GeoShark error'), _('GeoShark is not responding.'))
            return

        if res.ok:
            progress.setValue(100)

            with open(save_to_file, 'wb') as file:
                file.write(b)
        for i in reversed(range(self.file_manager_layout.count())):
            if isinstance(self.file_manager_layout.itemAt(i).widget(), QProgressBar):
                self.file_manager_layout.itemAt(i).widget().setParent(None)
        self.file_manager_layout.addWidget(self.right_file_model_auto_sync_label, 6, 12, 1, 9)

    def upload_file_to_device(self):
        if not self.parent.geoshark_widget.device_on_connect or self.server is None:
            return
        file = self.left_file_model.filePath(self.lefttableview.currentIndex())
        filename = file.split('/')[-1]
        url = 'http://{}/data/{}'.format(self.server, '/'.join(self.right_file_model_path))
        filesize = os.path.getsize(file)
        if filesize == 0:
            show_error(_('File error'), _('File size must be non zero.'))
            return
        progress = ProgressBar(text=_('Upload File Into GeoShark'), window_title=_('Upload file to GeoShark'))
        encoder = MultipartEncoder(
            fields={'upload_file': (filename, open(file, 'rb'))}  # added mime-type here
        )
        data = MultipartEncoderMonitor(encoder, lambda monitor: progress.update((monitor.bytes_read/filesize)*99))

        try:
            res = requests.post(url, data=data, headers={'Content-Type': encoder.content_type}, timeout=5)
        except requests.exceptions.RequestException:
            progress.close()
            show_error(_('GeoShark error'), _('GeoShark is not responding.'))
            return
        if res.ok:
            progress.update(100)
            self.right_file_model_update()

    def delete_file_from_file_model(self, index=None):
        selected = self.find_selected_idx()
        if index is None and selected is None:
            return
        if index is None:
            index = selected
        model = index.model()
        index_row = index.row()
        path = model.filePath(index) if hasattr(model, 'filePath') else model.index(index_row, 0).data()
        answer = show_warning_yes_no(_('Remove File warning'),
                                     _('Do you really want to remove:\n{}').format(path))
        if answer == QMessageBox.No:
            return

        if isinstance(model, QFileSystemModel):
            model.remove(index)

        elif isinstance(model, QStandardItemModel):
            if not self.parent.geoshark_widget.device_on_connect or self.server is None:
                return
            filename = self.right_file_model.item(index.row(), 0).text()
            path = '/'.join(self.right_file_model_path + [filename])

            url = 'http://{}/data/{}'.format(self.server, path)
            try:
                res = requests.delete(url)
            except requests.exceptions.RequestException:
                show_error(_('GeoShark error'), _('GeoShark is not responding.'))
                return
            if res.ok:
                self.right_file_model_update()
            elif res.status_code == 400:
                self.right_file_model.removeRow(index.row())
            elif res.status_code == 409:
                show_error(_('GeoShark error'),
                           _('Request declined - directory is the part of active session working directory.'))
                return

    def find_selected_idx(self):
        left_indexes = self.lefttableview.selectedIndexes()
        right_indexes = self.righttableview.selectedIndexes()
        if len(left_indexes) == 0 and len(right_indexes) == 0:
            return None
        index = left_indexes[0] if len(left_indexes) > len(right_indexes) else right_indexes[0]
        return index

    def save_file_models_folder(self):
        self.left_file_model_auto_sync_label.setText(self.parent.settings_widget.left_folder_tracked.text())
        self.right_file_model_auto_sync_label.setText(self.parent.settings_widget.right_folder_tracked.text())
Exemplo n.º 10
0
class ERUploaderWindow(QDialog):
    """This window provides the user a visual picture of the local and online status of the Extra Reflectance calibration file repository. It also allows uploading
    of files that are present locally but not on the server. It does not have good handling of edge cases, e.g. online server in inconsistent state."""
    def __init__(self, manager: ERManager, parent: Optional[QWidget] = None):
        self._dataComparator = ERDataComparator(manager.onlineDirectory,
                                                manager.localDirectory)
        self._manager = manager
        self._selectedId: str = None
        super().__init__(parent)
        self.setModal(False)
        self.setWindowTitle("Extra Reflectance File Manager")
        self.setLayout(QVBoxLayout())
        self.table = QTableView(self)
        self.fileStatus = self._dataComparator.compare()
        self.table.setModel(PandasModel(self.fileStatus))
        self.table.setSelectionMode(QTableView.SingleSelection)
        self.table.setSelectionBehavior(QTableView.SelectRows)
        self.table.customContextMenuRequested.connect(self.openContextMenu)
        self.table.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.uploadButton = QPushButton("Upload to Drive")
        self.uploadButton.released.connect(self._updateGDrive)
        self.uploadButton.setToolTip(
            "Upload any files for which the status is `Local Only` to the google drive account."
        )
        self.refreshButton = QPushButton('Refresh')
        self.refreshButton.setToolTip(
            "Rescan the files in the applications data directory.")
        self.refreshButton.released.connect(self.refresh)
        self.updateIndexButton = QPushButton("Update Index File")
        self.updateIndexButton.setToolTip(
            "Download the online index file and merge it with our local index file."
        )
        self.updateIndexButton.released.connect(self._updateIndexFile)
        self.layout().addWidget(self.table)
        l = QHBoxLayout()
        l.setContentsMargins(0, 0, 0, 0)
        l.addWidget(self.uploadButton)
        l.addWidget(self.updateIndexButton)
        l.addWidget(self.refreshButton)
        w = QWidget()
        w.setLayout(l)
        self.layout().addWidget(w)
        self.table.setColumnWidth(0, 300)
        self.table.setColumnWidth(1, 150)
        self.table.setColumnWidth(2, 150)
        self.table.setMinimumWidth(
            sum(
                self.table.columnWidth(i)
                for i in range(self.table.model().columnCount())) +
            self.table.verticalHeader().width() + 20)

    def displayInfo(self, index: QModelIndex):
        msg = QMessageBox.information(self, 'Info',
                                      repr(self.fileStatus.iloc[index.row()]))

    def plotData(self, index: QModelIndex):
        idTag = self.fileStatus.iloc[index.row()]['idTag']
        md = self._dataComparator.local.getMetadataFromId(idTag)
        erCube = ExtraReflectanceCube.fromMetadata(md)
        self.plotHandle = PlotNd(erCube.data)

    def openContextMenu(self, pos: QPoint):
        """This method opens a context menu, it should be called when the user right clicks."""
        index = self.table.indexAt(pos)
        row = self.fileStatus.iloc[index.row()]
        menu = QMenu()
        displayAction = QAction("Display Info")
        displayAction.triggered.connect(lambda: self.displayInfo(index))
        menu.addAction(displayAction)
        if row['Local Status'] == self._dataComparator.local.DataStatus.found.value:
            plotAction = QAction("Plot Local Data")
            plotAction.triggered.connect(lambda: self.plotData(index))
            menu.addAction(plotAction)
        menu.exec(self.mapToGlobal(pos))

    def _updateGDrive(self):
        """Checks for all files taht are present locally but not on the server. Uploads those file and then overwrites the index."""
        try:
            status = self.fileStatus
            if not np.all((status['Index Comparison'] ==
                           ERDataComparator.ComparisonStatus.LocalOnly.value)
                          | (status['Index Comparison'] ==
                             ERDataComparator.ComparisonStatus.Match.value)):
                raise ValueError(
                    "Uploading cannot be performed if the local index file is not valid. Try updating the index file."
                )
            uploadableRows = (
                status['Index Comparison']
                == ERDataComparator.ComparisonStatus.LocalOnly.value) | (
                    status['Online Status']
                    == ERDataDirectory.DataStatus.missing.value)
            if np.any(uploadableRows):  # There is something to upload
                for i, row, in status.loc[uploadableRows].iterrows():
                    fileName = [
                        i.fileName
                        for i in self._dataComparator.local.index.cubes
                        if i.idTag == row['idTag']
                    ][0]
                    self._manager.upload(fileName)
                self._manager.upload('index.json')
            self.refresh()
        except Exception as e:
            logger = logging.getLogger(__name__)
            logger.exception(e)
            mess = QMessageBox.information(self, 'Sorry', str(e))

    def refresh(self):
        """Scans local and online files to refresh the display."""
        self._dataComparator.updateIndexes()
        self.fileStatus = self._dataComparator.compare()
        self.table.setModel(PandasModel(self.fileStatus))

    def _updateIndexFile(self):
        self._dataComparator.online.updateIndex()
        index = ERIndex.merge(self._dataComparator.local.index,
                              self._dataComparator.online.index)
        self._dataComparator.local.saveNewIndex(index)
        self.refresh()
Exemplo n.º 11
0
class FreezeTableWidget(QTableView):
    def __init__(self, model):
        super(FreezeTableWidget, self).__init__()
        self.setModel(model)
        self.frozenTableView = QTableView(self)
        self.init()
        self.horizontalHeader().sectionResized.connect(self.updateSectionWidth)
        self.verticalHeader().sectionResized.connect(self.updateSectionHeight)
        self.frozenTableView.verticalScrollBar().valueChanged.connect(
            self.verticalScrollBar().setValue)
        self.verticalScrollBar().valueChanged.connect(
            self.frozenTableView.verticalScrollBar().setValue)

    def init(self):
        self.frozenTableView.setModel(self.model())
        self.frozenTableView.setFocusPolicy(Qt.NoFocus)
        self.frozenTableView.verticalHeader().hide()
        self.frozenTableView.horizontalHeader().setSectionResizeMode(
                QHeaderView.Fixed)
        self.viewport().stackUnder(self.frozenTableView)

        self.frozenTableView.setStyleSheet('''
            QTableView { border: none;
                         background-color: #8EDE21;
                         selection-background-color: #999;
            }''') # for demo purposes

        self.frozenTableView.setSelectionModel(self.selectionModel())
        for col in range(1, self.model().columnCount()):
            self.frozenTableView.setColumnHidden(col, True)
        self.frozenTableView.setColumnWidth(0, self.columnWidth(0))
        self.frozenTableView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.frozenTableView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.frozenTableView.show()
        self.updateFrozenTableGeometry()
        self.setHorizontalScrollMode(self.ScrollPerPixel)
        self.setVerticalScrollMode(self.ScrollPerPixel)
        self.frozenTableView.setVerticalScrollMode(self.ScrollPerPixel)

    def updateSectionWidth(self, logicalIndex, oldSize, newSize):
        if self.logicalIndex == 0:
            self.frozenTableView.setColumnWidth(0, newSize)
            self.updateFrozenTableGeometry()

    def updateSectionHeight(self, logicalIndex, oldSize, newSize):
        self.frozenTableView.setRowHeight(logicalIndex, newSize)

    def resizeEvent(self, event):
        super(FreezeTableWidget, self).resizeEvent(event)
        self.updateFrozenTableGeometry()

    def moveCursor(self, cursorAction, modifiers):
        current = super(FreezeTableWidget, self).moveCursor(cursorAction, modifiers)
        if (cursorAction == self.MoveLeft and
                self.current.column() > 0 and
                self.visualRect(current).topLeft().x() <
                    self.frozenTableView.columnWidth(0)):
            newValue = (self.horizontalScrollBar().value() +
                        self.visualRect(current).topLeft().x() -
                        self.frozenTableView.columnWidth(0))
            self.horizontalScrollBar().setValue(newValue)
        return current

    def scrollTo(self, index, hint):
        if index.column() > 0:
            super(FreezeTableWidget, self).scrollTo(index, hint)

    def updateFrozenTableGeometry(self):
        self.frozenTableView.setGeometry(
                self.verticalHeader().width() + self.frameWidth(),
                self.frameWidth(), self.columnWidth(0),
                self.viewport().height() + self.horizontalHeader().height())
Exemplo n.º 12
0
class Widget(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)

        self.setGeometry(100, 150, 1200, 600)

        self.Columns = '*'
        self.font = None
        self.HeaderList = None
        self.left_padding = 0
        self.right_padding = 0
        self.search_field_spacing = 5

        self.createDB()
        self.getHeaders()

        layout = QVBoxLayout(self)

        buttons_layout = QHBoxLayout()
        show_plant_view = QPushButton('Plant photo with details')
        font_button = QPushButton('Font')
        buttons_layout.addWidget(show_plant_view)
        buttons_layout.addWidget(font_button)

        layout.addLayout(buttons_layout)

        show_plant_view.clicked.connect(self._show_photo_view)
        font_button.clicked.connect(self.font_dialog)

        self.model = MySqlModel(self.HeaderList)
        self.SearchQuery = "select {} from {}".format(self.Columns, _DB_TABLE)
        self.model.setQuery(self.SearchQuery, self.DB)

        self.view = QTableView(self)
        self.view.setMinimumHeight(325)
        self.font = self.view.property('font')
        self.view.setModel(self.model)

        self.view.setColumnHidden(self.model.image_column, True)
        self.view.setColumnHidden(self.model.info_column, True)

        horizontal_header = self.view.horizontalHeader()
        for i in range(len(horizontal_header)):
            horizontal_header.setSectionResizeMode(i, QHeaderView.Stretch)

        self.search_layout = QHBoxLayout()
        self.search_layout.insertSpacing(0, self.left_padding)
        self.SearchFieldsGrid = QGridLayout()
        self.makeSearchFieldsGrid()
        self.search_layout.addLayout(self.SearchFieldsGrid)
        self.search_layout.insertSpacing(-1, self.right_padding)
        layout.addLayout(self.search_layout)

        #self.view.horizontalHeader().setStretchLastSection(True)
        #self.view.resizeColumnsToContents()
        #self.view.horizontalHeader().ResizeMode(QHeaderView.Interactive)

        layout.addWidget(self.view)

        self.view.resizeRowsToContents()
        self.view_vertical_header = self.view.verticalHeader()
        self.view_vertical_header.geometriesChanged.connect(
            self._align_search_layout)

    def createDB(self):
        # binding to an existing database

        self.DB = QtSql.QSqlDatabase.addDatabase('QSQLITE')

        self.DB.setDatabaseName(_PATH_TO_DB)
        self.DB.open()

    def getHeaders(self):
        # getting a list of Headers
        self.query = QtSql.QSqlQuery(db=self.DB)
        self.query.exec_("PRAGMA table_info({})".format(_DB_TABLE))

        # filling the list of headings
        self.HeaderList = []
        while self.query.next():
            self.HeaderList.append(self.query.value(1))

        # create a query parameter dictionary
        self.paramsDict = {x: ['', '', ''] for x in self.HeaderList}
        self.paramsDict[''] = ["{} {} '%{}%'", '', '']

    def makeSearchFieldsGrid(self):
        self.SearchFieldsGrid.setSpacing(self.search_field_spacing)

        self.clearLayout(self.SearchFieldsGrid)

        self.cb = QCheckBox(self)
        self.cb.stateChanged.connect(self.changeQuery)
        self.SearchFieldsGrid.addWidget(self.cb, 1, 0)

        n = len(self.HeaderList)
        qwidth = [self.view.columnWidth(i) for i in range(n)]
        self.qles = [None for i in range(n)]

        for i in range(n):
            self.qles[i] = QLineEdit(self)
            self.qles[i].setObjectName(self.HeaderList[i])
            self.qles[i].textChanged[str].connect(self.setSearchQuery)
            label = QLabel(self.HeaderList[i])

            self.SearchFieldsGrid.addWidget(label,
                                            0,
                                            i + 1,
                                            alignment=Qt.AlignCenter)
            self.SearchFieldsGrid.addWidget(self.qles[i], 1, i + 1)

    def clearLayout(self, layout):
        while layout.count():
            child = layout.takeAt(0)
            if child.widget() is not None:
                child.widget().deleteLater()
            elif child.layout() is not None:
                clearLayout(child.layout())

    # remembering the status of the switch after pressing and updating the table
    def changeQuery(self, state):

        self.state = state
        self.setSearchQuery('')

    def setSearchQuery(self, text):
        # switch handling
        try:
            if self.state == Qt.Checked:
                self.paramsDict[''] = [
                    "{0} {1} '% {2}%' or {0} {1} '{2}%'", '', ''
                ]
            else:
                self.paramsDict[''] = ["{} {} '%{}%'", '', '']
        except:
            self.paramsDict[''] = ["{} {} '%{}%'", '', '']
        # processing of more and less characters
        if text != '':
            if text[0] == '<':
                matching = '<'
                queryString = "{} {} {}"
                text = text[1:]
            elif text[0] == '>':
                matching = '>'
                queryString = "{} {} {}"
                text = text[1:]
            else:
                queryString = self.paramsDict[''][0]
                matching = 'like'
        else:
            queryString, matching, text = self.paramsDict['']

        # filling in the query parameters dictionary
        self.paramsDict[self.sender().objectName()] = [
            queryString, matching, text
        ]
        paramList = []
        # assembling query parameters into a list
        for name, value in self.paramsDict.items():
            if len(value) == 3:
                queryString, matching, text = value
                if queryString.find('%') != -1:
                    queryString = self.paramsDict[''][0]
                if text != '':
                    paramList.append(queryString.format(name, matching, text))

        # assembling query parameters into a string
        if len(paramList) == 0:
            params = ''
        elif len(paramList) == 1:
            params = 'where {}'.format(paramList[0])
        else:
            params = 'where {}'.format(" and ".join(paramList))
        # assembling the query and updating the table according to it

        self.Columns = '*' if self.Columns == '' else self.Columns
        self.searchQuery = "select {} from {} {}".format(
            self.Columns, _DB_TABLE, params)
        self.model.setQuery(self.searchQuery, self.DB)

        self.view.resizeRowsToContents()

        #header = self.view.horizontalHeader()
        #for i in range(len(header)):
        #header.setSectionResizeMode(i, QHeaderView.Stretch)

    def font_dialog(self):

        self.font, valid = QFontDialog.getFont(self.font)
        if valid:
            self.view.setFont(self.font)
            self.view.resizeRowsToContents()
            for i in self.qles:
                i.setFont(self.font)

    def _align_search_layout(self):
        vertical_header_width = self.view_vertical_header.width()
        checkbox_width = self.cb.width()
        self.left_padding = vertical_header_width - checkbox_width - self.search_field_spacing
        vertical_scrollbar_width = self.view.verticalScrollBar().width()
        self.right_padding = vertical_scrollbar_width

        left_spacer = self.search_layout.itemAt(0)
        left_spacer.changeSize(self.left_padding, 10)

        right_spacer = self.search_layout.itemAt(2)
        right_spacer.changeSize(self.right_padding, 10)

        self.search_layout.invalidate()

    def _show_photo_view(self):
        #image_data = _get_image_paths_names(self.model)
        viewer = PhotoViewe(self.model, self)
        viewer.show()