Ejemplo n.º 1
0
class MainTable(QWidget):
    def __init__(self, change_set_a, change_set_b):
        """
        Initialize the MainTable class
        """
        super().__init__()

        self.rows: list = []
        grid = QGridLayout()
        self.setLayout(grid)
        self.table = QTableWidget()
        self.table.setSelectionMode(
            QtWidgets.QAbstractItemView.SingleSelection)
        self.file_dropped = ""
        self.table.setRowCount(0)  # Set the initial row count to 0
        self.table.setColumnCount(5)  # Set the column count to 5
        self.setAcceptDrops(True)
        self.undo_ctrlr: undo_redo.UndoRedo = undo_redo.UndoRedo.get_instance()

        # List containing indices of all diff rows. This is used for jump to diff functions
        self.diff_indices: list = []
        self.diff_index_block_end: list = []
        # Contains the index of the current diff that has been jumped to
        self.curr_diff_idx: int = -1
        self.selected_block: list = [0, 0]
        self.block_undo_size: list = []
        self.block_redo_size: list = []

        self.table.cellClicked.connect(self.cellClickedEvent)

        self.change_set_a = change_set_a
        self.change_set_b = change_set_b
        self.left_file: str = ""
        self.right_file: str = ""

        self.table.verticalHeader().setVisible(
            False)  # Disable the automatic line numbers.
        self.table.setVerticalScrollMode(0)

        # Set the head text
        self.table.setHorizontalHeaderItem(0, QTableWidgetItem("Line"))
        self.table.setHorizontalHeaderItem(1, QTableWidgetItem(""))
        self.table.setHorizontalHeaderItem(2, QTableWidgetItem("Merge\nRight"))
        self.table.setHorizontalHeaderItem(3, QTableWidgetItem("Merge\nLeft "))
        self.table.setHorizontalHeaderItem(4, QTableWidgetItem(""))

        # Set the header font
        self.table.horizontalHeader().setFont(
            gui_cfg.FONTS["TBL_HEADER_DEFAULT"])

        # Set the header text alignment
        self.table.horizontalHeaderItem(0).setTextAlignment(Qt.AlignCenter)
        self.table.horizontalHeaderItem(1).setTextAlignment(Qt.AlignCenter)
        self.table.horizontalHeaderItem(2).setTextAlignment(Qt.AlignCenter)
        self.table.horizontalHeaderItem(3).setTextAlignment(Qt.AlignCenter)
        self.table.horizontalHeaderItem(4).setTextAlignment(Qt.AlignCenter)

        # Set column resize modes
        self.table.horizontalHeader().setSectionResizeMode(
            0, QHeaderView.ResizeToContents)
        self.table.horizontalHeader().setSectionResizeMode(
            1, QHeaderView.Stretch)
        self.table.horizontalHeader().setSectionResizeMode(
            2, QHeaderView.ResizeToContents)
        self.table.horizontalHeader().setSectionResizeMode(
            3, QHeaderView.ResizeToContents)
        self.table.horizontalHeader().setSectionResizeMode(
            4, QHeaderView.Stretch)

        self.set_tbl_fonts_and_colors()  # Set the color and fonts
        self.table.setGridStyle(Qt.PenStyle(Qt.DotLine))

        # Make the table read only for the user
        self.table.setEditTriggers(QTableWidget.NoEditTriggers)

        # Convert icon paths from gui_config.py to QIcon objects
        # gui_cgf.converted ensures test software can run correctly
        if not gui_cfg.converted:
            gui_cfg.convert_icon_dict()

        grid.addWidget(self.table)

    def set_tbl_fonts_and_colors(self):
        """
        Contains all the function calls required to setup the color and text formatting for the table.
        :return:
        """
        # Set the header background colors
        self.table.horizontalHeaderItem(0).setBackground(
            gui_cfg.COLORS["TBL_HDR_DEFAULT_BG"])
        self.table.horizontalHeaderItem(1).setBackground(
            gui_cfg.COLORS["TBL_HDR_DEFAULT_BG"])
        self.table.horizontalHeaderItem(2).setBackground(
            gui_cfg.COLORS["TBL_HDR_DEFAULT_BG"])
        self.table.horizontalHeaderItem(3).setBackground(
            gui_cfg.COLORS["TBL_HDR_DEFAULT_BG"])
        self.table.horizontalHeaderItem(4).setBackground(
            gui_cfg.COLORS["TBL_HDR_DEFAULT_BG"])

        # Setup the text and background colors for active and inactive rows (selections)
        table_palette = QtGui.QPalette(self.table.palette())
        table_palette.setBrush(
            QtGui.QPalette.Active,
            QtGui.QPalette.HighlightedText,
            QtGui.QBrush(gui_cfg.COLORS["ROW_ACTV_TXT"]),
        )
        table_palette.setBrush(
            QtGui.QPalette.Inactive,
            QtGui.QPalette.HighlightedText,
            QtGui.QBrush(gui_cfg.COLORS["ROW_INACTV_TXT"]),
        )
        table_palette.setBrush(
            QtGui.QPalette.Active,
            QtGui.QPalette.Highlight,
            QtGui.QBrush(gui_cfg.COLORS["ROW_ACTV_BG"]),
        )
        table_palette.setBrush(
            QtGui.QPalette.Inactive,
            QtGui.QPalette.Highlight,
            QtGui.QBrush(gui_cfg.COLORS["ROW_INACTV_BG"]),
        )
        self.table.setPalette(table_palette)

    def dragEnterEvent(self, event):
        """
        Override the dragEnterEvent method from PyQt
        :param event:
        :return:
        """
        event.accept() if event.mimeData().hasUrls else event.ignore()

    def dragMoveEvent(self, event):
        """
        Override the dragMoveEvent method from PyQt
        :param event:
        :return:
        """
        if event.mimeData().hasUrls:
            event.setDropAction(Qt.CopyAction)
            event.accept()
        else:
            event.ignore()

    def dropEvent(self, event):
        """
        Override the dropEvent method
        :param event:
        :return:
        """
        if event.mimeData().hasUrls:
            event.setDropAction(Qt.CopyAction)
            event.accept()

            for url in event.mimeData().urls():
                path = url.toLocalFile()

            if self.file_dropped == "":
                self.file_dropped = path
            else:
                self.clear_table()
                fileB = path

                if not utilities.file_writable(self.file_dropped):
                    QMessageBox.about(
                        self, "Warning ",
                        os.path.basename(self.file_dropped) + " is read only")
                if not utilities.file_writable(fileB):
                    QMessageBox.about(
                        self, "Warning ",
                        os.path.basename(fileB) + " is read only")

                # I use a local instance of fileIO to generate changesets, since
                # main_table can't access the main window instance of fileIO
                self.file_io = file_io.FileIO()
                result = self.file_io.diff_files(self.file_dropped, fileB)
                if result == pymerge_enums.RESULT.GOOD:
                    result = result = self.file_io.get_change_sets(
                        self.file_io.changes_a, self.file_io.changes_b)

                # I point the local changeSets to a local changeSet
                # but I must point the local changeSets back at the mainWindow changeSets
                # so I user could open different file via file open after they do a click and drag
                change_set_rereference_a = self.change_set_a
                change_set_rereference_b = self.change_set_b
                self.change_set_a = self.file_io.changes_a
                self.change_set_b = self.file_io.changes_b

                self.load_table_contents(self.file_dropped, fileB)

                self.change_set_a = change_set_rereference_a
                self.change_set_b = change_set_rereference_b

                self.file_dropped = ""

        else:
            event.ignore()

    @pyqtSlot()
    def goto_next_diff(self):
        """
        Scrolls the table window to the next difference incrementally (starts at the first diff)
        :return: No return value
        """
        if len(self.diff_indices) == 0:
            return

        if self.curr_diff_idx == len(self.diff_indices) - 1:
            self.curr_diff_idx = 0
            self.jump_to_line(self.diff_indices[self.curr_diff_idx])
        else:
            self.curr_diff_idx += 1
            self.jump_to_line(self.diff_indices[self.curr_diff_idx])

        self.select_block()
        return

    @pyqtSlot()
    def goto_prev_diff(self):
        """
        Scrolls the table window to the previous difference incrementally
        :return: No return value
        """
        if len(self.diff_indices) == 0:
            return

        if self.curr_diff_idx == 0 or self.curr_diff_idx == -1:
            self.curr_diff_idx = len(self.diff_indices) - 1
            self.jump_to_line(self.diff_indices[self.curr_diff_idx])
        else:
            self.curr_diff_idx -= 1
            self.jump_to_line(self.diff_indices[self.curr_diff_idx])

        self.select_block()
        self.table.repaint()
        return

    @pyqtSlot()
    def undo_last_change(self):
        """
        undoes last change or group of changes
        :return: No return value
        """
        undo_stack_size = 0
        for n in self.block_undo_size:
            undo_stack_size += n

        difference = self.undo_ctrlr.undo_buf_size - undo_stack_size
        for i in range(difference):
            self.block_undo_size.append(1)

        if len(self.block_undo_size) != 0:
            n = self.block_undo_size.pop()
            self.block_redo_size.append(n)
            for i in range(n):
                self.undo_ctrlr.undo()
                self.undo_ctrlr.undo_buf_size -= 1
        else:
            self.undo_ctrlr.undo()
            if self.undo_ctrlr.undo_buf_size != 0:
                self.undo_ctrlr.undo_buf_size -= 1
        for row in self.rows:
            row.set_row_state()

    @pyqtSlot()
    def redo_last_undo(self):
        """
        redo last undo performed
        :return: No return value
        """
        if len(self.block_redo_size) != 0:
            n = self.block_redo_size.pop()
            self.block_undo_size.append(n)
            for i in range(n):
                self.undo_ctrlr.redo()
        else:
            self.undo_ctrlr.redo()
        for row in self.rows:
            row.set_row_state()

    @pyqtSlot()
    def merge_left(self):
        """
        merge the whole left selection into the right
        """

        self.table.clearSelection()
        for n in range(self.selected_block[0], self.selected_block[1]):
            self.rows[n].merge_left()

        self.block_undo_size.append(self.selected_block[1] -
                                    self.selected_block[0])

        undo_stack_size = 0
        for n in self.block_undo_size:
            undo_stack_size += n

        difference = undo_stack_size - self.undo_ctrlr.undo_buf_size
        difference = abs(difference)
        for i in range(difference):
            self.block_undo_size.insert(len(self.block_undo_size) - 1, 1)

        return

    @pyqtSlot()
    def merge_right(self):
        """
        merge the whole right selection into the left
        """
        self.table.clearSelection()
        for n in range(self.selected_block[0], self.selected_block[1]):
            self.rows[n].merge_right()

        self.block_undo_size.append(self.selected_block[1] -
                                    self.selected_block[0])

        undo_stack_size = 0
        for n in self.block_undo_size:
            undo_stack_size += n

        difference = undo_stack_size - self.undo_ctrlr.undo_buf_size
        difference = abs(difference)
        for i in range(difference):
            self.block_undo_size.insert(len(self.block_undo_size) - 1, 1)

        return

    def jump_to_line(self, line_num, col=0):
        self.table.clearSelection()
        self.table.scrollToItem(self.table.item(line_num - 1, col),
                                QtWidgets.QAbstractItemView.PositionAtTop)

    def add_line(
        self,
        right_text: str,
        left_text: str,
        line_num: int or str,
        change_flags,
        left_line_num=0,
        right_line_num=0,
    ):
        """
        Add a row into the table using the right and left text provided as parameters.
        :param right_line_num:
        :param left_line_num:
        :param right_text: Right text to display
        :param left_text: Left text to display
        :param line_num: Line number to display. This isn't exactly where it's inserted, just a display value
        :param change_flags:
        :return: No return value

        """
        self.table.insertRow(line_num)
        self.table.setRowHeight(line_num, 28)
        self.table.setItem(line_num, 0, QTableWidgetItem(str(line_num + 1)))
        self.table.setItem(line_num, 1, QTableWidgetItem(str(right_text)))
        self.table.setItem(line_num, 2, QTableWidgetItem(""))
        self.table.setItem(line_num, 3, QTableWidgetItem(""))
        self.table.setItem(line_num, 4, QTableWidgetItem(str(left_text)))

        self.table.item(line_num, 0).setTextAlignment(Qt.AlignCenter)
        self.table.item(line_num, 2).setTextAlignment(Qt.AlignCenter)
        self.table.item(line_num, 3).setTextAlignment(Qt.AlignCenter)

        self.table.item(line_num, 0).setBackground(
            gui_cfg.COLORS["TBL_LINE_COL_DEFAULT_BG"])
        self.table.item(line_num, 2).setBackground(
            gui_cfg.COLORS["TBL_LINE_COL_DEFAULT_BG"])
        self.table.item(line_num, 3).setBackground(
            gui_cfg.COLORS["TBL_LINE_COL_DEFAULT_BG"])
        self.table.item(line_num, 4).setBackground(
            gui_cfg.COLORS["TBL_LINE_COL_DEFAULT_BG"])

        row_instance = table_row.Row(line_num, self.table, right_text,
                                     left_text, line_num, change_flags)
        row_instance.actual_indices[0] = left_line_num
        row_instance.actual_indices[1] = right_line_num

        self.rows.append(row_instance)

    def get_lines_from_tbl(self) -> list:
        """
        Gets the data from the table and returns it as a 2D list.
        :return: list containing right and left hand file data
        """
        outp_left: list = []
        outp_right: list = []

        for row in self.rows:
            if row.row_deleted[1]:
                outp_left.append(None)
            else:
                outp_left.append(row.left_text)
            if row.row_deleted[0]:
                outp_right.append(None)
            else:
                outp_right.append(row.right_text)

        return [outp_left, outp_right]

    def clear_table(self) -> bool:
        for row in self.rows:
            try:
                self.table.removeRow(row.row_num)
            except (IndexError, Exception):
                print("Error: could not clear main table.")
                return False
        self.rows.clear()
        self.table.setRowCount(0)
        del self.change_set_a.change_list[:]
        del self.change_set_b.change_list[:]
        self.block_undo_size.clear()
        self.block_redo_size.clear()
        self.curr_diff_idx = -1
        self.selected_block[0] = 0
        self.selected_block[1] = 0
        self.diff_indices.clear()
        self.diff_index_block_end.clear()
        return True

    def load_table_contents(self, file1=0, file2=0):
        if file1 == 0 or file2 == 0:
            return
        """
        Load the contents of two data structures containing the lines to be displayed, into the tables
        :param left_lines: left hand data to show
        :param right_lines: right hand data to show
        :return: No return value
        """

        self.table.horizontalHeaderItem(1).setText(os.path.abspath(file1))
        self.table.horizontalHeaderItem(4).setText(os.path.abspath(file2))
        self.left_file = file1
        self.right_file = file2

        # Get the change information for each line. Skip the last line, as that is the
        # match token that has been appened on by diff_set in order to capture entire file
        # contents.
        for n in range(len(self.change_set_a.change_list) - 1):
            data_a = [""]
            data_b = [""]
            change_type_a = [pymerge_enums.CHANGEDENUM.SAME]
            change_type_b = [pymerge_enums.CHANGEDENUM.SAME]
            self.change_set_a.get_change(n, change_type_a, data_a)
            self.change_set_b.get_change(n, change_type_b, data_b)

            self.add_line(data_a[0], data_b[0], n,
                          [change_type_a[0], change_type_b[0]])

        # generate list of diff lines, to enable prev/next diff jump buttons
        n = 0
        while n < len(self.change_set_a.change_list) - 1:
            data_a = [""]
            change_type_a = [pymerge_enums.CHANGEDENUM.SAME]
            self.change_set_a.get_change(n, change_type_a, data_a)
            if change_type_a[0] != pymerge_enums.CHANGEDENUM.SAME:
                self.diff_indices.append(n)
                while change_type_a[0] != pymerge_enums.CHANGEDENUM.SAME:
                    n += 1
                    self.change_set_a.get_change(n, change_type_a, data_a)
                self.diff_index_block_end.append(n)
            n += 1

    @pyqtSlot()
    def write_merged_files(self):
        merged_file_contents = self.get_lines_from_tbl()
        merge_writer = merge_finalizer.MergeFinalizer(self.left_file,
                                                      self.right_file,
                                                      "file_backup")
        if not merge_writer.set_equal(merged_file_contents[0][:-1],
                                      merged_file_contents[1][:-1]):
            print(
                "Warning: Files are not identicle, merge all lines before saving in order for files to be 100% syncronized."
            )

        merge_writer.finalize_merge(merged_file_contents[0][:-1],
                                    merged_file_contents[1][:-1])

    def load_test_files(self, file1: str, file2: str):
        """
        Load two arbitrary files as as test
        :param file1: right hand file to load
        :param file2: left hand file to load
        :return: No return value
        """
        self.table.horizontalHeaderItem(1).setText(os.path.abspath(file1))
        self.table.horizontalHeaderItem(4).setText(os.path.abspath(file2))

        with open(file1, "r") as file:
            file1_contents = file.read().splitlines()

        with open(file2, "r") as file:
            file2_contents = file.read().splitlines()

        self.load_table_contents(file1_contents, file2_contents)
        self.jump_to_line(77)

    def select_block(self, n=-1):

        if n != -1:
            j = 0
            for i in self.diff_indices:
                if n >= i:
                    self.curr_diff_idx = j
                j += 1

        self.table.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
        self.table.clearSelection()
        self.selected_block[0] = self.diff_indices[self.curr_diff_idx]
        self.selected_block[1] = self.diff_index_block_end[self.curr_diff_idx]
        for n in range(self.diff_indices[self.curr_diff_idx],
                       self.diff_index_block_end[self.curr_diff_idx]):
            self.table.selectRow(n)

        self.table.setSelectionMode(
            QtWidgets.QAbstractItemView.SingleSelection)

    @pyqtSlot()
    def cellClickedEvent(self):
        if self.rows[self.table.currentRow(
        )].change_state_flags[0] == pymerge_enums.CHANGEDENUM.SAME:
            self.table.clearSelection()
        else:
            self.select_block(self.table.currentRow())
Ejemplo n.º 2
0
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setupTrayicon()
        self.setupVariables()
        self.setupUi()
        self.setupConnections()
        self.show()

    def setupVariables(self):
        settings = QSettings()
        self.workEndTime = QTime(
            int(settings.value(workHoursKey, 0)),
            int(settings.value(workMinutesKey, 25)),
            int(settings.value(workSecondsKey, 0)),
        )
        self.restEndTime = QTime(
            int(settings.value(restHoursKey, 0)),
            int(settings.value(restMinutesKey, 5)),
            int(settings.value(restSecondsKey, 0)),
        )
        self.timeFormat = "hh:mm:ss"
        self.time = QTime(0, 0, 0, 0)
        self.workTime = QTime(0, 0, 0, 0)
        self.restTime = QTime(0, 0, 0, 0)
        self.totalTime = QTime(0, 0, 0, 0)
        self.currentMode = Mode.work
        self.maxRepetitions = -1
        self.currentRepetitions = 0

    def setupConnections(self):
        """ Create button connections """
        self.startButton.clicked.connect(self.startTimer)
        self.startButton.clicked.connect(
            lambda: self.startButton.setDisabled(True))
        self.startButton.clicked.connect(
            lambda: self.pauseButton.setDisabled(False))
        self.startButton.clicked.connect(
            lambda: self.resetButton.setDisabled(False))
        self.pauseButton.clicked.connect(self.pauseTimer)
        self.pauseButton.clicked.connect(
            lambda: self.startButton.setDisabled(False))
        self.pauseButton.clicked.connect(
            lambda: self.pauseButton.setDisabled(True))
        self.pauseButton.clicked.connect(
            lambda: self.resetButton.setDisabled(False))
        self.pauseButton.clicked.connect(
            lambda: self.startButton.setText("continue"))
        self.resetButton.clicked.connect(self.resetTimer)
        self.resetButton.clicked.connect(
            lambda: self.startButton.setDisabled(False))
        self.resetButton.clicked.connect(
            lambda: self.pauseButton.setDisabled(True))
        self.resetButton.clicked.connect(
            lambda: self.resetButton.setDisabled(True))
        self.resetButton.clicked.connect(
            lambda: self.startButton.setText("start"))
        self.acceptTaskButton.pressed.connect(self.insertTask)
        self.deleteTaskButton.pressed.connect(self.deleteTask)
        """ Create spinbox  connections """
        self.workHoursSpinBox.valueChanged.connect(self.updateWorkEndTime)
        self.workMinutesSpinBox.valueChanged.connect(self.updateWorkEndTime)
        self.workSecondsSpinBox.valueChanged.connect(self.updateWorkEndTime)
        self.restHoursSpinBox.valueChanged.connect(self.updateRestEndTime)
        self.restMinutesSpinBox.valueChanged.connect(self.updateRestEndTime)
        self.restSecondsSpinBox.valueChanged.connect(self.updateRestEndTime)
        self.repetitionsSpinBox.valueChanged.connect(self.updateMaxRepetitions)
        """ Create combobox connections """
        self.modeComboBox.currentTextChanged.connect(self.updateCurrentMode)
        """ Create tablewidget connections """
        self.tasksTableWidget.cellDoubleClicked.connect(
            self.markTaskAsFinished)

    def setupUi(self):
        self.size_policy = sizePolicy = QSizePolicy(QSizePolicy.Expanding,
                                                    QSizePolicy.Expanding)
        """ Create tabwidget """
        self.tabWidget = QTabWidget()
        """ Create tab widgets """
        timerWidget = self.setupTimerTab()
        tasksWidget = self.setupTasksTab()
        statisticsWidget = self.setupStatisticsTab()
        """ add tab widgets to tabwidget"""
        self.timerTab = self.tabWidget.addTab(timerWidget, makeIcon("timer"),
                                              "Timer")
        self.tasksTab = self.tabWidget.addTab(tasksWidget, makeIcon("tasks"),
                                              "Tasks")
        self.statisticsTab = self.tabWidget.addTab(statisticsWidget,
                                                   makeIcon("statistics"),
                                                   "Statistics")
        """ Set mainwindows central widget """
        self.setCentralWidget(self.tabWidget)

    def setupTimerTab(self):
        settings = QSettings()
        self.timerContainer = QWidget(self)
        self.timerContainerLayout = QVBoxLayout(self.timerContainer)
        self.timerContainer.setLayout(self.timerContainerLayout)
        """ Create work groupbox"""
        self.workGroupBox = QGroupBox("Work")
        self.workGroupBoxLayout = QHBoxLayout(self.workGroupBox)
        self.workGroupBox.setLayout(self.workGroupBoxLayout)
        self.workHoursSpinBox = QSpinBox(
            minimum=0,
            maximum=24,
            value=int(settings.value(workHoursKey, 0)),
            suffix="h",
            sizePolicy=self.size_policy,
        )
        self.workMinutesSpinBox = QSpinBox(
            minimum=0,
            maximum=60,
            value=int(settings.value(workMinutesKey, 25)),
            suffix="m",
            sizePolicy=self.size_policy,
        )
        self.workSecondsSpinBox = QSpinBox(
            minimum=0,
            maximum=60,
            value=int(settings.value(workSecondsKey, 0)),
            suffix="s",
            sizePolicy=self.size_policy,
        )
        """ Create rest groupbox"""
        self.restGroupBox = QGroupBox("Rest")
        self.restGroupBoxLayout = QHBoxLayout(self.restGroupBox)
        self.restGroupBox.setLayout(self.restGroupBoxLayout)
        self.restHoursSpinBox = QSpinBox(
            minimum=0,
            maximum=24,
            value=int(settings.value(restHoursKey, 0)),
            suffix="h",
            sizePolicy=self.size_policy,
        )
        self.restMinutesSpinBox = QSpinBox(
            minimum=0,
            maximum=60,
            value=int(settings.value(restMinutesKey, 5)),
            suffix="m",
            sizePolicy=self.size_policy,
        )
        self.restSecondsSpinBox = QSpinBox(
            minimum=0,
            maximum=60,
            value=int(settings.value(restSecondsKey, 0)),
            suffix="s",
            sizePolicy=self.size_policy,
        )
        self.restGroupBoxLayout.addWidget(self.restHoursSpinBox)
        self.restGroupBoxLayout.addWidget(self.restMinutesSpinBox)
        self.restGroupBoxLayout.addWidget(self.restSecondsSpinBox)
        """ Create other groupbox"""
        self.otherGroupBox = QGroupBox("Other")
        self.otherGroupBoxLayout = QHBoxLayout(self.otherGroupBox)
        self.otherGroupBox.setLayout(self.otherGroupBoxLayout)
        self.repetitionsLabel = QLabel("Repetitions")
        self.repetitionsSpinBox = QSpinBox(
            minimum=0,
            maximum=10000,
            value=0,
            sizePolicy=self.size_policy,
            specialValueText="∞",
        )
        self.modeLabel = QLabel("Mode")
        self.modeComboBox = QComboBox(sizePolicy=self.size_policy)
        self.modeComboBox.addItems(["work", "rest"])
        self.otherGroupBoxLayout.addWidget(self.repetitionsLabel)
        self.otherGroupBoxLayout.addWidget(self.repetitionsSpinBox)
        self.otherGroupBoxLayout.addWidget(self.modeLabel)
        self.otherGroupBoxLayout.addWidget(self.modeComboBox)
        """ Create timer groupbox"""
        self.lcdDisplayGroupBox = QGroupBox("Time")
        self.lcdDisplayGroupBoxLayout = QHBoxLayout(self.lcdDisplayGroupBox)
        self.lcdDisplayGroupBox.setLayout(self.lcdDisplayGroupBoxLayout)
        self.timeDisplay = QLCDNumber(8, sizePolicy=self.size_policy)
        self.timeDisplay.setFixedHeight(100)
        self.timeDisplay.display("00:00:00")
        self.lcdDisplayGroupBoxLayout.addWidget(self.timeDisplay)
        """ Create pause, start and reset buttons"""
        self.buttonContainer = QWidget()
        self.buttonContainerLayout = QHBoxLayout(self.buttonContainer)
        self.buttonContainer.setLayout(self.buttonContainerLayout)
        self.startButton = self.makeButton("start", disabled=False)
        self.resetButton = self.makeButton("reset")
        self.pauseButton = self.makeButton("pause")
        """ Add widgets to container """
        self.workGroupBoxLayout.addWidget(self.workHoursSpinBox)
        self.workGroupBoxLayout.addWidget(self.workMinutesSpinBox)
        self.workGroupBoxLayout.addWidget(self.workSecondsSpinBox)
        self.timerContainerLayout.addWidget(self.workGroupBox)
        self.timerContainerLayout.addWidget(self.restGroupBox)
        self.timerContainerLayout.addWidget(self.otherGroupBox)
        self.timerContainerLayout.addWidget(self.lcdDisplayGroupBox)
        self.buttonContainerLayout.addWidget(self.pauseButton)
        self.buttonContainerLayout.addWidget(self.startButton)
        self.buttonContainerLayout.addWidget(self.resetButton)
        self.timerContainerLayout.addWidget(self.buttonContainer)
        return self.timerContainer

    def setupTasksTab(self):
        settings = QSettings()
        """ Create vertical tasks container """
        self.tasksWidget = QWidget(self.tabWidget)
        self.tasksWidgetLayout = QVBoxLayout(self.tasksWidget)
        self.tasksWidget.setLayout(self.tasksWidgetLayout)
        """ Create horizontal input container """
        self.inputContainer = QWidget()
        self.inputContainer.setFixedHeight(50)
        self.inputContainerLayout = QHBoxLayout(self.inputContainer)
        self.inputContainerLayout.setContentsMargins(0, 0, 0, 0)
        self.inputContainer.setLayout(self.inputContainerLayout)
        """ Create text edit """
        self.taskTextEdit = QTextEdit(
            placeholderText="Describe your task briefly.",
            undoRedoEnabled=True)
        """ Create vertical buttons container """
        self.inputButtonContainer = QWidget()
        self.inputButtonContainerLayout = QVBoxLayout(
            self.inputButtonContainer)
        self.inputButtonContainerLayout.setContentsMargins(0, 0, 0, 0)
        self.inputButtonContainer.setLayout(self.inputButtonContainerLayout)
        """ Create buttons """
        self.acceptTaskButton = QToolButton(icon=makeIcon("check"))
        self.deleteTaskButton = QToolButton(icon=makeIcon("trash"))
        """ Create tasks tablewidget """
        self.tasksTableWidget = QTableWidget(0, 1)
        self.tasksTableWidget.setHorizontalHeaderLabels(["Tasks"])
        self.tasksTableWidget.horizontalHeader().setStretchLastSection(True)
        self.tasksTableWidget.verticalHeader().setVisible(False)
        self.tasksTableWidget.setWordWrap(True)
        self.tasksTableWidget.setTextElideMode(Qt.ElideNone)
        self.tasksTableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.tasksTableWidget.setSelectionMode(
            QAbstractItemView.SingleSelection)
        self.insertTasks(*settings.value(tasksKey, []))
        """ Add widgets to container widgets """
        self.inputButtonContainerLayout.addWidget(self.acceptTaskButton)
        self.inputButtonContainerLayout.addWidget(self.deleteTaskButton)
        self.inputContainerLayout.addWidget(self.taskTextEdit)
        self.inputContainerLayout.addWidget(self.inputButtonContainer)
        self.tasksWidgetLayout.addWidget(self.inputContainer)
        self.tasksWidgetLayout.addWidget(self.tasksTableWidget)
        return self.tasksWidget

    def setupStatisticsTab(self):
        """ Create statistics container """
        self.statisticsContainer = QWidget()
        self.statisticsContainerLayout = QVBoxLayout(self.statisticsContainer)
        self.statisticsContainer.setLayout(self.statisticsContainerLayout)
        """ Create work time groupbox """
        self.statisticsWorkTimeGroupBox = QGroupBox("Work Time")
        self.statisticsWorkTimeGroupBoxLayout = QHBoxLayout()
        self.statisticsWorkTimeGroupBox.setLayout(
            self.statisticsWorkTimeGroupBoxLayout)
        self.statisticsWorkTimeDisplay = QLCDNumber(8)
        self.statisticsWorkTimeDisplay.display("00:00:00")
        self.statisticsWorkTimeGroupBoxLayout.addWidget(
            self.statisticsWorkTimeDisplay)
        """ Create rest time groupbox """
        self.statisticsRestTimeGroupBox = QGroupBox("Rest Time")
        self.statisticsRestTimeGroupBoxLayout = QHBoxLayout()
        self.statisticsRestTimeGroupBox.setLayout(
            self.statisticsRestTimeGroupBoxLayout)
        self.statisticsRestTimeDisplay = QLCDNumber(8)
        self.statisticsRestTimeDisplay.display("00:00:00")
        self.statisticsRestTimeGroupBoxLayout.addWidget(
            self.statisticsRestTimeDisplay)
        """ Create total time groupbox """
        self.statisticsTotalTimeGroupBox = QGroupBox("Total Time")
        self.statisticsTotalTimeGroupBoxLayout = QHBoxLayout()
        self.statisticsTotalTimeGroupBox.setLayout(
            self.statisticsTotalTimeGroupBoxLayout)
        self.statisticsTotalTimeDisplay = QLCDNumber(8)
        self.statisticsTotalTimeDisplay.display("00:00:00")
        self.statisticsTotalTimeGroupBoxLayout.addWidget(
            self.statisticsTotalTimeDisplay)
        """ Add widgets to container """
        self.statisticsContainerLayout.addWidget(
            self.statisticsTotalTimeGroupBox)
        self.statisticsContainerLayout.addWidget(
            self.statisticsWorkTimeGroupBox)
        self.statisticsContainerLayout.addWidget(
            self.statisticsRestTimeGroupBox)
        return self.statisticsContainer

    def setupTrayicon(self):
        self.trayIcon = QSystemTrayIcon(makeIcon("tomato"))
        self.trayIcon.setContextMenu(QMenu())
        self.quitAction = self.trayIcon.contextMenu().addAction(
            makeIcon("exit"), "Quit", self.exit)
        self.quitAction.triggered.connect(self.exit)
        self.trayIcon.activated.connect(self.onActivate)
        self.trayIcon.show()

    def leaveEvent(self, event):
        super(MainWindow, self).leaveEvent(event)
        self.tasksTableWidget.clearSelection()

    def closeEvent(self, event):
        super(MainWindow, self).closeEvent(event)
        settings = QSettings()
        settings.setValue(workHoursKey, self.workHoursSpinBox.value())
        settings.setValue(
            workMinutesKey,
            self.workMinutesSpinBox.value(),
        )
        settings.setValue(
            workSecondsKey,
            self.workSecondsSpinBox.value(),
        )
        settings.setValue(restHoursKey, self.restHoursSpinBox.value())
        settings.setValue(
            restMinutesKey,
            self.restMinutesSpinBox.value(),
        )
        settings.setValue(
            restSecondsKey,
            self.restSecondsSpinBox.value(),
        )

        tasks = []
        for i in range(self.tasksTableWidget.rowCount()):
            item = self.tasksTableWidget.item(i, 0)
            if not item.font().strikeOut():
                tasks.append(item.text())
        settings.setValue(tasksKey, tasks)

    def startTimer(self):
        try:
            if not self.timer.isActive():
                self.createTimer()
        except:
            self.createTimer()

    def createTimer(self):
        self.timer = QTimer()
        self.timer.timeout.connect(self.updateTime)
        self.timer.timeout.connect(self.maybeChangeMode)
        self.timer.setInterval(1000)
        self.timer.setSingleShot(False)
        self.timer.start()

    def pauseTimer(self):
        try:
            self.timer.stop()
            self.timer.disconnect()
        except:
            pass

    def resetTimer(self):
        try:
            self.pauseTimer()
            self.time = QTime(0, 0, 0, 0)
            self.displayTime()
        except:
            pass

    def maybeStartTimer(self):
        if self.currentRepetitions != self.maxRepetitions:
            self.startTimer()
            started = True
        else:
            self.currentRepetitions = 0
            started = False
        return started

    def updateWorkEndTime(self):
        self.workEndTime = QTime(
            self.workHoursSpinBox.value(),
            self.workMinutesSpinBox.value(),
            self.workSecondsSpinBox.value(),
        )

    def updateRestEndTime(self):
        self.restEndTime = QTime(
            self.restHoursSpinBox.value(),
            self.restMinutesSpinBox.value(),
            self.restSecondsSpinBox.value(),
        )

    def updateCurrentMode(self, mode: str):
        self.currentMode = Mode.work if mode == "work" else Mode.rest

    def updateTime(self):
        self.time = self.time.addSecs(1)
        self.totalTime = self.totalTime.addSecs(1)
        if self.modeComboBox.currentText() == "work":
            self.workTime = self.workTime.addSecs(1)
        else:
            self.restTime = self.restTime.addSecs(1)
        self.displayTime()

    def updateMaxRepetitions(self, value):
        if value == 0:
            self.currentRepetitions = 0
            self.maxRepetitions = -1
        else:
            self.maxRepetitions = 2 * value

    def maybeChangeMode(self):
        if self.currentMode is Mode.work and self.time >= self.workEndTime:
            self.resetTimer()
            self.modeComboBox.setCurrentIndex(1)
            self.incrementCurrentRepetitions()
            started = self.maybeStartTimer()
            self.showWindowMessage(
                Status.workFinished if started else Status.repetitionsReached)
        elif self.currentMode is Mode.rest and self.time >= self.restEndTime:
            self.resetTimer()
            self.modeComboBox.setCurrentIndex(0)
            self.incrementCurrentRepetitions()
            started = self.maybeStartTimer()
            self.showWindowMessage(
                Status.restFinished if started else Status.repetitionsReached)

    def incrementCurrentRepetitions(self):
        if self.maxRepetitions > 0:
            self.currentRepetitions += 1

    def insertTask(self):
        task = self.taskTextEdit.toPlainText()
        self.insertTasks(task)

    def insertTasks(self, *tasks):
        for task in tasks:
            if task:
                rowCount = self.tasksTableWidget.rowCount()
                self.tasksTableWidget.setRowCount(rowCount + 1)
                self.tasksTableWidget.setItem(rowCount, 0,
                                              QTableWidgetItem(task))
                self.tasksTableWidget.resizeRowsToContents()
                self.taskTextEdit.clear()

    def deleteTask(self):
        selectedIndexes = self.tasksTableWidget.selectedIndexes()
        if selectedIndexes:
            self.tasksTableWidget.removeRow(selectedIndexes[0].row())

    def markTaskAsFinished(self, row, col):
        item = self.tasksTableWidget.item(row, col)
        font = self.tasksTableWidget.item(row, col).font()
        font.setStrikeOut(False if item.font().strikeOut() else True)
        item.setFont(font)

    def displayTime(self):
        self.timeDisplay.display(self.time.toString(self.timeFormat))
        self.statisticsRestTimeDisplay.display(
            self.restTime.toString(self.timeFormat))
        self.statisticsWorkTimeDisplay.display(
            self.workTime.toString(self.timeFormat))
        self.statisticsTotalTimeDisplay.display(
            self.totalTime.toString(self.timeFormat))

    def showWindowMessage(self, status):
        if status is Status.workFinished:
            self.trayIcon.showMessage("Break", choice(work_finished_phrases),
                                      makeIcon("tomato"))
        elif status is Status.restFinished:
            self.trayIcon.showMessage("Work", choice(rest_finished_phrases),
                                      makeIcon("tomato"))
        else:
            self.trayIcon.showMessage("Finished",
                                      choice(pomodoro_finished_phrases),
                                      makeIcon("tomato"))
            self.resetButton.click()

    def makeButton(self, text, iconName=None, disabled=True):
        button = QPushButton(text, sizePolicy=self.size_policy)
        if iconName:
            button.setIcon(makeIcon(iconName))
        button.setDisabled(disabled)
        return button

    def exit(self):
        self.close()
        app = QApplication.instance()
        if app:
            app.quit()

    def onActivate(self, reason):
        if reason == QSystemTrayIcon.Trigger:
            self.show()
Ejemplo n.º 3
0
class ExTags(QDialog):
    """A dialog that shows you the tags in a file

    In addition, any attached cover art is shown."""
    rowChanged = pyqtSignal(object, name='rowChanged')
    extendedtags = pyqtSignal(dict, name='extendedtags')

    def __init__(self, parent=None, row=None, files=None, preview_mode=False,
                 artwork=True, status=None):

        if status is None:
            status = {'cover_pattern': 'folder'}

        self.status = status

        QDialog.__init__(self, parent)
        winsettings('extendedtags', self)
        self.get_fieldlist = []
        self.previewMode = preview_mode

        add = QColor.fromRgb(255, 255, 0)
        edit = QColor.fromRgb(0, 255, 0)
        remove = QColor.fromRgb(255, 0, 0)
        self._colors = {ADD: QBrush(add),
                        EDIT: QBrush(edit), REMOVE: QBrush(remove)}

        self.table = QTableWidget(0, 2, self)
        self.table.setVerticalHeader(VerticalHeader())
        self.table.verticalHeader().setVisible(False)
        self.table.setSortingEnabled(True)
        self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.table.setHorizontalHeaderLabels([
            translate('Extended Tags', 'Field'),
            translate('Extended Tags', 'Value')])

        header = self.table.horizontalHeader()
        header.setVisible(True)
        header.setSortIndicatorShown(True)
        header.setStretchLastSection(True)
        header.setSortIndicator(0, Qt.AscendingOrder)

        self.piclabel = PicWidget(buttons=True)
        self.piclabel.imageChanged.connect(
            self._imageChanged)

        if not isinstance(self.piclabel.removepic, QAction):
            self.piclabel.removepic.clicked.connect(
                self.removePic)
        else:
            self.piclabel.removepic.triggered.connect(self.removePic)

        if row and row >= 0 and files:
            buttons = MoveButtons(files, row)
            buttons.indexChanged.connect(self._prevnext)
            buttons.setVisible(True)
        else:
            buttons = MoveButtons([], row)
            buttons.setVisible(False)

        self._files = files

        self.okcancel = OKCancel()
        self.okcancel.insertWidget(0, buttons)

        self._reset = QToolButton()
        self._reset.setToolTip(translate('Extended Tags',
                                         'Resets the selected fields to their original value.'))
        self._reset.setIcon(get_icon('edit-undo', ':/undo.png'))
        self._reset.clicked.connect(self.resetFields)

        self.listbuttons = ListButtons()
        self.listbuttons.layout().addWidget(self._reset)
        self.listbuttons.moveupButton.hide()
        self.listbuttons.movedownButton.hide()

        listframe = QFrame()
        listframe.setFrameStyle(QFrame.Box)
        hbox = QHBoxLayout()
        hbox.addWidget(self.table, 1)
        hbox.addLayout(self.listbuttons, 0)
        listframe.setLayout(hbox)

        layout = QVBoxLayout()
        if artwork:
            imageframe = QFrame()
            imageframe.setFrameStyle(QFrame.Box)
            vbox = QVBoxLayout()
            vbox.setContentsMargins(0, 0, 0, 0)
            vbox.addWidget(self.piclabel)
            vbox.addStretch()
            vbox.addStrut(0)
            imageframe.setLayout(vbox)

            hbox = QHBoxLayout()
            hbox.addWidget(listframe, 1)
            hbox.addSpacing(4)
            hbox.addWidget(imageframe)
            hbox.addStrut(1)
            layout.addLayout(hbox)
        else:
            layout.addWidget(listframe)

        layout.addLayout(self.okcancel)
        self.setLayout(layout)

        self.okcancel.cancel.connect(self.closeMe)
        self.table.itemDoubleClicked.connect(self.editField)
        self.table.itemSelectionChanged.connect(self._checkListBox)
        self.okcancel.ok.connect(self.okClicked)

        self.listbuttons.edit.connect(self.editField)
        self.listbuttons.addButton.clicked.connect(self.addField)
        self.listbuttons.removeButton.clicked.connect(self.removeField)
        self.listbuttons.duplicate.connect(self.duplicate)

        self.setMinimumSize(450, 350)

        self.canceled = False
        self.filechanged = False

        if row and row >= 0 and files:
            self._prevnext(row)
        else:
            self.loadFiles(files)

    def addField(self):
        win = EditField(parent=self, field_list=self.get_fieldlist)
        win.setModal(True)
        win.show()
        win.donewithmyshit.connect(self.editFieldBuddy)

    def _checkListBox(self):
        if self.table.rowCount() <= 0:
            self.table.setEnabled(False)
            self.listbuttons.editButton.setEnabled(False)
            self.listbuttons.removeButton.setEnabled(False)
            self.listbuttons.duplicateButton.setEnabled(False)
            self._reset.setEnabled(False)
        else:
            self.table.setEnabled(True)
            self._reset.setEnabled(True)
            if len(self.table.selectedIndexes()) / 2 > 1:
                self.listbuttons.editButton.setEnabled(False)
                self.listbuttons.duplicateButton.setEnabled(False)
            else:
                self.listbuttons.editButton.setEnabled(True)
                self.listbuttons.removeButton.setEnabled(True)
                self.listbuttons.duplicateButton.setEnabled(True)
        self.table.resizeColumnToContents(0)

    def closeEvent(self, event):
        self.piclabel.close()
        QDialog.closeEvent(self, event)

    def closeMe(self):
        self.canceled = True
        self.close()

    def _deletePressed(self, item):
        if self.table.deletePressed:
            self.table.deletePressed = False
            self.removeField()

    def duplicate(self):
        self.editField(True)

    def editField(self, duplicate=False):
        """Opens a dialog to edit the currently selected Field.

        If duplicate is True the Edit Field dialog will be populated
        with the currently selected field's values. The new field'll then
        be added to the field list."""
        row = self.table.currentRow()
        if row != -1:
            prevtag = self.get_field(row)
            if duplicate is True:
                win = EditField(prevtag, self, self.get_fieldlist, edit=False)
            else:
                win = EditField(prevtag, self, self.get_fieldlist)
            win.setModal(True)
            win.show()

            # Have to check for truth, because this method is
            # called by the doubleclicked signal.
            if duplicate is True:
                buddy = partial(self.editFieldBuddy, duplicate=True)
            else:
                buddy = self.editFieldBuddy
            win.donewithmyshit.connect(buddy)

    def editFieldBuddy(self, tag, value, prevtag=None, duplicate=False):
        rowcount = self.table.rowCount()
        if prevtag is not None:
            if duplicate:
                row = rowcount
                self._settag(rowcount, tag, value, ADD,
                             self.previewMode, True)
            else:
                if tag == prevtag[0]:
                    row = self.table.currentRow()
                    self._settag(row, tag, value, EDIT,
                                 self.previewMode, True)
                    if row + 1 < rowcount:
                        self.table.selectRow(row + 1)
                else:
                    cur_item = self.table.item(self.table.currentRow(), 0)
                    self.resetFields([cur_item])
                    self.table.setCurrentItem(cur_item,
                                              QItemSelectionModel.ClearAndSelect)
                    self.table.selectRow(self.table.row(cur_item))
                    self.removeField()
                    valitem = self._settag(rowcount, tag,
                                           value, ADD, self.previewMode, True)
                    cur_item.linked = [valitem]
        else:
            self._settag(rowcount, tag, value, ADD, self.previewMode, True)
        self._checkListBox()
        self.filechanged = True
        self.table.clearSelection()

    def get_field(self, row, status=None):
        getitem = self.table.item
        item = getitem(row, 0)
        tag = str(item.text())
        try:
            value = str(getitem(row, 1).text())
        except AttributeError:
            value = str(self.table.cellWidget(row, 1).currentText())
        if status:
            return (tag, value, item.status)
        else:
            return (tag, value)

    def _imageChanged(self):
        self.filechanged = True

    def loadSettings(self):
        cparser = PuddleConfig()
        self.get_fieldlist = gettaglist()
        get = lambda k, v: cparser.get('extendedtags', k, v, True)
        add = QColor.fromRgb(*get('add', [255, 255, 0]))
        edit = QColor.fromRgb(*get('edit', [0, 255, 0]))
        remove = QColor.fromRgb(*get('remove', [255, 0, 0]))

        self._colors = {ADD: QBrush(add),
                        EDIT: QBrush(edit), REMOVE: QBrush(remove)}

        item = self.table.item
        for row in range(self.table.rowCount()):
            field_item = self.get_item(row, 0)
            field_item.statusColors = self._colors
            field_item.status = field_item.status

            val_item = self.get_item(row, 1)
            val_item.statusColors = self._colors
            val_item.status = val_item.status

    def listtotag(self):
        get_field = self.get_field
        tags = {}
        lowered = {}
        listitems = [get_field(row, True) for row
                     in range(self.table.rowCount())]

        for field, val, status in listitems:
            if status != REMOVE:
                if val == KEEP:
                    continue
                l_field = field.lower()
                if l_field in lowered:
                    tags[lowered[l_field]].append(val)
                else:
                    lowered[l_field] = field
                    tags[field] = [z.strip() for z in val.split('\\') if z.strip()]
            else:
                if field.lower() not in lowered:
                    tags[field] = []
                    lowered[field.lower()] = field
        return tags

    def loadFiles(self, audios):
        if self.filechanged:
            self.save()
        self.filechanged = False
        self.table.clearContents()
        self.table.setRowCount(0)
        self.piclabel.lastfilename = audios[0].filepath
        self.piclabel.setEnabled(False)
        self.piclabel.setImages(None)

        if len(audios) == 1:
            audio = audios[0]
            self.setWindowTitle(audios[0].filepath)
            self._loadsingle(audio)
        else:
            self.setWindowTitle(
                translate('Extended Tags', 'Different files.'))

            from .tagmodel import status
            k = status['table'].model().taginfo[0]
            common, numvalues, imagetags = commontags(audios)
            images = common['__image']
            del (common['__image'])
            previews = set(audios[0].preview)
            italics = set(audios[0].equal_fields())
            self.piclabel.currentFile = audios[0]
            self.piclabel.filePattern = self.status['cover_pattern']

            for audio in audios[1:]:
                previews = previews.intersection(audio.preview)
                italics = italics.intersection(audio.equal_fields())

            row = 0

            for field, values in common.items():
                if field in italics:
                    preview = UNCHANGED
                # field in italics => field in previews.
                elif field in previews:
                    preview = BOLD
                else:
                    preview = UNCHANGED
                if numvalues[field] != len(audios):
                    self._settag(row, field, values, multi=True)
                    row += 1
                else:
                    if isinstance(values, str):
                        self._settag(row, field, values, None, preview)
                        row += 1
                    else:
                        for v in values:
                            self._settag(row, field, v, None, preview)
                            row += 1

            self.piclabel.setImageTags(imagetags)
            if images:
                self.piclabel.setEnabled(True)
                self.piclabel.setImages(images)
            else:
                self.piclabel.setImages(None)
                self.piclabel.setEnabled(True)
                if images == 0:
                    self.piclabel.context = 'Cover Varies'
                    self.piclabel.removepic.setEnabled(True)
        self._checkListBox()

    def _loadsingle(self, tags):
        items = []
        d = tags.usertags.copy()
        italics = tags.equal_fields()
        self.piclabel.currentFile = tags
        self.piclabel.filePattern = self.status['cover_pattern']

        for key, val in sorted(d.items()):
            if key in italics:
                preview = UNCHANGED
            elif key in tags.preview:
                preview = BOLD
            else:
                preview = UNCHANGED
            if isinstance(val, str):
                items.append([key, val, None, preview])
            else:
                [items.append([key, z, None, preview]) for z in val]

        [self._settag(i, *item) for i, item in enumerate(items)]

        self.piclabel.lastfilename = tags.filepath
        if not tags.library:
            self.piclabel.setImageTags(tags.IMAGETAGS)
            if tags.IMAGETAGS:
                if '__image' in tags.preview:
                    images = tags.preview['__image']
                else:
                    images = tags.images
                self.piclabel.setEnabled(True)
                if images:
                    self.piclabel.setImages(deepcopy(images))
                else:
                    self.piclabel.setImages(None)
        self._checkListBox()
        self.setWindowTitle(tags[PATH])

    def okClicked(self):
        self.save()
        self.close()

    def _prevnext(self, row):
        if self.filechanged:
            self.save()
        self.loadFiles([self._files[row]])
        self.rowChanged.emit(row)

    def get_item(self, row, column=None):
        if column is None:  # Assume QModelIndex passed
            column = row.column()
            row = row.row()
        item = self.table.item(row, column)
        if item is None:
            item = self.table.cellWidget(row, column)
        return item

    def removeField(self):
        tb = self.table
        tb.setSortingEnabled(False)
        to_remove = {}
        rows = []
        for index in self.table.selectedIndexes():
            row = index.row()
            item = self.get_item(index)
            if item.status == ADD:
                to_remove[row] = item
            rows.append(row)
            item.status = REMOVE
            item.status = REMOVE
        [tb.removeRow(tb.row(z)) for z in to_remove.values()]
        tb.setSortingEnabled(True)
        self.filechanged = True
        self._checkListBox()
        if rows:
            row = max(rows)
            self.table.clearSelection()
            if row + 1 < self.table.rowCount():
                self.table.selectRow(row + 1)

    def resetFields(self, items=None):
        box = self.table
        to_remove = {}  # Stores row: item values so that only one item
        # gets removed per row.

        max_row = -1
        for index in box.selectedIndexes():
            row = index.row()
            item = self.table.item(row, index.column())
            if item is None:
                item = self.table.cellWidget(row, index.column())
            for i in item.linked:
                try:
                    to_remove[box.row(i)] = i
                except RuntimeError:
                    pass
            item.reset()
            if row > max_row:
                max_row = row
            if item.status == REMOVE:
                to_remove[row] = item

        self.table.clearSelection()
        if max_row != -1 and max_row + 1 < self.table.rowCount():
            self.table.selectRow(max_row + 1)

        for item in to_remove.values():
            self.table.removeRow(self.table.row(item))
        self._checkListBox()

    def removePic(self):
        if self.piclabel.context == 'Cover Varies':
            self.piclabel.context = 'No Images'
            self.piclabel.removepic.setEnabled(False)
            if not isinstance(self.piclabel.removepic, QAction):
                self.piclabel.removepic.clicked.disconnect(
                    self.removePic)
            else:
                self.piclabel.removepic.triggered.disconnect(self.removePic)

            self.piclabel.setImages(None)

    def save(self):

        if not self.filechanged:
            table = self.table
            for row in range(table.rowCount()):
                combo = table.cellWidget(row, 1)
                if combo is not None and combo.currentIndex() != 0:
                    self.filechanged = True
                    break

        if not self.filechanged:
            return

        tags = self.listtotag()
        if self.piclabel.context != 'Cover Varies':
            if not self.piclabel.images:
                tags['__image'] = []
            else:
                tags["__image"] = self.piclabel.images
        newtags = [z for z in tags if z not in self.get_fieldlist]
        if newtags and newtags != ['__image']:
            settaglist(newtags + self.get_fieldlist)
        self.extendedtags.emit(tags)

    def _settag(self, row, field, value, status=None, preview=False,
                check=False, multi=False):

        tb = self.table
        tb.setSortingEnabled(False)
        if row >= tb.rowCount():
            tb.insertRow(row)
            field_item = StatusWidgetItem(field, status,
                                          self._colors, preview)
            tb.setItem(row, 0, field_item)
            if not multi and (len(value) == 1 or isinstance(value, str)):
                valitem = StatusWidgetItem(to_string(value), status, self._colors, preview)
                tb.setItem(row, 1, valitem)
            else:
                valitem = StatusWidgetCombo(value, status, self._colors, preview)
                tb.setCellWidget(row, 1, valitem)
        else:
            field_item = tb.item(row, 0)
            field_item.setText(field)
            field_item.status = status

            val_item = self.get_item(row, 1)
            val_item.setText(value)
            val_item.status = status

        if check:
            lowered_tag = field.lower()
            for row in range(tb.rowCount()):
                item = tb.item(row, 0)
                text = str(item.text())
                if text != field and text.lower() == lowered_tag:
                    item.setText(field)
                    if item.status not in [ADD, REMOVE]:
                        item.status = EDIT
                        try:
                            tb.item(row, 1).status = EDIT
                        except AttributeError:
                            tb.cellWidget(row, 1).status = EDIT

        tb.setSortingEnabled(True)
        return field_item
Ejemplo n.º 4
0
class tableWidget(QDialog):
    def __init__(self, parent=None):
        super(tableWidget, self).__init__(parent)

        self.setWindowTitle("QTableWidget en PyQt5 por: ANDRES NIÑO")
        self.setWindowIcon(QIcon("Qt.png"))
        self.setWindowFlags(Qt.WindowMinimizeButtonHint | Qt.WindowCloseButtonHint |
                            Qt.MSWindowsFixedSizeDialogHint)
        self.setFixedSize(740, 348)

        self.initUI()

    def initUI(self):

      # ================== WIDGET  QTableWidget ==================
      
        self.tabla = QTableWidget(self)

        # Deshabilitar edición
        self.tabla.setEditTriggers(QAbstractItemView.NoEditTriggers)

        # Deshabilitar el comportamiento de arrastrar y soltar
        self.tabla.setDragDropOverwriteMode(False)

        # Seleccionar toda la fila
        self.tabla.setSelectionBehavior(QAbstractItemView.SelectRows)

        # Seleccionar una fila a la vez
        self.tabla.setSelectionMode(QAbstractItemView.SingleSelection)

        # Especifica dónde deben aparecer los puntos suspensivos "..." cuando se muestran
        # textos que no encajan
        self.tabla.setTextElideMode(Qt.ElideRight)# Qt.ElideNone

        # Establecer el ajuste de palabras del texto 
        self.tabla.setWordWrap(False)

        # Deshabilitar clasificación
        self.tabla.setSortingEnabled(False)

        # Establecer el número de columnas
        self.tabla.setColumnCount(6)

        # Establecer el número de filas
        self.tabla.setRowCount(0)

        # Alineación del texto del encabezado
        self.tabla.horizontalHeader().setDefaultAlignment(Qt.AlignHCenter|Qt.AlignVCenter|
                                                          Qt.AlignCenter)

        # Deshabilitar resaltado del texto del encabezado al seleccionar una fila
        self.tabla.horizontalHeader().setHighlightSections(False)

        # Hacer que la última sección visible del encabezado ocupa todo el espacio disponible
        self.tabla.horizontalHeader().setStretchLastSection(True)

        # Ocultar encabezado vertical
        self.tabla.verticalHeader().setVisible(False)

        # Dibujar el fondo usando colores alternados
        self.tabla.setAlternatingRowColors(True)

        # Establecer altura de las filas
        self.tabla.verticalHeader().setDefaultSectionSize(20)
        
        # self.tabla.verticalHeader().setHighlightSections(True)

        nombreColumnas = ("Id","Nombre", "Apellido", "Sexo", "Fecha de nacimiento", "País")

        # Establecer las etiquetas de encabezado horizontal usando etiquetas
        self.tabla.setHorizontalHeaderLabels(nombreColumnas)
        
        # Menú contextual
        self.tabla.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tabla.customContextMenuRequested.connect(self.menuContextual)
        
        # Establecer ancho de las columnas
        for indice, ancho in enumerate((80, 120, 120, 110, 150), start=0):
            self.tabla.setColumnWidth(indice, ancho)

        self.tabla.resize(700, 240)
        self.tabla.move(20, 56)

      # =================== WIDGETS QPUSHBUTTON ==================

        botonMostrarDatos = QPushButton("Mostrar datos", self)
        botonMostrarDatos.setFixedWidth(140)
        botonMostrarDatos.move(20, 20)

        menu = QMenu()
        for indice, columna in enumerate(nombreColumnas, start=0):
            accion = QAction(columna, menu)
            accion.setCheckable(True)
            accion.setChecked(True)
            accion.setData(indice)

            menu.addAction(accion)

        botonMostrarOcultar = QPushButton("Motrar/ocultar columnas", self)
        botonMostrarOcultar.setFixedWidth(180)
        botonMostrarOcultar.setMenu(menu)
        botonMostrarOcultar.move(170, 20)

        botonEliminarFila = QPushButton("Eliminar fila", self)
        botonEliminarFila.setFixedWidth(100)
        botonEliminarFila.move(530, 20)

        botonLimpiar = QPushButton("Limpiar", self)
        botonLimpiar.setFixedWidth(80)
        botonLimpiar.move(640, 20)

        botonCerrar = QPushButton("Cerrar", self)
        botonCerrar.setFixedWidth(80)
        botonCerrar.move(640, 306)

      # ======================== EVENTOS =========================

        botonMostrarDatos.clicked.connect(self.datosTabla)
        botonEliminarFila.clicked.connect(self.eliminarFila)
        botonLimpiar.clicked.connect(self.limpiarTabla)
        botonCerrar.clicked.connect(self.close)

        self.tabla.itemDoubleClicked.connect(self.Suscribete)

        menu.triggered.connect(self.mostrarOcultar)

  # ======================= FUNCIONES ============================

    def Suscribete(self, celda):
        QMessageBox.warning(self, "Suscribirse", "Hola, l@ invito a que se suscriba al "
                            "canal.\nPor cierto hiciste doble clic sobre esta "
                            "celda: {}.   ".format(celda.text()), QMessageBox.Ok)

    def datosTabla(self):
        datos = [("1", "Andres", "Niño", "Masculino", "06/12/2019", "Colombia"),
                 ("2", "Donald", "Trump", "Masculino", "06/12/1950", "Estados Unidos"),
                 ("3", "María Fernanda", "Espinosa", "Femenino", "06/10/1980", "Ecuador"),
                 ("4", "Alberto", "Canosa", "Masculino", "04/05/1876", "España"),
                 ("5", "Virtud", "Pontes", "Femenino", "23/18/1965", "España"),
                 ("6", "Elon", "Musk", "Masculino", "06/12/1960", "Estados Unidos"),
                 ("7", "Richard", "Branson", "Masculino", "14/12/1956", "Reino Unido"),
                 ("8", "Gabriel", "Garcia Marquez", "Masculino", "19/11/1948", "Colombia"),
                 ("9", "Valentina", "Tereshkova", "Femenino", "06/03/1937", "Rusia"),
                 ("10", "Artur", "Fischer", "Masculino", "31/12/1919", "Alemania"),
                 ("11", "Grace", "Murray Hopper", "Femenino", "09/12/1906", "Estados Unidos"),
                 ("12", "Guido van", "Rossum", "Masculino", "31/01/1956", "Países Bajos")]

        self.tabla.clearContents()

        row = 0
        for endian in datos:
            self.tabla.setRowCount(row + 1)
            
            idDato = QTableWidgetItem(endian[0])
            idDato.setTextAlignment(4)
            
            self.tabla.setItem(row, 0, idDato)
            self.tabla.setItem(row, 1, QTableWidgetItem(endian[1]))
            self.tabla.setItem(row, 2, QTableWidgetItem(endian[2]))
            self.tabla.setItem(row, 3, QTableWidgetItem(endian[3]))
            self.tabla.setItem(row, 4, QTableWidgetItem(endian[4]))
            self.tabla.setItem(row, 5, QTableWidgetItem(endian[5]))

            row += 1

    def mostrarOcultar(self, accion):
        columna = accion.data()
        
        if accion.isChecked():
            self.tabla.setColumnHidden(columna, False)
        else:
            self.tabla.setColumnHidden(columna, True)

    def eliminarFila(self):
        filaSeleccionada = self.tabla.selectedItems()

        if filaSeleccionada:
            fila = filaSeleccionada[0].row()
            self.tabla.removeRow(fila)

            self.tabla.clearSelection()
        else:
            QMessageBox.critical(self, "Eliminar fila", "Seleccione una fila.   ",
                                 QMessageBox.Ok)

    def limpiarTabla(self):
        self.tabla.clearContents()
        self.tabla.setRowCount(0)

    def menuContextual(self, posicion):
        indices = self.tabla.selectedIndexes()

        if indices:
            menu = QMenu()

            itemsGrupo = QActionGroup(self)
            itemsGrupo.setExclusive(True)
            
            menu.addAction(QAction("Copiar todo", itemsGrupo))

            columnas = [self.tabla.horizontalHeaderItem(columna).text()
                        for columna in range(self.tabla.columnCount())
                        if not self.tabla.isColumnHidden(columna)]

            copiarIndividual = menu.addMenu("Copiar individual") 
            for indice, item in enumerate(columnas, start=0):
                accion = QAction(item, itemsGrupo)
                accion.setData(indice)
                
                copiarIndividual.addAction(accion)

            itemsGrupo.triggered.connect(self.copiarTableWidgetItem)
            
            menu.exec_(self.tabla.viewport().mapToGlobal(posicion))

    def copiarTableWidgetItem(self, accion):
        filaSeleccionada = [dato.text() for dato in self.tabla.selectedItems()]
            
        if accion.text() == "Copiar todo":
            filaSeleccionada = tuple(filaSeleccionada)
        else:
            filaSeleccionada = filaSeleccionada[accion.data()]

        print(filaSeleccionada)

        return
Ejemplo n.º 5
0
class LabelDataTable(QWidget):
    labelSelectedSignal = pyqtSignal([object],
                                     name='Table selected label changed')

    def __init__(self):
        super(LabelDataTable, self).__init__()
        self.selectedRows = np.array([], dtype=int)
        self.realScale = None
        self.polygon = None

    def initUi(self):
        self.tableHeaders = [
            'Center X(px)', 'Center Y(px)', 'Area(mm^2)', 'Perimeter(mm)',
            'Area(px^2)', 'Perimeter(px)'
        ]
        self.tableData = np.array([])

        # add action
        self.toolbarHBox = QHBoxLayout()
        self.toolbar = QToolBar()

        # cancel section action
        self.showAllAction = QAction(QIcon('./images/icons/show.png'),
                                     'Show all regions')
        self.showAllAction.triggered.connect(self.showAllRegion)

        # save action
        self.saveAction = QAction(QIcon('./images/icons/CSV.png'),
                                  'Export table as csv')
        self.saveAction.triggered.connect(self.saveAsCsv)

        self.toolbar.addAction(self.showAllAction)
        self.toolbar.addAction(self.saveAction)
        self.toolbarHBox.addSpacerItem(
            QSpacerItem(20, 5, QSizePolicy.Expanding, QSizePolicy.Minimum))
        self.toolbarHBox.addWidget(self.toolbar)

        # add a status of total information, area, perimeter
        shearPerimeterHBox = QHBoxLayout()
        shearPerimeterLabel = QLabel('Shear Perimeter: ')
        shearPerimeterValue = QLineEdit()
        shearPerimeterValue.setText('0')
        shearPerimeterValue.setDisabled(True)
        shearPerimeterHBox.addWidget(shearPerimeterLabel)
        shearPerimeterHBox.addWidget(shearPerimeterValue)
        self.shearPerimeterValue = shearPerimeterValue

        shearAreaHBox = QHBoxLayout()
        shearAreaLabel = QLabel('Shear Area: ')
        shearAreaValue = QLineEdit()
        shearAreaValue.setText('0')
        shearAreaValue.setDisabled(True)
        # shearAreaHBox.addWidget(shearAreaLabel)
        # shearAreaHBox.addWidget(shearAreaValue)
        shearPerimeterHBox.addWidget(shearAreaLabel)
        shearPerimeterHBox.addWidget(shearAreaValue)
        self.shearAreaValue = shearAreaValue

        totalShearFailureRegionAreaHBox = QHBoxLayout()
        totalShearFailureRegionAreaLabel = QLabel(
            'Shear Failure Region Area (total):')
        totalShearFailureRegionAreaValue = QLineEdit()
        totalShearFailureRegionAreaValue.setText('0')
        totalShearFailureRegionAreaValue.setDisabled(True)
        totalShearFailureRegionAreaHBox.addWidget(
            totalShearFailureRegionAreaLabel)
        totalShearFailureRegionAreaHBox.addWidget(
            totalShearFailureRegionAreaValue)
        # totalShearFailureRegionAreaHBox.addSpacerItem(QSpacerItem(20, 5, QSizePolicy.Expanding, QSizePolicy.Minimum))
        self.totalShearFailureRegionAreaValue = totalShearFailureRegionAreaValue

        group = QGroupBox()
        group.setTitle('Summary')
        vBox = QVBoxLayout(group)
        vBox.addLayout(shearPerimeterHBox)
        vBox.addLayout(shearAreaHBox)
        vBox.addLayout(totalShearFailureRegionAreaHBox)
        group.setLayout(vBox)

        self.table = QTableWidget(
            0, 6
        )  # id,area(mm^2), perimeter(mm), area(px^2), perimeter(px),cx(px),cy(px)
        self.table.setHorizontalHeaderLabels(self.tableHeaders)
        self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
        # set triggers for select
        # selectionModel = self.table.selectionModel()
        self.table.selectionModel().selectionChanged.connect(
            self.itemClickedAction)

        self.setWindowTitle('Shear Failure Region Detection Result')
        self.setWindowIcon(QIcon('./images/icons/table-white.png'))
        self.table.verticalHeader().setVisible(True)

        self.mainLayout = QVBoxLayout()
        self.mainLayout.addWidget(group)
        self.mainLayout.addWidget(self.table)
        self.mainLayout.addLayout(self.toolbarHBox)
        self.setLayout(self.mainLayout)
        self.labelData = []
        self.resize(self.table.size().width(), self.size().height())

    def setData(self, labelMask, realScale, cropPolygon: QPolygonF):
        self.initUi()
        from Image import imageLabelProperty
        self.realScale = realScale
        self.labelData = imageLabelProperty(labelMask)
        self.tableData = np.zeros([len(self.labelData), 6])
        for i, row in enumerate(self.labelData):
            self.tableData[i, 0:6] = [
                row.centroid[0], row.centroid[1],
                row.area * realScale * realScale if realScale else 0,
                row.perimeter * realScale if realScale else 0, row.area,
                row.perimeter
            ]
        # shapely
        from shapely.geometry import Polygon
        data = []
        for point in cropPolygon:
            data.append([point.x(), point.y()])
        self.polygon = Polygon(data)
        if not realScale:
            self.shearPerimeterValue.setText('%.2f px' % (self.polygon.length))
            self.shearAreaValue.setText('%.2f px^2' % (self.polygon.area))
            self.totalShearFailureRegionAreaValue.setText(
                '%.2f px^2' % (np.sum(self.tableData[:, 4])))
        else:
            self.shearPerimeterValue.setText(
                '%.2f px / %.2f mm' %
                (self.polygon.length, self.polygon.length * self.realScale))
            self.shearAreaValue.setText('%.2f px^2 / %.2f mm^2' %
                                        (self.polygon.area, self.polygon.area *
                                         self.realScale * self.realScale))
            self.totalShearFailureRegionAreaValue.setText(
                '%.2f px^2 / %.2f mm^2' %
                (np.sum(self.tableData[:, 4]), np.sum(self.tableData[:, 2])))
        self.updateTable()

    def updateTable(self):
        self.table.setRowCount(len(self.labelData) + 1)
        for r in range(self.tableData.shape[0]):
            for c in range(self.tableData.shape[1]):
                item = QTableWidgetItem('%.2f' % self.tableData[r, c])
                item.setTextAlignment(Qt.AlignCenter | Qt.AlignVCenter)
                self.table.setItem(r, c, item)
        totalRow = len(self.tableData)
        item = QTableWidgetItem('Total')
        item.setTextAlignment(Qt.AlignCenter | Qt.AlignVCenter)
        item.setBackground(QColor(240, 240, 240))
        self.table.setItem(totalRow, 0, item)
        self.table.setSpan(totalRow, 0, 1, 2)
        for i in range(2, 6):
            item = QTableWidgetItem('%.2f' % np.sum(self.tableData[:, i]))
            item.setTextAlignment(Qt.AlignCenter | Qt.AlignVCenter)
            item.setBackground(QColor(240, 240, 240))
            self.table.setItem(totalRow, i, item)
        self.update()

    def showAllRegion(self):
        self.table.clearSelection()

    def saveAsCsv(self):
        import datetime
        filePath, fileType = QFileDialog.getSaveFileName(
            self, 'Save File', './ShearFailureRegion-%s.csv' %
            (datetime.datetime.now().strftime('%Y%m%d%H%M%S')), 'CSV(*.csv)')
        if not filePath:
            QMessageBox.warning(self, 'No Path Selected',
                                'No Path is selected.')
        else:
            with open(filePath, 'w') as stream:
                writer = csv.writer(stream, lineterminator='\n')
                writer.writerow(
                    ['Rock Joint Shear Failure Region Detail Information'])
                if not self.realScale:
                    writer.writerow([
                        'Shear Perimeter',
                        '%.2f px' % (self.polygon.length), 'Shear Area',
                        '%.2f px^2' % (self.polygon.area)
                    ])
                else:
                    writer.writerow([
                        'Shear Perimeter',
                        '%.2f px / %.2f mm' %
                        (self.polygon.length,
                         self.polygon.length * self.realScale), 'Shear Area',
                        '%.2f px^2 / %.2f mm^2' %
                        (self.polygon.area,
                         self.polygon.area * self.realScale * self.realScale),
                        'Real Scale', self.realScale
                    ])
                writer.writerow(self.tableHeaders)
                writer.writerows(list(self.tableData))
                writer.writerow([
                    'Total',
                    '',
                    self.table.item(self.table.rowCount() - 1, 2).text(),
                    self.table.item(self.table.rowCount() - 1, 3).text(),
                    self.table.item(self.table.rowCount() - 1, 4).text(),
                    self.table.item(self.table.rowCount() - 1, 5).text(),
                ])

    def itemClickedAction(self, selected, deselected):
        selectedRows = np.unique(
            np.array(list(map(lambda x: x.row() + 1, selected.indexes()))))
        deselectedRows = np.unique(
            np.array(list(map(lambda x: x.row() + 1, deselected.indexes()))))
        print("selected add: %s; deselected: %s" %
              (selectedRows, deselectedRows))
        self.selectedRows = np.unique(
            np.append(self.selectedRows, selectedRows)).astype(np.int)
        self.selectedRows = np.setdiff1d(self.selectedRows,
                                         deselectedRows).astype(np.int)
        selectedRows = self.selectedRows
        if not len(self.selectedRows):
            selectedRows = np.arange(1, self.table.rowCount())
        print("selected: %s" % selectedRows)
        self.labelSelectedSignal.emit(selectedRows)
Ejemplo n.º 6
0
class Window(QWidget):
    def __init__(self):
        super(Window, self).__init__()

        self.icon_path = 'resources\\warframe.ico'
        self.app_title = 'Warframe Prime Helper'
        self.company_name = 'Warframe Tools'

        self.settings = QSettings(self.company_name, self.app_title)
        self.setWindowTitle(self.app_title)

        self.market_api = None

        self.image_label = None
        self.image_label2 = None

        self.warframe_height = 1080
        self.warframe_width = 1920

        self.table = None
        self.mission_table = None

        self.slider_names = None
        self.sliders = None
        self.slider_labels = None
        self.slider_default_values = None
        self.slider_orig_values = None
        self.slider_values = None
        self.is_slider_max_set = False

        #self.plat_check_box = QCheckBox("Prefer platinum")
        #self.plat_check_box.setChecked(True)

        self.update_prices_button = None
        self.update_ducats_button = None
        self.update_prices_progress = None
        self.update_ducats_progress = None
        self.last_updated_prices_value = None
        self.last_updated_ducats_value = None
        self.num_parts_value = None
        self.latest_item_value = None

        self.move_to_top_check_box = None
        self.pause_button = None
        self.is_paused = False

        self.hide_crop_check_box = None
        self.hide_filter_check_box = None
        self.hide_fissure_check_box = None

        self.relics = None
        self.hide_relics = {}
        self.hidden_relics = set()

        self.hide_missions = {}
        self.hidden_missions = set()
        self.hide_missions_box = None
        self.mission_names = None

        self.crop_img = None
        self.filter_img = None

        self.dialog = None
        self.layout = None

        self.filled_rows = 0
        self.max = -1
        self.max_row = -1

        self.ocr = None
        self.old_screenshot_shape = 0
        self.old_filtered_shape = 0

        self.missions = []

        self.num_primes = 100
        self.api = None

        self.prices_progress_lock = Lock()
        self.ducats_progress_lock = Lock()

        self.ducats_thread = None
        self.prices_thread = None

        self.timer = None

        self.init_image_labels()
        self.init_tables()
        self.init_sliders()
        self.init_dialog()
        self.set_layout()
        self.init_timer()

        self.show()

        #measured correct values
        self.setFixedSize(978, 617)

    def init_timer(self):
        self.timer = QTimer()
        self.timer.timeout.connect(self.update_mission_table_time)
        self.timer.start(1000)

    def init_image_labels(self):
        self.image_label = QLabel()
        image = QPixmap('temp\\crop_27.bmp')
        self.image_label.setPixmap(image)

        self.image_label2 = QLabel()
        self.image_label2.setPixmap(image)

    def set_layout(self):
        settings_button_box = self.make_settings_button_box()
        self.init_imgs()
        bot_box = self.make_bot_box()

        self.layout = QVBoxLayout()
        self.layout.setAlignment(Qt.AlignTop)
        self.layout.addSpacing(-12)
        self.layout.addLayout(settings_button_box)
        self.layout.addWidget(self.crop_img)
        self.layout.addWidget(self.filter_img)
        self.layout.addWidget(bot_box)
        self.setLayout(self.layout)

    def make_settings_button_box(self):
        settings_button = QPushButton()
        # Gear icon is from: https://iconscout.com/icon/gear-222
        style_sheet = """
        QPushButton {
            qproperty-icon: url(" ");
            qproperty-iconSize: 15px 15px;
            border-image: url("resources/Gear.svg");
            background-color: rgba(255, 255, 255, 0);
        }
        
        QPushButton:hover {
            border-image: url("resources/SelectedGear.svg");
        }"""
        settings_button.setStyleSheet(style_sheet)
        #settings_button.setStyleSheet("background-color: rgba(0, 0, 0, 255); font-size: 23px;")
        settings_button.clicked.connect(self.show_preferences)
        settings_button.setFixedWidth(30)
        settings_button.setFixedHeight(30)

        settings_button_hb = QHBoxLayout()
        settings_button_hb.setAlignment(Qt.AlignRight)
        settings_button_hb.addWidget(settings_button)
        settings_button_hb.addSpacing(-11)
        return settings_button_hb

    def make_bot_box(self):
        bot_layout = QHBoxLayout()
        bot_layout.addWidget(self.table)
        bot_layout.addWidget(self.mission_table)

        bot_box = QGroupBox()
        bot_box.setLayout(bot_layout)
        bot_box.setFixedHeight(287)
        return bot_box

    def init_dialog(self):
        crop_box = self.make_crop_box()
        filter_box = self.make_filter_box()
        other_box = self.make_other_box()

        settings_layout_1 = QVBoxLayout()
        settings_layout_1.addWidget(crop_box)
        settings_layout_1.addWidget(filter_box)
        settings_layout_1.addWidget(other_box)

        update_box = self.make_update_box()
        rate_box = self.make_rate_box()

        settings_layout_2 = QVBoxLayout()
        settings_layout_2.addWidget(update_box)
        settings_layout_2.addWidget(rate_box)

        hide_box = self.make_hide_box()
        hide_relics_box = self.make_hide_relics_box()
        button_box = self.make_button_box()

        settings_layout_3 = QVBoxLayout()
        settings_layout_3.addWidget(hide_box)
        settings_layout_3.addWidget(hide_relics_box)

        hide_missions_box = self.make_hide_missions_box()
        settings_layout_4 = QVBoxLayout()
        settings_layout_4.addWidget(hide_missions_box)
        settings_layout_4.addWidget(button_box)

        settings_layout = QHBoxLayout()
        settings_layout.addLayout(settings_layout_1)
        settings_layout.addLayout(settings_layout_2)
        settings_layout.addLayout(settings_layout_3)
        settings_layout.addLayout(settings_layout_4)

        self.dialog = QDialog()
        self.dialog.setWindowTitle("Preferences")
        self.dialog.setWindowModality(Qt.ApplicationModal)
        self.dialog.setLayout(settings_layout)

    def make_button_box(self):
        button_box = QDialogButtonBox()
        button_box.setOrientation(Qt.Horizontal)
        button_box.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok)
        button_box.accepted.connect(self.save_settings)
        button_box.rejected.connect(self.load_settings)
        return button_box

    def load_settings(self):
        self.settings.sync()
        slider_orig_values = {'x': 521, 'y': 400, 'w': 908, 'h': 70, 'v1': 197, 'v2': 180, 'd': 4,
                              'Screencap (hz)': 1, 'Fissure (s)': 30, 'API Threads': 4}
        self.slider_default_values = {}
        slider_default_max = {'x': self.warframe_width/2,
                              'y': self.warframe_height/2,
                              'w': self.warframe_width,
                              'h': self.warframe_height,
                              'v1': 255,
                              'v2': 255,
                              'd': 40}

        for slider_name in self.slider_names:
            self.slider_default_values[slider_name] = self.settings.value(slider_name,defaultValue=slider_orig_values[slider_name])
            if len(slider_name) <= 2:
                max_val = self.settings.value("{}_max".format(slider_name), defaultValue=slider_default_max[slider_name], type=int)
                self.sliders[slider_name].setMaximum(max_val)
            self.sliders[slider_name].setValue(self.slider_default_values[slider_name])

        prices = self.settings.value("last_updated_prices_value", defaultValue="Never", type=str)
        ducats = self.settings.value("last_updated_ducats_value", defaultValue="Never", type=str)
        num_parts = self.settings.value("num_parts_value", defaultValue=350, type=int)
        latest_item = self.settings.value("latest_item_value", defaultValue="", type=str)

        self.last_updated_prices_value.setText(prices)
        self.last_updated_ducats_value.setText(ducats)
        self.num_parts_value.setNum(num_parts)
        self.latest_item_value.setText(latest_item)

        for relic in self.relics:
            checked = self.settings.value("hide_{}".format(relic), defaultValue=False,type=bool)
            self.hide_relics[relic].setChecked(checked)
            if checked:
                self.set_hidden_relic(relic)

        for mission in self.mission_names:
            checked = self.settings.value("hide_{}".format(mission), defaultValue=False, type=bool)
            self.hide_missions[mission].setChecked(checked)
            if checked:
                self.set_hidden_mission(mission)

        if self.settings.value("toggle_fissure_table", defaultValue=False, type=bool):
            self.hide_fissure_check_box.setChecked(True)
            self.toggle_fissure_table()

        if self.settings.value("toggle_move_to_top", defaultValue=False, type=bool):
            self.move_to_top_check_box.setChecked(True)
            self.toggle_move_to_top()

        if self.settings.value("toggle_cropped_img", defaultValue=False, type=bool):
            self.hide_crop_check_box.setChecked(True)
            self.toggle_cropped_img()

        if self.settings.value("toggle_filtered_img", defaultValue=False, type=bool):
            self.hide_filter_check_box.setChecked(True)
            self.toggle_filtered_img()
        self.dialog.close()

    def save_settings(self):
        for slider_name in self.slider_names:
            self.settings.setValue(slider_name, self.sliders[slider_name].value())

        for relic in self.relics:
            self.settings.setValue("hide_{}".format(relic), self.hide_relics[relic].isChecked())

        for mission in self.mission_names:
            self.settings.setValue("hide_{}".format(mission), self.hide_missions[mission].isChecked())

        self.settings.setValue("toggle_fissure_table", self.hide_fissure_check_box.isChecked())
        self.settings.setValue("toggle_move_to_top", self.move_to_top_check_box.isChecked())
        self.settings.setValue("toggle_cropped_img", self.hide_crop_check_box.isChecked())
        self.settings.setValue("toggle_filtered_img", self.hide_filter_check_box.isChecked())
        self.dialog.close()
        self.settings.sync()

    def init_imgs(self):
        self.crop_img = QGroupBox("Crop")
        crop_img_layout = QVBoxLayout()
        crop_img_layout.addWidget(self.image_label)
        self.crop_img.setLayout(crop_img_layout)

        self.filter_img = QGroupBox("Filtered")
        filter_img_layout = QVBoxLayout()
        filter_img_layout.addWidget(self.image_label2)
        self.filter_img.setLayout(filter_img_layout)

    def make_hide_missions_box(self, missions=None):
        if self.hide_missions_box is None:
            self.hide_missions_box = QGroupBox("Hide Missions")
        if missions is not None:
            hide_missions_layout = QGridLayout()
            hide_missions_layout.setColumnStretch(2, 2)
            hide_missions_layout.setAlignment(Qt.AlignTop)
            hide_missions_layout.setContentsMargins(0, 0, 0, 0)

            skip_missions = ["MT_SECTOR", "MT_PVP", "MT_LANDSCAPE", "MT_EVACUATION", "MT_ASSASSINATION", "MT_ARENA"]
            seen_missions = set()
            i = 0
            for mission in missions:
                mission_name = missions[mission]['value']
                if mission_name == "Extermination":
                    mission_name = "Exterminate"
                if mission not in skip_missions and mission_name not in seen_missions:
                    self.hide_missions[mission_name] = QCheckBox(mission_name)
                    self.hide_missions[mission_name].setChecked(False)
                    self.hide_missions[mission_name].stateChanged.connect(partial(self.set_hidden_mission, mission_name))
                    hide_missions_layout.addWidget(self.hide_missions[mission_name], int(i/2), i % 2)
                    i += 1
                    seen_missions.add(mission_name)
            self.hide_missions_box.setLayout(hide_missions_layout)
            self.mission_names = list(seen_missions)

            self.load_settings()
        return self.hide_missions_box

    def set_hidden_mission(self, mission):
        if self.hide_missions[mission].isChecked():
            self.hidden_missions.add(mission)
        else:
            self.hidden_missions.remove(mission)
        self.update_mission_table_hidden()

    def make_hide_relics_box(self):
        hide_relics_layout = QVBoxLayout()
        hide_relics_layout.setAlignment(Qt.AlignTop)
        hide_relics_layout.setContentsMargins(0, 0, 0, 0)
        self.relics = ["Axi", "Neo", "Meso", "Lith", "Requiem"]

        for relic in self.relics:
            self.hide_relics[relic] = QCheckBox(relic)
            self.hide_relics[relic].setChecked(False)
            self.hide_relics[relic].stateChanged.connect(partial(self.set_hidden_relic, relic))
            hide_relics_layout.addWidget(self.hide_relics[relic])

        hide_relics_box = QGroupBox("Hide Relics")
        hide_relics_box.setLayout(hide_relics_layout)
        return hide_relics_box

    def make_hide_box(self):
        hide_layout = QVBoxLayout()
        hide_layout.setAlignment(Qt.AlignTop)
        hide_layout.setContentsMargins(0, 0, 0, 0)

        self.hide_crop_check_box = QCheckBox("Hide Crop")
        self.hide_crop_check_box.setChecked(False)
        self.hide_crop_check_box.stateChanged.connect(self.toggle_cropped_img)
        hide_layout.addWidget(self.hide_crop_check_box)

        self.hide_filter_check_box = QCheckBox("Hide Filtered")
        self.hide_filter_check_box.setChecked(False)
        self.hide_filter_check_box.stateChanged.connect(self.toggle_filtered_img)
        hide_layout.addWidget(self.hide_filter_check_box)

        self.hide_fissure_check_box = QCheckBox("Hide Fissure Table")
        self.hide_fissure_check_box.setChecked(False)
        self.hide_fissure_check_box.stateChanged.connect(self.toggle_fissure_table)
        hide_layout.addWidget(self.hide_fissure_check_box)

        hide_box = QGroupBox("Hide UI")
        hide_box.setLayout(hide_layout)
        return hide_box

    def make_rate_box(self):
        rate_grid = QGridLayout()
        rate_grid.setColumnStretch(3, 3)
        rate_grid.setContentsMargins(0, 0, 0, 0)
        for i in range(3):
            slider_name = self.slider_names[i + 7]
            rate_grid.addWidget(self.slider_labels[slider_name], i, 0)
            rate_grid.addWidget(self.slider_values[slider_name], i, 1)
            rate_grid.addWidget(self.sliders[slider_name], i, 2)

        rate_box = QGroupBox("Rates")
        rate_box.setLayout(rate_grid)
        return rate_box

    def make_other_box(self):
        self.move_to_top_check_box = QCheckBox("Bring to front")
        self.move_to_top_check_box.setChecked(True)
        self.move_to_top_check_box.stateChanged.connect(self.toggle_move_to_top)
        self.pause_button = QPushButton("Pause")
        self.pause_button.clicked.connect(self.toggle_button)
        self.is_paused = False
        other_layout = QVBoxLayout()
        other_layout.setAlignment(Qt.AlignTop)
        other_layout.setContentsMargins(0, 0, 0, 0)
        other_layout.addWidget(self.move_to_top_check_box)
        other_layout.addWidget(self.pause_button)

        other_box = QGroupBox("Other")
        other_box.setLayout(other_layout)
        return other_box

    def make_filter_box(self):
        filter_grid = QGridLayout()
        filter_grid.setColumnStretch(3, 3)
        filter_grid.setAlignment(Qt.AlignTop)
        filter_grid.setContentsMargins(0, 0, 0, 0)
        for i in range(3):
            slider_name = self.slider_names[i + 4]
            filter_grid.addWidget(self.slider_labels[slider_name], i, 0)
            filter_grid.addWidget(self.slider_values[slider_name], i, 1)
            filter_grid.addWidget(self.sliders[slider_name], i, 2)

        filter_box = QGroupBox("Filter Parameters")
        filter_box.setLayout(filter_grid)
        return filter_box

    def make_crop_box(self):
        crop_grid = QGridLayout()
        crop_grid.setColumnStretch(3, 4)
        crop_grid.setAlignment(Qt.AlignTop)
        crop_grid.setContentsMargins(0, 0, 0, 0)
        for i in range(4):
            slider_name = self.slider_names[i]
            crop_grid.addWidget(self.slider_labels[slider_name], i, 0)
            crop_grid.addWidget(self.slider_values[slider_name], i, 1)
            crop_grid.addWidget(self.sliders[slider_name], i, 2)

        crop_box = QGroupBox("Crop Parameters")
        crop_box.setLayout(crop_grid)
        return crop_box

    def make_update_box(self):
        update_layout = QGridLayout()
        update_layout.setColumnStretch(4, 2)
        update_layout.setAlignment(Qt.AlignTop)
        update_layout.setContentsMargins(0, 0, 0, 0)
        self.update_prices_button = QPushButton("Update Prices")
        self.update_prices_button.clicked.connect(self.update_prices)
        self.update_prices_progress = QProgressBar()
        self.update_prices_progress.setFixedWidth(110)
        self.update_prices_progress.setRange(0, 100)
        update_layout.addWidget(self.update_prices_button, 0, 0)
        update_layout.addWidget(self.update_prices_progress, 0, 1)

        self.update_ducats_button = QPushButton("Update Ducats")
        self.update_ducats_button.clicked.connect(self.update_ducats)
        self.update_ducats_progress = QProgressBar()
        self.update_ducats_progress.setFixedWidth(110)
        self.update_ducats_progress.setRange(0, 100)
        update_layout.addWidget(self.update_ducats_button, 1, 0)
        update_layout.addWidget(self.update_ducats_progress, 1, 1)

        last_updated_prices_label = QLabel("Prices Updated")

        prices = self.settings.value("last_updated_prices_value", defaultValue="Never", type=str)
        ducats = self.settings.value("last_updated_ducats_value", defaultValue="Never", type=str)
        num_parts = self.settings.value("num_parts_value", defaultValue=350, type=str)
        latest_item = self.settings.value("latest_item_value", defaultValue="", type=str)

        self.last_updated_prices_value = QLabel(prices)
        self.last_updated_ducats_value = QLabel(ducats)
        self.num_parts_value = QLabel(num_parts)
        self.latest_item_value = QLabel(latest_item)

        update_layout.addWidget(last_updated_prices_label, 2, 0)
        update_layout.addWidget(self.last_updated_prices_value, 2, 1)

        last_updated_ducats_label = QLabel("Ducats Updated")
        update_layout.addWidget(last_updated_ducats_label, 3, 0)
        update_layout.addWidget(self.last_updated_ducats_value, 3, 1)

        num_parts_label = QLabel("Prime Parts")
        update_layout.addWidget(num_parts_label, 4, 0)
        update_layout.addWidget(self.num_parts_value, 4, 1)

        latest_item_label = QLabel("Latest Prime")
        update_layout.addWidget(latest_item_label, 5, 0)
        update_layout.addWidget(self.latest_item_value, 5, 1)

        update_box = QGroupBox("Updates")
        update_box.setLayout(update_layout)
        return update_box

    def init_sliders(self):
        self.slider_names = ['x', 'y', 'w', 'h', 'v1', 'v2', 'd', 'Screencap (hz)', 'Fissure (s)', 'API Threads']
        self.sliders = {x: QSlider(Qt.Horizontal) for x in self.slider_names}
        self.slider_labels = {x: QLabel(x) for x in self.slider_names}
        self.slider_default_values = {}
        self.slider_orig_values = {'x': 521, 'y': 400, 'w': 908, 'h': 70, 'v1': 197, 'v2': 180, 'd': 4,
                                   'Screencap (hz)': 1, 'Fissure (s)': 30, 'API Threads': 4}
        for slider_name in self.slider_names:
            self.slider_default_values[slider_name] = self.settings.value(slider_name, defaultValue=self.slider_orig_values[slider_name])
        self.slider_values = {x: QLabel(str(self.slider_default_values[x])) for x in self.slider_names}
        self.slider_values['Screencap (hz)'].setNum(self.slider_default_values['Screencap (hz)']/4)
        self.slider_values['d'].setNum(self.slider_default_values['d'] / 4)

        self.slider_labels['d'].setText('\u0394')

        self.sliders['x'].setMaximum(int(self.warframe_width / 2))
        self.sliders['y'].setMaximum(int(self.warframe_height / 2))
        self.sliders['w'].setMaximum(self.warframe_width)
        self.sliders['h'].setMaximum(self.warframe_height)
        self.sliders['v1'].setMaximum(255)
        self.sliders['v2'].setMaximum(255)
        self.sliders['d'].setMaximum(40)
        self.sliders['Screencap (hz)'].setMaximum(20)
        self.sliders['Screencap (hz)'].setMinimum(1)
        self.sliders['Fissure (s)'].setMaximum(60)
        self.sliders['Fissure (s)'].setMinimum(10)
        self.sliders['API Threads'].setMaximum(10)
        self.sliders['API Threads'].setMinimum(2)
        for slider_name in self.slider_names:
            if len(slider_name) <= 2:
                self.sliders[slider_name].setMinimum(0)
            self.sliders[slider_name].setSingleStep(1)
            self.slider_values[slider_name].setFixedWidth(35)
            self.sliders[slider_name].setValue(self.slider_default_values[slider_name])

    def init_tables(self):
        self.table = QTableWidget(7, 3)
        self.table.setHorizontalHeaderLabels(['Prime Part', 'Plat', 'Ducats'])
        self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        header = self.table.horizontalHeader()
        header.setSectionResizeMode(0, QHeaderView.Stretch)
        header.setSectionResizeMode(1, QHeaderView.ResizeToContents)
        header.setSectionResizeMode(2, QHeaderView.ResizeToContents)

        self.mission_table = QTableWidget(30, 4)
        self.mission_table.setHorizontalHeaderLabels(['Relic', 'Mission', 'Type', 'Time Left'])
        self.mission_table.setEditTriggers(QAbstractItemView.NoEditTriggers)

        mission_header = self.mission_table.horizontalHeader()

        for i in range(4):
            mission_header.setSectionResizeMode(i, QHeaderView.Interactive)
        mission_header.resizeSection(0, 55)
        mission_header.resizeSection(1, 150)
        mission_header.resizeSection(2, 90)
        mission_header.resizeSection(3, 60)
        self.mission_table.setFixedWidth(405)

    def update_prices(self):
        self.prices_thread = threading.Thread(name="prices_thread", target=self.market_api.update_prices)
        self.prices_thread.start()

        self.update_prices_button.setEnabled(False)
        self.update_ducats_button.setEnabled(False)

    def update_ducats(self):
        self.ducats_thread = threading.Thread(name="ducats_thread", target=self.market_api.update_ducats)
        self.ducats_thread.start()

        self.update_prices_button.setEnabled(False)
        self.update_ducats_button.setEnabled(False)

    def update_primes_info(self, num, latest):
        self.num_parts_value.setNum(num)
        self.latest_item_value.setText(latest)
        self.update_prices_progress.setMaximum(num)
        self.update_ducats_progress.setMaximum(num)
        self.num_primes = num

    def get_datetime(self):
        return datetime.now().strftime("%b %d %Y %H:%M:%S")

    def update_ducats_time(self):
        self.last_updated_ducats_value.setText(self.get_datetime())
        self.ducats_progress_lock.acquire()
        self.update_ducats_progress.setValue(self.num_primes)
        self.ducats_progress_lock.release()

        self.settings.setValue("last_updated_ducats_value", self.last_updated_ducats_value.text())
        self.settings.setValue("num_parts_value", self.num_parts_value.text())
        self.settings.setValue("latest_item_value", self.latest_item_value.text())

    def update_prices_time(self):
        self.last_updated_prices_value.setText(self.get_datetime())
        self.prices_progress_lock.acquire()
        self.update_prices_progress.setValue(self.num_primes)
        self.prices_progress_lock.release()

        self.settings.setValue("last_updated_prices_value", self.last_updated_prices_value.text())
        self.settings.setValue("num_parts_value", self.num_parts_value.text())
        self.settings.setValue("latest_item_value", self.latest_item_value.text())

    def set_update_prices_progress(self, val):
        if self.prices_progress_lock.acquire():
            self.update_prices_progress.setValue(val)
            self.prices_progress_lock.release()

    def set_update_ducats_progress(self, val):
        if self.ducats_progress_lock.acquire():
            self.update_ducats_progress.setValue(val)
            self.ducats_progress_lock.release()

    def finished_update_progress(self):
        self.update_prices_button.setEnabled(True)
        self.update_ducats_button.setEnabled(True)

    def show_preferences(self):
        self.dialog.exec_()
        self.load_settings()

    def toggle_fissure_table(self):
        if self.hide_fissure_check_box.isChecked():
            self.mission_table.hide()
        else:
            self.mission_table.show()
        self.setFixedSize(self.layout.sizeHint())

    def toggle_move_to_top(self):
        self.ocr.set_move_to_top(self.move_to_top_check_box.isChecked())

    def toggle_cropped_img(self):
        if self.hide_crop_check_box.isChecked():
            self.crop_img.hide()
        else:
            self.crop_img.show()
        self.setFixedSize(self.layout.sizeHint())

    def toggle_filtered_img(self):
        if self.hide_filter_check_box.isChecked():
            self.filter_img.hide()
        else:
            self.filter_img.show()
        self.setFixedSize(self.layout.sizeHint())
        #print("{}h,{}w".format(self.frameGeometry().height(),self.frameGeometry().width()))

    def set_sliders_range(self, x, y):
        max_values = {'x': int(x/2), 'y': int(y/2), 'w':x, 'h':y}
        for slider_name in max_values:
            self.sliders[slider_name].setMaximum(max_values[slider_name])
            self.sliders[slider_name].setValue(self.slider_default_values[slider_name])
            self.settings.setValue("{}_max", max_values[slider_name])

    def toggle_button(self):
        self.is_paused = not self.is_paused
        if self.is_paused:
            self.pause_button.setText("Resume")
        else:
            self.pause_button.setText("Pause")
        if self.ocr is not None:
            if self.is_paused:
                self.ocr.save_screenshot()
                self.ocr.skip_screenshot = True
            else:
                self.ocr.skip_screenshot = False

    def clear_table(self):
        self.table.clearSelection()
        self.table.clearContents()
        self.filled_rows = 0
        #self.table.setRowCount(self.filled_rows)

    def is_plat_preferred(self):
        return self.plat_check_box.isChecked()

    def insert_table_row(self, row):
        for i in range(3):
            self.table.setItem(self.filled_rows, i, QTableWidgetItem(str(row[i])))

        self.filled_rows = self.filled_rows + 1
        #self.table.setRowCount(self.filled_rows)

    def update_mission_table(self, missions):
        self.missions = list(missions)
        cur_time = time.time()
        for i in range(len(missions)):
            for j in range(3):
                self.mission_table.setItem(i, j, QTableWidgetItem(str(self.missions[i][j])))

            self.mission_table.setItem(i, 3, QTableWidgetItem(self.get_duration_str(self.missions[i][3]-cur_time)))
            if self.missions[i][0] in self.hidden_relics:
                self.mission_table.setRowHidden(i, True)
            if self.missions[i][2] in self.hidden_missions:
                self.mission_table.setRowHidden(i, True)
            else:
                self.mission_table.setRowHidden(i, False)

        self.mission_table.setRowCount(len(self.missions)-1)

    def update_mission_table_time(self):
        cur_time = time.time()
        needs_update = False
        for i in range(len(self.missions)):
            self.mission_table.setItem(i, 3, QTableWidgetItem(self.get_duration_str(self.missions[i][3]-cur_time)))
            if self.missions[i][3]-cur_time < 0:
                needs_update = True
        if needs_update:
            self.api.filter_expired_missions()

    def update_mission_table_hidden(self):
        for i in range(len(self.missions)):
            if self.missions[i][0] in self.hidden_relics:
                self.mission_table.setRowHidden(i, True)
            elif self.missions[i][2] in self.hidden_missions:
                self.mission_table.setRowHidden(i, True)
            else:
                self.mission_table.setRowHidden(i, False)

    def get_duration_str(self, duration):
        m, s = divmod(int(duration), 60)
        h, m = divmod(m, 60)
        return '{:d}:{:02d}:{:02d}'.format(h, m, s)

    def set_ocr_connection(self, ocr):
        for slider_name in self.slider_names:
            self.sliders[slider_name].valueChanged.connect(partial(self.set_ocr_crop, ocr, slider_name))
        self.ocr = ocr
        self.market_api = MarketReader(ocr=self.ocr, gui=self)

    def set_api(self, wf_api):
        self.api = wf_api
        self.make_hide_missions_box(self.api.mission_types)

    def set_hidden_relic(self, relic):
        if self.hide_relics[relic].isChecked():
            self.hidden_relics.add(relic)
        else:
            self.hidden_relics.remove(relic)
        self.update_mission_table_hidden()

    def set_ocr_crop(self, ocr, dim, val):
        if dim == 'Screencap (hz)' or dim == 'd':
            val = val / 4
        self.slider_values[dim].setNum(val)
        if val < 0 or val > 100000 or val is None:
            return
        if dim == 'x':
            ocr.set_x_offset(val)
        if dim == 'y':
            ocr.set_y_offset(val)
        if dim == 'w':
            ocr.set_w(val)
        if dim == 'h':
            ocr.set_h(val)
        if dim == 'v1':
            ocr.set_v1(val)
        if dim == 'v2':
            ocr.set_v2(val)
        if dim == 'd':
            self.ocr.set_diff_threshold(val/4)
        if dim == 'Screencap (hz)':
            ocr.set_interval(1/val)
        if dim == 'Fissure (s)':
            self.api.set_rate(val)
        if dim == 'API Threads':
            self.market_api.set_num_threads(val)

    #def select_max(self):
    #    # TODO doesnt work
    #    self.table.clearSelection()
    #    self.table.selectRow(self.max_row)

    def update_filtered(self, filtered):
        filtered_shape = None
        if not self.hide_filter_check_box.isChecked():
            filtered_shape = filtered.shape
            h, w = filtered.shape
            bytes_per_line = w
            filtered_pix = QPixmap(QImage(filtered, w, h, bytes_per_line, QImage.Format_Grayscale8))
            filtered_pix = filtered_pix.scaled(908, 70, Qt.KeepAspectRatio)
            self.image_label2.setPixmap(filtered_pix)
        #self.update_window_size(None, filtered_shape)

    def update_screenshot(self, screenshot):
        screenshot_shape = None
        if not self.hide_crop_check_box.isChecked():
            screenshot_shape = screenshot.shape
            h, w, ch = screenshot.shape
            bytes_per_line = ch * w
            screenshot_pix = QPixmap(QImage(screenshot, w, h, bytes_per_line, QImage.Format_RGB888))
            screenshot_pix = screenshot_pix.scaled(908, 70, Qt.KeepAspectRatio)
            self.image_label.setPixmap(screenshot_pix)
        #self.update_window_size(screenshot_shape, None)

    def update_window_size(self, screenshot_shape, filtered_shape):
        should_update = False
        if screenshot_shape is not None and screenshot_shape == self.old_screenshot_shape:
            self.old_screenshot_shape = screenshot_shape
            should_update = True
        if filtered_shape is not None and filtered_shape == self.old_filtered_shape:
            self.old_filtered_shape = filtered_shape
            should_update = True
        if should_update:
            self.setFixedSize(self.layout.sizeHint())

    def __exit__(self):
        self.market_api.exit_now = True
        self.ocr.exit_now = True
Ejemplo n.º 7
0
class FourBarOptimizer(QWidget):

    def __init__(self):
        super().__init__()

        # Upon startup, run a user interface routine
        self.init_ui()

    def init_ui(self):
        self.damping = 0.1
        self.iterations = 0
        self.maxIterations = 1
        self.mechanismStartAngle = 0.017

        #self.thetaTargets = [0,90,180,270]
        #self.xTargets = [1,4,6,3]
        #self.yTargets = [1,0,1,2]
        self.thetaTargets = [0,90,180,270]
        self.xTargets = [1,3,1,2]
        self.yTargets = [1,2,2,1]
        self.betas = [0,10,20]
        self.gammas = [5,15,25]
        self.targets = [self.thetaTargets,self.xTargets,self.yTargets]
        self.exact = [True,True,False,True]
        self.exactSelected = sum(self.exact)
        self.fixedPointCount = min(len(self.thetaTargets),len(self.xTargets),len(self.yTargets))
        # Mechanism encoding: [[lengths],[base1],[base2],]
        self.initialMechanismBases = [[0.06,0.04],[1.5,-0.02]]
        baselength = self.vLen(self.initialMechanismBases[0],self.initialMechanismBases[1])
        #self.initialMechanismLengths = [baselength,0.3,0.75,0.6,1,1.5]
        self.initialMechanismLengths = [baselength,0.25, 1.1,0.83,1.25,1.46]
        self.initialAlpha = 0.75

        # Four Bar Properties
        self.mechanismBases = self.initialMechanismBases
        self.mechanismLengths = self.initialMechanismLengths
        self.mechanismPoints = self.calculateFourBarPoint(self.initialAlpha)

        self.plotAngles = np.linspace(0.0,6.28318530718,num=20).tolist()
        self.plotAngles.append(self.plotAngles[0])
        self.pathX = [0]*len(self.plotAngles)
        self.pathY = [0]*len(self.plotAngles)

        #Builds GUI
        self.setGeometry(200,30,1000,700)

        self.load_button = QPushButton('Load Data',self)
        self.load_button.clicked.connect(self.load_data)

        self.runButton = QPushButton('Run Optimization',self)
        self.runButton.clicked.connect(self.runFourBarOptimization)

        self.dampingSlider = QSlider(Qt.Horizontal)
        self.dampingSlider.setMinimum(1)
        self.dampingSlider.setMaximum(1000)
        #self.dampingSlider.setTickInterval(10)
        #self.dampingSlider.setSingleStep(0.01)
        self.dampingSlider.setValue(self.damping*1000)
        self.dampingSlider.valueChanged.connect(self.dampingChanged)
        self.dampingLabel = QLabel("Damping = %1.2f"%(self.damping),self)

        # Results Labels
        self.iterationLabel = QLabel("Iterations Not Started",self)
        self.length1Label = QLabel("Length 1 Not Computed Yet",self)
        self.length2Label = QLabel("Length 2 Not Computed Yet",self)
        self.length3Label = QLabel("Length 3 Not Computed Yet",self)
        self.length4Label = QLabel("Length 4 Not Computed Yet",self)
        self.length5Label = QLabel("Length 5 Not Computed Yet",self)
        self.base1Label = QLabel("Base 1 Location Not Computed Yet",self)
        self.base2Label = QLabel("Base 2 Location Not Computed Yet",self)

        #Set up a Table to display data
        self.data_table = QTableWidget()
        self.data_table.itemSelectionChanged.connect(self.selectedTableItem)
        self.data_table.cellChanged.connect(self.cellChanged)
        self.data_table.setColumnCount(4)
        self.data_table.setRowCount(len(self.thetaTargets)+1)
        self.data_table.setHorizontalHeaderLabels(['Exact Match?','Crank Angle','X','Y'])



        self.main_widget = QWidget(self)
        self.graph_canvas = MyDynamicMplCanvas(self.main_widget, width=5, height=4, dpi=120)

        targets = [self.thetaTargets,self.xTargets,self.yTargets]
        self.calculateActualPath(self.plotAngles)
        path = [self.pathX,self.pathY]
        mechanismPoints = self.calculateFourBarPoint(self.initialAlpha)
        self.graph_canvas.plotFourBar(targets, mechanismPoints,path)

        #Define where the widgets go in the window
        #We start by defining some boxes that we can arrange

        #Create a GUI box to put all the table and data widgets in
        table_box = QGroupBox("Data Table")
        #Create a layout for that box using the vertical
        table_box_layout = QVBoxLayout()
        #Add the widgets into the layout
        table_box_layout.addWidget(self.load_button)
        table_box_layout.addWidget(self.data_table)

        #setup the layout to be displayed in the box
        table_box.setLayout(table_box_layout)

        # Results Label Box
        resultsBox = QGroupBox("Results")
        resultsBoxLayout = QVBoxLayout()
        resultsBoxLayout.addWidget(self.iterationLabel)
        resultsBoxLayout.addWidget(self.length1Label)
        resultsBoxLayout.addWidget(self.length2Label)
        resultsBoxLayout.addWidget(self.length3Label)
        resultsBoxLayout.addWidget(self.length4Label)
        resultsBoxLayout.addWidget(self.length5Label)
        resultsBoxLayout.addWidget(self.base1Label)
        resultsBoxLayout.addWidget(self.base2Label)
        resultsBox.setLayout(resultsBoxLayout)

        # Controls Box
        controlsBox = QGroupBox("Controls")
        controlsBoxLayout = QVBoxLayout()
        controlsBoxLayout.addWidget(self.runButton)
        controlsBoxLayout.addWidget(self.dampingLabel)
        controlsBoxLayout.addWidget(self.dampingSlider)
        controlsBox.setLayout(controlsBoxLayout)

        #Now we can set all the previously defined boxes into the main window
        grid_layout = QGridLayout()
        grid_layout.addWidget(table_box,0,0)
        grid_layout.addWidget(resultsBox,1,0)
        grid_layout.addWidget(controlsBox,1,1)
        grid_layout.addWidget(self.graph_canvas,0,1)
        #grid_layout.addWidget(distribution_box,1,1)

        self.redrawTable()
        self.setLayout(grid_layout)

        self.setWindowTitle('Four Bar Linkage Optimization')
        self.activateWindow()
        self.raise_()
        self.show()

    def synthesizeFourBar(self,betas,gammas):
        exactPoints = []
        for i in range(0,len(thetaTargets)):
            if exact[i] == True:
                exactPoints.append([thetaTargets[i],xTargets[i],yTargets[i]])
        delta2 = (exactPoints[1][1]-exactPoints[0][1]) + (exactPoints[1][2]-exactPoints[0][2])j
        delta3 = (exactPoints[2][1]-exactPoints[0][1]) + (exactPoints[2][2]-exactPoints[0][2])j

    def load_data(self):
        #Write this function
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        fileName, _ = QFileDialog.getOpenFileName(self,
            "QFileDialog.getOpenFileName()",
            "","All Files (*);;Python Files (*.py)",
            options=options)
        if fileName:
            f= open(fileName,"r")
            if f.mode == 'r':
                contents =f.read()
                # Do stuff with contents

    def save_data(self):
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        fileName, _ = QFileDialog.getSaveFileName(self,
            "QFileDialog.getSaveFileName()","",
            "All Files (*);;Text Files (*.txt)",
            options=options)
        # Check to make sure ends in .txt
        if fileName:
            f= open(fileName,"w+")
            f.write("%i" % (self.counter_value))
            f.close()

    def calculateActualPath(self,angleList):
        xActual = [0]*len(angleList)
        yActual = [0]*len(angleList)
        for i in range(0,len(angleList)):
            points = self.calculateFourBarPoint(angleList[i])
            xActual[i] = points[4][0]
            yActual[i] = points[4][1]
        self.pathX = xActual
        self.pathY = yActual

    def fourBarExpression(self):
        # variables = b1x,b1y,b2x,b2y,l0,l1,l2,l3,l4,l5,alpha
        b1x,b1y,b2x,b2y,l0,l1,l2,l3,l4,l5,alpha, a0 = symbols('b1x,b1y,b2x,b2y,l0,l1,l2,l3,l4,l5,alpha,a0')
        baseAngle = atan((b2y-b1y)/(b2x-b1x))

        x3 = l0*cos(baseAngle) - l1*cos(alpha + a0)
        y3 = l0*sin(baseAngle) - l1*sin(alpha + a0)
        theta3ArccosValue = (x3**2 + y3**2 + (-l3)**2 - l5**2)/2 * (-l3) * sqrt(x3**2 + y3**2)
        theta3 = atan2(y3,x3) + acos(theta3ArccosValue)
        theta5 = atan2((y3-(-l3)*sin(theta3))/l5, (x3-(-l3)*cos(theta3))/l5)

        dyadAngle1 = acos((l5**2 + l2**2 - l4**2)/(2*l5*l2))
        Cx = b1x+l1*cos(alpha + a0) + l2*cos(theta5 + dyadAngle1)
        Cy = b1y+l1*sin(alpha + a0) + l2*sin(theta5 + dyadAngle1)

        return (Cx,Cy)

    def calculateFourBarPoint(self,alphaInput):
        # lengths is in format [base, z1,z2,z3,z4,z5]
        # bases are in format [[base1X,base1Y],[base2X,base2Y]]
        # alpha is a single float for crank angle from horizontal

        bases = list(self.mechanismBases)
        length = list(self.mechanismLengths)
        alpha = alphaInput + self.mechanismStartAngle

        point1 = [0,0]
        point1[0] = bases[0][0] + length[1]*np.cos(alpha)
        point1[1] = bases[0][1] + length[1]*np.sin(alpha)

        baseRun = np.float64(bases[1][0] - bases[0][0])
        baseRise = np.float64(bases[1][1]-bases[0][1])
        #print(baseRun)
        #print(baseRise)
        baseAngle = 0
        if baseRise == 0:
            if baseRun > 0:
                baseAngle = 0
            elif baseRun < 0:
                baseAngle = pi()
        elif baseRun == 0:
            if baseRise > 0:
                baseAngle = pi()/2
            elif baseRise < 0:
                baseAngle = 3*pi()/2
        else:
            baseAngle = np.arctan(baseRise/baseRun)

        x3 = length[0]*cos(baseAngle) - length[1]*cos(alpha)
        y3 = length[0]*sin(baseAngle) - length[1]*sin(alpha)
        theta3ArccosValue = (x3**2 + y3**2 + (-length[3])**2 - length[5]**2)/2 * (-length[3]) * math.sqrt(x3*x3 + y3*y3)
        theta3ArccosValue = np.float64(theta3ArccosValue)
        theta3pos = math.atan2(y3,x3) + np.arccos(theta3ArccosValue)
        #print(theta3pos)
        theta3neg = math.atan2(y3,x3) - np.arccos(theta3ArccosValue)

        theta3 = theta3pos
        theta5 = math.atan2((y3-(-length[3])*np.sin(theta3))/length[5], (x3-(-length[3])*np.cos(theta3))/length[5])
        point2 = [0,0]
        point2[0] = bases[1][0] + length[3]*np.cos(theta3)
        point2[1] = bases[1][1] + length[3]*np.sin(theta3)

        dyadAngle1 = np.arccos(np.float64(length[5]**2 + length[2]**2 - length[4]**2)/np.float64(2*length[5]*length[2]))
        pointC = [0,0]
        pointC[0] = point1[0]+length[2]*np.cos(theta5 + dyadAngle1)
        pointC[1] = point1[1]+length[2]*np.sin(theta5 + dyadAngle1)

        self.mechanismPoints = [bases[0],bases[1],point1,point2,pointC]

        return self.mechanismPoints

    def runFourBarOptimization(self):
        # Calculate betas and gammas for target design - 3 points
        # Evaluate error from target path
        #
        print('Starting Optimization')
        (xExpression,yExpression) = self.fourBarExpression()
        objectiveFunction = 0

        for i in range(0,len(self.xTargets)):
            objectiveExpression = (self.xTargets[i] - xExpression)**2 + (self.yTargets[i] - yExpression)**2
            objectiveExpression = objectiveExpression.subs(symbols('alpha'),self.thetaTargets[i])
            objectiveFunction = objectiveFunction + objectiveExpression

        variables = ['l0','l1','l2','l3','l4','l5','a0','b1x','b1y','b2x','b2y']
        rpSymbol = symbols('rp')
        g1 = 'l5 - (l2 + l4) + 0.01'
        g2 = '(l1 + l0 + 0.01) - (l5 + l3)'
        g3 = '-l1'
        g4 = '-l2'
        g5 = '-l3'
        g6 = '-l4'
        g7 = '-l5'
        inequalityConstraints = [g1,g2,g3,g4,g5,g6,g7]
        equalityConstraints = []
        startingPoint = [self.mechanismLengths[0],
            self.mechanismLengths[1],
            self.mechanismLengths[2],
            self.mechanismLengths[3],
            self.mechanismLengths[4],
            self.mechanismLengths[5],
            self.mechanismStartAngle,
            self.mechanismBases[0][0],
            self.mechanismBases[0][1],
            self.mechanismBases[1][0],
            self.mechanismBases[1][1]]
        shouldContinue = True
        rp = 0.5
        testSteps = [0,0.01,0.02]
        expression = objectiveFunction
        epsilon = 0.001
        print('Set up initial constants and expressions')
        self.iterations = 0
        position = startingPoint
        objectiveValue = opt.evaluateLinearExtendedPenalty(expression,
            inequalityConstraints=inequalityConstraints,
            equalityConstraints=equalityConstraints,
            variables = variables,
            values = position,
            rp = rp,
            evaluate=True)

        print('Calculated initial objective function:')
        print(objectiveValue)
        while shouldContinue == True:
            # perform 1 iteration
            # check validity
            # plot
            ########################
            self.iterations = self.iterations + 1

            print('Calculating expression for this rp')
            expressionHere = opt.evaluateLinearExtendedPenalty(expression,
                inequalityConstraints=inequalityConstraints,
                equalityConstraints=equalityConstraints,
                variables = variables,
                values = position,
                rp = rp,
                evaluate=False)
            expressionHere = expressionHere.subs(rpSymbol,float(rp))
            print('Calculating gradients:')
            slopeList = opt.getNumGradient(expressionHere,variables,position,normalize=False)
            print(slopeList)
            #print(slopeList)
            # Get three points in that direction at intervals of 0.5,1,2
            #
            #Constant step toward goal
            """
            functionValues = [objectiveValue]
            for alphaValue in testSteps:
                if alphaValue != testSteps[0]:
                    testLocation = []
                    for oldPosition, slope in zip(position,slopeList):
                        testLocation.append(oldPosition-slope*alphaValue)
                    #print('Location to test:')
                    #print(testLocation)
                    functionValues.append(opt.evaluateLinearExtendedPenalty(expression,
                        inequalityConstraints=inequalityConstraints,
                        equalityConstraints=equalityConstraints,
                        variables = variables,
                        values = testLocation,
                        rp = rp))
            print('Calculated test positions')
            # Fit parabola to curve
            print(functionValues)
            C = approx.threePointQuadraticApprox(testSteps, functionValues)
            print(C)
            # Check parabola is concave up
            # Calculate alpha that gives minimum
            alphaStar = 0.0
            if C[2] < 0.00001:
                print("Fitted parabola is concave down. Minimum alpha value is not bounded.")
                alphaStar = 0.5
            else:
                (alphaStar,bestY) = opt.minimizeParabola(C)
            """
            alphaStar = 0.1
            print('Calculating New Position')
            # Move to position of calculated alpha
            newPosition = []
            for oldPosition, slope in zip(position,slopeList):
                newPosition.append(oldPosition-slope*self.damping*alphaStar)
            lastPosition = position
            position = newPosition
            objectiveValueLast = objectiveValue
            print('Finding New error')
            objectiveValue = opt.evaluateLinearExtendedPenalty(expression,
                inequalityConstraints=inequalityConstraints,
                equalityConstraints=equalityConstraints,
                variables = variables,
                values = position,
                rp = rp,
                evaluate=True)
            print('New error is:')
            print(objectiveValue)
            print('New Design is:')
            print(position)
            print('Updating Mechanism parameters')
            self.mechanismLengths = [position[0],position[1],position[2],position[3],position[4],position[5]]
            self.mechanismAngle0 = position[6]
            self.mechanismBases = [[position[7],position[8]],[position[9],position[10]]]

            print('Redrawing')
            # Redraw results labels
            self.redrawResultsLabels()
            # Redraw graph
            self.calculateActualPath(self.plotAngles)
            path = [self.pathX,self.pathY]
            mechanismPoints = self.calculateFourBarPoint(self.initialAlpha)
            targets = [self.thetaTargets,self.xTargets,self.yTargets]
            path = [self.pathX,self.pathY]

            self.graph_canvas.plotFourBar(targets, mechanismPoints,path)

            print('Checking Convergence')
            # Check convergence
            deltaObjective = abs(float(abs(objectiveValueLast) - abs(objectiveValue)))
            deltaVariables = [abs(new - old) for new, old in zip(position,lastPosition)]
            maxDelta = max(deltaVariables)
            if max(deltaObjective,maxDelta) < epsilon:
                shouldContinue = False
                print("Local Optimium found")

            if self.iterations > self.maxIterations:
                print("Function timed out. Returning final result")
                shouldContinue = False

            #######################

        path = [self.pathX,self.pathY]
        mechanismPoints = self.calculateFourBarPoint(self.initialAlpha)
        targets = [self.thetaTargets,self.xTargets,self.yTargets]
        self.graph_canvas.plotFourBar(targets, self.mechanismPoints,path)

    def vLen(self,point1,point2):
        # takes in two points in the format [x,y] and returns the float of vector length
        dx = point1[0] - point2[0]
        dy = point1[1] - point2[1]

        length = np.sqrt(dx*dx + dy*dy)
        return length

    def dampingChanged(self,value):
        self.damping = float(value)/1000
        self.dampingLabel.setText("Damping = %1.2f"%(self.damping))

    def cellChanged(self,row,column):
        if row == len(self.xTargets):
            if column == 1:
                cell = self.data_table.item(row, column)
                cellText = cell.text()
                cellValue = float(cellText)
                self.thetaTargets.append(cellValue)
                self.xTargets.append(0)
                self.yTargets.append(0)
                self.exact.append(False)
            elif column == 2:
                cell = self.data_table.item(row, column)
                cellText = cell.text()
                cellValue = float(cellText)
                self.xTargets.append(cellValue)
                self.thetaTargets.append(0)
                self.ytargets.append(0)
                self.exact.append(False)
            elif column == 3:
                cell = self.data_table.item(row, column)
                cellText = cell.text()
                cellValue = float(cellText)
                self.thetaTargets.append(0)
                self.xTargets.append(0)
                self.yTargets.append(cellValue)
                self.exact.append(False)
        else:
            if column == 1:
                cell = self.data_table.item(row, column)
                cellText = cell.text()
                cellValue = float(cellText)
                self.thetaTargets[row] = cellValue
            elif column == 2:
                cell = self.data_table.item(row, column)
                cellText = cell.text()
                cellValue = float(cellText)
                self.xTargets[row] = cellValue
            elif column == 3:
                cell = self.data_table.item(row, column)
                cellText = cell.text()
                cellValue = float(cellText)
                self.yTargets[row] = cellValue
        self.data_table.setRowCount(len(self.thetaTargets)+1)
        targets = [self.thetaTargets,self.xTargets,self.yTargets]
        path = [self.pathX,self.pathY]
        self.graph_canvas.plotFourBar(targets, self.mechanismPoints, path)

    def selectedTableItem(self):
        #print("\n")
        for currentQTableWidgetItem in self.data_table.selectedItems():
            #print(currentQTableWidgetItem.row(), currentQTableWidgetItem.column(), currentQTableWidgetItem.text())
            if currentQTableWidgetItem.column() == 0:
                cellValue = self.exact[currentQTableWidgetItem.row()]
                if cellValue == True:
                    self.exact[currentQTableWidgetItem.row()] = not self.exact[currentQTableWidgetItem.row()]
                elif cellValue == False:
                    if self.exactSelected < 3:
                        self.exact[currentQTableWidgetItem.row()] = not self.exact[currentQTableWidgetItem.row()]
            else:
                self.data_table.editItem(currentQTableWidgetItem)

            if self.exact[currentQTableWidgetItem.row()] == True:
                self.data_table.setItem(currentQTableWidgetItem.row(),0, QTableWidgetItem('\u2714'))
            else:
                self.data_table.setItem(currentQTableWidgetItem.row(),0, QTableWidgetItem(''))
        self.exactSelected = sum(self.exact)
        self.data_table.clearSelection()
        #self.redrawTable()

    def redrawTable(self):
       self.data_table.setRowCount(len(self.thetaTargets)+1)
       for i in range(0,len(self.thetaTargets)):
            if self.exact[i] == True:
                self.data_table.setItem(i,0, QTableWidgetItem('\u2714'))
            else:
                self.data_table.setItem(i,0, QTableWidgetItem(''))

            self.data_table.setItem(i,1, QTableWidgetItem('%2.4f'%(self.thetaTargets[i])))
            self.data_table.setItem(i,2, QTableWidgetItem('%2.4f'%(self.xTargets[i])))
            self.data_table.setItem(i,3, QTableWidgetItem('%2.4f'%(self.yTargets[i])))

    def redrawResultsLabels(self):
        self.iterationLabel.setText("Iteration %i"%(self.damping))
        self.length1Label.setText("Length 1 = %2.4f"%(self.mechanismLengths[1]))
        self.length2Label.setText("Length 2 = %2.4f"%(self.mechanismLengths[2]))
        self.length3Label.setText("Length 3 = %2.4f"%(self.mechanismLengths[3]))
        self.length4Label.setText("Length 4 = %2.4f"%(self.mechanismLengths[4]))
        self.length5Label.setText("Length 5 = %2.4f"%(self.mechanismLengths[5]))
        self.base1Label.setText("Base 1 Location  = (%2.4f, %2.4f)"%(self.mechanismBases[0][0],self.mechanismBases[0][1]))
        self.base2Label.setText("Base 2 Location  = (%2.4f, %2.4f)"%(self.mechanismBases[1][0],self.mechanismBases[1][1]))
Ejemplo n.º 8
0
class MeaGrid(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.layout = QtWidgets.QVBoxLayout(self)

        self.grid_table = QTableWidget(self)
        self.grid_table.setRowCount(16)
        self.grid_table.setColumnCount(16)
        self.grid_table.horizontalHeader().setVisible(False)
        self.grid_table.verticalHeader().setVisible(False)
        self.layout.addWidget(self.grid_table)

        self.labels = []
        self.label_indices_map = dict()
        for col, c in enumerate([
                'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M',
                'N', 'O', 'P', 'R'
        ]):
            for row, n in enumerate(range(1, 17)):
                if c == 'A' and n == 1 or c == 'A' and n == 16 or c == 'R' and n == 1 or c == 'R' and n == 16:
                    self.grid_table.setColumnWidth(col, 35)
                    self.grid_table.setItem(row, col, QTableWidgetItem(''))
                    self.grid_table.item(row,
                                         col).setFlags(QtCore.Qt.NoItemFlags)
                    # self.grid_table.item(row, col).connect(self.on_channel_selected)
                    continue

                number_str = str(n)
                self.labels.append(c + number_str)
                # if n < 10:
                #     number_str = "0" + number_str
                label = (c + number_str)

                self.grid_table.setColumnWidth(col, 35)
                self.grid_table.setItem(row, col, QTableWidgetItem(label))

                # creation of dictionary
                id = c + str(n)

                self.label_indices_map[id] = {}
                if col == 0:
                    self.label_indices_map[id]['grid index'] = row - 1
                elif col != 0 and col != 15:
                    self.label_indices_map[id]['grid index'] = row + (col *
                                                                      16) - 2
                else:
                    self.label_indices_map[id]['grid index'] = row + (col *
                                                                      16) - 3

        self.all_channel_indices = set(
            [v['grid index'] for v in list(self.label_indices_map.values())])
        print(self.all_channel_indices)
        self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.on_context_menu)

    def get_selected_channels(self):
        selected_channels = []
        selected_indices = []
        for item in self.grid_table.selectedItems():
            label = item.text()
            selected_channels.append(
                (label, self.label_indices_map[label]['grid index']))
            selected_indices.append(
                self.label_indices_map[label]['grid index'])
        selected_indices = set(selected_indices)
        dead_channels = self.all_channel_indices - selected_indices

        return selected_channels, dead_channels

    def select_all(self):
        self.grid_table.selectAll()

    def select_none(self):
        self.grid_table.clearSelection()

    def invert_selection(self):
        for row in range(self.grid_table.rowCount()):
            for column in range(self.grid_table.columnCount()):
                is_selected = self.grid_table.item(row, column).isSelected()
                self.grid_table.item(row, column).setSelected(not is_selected)

    def are_all_selected(self):
        channel_count = len(self.labels)
        return len(self.grid_table.selectedItems()) == channel_count

    def is_none_selected(self):
        return len(self.grid_table.selectedItems()) == 0

    @QtCore.pyqtSlot(QtCore.QPoint)
    def on_context_menu(self, point):
        menu = QtWidgets.QMenu(self)

        select_all_action = QtWidgets.QAction("Select All")
        select_all_action.triggered.connect(self.select_all)
        select_all_action.setEnabled(not self.are_all_selected())
        menu.addAction(select_all_action)

        select_none_action = QtWidgets.QAction("Select None")
        select_none_action.triggered.connect(self.select_none)
        select_none_action.setEnabled(not self.is_none_selected())
        menu.addAction(select_none_action)

        invert_selection_action = QtWidgets.QAction("Invert Selection")
        invert_selection_action.triggered.connect(self.invert_selection)
        menu.addAction(invert_selection_action)

        menu.exec(self.mapToGlobal(point))
Ejemplo n.º 9
0
class QShapingDebugger(QSplitter):
    def __init__(self, editor, project):
        self.editor = editor
        self.project = project
        super(QSplitter, self).__init__()
        self.text = self.project.debuggingText or self.getReasonableTextForFont(
            self.project.font)

        # First box: Text and features
        self.firstbox = QWidget()
        self.firstboxLayout = QVBoxLayout()
        self.firstbox.setLayout(self.firstboxLayout)

        textbox = QLineEdit()
        textbox.setText(self.text)
        textbox.setMaximumHeight(textbox.height())
        textbox.textChanged[str].connect(self.textChanged)

        self.featuregroup = QGroupBox("Features")
        self.featuregrouplayout = QFlowLayout()
        self.featuregroup.setLayout(self.featuregrouplayout)
        self.features = {}
        self.fillFeatureGroup()
        self.firstboxLayout.addWidget(textbox)
        self.firstboxLayout.addWidget(self.featuregroup)

        # Second box: Variations
        self.secondbox = QWidget()
        self.secondboxLayout = QHBoxLayout()
        self.secondbox.setLayout(self.secondboxLayout)
        self.sliders = []

        if self.project.variations:
            for axis in self.project.variations.designspace.axes:
                self.secondboxLayout.addWidget(QLabel(axis.name))
                slider = QSlider(0x01)
                slider.name = axis.name
                slider.setMinimum(axis.map_forward(axis.minimum))
                slider.setMaximum(axis.map_forward(axis.maximum))
                self.sliders.append(slider)

                slider.valueChanged.connect(self.shapeText)
                self.secondboxLayout.addWidget(slider)
        # Third box: Output and renderer
        self.thirdbox = QWidget()
        self.thirdboxLayout = QVBoxLayout()
        self.thirdbox.setLayout(self.thirdboxLayout)

        self.shaperOutput = QLabel()
        self.shaperOutput.setWordWrap(True)
        sp = self.shaperOutput.sizePolicy()
        sp.setVerticalPolicy(QSizePolicy.Maximum)
        self.shaperOutput.setSizePolicy(sp)

        self.qbr = QBufferRenderer(project,
                                   VariationAwareBuffer(self.project.font))
        sp = self.thirdbox.sizePolicy()
        sp.setHorizontalPolicy(QSizePolicy.Maximum)
        sp.setVerticalPolicy(QSizePolicy.MinimumExpanding)
        self.thirdbox.setSizePolicy(sp)

        self.thirdboxLayout.addWidget(self.shaperOutput)
        self.thirdboxLayout.addWidget(self.qbr)

        # Third box: message table
        self.messageTable = QTableWidget()
        self.messageTable.setColumnCount(2)
        self.messageTable.verticalHeader().setVisible(False)
        self.messageTable.setHorizontalHeaderLabels(["message", "buffer"])
        header = self.messageTable.horizontalHeader()
        headerWidth = self.messageTable.viewport().size().width()
        header.resizeSection(0, headerWidth * 2 / 3)
        header.setStretchLastSection(True)
        self.messageTable.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.messageTable.selectionModel().selectionChanged.connect(
            self.renderPartialTrace)

        self.setOrientation(Qt.Vertical)
        self.addWidget(self.firstbox)
        if self.project.variations:
            self.addWidget(self.secondbox)
        self.addWidget(self.thirdbox)
        self.addWidget(self.messageTable)
        self.fullBuffer = None
        self.lastBuffer = None
        self.shapeText()

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

    def fillFeatureGroup(self):
        prev = self.features
        fkeys = self.project.fontfeatures.features.keys()
        self.clearLayout(self.featuregrouplayout)
        self.features = {}
        for k in fkeys:
            box = self.features[k] = QCheckBox(k)
            box.setTristate()
            if k in prev:
                box.setCheckState(prev[k].checkState())
            else:
                box.setCheckState(Qt.PartiallyChecked)
            box.stateChanged.connect(self.shapeText)
            self.featuregrouplayout.addWidget(box)

    def update(self):
        self.fillFeatureGroup()
        self.shapeText()

    def buildBuffer(self):
        buf = VariationAwareBuffer(self.project.font)
        t = self.text
        i = 0
        while i < len(t):
            if t[i] == "/":  # Start of glyph name
                i = i + 1
                glyphname = ""
                while i < len(t) and t[i] in valid_glyph_name_chars:
                    glyphname += t[i]
                    i = i + 1
                if len(glyphname) and glyphname in self.project.font:
                    item = VariationAwareBufferItem.new_glyph(
                        glyphname, self.project.font, buf)
                    item.codepoint = self.project.font.codepointForGlyph(
                        glyphname)
                    buf.items.append(item)
                else:
                    buf.items.extend([
                        VariationAwareBufferItem.new_unicode(ord(x), buf)
                        for x in "/" + glyphname
                    ])
            else:
                item = VariationAwareBufferItem.new_unicode(ord(t[i]), buf)
                i = i + 1
                buf.items.append(item)
        buf.guess_segment_properties()
        return buf

    def shapeText(self):
        features = []
        for k, box in self.features.items():
            if box.checkState() == Qt.PartiallyChecked:
                continue
            features.append({"tag": k, "value": box.isChecked()})

        buf = self.buildBuffer()

        self.messageTable.setRowCount(0)
        if not self.text:
            buf.clear_mask()
            self.qbr.set_buf(buf)
            self.fullBuffer = buf
            self.shaperOutput.setText(buf.serialize())
            return
        self.messageTable.clearSelection()
        self.lastBuffer = None
        self.skipped = []
        self.partialBuffers = {}
        shaper = Shaper(
            self.project.fontfeatures,
            self.project.font,
            message_function=self.addToTable,
        )
        self.prep_shaper(shaper, buf, features)
        shaper.execute(buf, features=features)

        self.qbr.set_buf(buf)
        self.fullBuffer = buf
        self.shaperOutput.setText(buf.serialize())

    def prep_shaper(self, shaper, buf, features):
        if not self.sliders:
            return
        buf.vf = self.project.variations
        loc = {slider.name: slider.value() for slider in self.sliders}
        buf.location = loc

        self.qbr.set_location(loc)

    def addToTable(self, msg, buffer=None, serialize_options=None):
        if msg.startswith("Before"):
            return
        if not buffer:  # Easy one
            rowPosition = self.messageTable.rowCount()
            self.messageTable.insertRow(rowPosition)
            message_item = QTableWidgetItem(msg)
            self.messageTable.setItem(rowPosition, 0, message_item)
            return

        # Urgh
        b = BaseShaper(None, None, buffer)
        for i in range(0, len(buffer.items)):
            b.propagate_attachment_offsets(i)

        ser = buffer.serialize(additional=serialize_options)

        if self.lastBuffer == ser:
            m = re.match(r"After (\w+ \(\w+\))", msg)
            if m:
                self.skipped.append(m[1])
                return
        elif self.skipped:
            rowPosition = self.messageTable.rowCount()
            self.messageTable.insertRow(rowPosition)
            message_item = QTableWidgetItem(
                "Routines executed but had no effect: %s" %
                ",".join(self.skipped))
            self.messageTable.setItem(rowPosition, 0, message_item)
            self.skipped = []
        self.lastBuffer = ser
        rowPosition = self.messageTable.rowCount()
        self.messageTable.insertRow(rowPosition)
        message_item = QTableWidgetItem(msg)
        self.messageTable.setItem(rowPosition, 0, message_item)
        self.partialBuffers[rowPosition] = (copy(buffer), msg)
        self.partialBuffers[rowPosition][0].items = deepcopy(buffer.items)
        buffer_item = QTableWidgetItem(ser)
        self.messageTable.setItem(rowPosition, 1, buffer_item)

    def renderPartialTrace(self):
        indexes = self.messageTable.selectedIndexes()
        if len(indexes) != 2:
            return
        row = indexes[0].row()
        if row in self.partialBuffers:
            buf, msg = self.partialBuffers[row]
            self.qbr.set_buf(buf)
            m = re.match(r"After (\w+) \((\w+)\)", msg)
            if m and self.editor:
                routine, feature = m[1], m[2]
                self.editor.fontfeaturespanel.lookuplist.highlight(routine)
                self.editor.fontfeaturespanel.featurelist.highlight(
                    feature, routine)

        # else:
        #     self.qbr.set_buf(self.fullBuffer)

    def textChanged(self, text):
        self.text = text
        self.project.debuggingText = text
        self.shapeText()

    def getReasonableTextForFont(self, font):
        text = ""
        if font.glyphForCodepoint(0x627, fallback=False):  # Arabic
            text = text + "ابج "
        if font.glyphForCodepoint(0x915, fallback=False):  # Devanagari
            text = text + "कचण "
        if font.glyphForCodepoint(0x61, fallback=False):  # Latin
            text = text + "abc "
        return text.strip()
Ejemplo n.º 10
0
class Mostrar_Notificacion(QDialog):
    global nombres
    global tareas

    def __init__(self, parent=None):
        super(Mostrar_Notificacion, self).__init__(parent)

        self.setWindowTitle("Tabla de notificaciones")
        self.setWindowIcon(QIcon("Qt.png"))
        self.setWindowFlags(Qt.WindowMinimizeButtonHint
                            | Qt.WindowCloseButtonHint
                            | Qt.MSWindowsFixedSizeDialogHint)
        self.setFixedSize(740, 348)

        self.initUI()

    def initUI(self):

        # ================== WIDGET  QTableWidget ==================

        self.tabla = QTableWidget(self)

        # Deshabilitar edición
        self.tabla.setEditTriggers(QAbstractItemView.NoEditTriggers)

        # Deshabilitar el comportamiento de arrastrar y soltar
        self.tabla.setDragDropOverwriteMode(False)

        # Seleccionar toda la fila
        self.tabla.setSelectionBehavior(QAbstractItemView.SelectRows)

        # Seleccionar una fila a la vez
        self.tabla.setSelectionMode(QAbstractItemView.SingleSelection)

        # Especifica dónde deben aparecer los puntos suspensivos "..." cuando se muestran
        # textos que no encajan
        self.tabla.setTextElideMode(Qt.ElideRight)  # Qt.ElideNone

        # Establecer el ajuste de palabras del texto
        self.tabla.setWordWrap(False)

        # Deshabilitar clasificación

        # Establecer el número de columnas
        self.tabla.setColumnCount(2)

        # Establecer el número de filas
        self.tabla.setRowCount(0)

        # Alineación del texto del encabezado
        self.tabla.horizontalHeader().setDefaultAlignment(Qt.AlignHCenter
                                                          | Qt.AlignVCenter
                                                          | Qt.AlignCenter)

        # Deshabilitar resaltado del texto del encabezado al seleccionar una fila
        self.tabla.horizontalHeader().setHighlightSections(False)

        # Hacer que la última sección visible del encabezado ocupa todo el espacio disponible
        self.tabla.horizontalHeader().setStretchLastSection(True)

        # Ocultar encabezado vertical
        self.tabla.verticalHeader().setVisible(False)

        # Dibujar el fondo usando colores alternados
        self.tabla.setAlternatingRowColors(True)

        # Establecer altura de las filas
        self.tabla.verticalHeader().setDefaultSectionSize(20)

        # self.tabla.verticalHeader().setHighlightSections(True)

        nombreColumnas = ("Planta", "Tarea")

        # Establecer las etiquetas de encabezado horizontal usando etiquetas
        self.tabla.setHorizontalHeaderLabels(nombreColumnas)

        # Menú contextual
        self.tabla.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tabla.customContextMenuRequested.connect(self.menuContextual)

        # Establecer ancho de las columnas
        for indice, ancho in enumerate((80, 120, 120, 110, 150), start=0):
            self.tabla.setColumnWidth(indice, ancho)

        self.tabla.resize(700, 240)
        self.tabla.move(20, 56)

        # =================== WIDGETS QPUSHBUTTON ==================

        botonMostrarDatos = QPushButton("Mostrar datos", self)
        botonMostrarDatos.setFixedWidth(140)
        botonMostrarDatos.move(20, 20)

        menu = QMenu()
        for indice, columna in enumerate(nombreColumnas, start=0):
            accion = QAction(columna, menu)
            accion.setCheckable(True)
            accion.setChecked(True)
            accion.setData(indice)

            menu.addAction(accion)

        botonMostrarOcultar = QPushButton("Motrar/ocultar columnas", self)
        botonMostrarOcultar.setFixedWidth(180)
        botonMostrarOcultar.setMenu(menu)
        botonMostrarOcultar.move(170, 20)

        botonCerrar = QPushButton("Cerrar", self)
        botonCerrar.setFixedWidth(80)
        botonCerrar.move(640, 306)

        # ======================== EVENTOS =========================

        botonMostrarDatos.clicked.connect(self.datosTabla)

        botonCerrar.clicked.connect(self.close)

        menu.triggered.connect(self.mostrarOcultar)

# ======================= FUNCIONES ============================

    def datosTabla(self):
        global nombres
        global tareas
        nombres = tuple(nombres)
        tareas = tuple(tareas)

        datos = []
        for i in range(len(nombres)):
            par = []
            par.append(nombres[i])
            par.append(tareas[i])
            par = tuple(par)
            datos.append(par)
        self.tabla.clearContents()

        row = 0
        for endian in datos:
            self.tabla.setRowCount(row + 1)

            idDato = QTableWidgetItem(endian[0])
            idDato.setTextAlignment(4)

            self.tabla.setItem(row, 0, idDato)
            self.tabla.setItem(row, 1, QTableWidgetItem(endian[1]))

            row += 1

    def mostrarOcultar(self, accion):
        columna = accion.data()

        if accion.isChecked():
            self.tabla.setColumnHidden(columna, False)
        else:
            self.tabla.setColumnHidden(columna, True)

    def eliminarFila(self):
        filaSeleccionada = self.tabla.selectedItems()

        if filaSeleccionada:
            fila = filaSeleccionada[0].row()
            self.tabla.removeRow(fila)

            self.tabla.clearSelection()
        else:
            QMessageBox.critical(self, "Eliminar fila",
                                 "Seleccione una fila.   ", QMessageBox.Ok)

    def menuContextual(self, posicion):
        indices = self.tabla.selectedIndexes()

        if indices:
            menu = QMenu()

            itemsGrupo = QActionGroup(self)
            itemsGrupo.setExclusive(True)

            menu.addAction(QAction("Copiar todo", itemsGrupo))

            columnas = [
                self.tabla.horizontalHeaderItem(columna).text()
                for columna in range(self.tabla.columnCount())
                if not self.tabla.isColumnHidden(columna)
            ]

            copiarIndividual = menu.addMenu("Copiar individual")
            for indice, item in enumerate(columnas, start=0):
                accion = QAction(item, itemsGrupo)
                accion.setData(indice)

                copiarIndividual.addAction(accion)

            itemsGrupo.triggered.connect(self.copiarTableWidgetItem)

            menu.exec_(self.tabla.viewport().mapToGlobal(posicion))

    def copiarTableWidgetItem(self, accion):
        filaSeleccionada = [dato.text() for dato in self.tabla.selectedItems()]

        if accion.text() == "Copiar todo":
            filaSeleccionada = tuple(filaSeleccionada)
        else:
            filaSeleccionada = filaSeleccionada[accion.data()]

        print(filaSeleccionada)

        return
Ejemplo n.º 11
0
class EnrollPlayers(QWidget):

    current_id_num = 0

    def __init__(self, tournament):

        super().__init__()
        # Runs the __init__ of QWidget, which EnrollPlayers inherits from

        if os.path.exists(tournament):
            # Check to make sure the tournament exists

            self.tournament = tournament

            self.tree = self.loadTournament(self.tournament)

            self.tournament_root = self.tree.getroot()

            # self.tournament, self.tree, and self.tournament_root are all used
            # to help write the xml

            this_tournament_name = self.tournament_root[0][0].text

            # Used to make the GUI display the tournament name
            # as the title of the window

            self.initUI(this_tournament_name)

        else:

            error = QMessageBox()

            error.setIcon(QMessageBox.Information)
            error.setText('No Tournament Found!')
            error.setWindowTitle('No Tournament Found')

            error.exec_()

            sys.exit(0) 

    def initUI(self, tournamentName):

        window_layout = QHBoxLayout()
        self.setLayout(window_layout)
        window_layout.setSpacing(5)
        # Sets a horizontal layout for the window itself

        ### Enrolling Players Section ###
        
        add_player_layout = QVBoxLayout()
        add_player_layout.addStretch(1)

        first_name_layout = QHBoxLayout()
        first_name_layout.setSpacing(1)

        self.first_name_label = QLabel('First Name: ', self)

        self.player_first_name = QLineEdit()
        self.player_first_name.returnPressed.connect(self.addPlayer)
        self.player_first_name.setFocus(True)
        # Line that holds the player's first name

        first_name_layout.addWidget(self.first_name_label)
        first_name_layout.addWidget(self.player_first_name)

        add_player_layout.addLayout(first_name_layout)
        
        last_name_layout = QHBoxLayout()
        last_name_layout.setSpacing(2)

        self.lastNameLabel = QLabel('Last Name: ', self)

        self.player_last_name = QLineEdit()
        self.player_last_name.returnPressed.connect(self.addPlayer)
        # Line that holds the player's last name

        last_name_layout.addWidget(self.lastNameLabel)
        last_name_layout.addWidget(self.player_last_name)
        
        add_player_layout.addLayout(last_name_layout)

        button_layout = QHBoxLayout()

        self.enroll_button = QPushButton('Enroll Player', self)
        self.enroll_button.clicked.connect(self.addPlayer)
        self.enroll_button.setAutoDefault(True)

        button_layout.addWidget(self.enroll_button)

        self.clear_button = QPushButton('Clear', self)
        self.clear_button.clicked.connect(self.clear)
        self.clear_button.setAutoDefault(True)

        button_layout.addWidget(self.clear_button)

        add_player_layout.addLayout(button_layout)
        add_player_layout.addStretch(1)

        begin_tournament_layout = QHBoxLayout()

        begin_tournament_button = QPushButton('Begin Tournament', self)
        begin_tournament_button.clicked.connect(self.beginTournament)

        begin_tournament_layout.addStretch(1)

        begin_tournament_layout.addWidget(begin_tournament_button)

        add_player_layout.addLayout(begin_tournament_layout)

        ### Table View For Enrolled Players Section ###

        self.enrolled_table = QTableWidget()

        # The following options all change how the user interacts
        # with the table
        
        self.enrolled_table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        # These prevent the user from editing the table cells,
        self.enrolled_table.setSelectionBehavior(QAbstractItemView.SelectRows)
        # Select the whole row when one is clicked
        self.enrolled_table.setSelectionMode(QAbstractItemView.SingleSelection)
        # Prevents selection of multiple rows.
        self.enrolled_table.verticalHeader().hide()
        # and hide the headers that appear to the left of the rows.
        
        self.enrolled_table.setColumnCount(2)
        self.enrolled_table.setHorizontalHeaderItem(0, QTableWidgetItem('Player'))
        self.enrolled_table.setHorizontalHeaderItem(1, QTableWidgetItem('ID'))
        self.enrolled_table.setColumnWidth(0, 235)
        self.enrolled_table.horizontalHeader().setSectionResizeMode(
            QHeaderView.ResizeMode(2))
        # ResizeMode(2) is fixed size, meaning the user can't change the size
        # of the table

        window_layout.addWidget(self.enrolled_table)

        ### Misc Window Settings ###

        window_layout.addLayout(add_player_layout)

        self.setGeometry(200, 200, 700, 500)
        self.setWindowTitle(tournamentName)

        self.player_first_name.setFocus(True)
        self.show()

    def addPlayer(self):

        first_name = self.player_first_name.text()
        lastName = self.player_last_name.text()

        if first_name.strip() != '' and lastName.strip() != '':

            self.current_id_num += 1

            tempID = 'TEMP{}'.format(str(self.current_id_num).zfill(4))
            # Builds a temporary ID for the player.
            # Temp IDs are good for just getting a tournament up and running.

            self.enrolled_table.insertRow(self.enrolled_table.rowCount())

            currentRow = self.enrolled_table.rowCount() - 1

            self.enrolled_table.setItem(currentRow, 0, QTableWidgetItem('{}, {}'.
                                                        format(lastName, first_name)))
            self.enrolled_table.setItem(currentRow, 1, QTableWidgetItem(tempID))

            self.enrolled_table.setSortingEnabled(True)
            self.enrolled_table.horizontalHeader().setSortIndicator(0, Qt.AscendingOrder)
            self.enrolled_table.setSortingEnabled(False)
            # This quickly enables sorting, sorts by the first column which is player
            # name, and then disables sorting so the user can't change the order.
            # This doesn't care about the order people were entered in, users just
            # need to be able to quickly see who is enrolled

            self.clear()
            # Calls clear to erase the entrant's name after they've been enrolled.

            self.player_first_name.setFocus()
            # Returns the cursor to the first name box to make entering
            # players faster!

        else:

            nameError = QMessageBox()
            nameError.setIcon(QMessageBox.Information)
            nameError.setWindowTitle('Blank Name')

            if first_name.strip() == '':

                self.player_first_name.setFocus()
                nameError.setText("The Player's first name is blank.")

            else:

                self.player_last_name.setFocus()
                nameError.setText("The Player's last name is blank.")

            nameError.exec_()

    def contextMenuEvent(self, event):

        selection = self.enrolled_table.selectedItems()

        if len(selection) > 0:

            table_menu = QMenu(self)

            dropPlayer = table_menu.addAction('Drop Player')
            renamePlayer = table_menu.addAction('Rename Player')

            action = table_menu.exec_(self.mapToGlobal(event.pos()))

            if action == dropPlayer:

                row = selection[0].row()

                self.enrolled_table.removeRow(row)

            elif action == renamePlayer:

                player_last_name, player_first_name = selection[0].text().split(', ')

                editNameWindow = QDialog(None, Qt.WindowCloseButtonHint)
                # Creates a dialog box that will pop up if the user choses rename player

                dialogLayout = QVBoxLayout()

                ### Dialog First Name Change ###

                dialogFirstNameLayout = QHBoxLayout()
                editFirstNameLabel = QLabel('New First Name:')
                editFirstName = QLineEdit()
                editFirstName.setText(player_first_name)

                dialogFirstNameLayout.addWidget(editFirstNameLabel)
                dialogFirstNameLayout.addWidget(editFirstName)

                dialogLayout.addLayout(dialogFirstNameLayout)

                ### Dialog Last Name Change ###
                
                dialogLastNameLayout = QHBoxLayout()
                
                editLastNameLabel = QLabel('New Last Name:')
                editLastName = QLineEdit()
                editLastName.setText(player_last_name)

                dialogLastNameLayout.addWidget(editLastNameLabel)
                dialogLastNameLayout.addWidget(editLastName)

                dialogLayout.addLayout(dialogLastNameLayout)

                ### Dialog Buttons ###
                 
                dialogButtons = QHBoxLayout()
                
                editName = QPushButton('Edit Name')
                editName.clicked.connect(editNameWindow.accept)
                
                cancelName = QPushButton('Cancel')
                cancelName.clicked.connect(editNameWindow.reject)

                dialogButtons.addWidget(editName)
                dialogButtons.addWidget(cancelName)

                dialogLayout.addLayout(dialogButtons)

                ### Misc Window Settings ###
            
                editNameWindow.setWindowTitle('Change Player Name')
                editNameWindow.setGeometry(300, 300, 300, 100)
                editNameWindow.setLayout(dialogLayout)

                choice = editNameWindow.exec_()
                # Returns a number corresponding to the user's choice.
                # 1 = Accept (Hit the ok button)
                # 0 = Reject (Hit the cancel button)

                if choice == 1:

                    selection[0].setText('{}, {}'.format(editLastName.text(), editFirstName.text()))
                    
                    self.enrolled_table.setSortingEnabled(True)
                    self.enrolled_table.horizontalHeader().setSortIndicator(0, Qt.AscendingOrder)
                    self.enrolled_table.setSortingEnabled(False)
                    # Resorts the players names after a name is changed
            
            self.enrolled_table.clearSelection()
            # Automatically clears the selection after it is right clicked
            # So the user doesn't accidently keep clicking the same cell


    def clear(self):

        # Helper function to clear the player's name after something is done,
        # such as when a player is entered

        self.player_first_name.setText('')
        self.player_last_name.setText('')

        self.player_first_name.setFocus(True)

    def getTableData(self):

        enrolled_players = []

        for row in range(self.enrolled_table.rowCount()):

            playerNameItem = self.enrolled_table.item(row, 0)
            playerIDItem = self.enrolled_table.item(row, 1)
            # gets the items from the table

            player_last_name, player_first_name = playerNameItem.text().split(', ')
            # Split's first and last name, as they are combined in the cell
            # but saved separately in the xml document
            
            playerID = playerIDItem.text()

            enrolled_players.append((playerID, player_first_name, player_last_name))
            # appends a tuple with the information to the enrolled_players list

        return enrolled_players
        # This is passed to writeToFile

    def loadTournament(self, tournament):

        # Helper function to load the event so it can be accessed by
        # the other methods

        tree = ET.parse(tournament)

        return tree
        # this is used by the __init__ to load the xml tree

    def writeToFile(self, enrolled_players):

        players = self.tournament[1]

        for idNum, first, last in enrolled_players:

            # Unpacks the tuples saved in enrolled_players
            # to be written to the xml file

            player = ET.SubElement(players, 'Player')

            idNumber = ET.SubElement(player, 'IDNumber')
            idNumber.text = idNum

            first_name = ET.SubElement(player, 'FirstName')
            first_name.text = first

            lastName = ET.SubElement(player, 'LastName')
            lastName.text = last

            wins = ET.SubElement(player, 'Wins')
            wins.text = '0'

            draws = ET.SubElement(player, 'Draws')
            draws.text = '0'

            # Wins and draws are both used during player pairings

        to_write = self.tree

        to_write.write(self.tournament,
                       encoding = 'utf-8',
                       xml_declaration = True)

    def beginTournament(self):

        enrolled_players = self.getTableData()

        total_players = len(enrolled_players)

        if len(enrolled_players) < 4:

            # Prevents the user from creating an event with less than 4 players

            lessThan4Error = QMessageBox()
            lessThan4Error.setIcon(QMessageBox.Information)
            lessThan4Error.setText('A tournament cannot have less than 4 players!')
            lessThan4Error.setWindowTitle('Not Enough Players')

            # Tournaments with less than 4 players just don't work. With 4 players
            # You can have 3 rounds and a definite winner.

            self.player_first_name.setFocus()

            lessThan4Error.exec_()

        else:

            tournament_created = QMessageBox()
            tournament_created.setIcon(QMessageBox.Information)
            tournament_created.setText('{} Players were enrolled.'.format(total_players))
            tournament_created.setWindowTitle('Players Successfully Enrolled')

            # Alerts the user that players have been entered, and gives the total number
            # so the user can double check how many people have been entered.

            tournament_created.exec_()

            self.writeToFile(enrolled_players)

            if __name__ == '__main__':

                self.close()
Ejemplo n.º 12
0
class SerialScan(QMainWindow):
    def __init__(self, serial, parent=None):
        super(SerialScan, self).__init__(parent)
        self.serial = serial
        self.setWindowIcon(QIcon('resources/mouse.PNG'))
        self.IdToName = {}
        self.front()
        self.mouseThread = ScanMouseIdThread(self.serial)
        self.mouseThread.start()
        self.mouseThread.sig1.connect(self.on_info)

    def front(self):
        self.setGeometry(500, 500, 500, 500)
        self.setWindowTitle("TEAM")
        self.setWindowIcon(QIcon('resources/mouse.PNG'))
        self.setStyleSheet("background-color: #03795E")

        grid = QGridLayout()

        logo_title = QLabel("Serial Input: Scan IDs", self)
        font = QFont('Arial', 30)
        font.setBold(True)
        logo_title.setStyleSheet("QLabel {color: #fcba03}")
        logo_title.setFont(font)
        logo_title.setAlignment(Qt.AlignCenter)
        grid.addWidget(logo_title, 0, 1)

        logo_instr = QLabel(
            "Scan mouse tags, enter what cage they are for, and their name:",
            self)
        font = QFont('Arial', 15)
        font.setBold(True)
        logo_instr.setStyleSheet("QLabel {color: #fcba03}")
        logo_instr.setFont(font)
        logo_instr.setAlignment(Qt.AlignCenter)
        grid.addWidget(logo_instr, 1, 1)

        self.miceTable = QTableWidget()
        self.miceTable.setStyleSheet("QTableWidget {background: #ffffff}")
        self.miceTable.setRowCount(1)
        self.miceTable.setColumnCount(3)
        self.miceTable.setHorizontalHeaderLabels(
            ["Mouse Tag", "Cage", "Mouse Name"])
        header = self.miceTable.horizontalHeader()
        header.setSectionResizeMode(0, QtWidgets.QHeaderView.Stretch)
        header.setSectionResizeMode(1, QtWidgets.QHeaderView.ResizeToContents)
        header.setSectionResizeMode(2, QtWidgets.QHeaderView.ResizeToContents)
        self.miceTable.move(0, 0)
        grid.addWidget(self.miceTable, 2, 1)

        self.back = QPushButton("Back", self)
        self.back.setStyleSheet(
            "QPushButton:hover:!pressed{ background: #fcba03}")
        self.back.clicked.connect(self.stopThread)
        grid.addWidget(self.back, 4, 0, 1, 1)

        self.start = QPushButton("Start", self)
        self.start.setStyleSheet(
            "QPushButton:hover:!pressed{ background: #fcba03}")
        self.start.clicked.connect(self.stopThread)
        grid.addWidget(self.start, 4, 2, 1, 1)

        central = QWidget()
        central.setLayout(grid)
        self.setCentralWidget(central)

    def on_info(self, info):
        rowPos = self.miceTable.rowCount() - 1
        item = QTableWidgetItem(info)
        self.miceTable.setItem(rowPos, 0, item)
        self.miceTable.insertRow(rowPos + 1)

    def stopThread(self):
        try:
            self.mouseThread.running = False
            time.sleep(3)
            self.miceTable.clearSelection()
            for row in range(self.miceTable.rowCount()):
                if self.miceTable.item(row, 0) and self.miceTable.item(
                        row, 1) and self.miceTable.item(row, 2):
                    mouseId = self.miceTable.item(row, 0).text().strip()
                    cage = int(self.miceTable.item(row, 1).text().strip())
                    name = self.miceTable.item(row, 2).text().strip()
                    self.IdToName[mouseId] = [cage, name]
            self.mouseThread.serial_port.close()
            self.hide()
        except:
            traceback.print_exc()
Ejemplo n.º 13
0
class flavorDlg(ArtisanResizeablDialog):
    def __init__(self, parent=None, aw=None):
        super(flavorDlg, self).__init__(parent, aw)
        self.setModal(True)
        rcParams['path.effects'] = []
        #avoid question mark context help
        flags = self.windowFlags()
        helpFlag = Qt.WindowContextHelpButtonHint
        flags = flags & (~helpFlag)
        self.setWindowFlags(flags)
        self.setWindowTitle(
            QApplication.translate("Form Caption", "Cup Profile", None))

        settings = QSettings()
        if settings.contains("FlavorProperties"):
            self.restoreGeometry(settings.value("FlavorProperties"))

        defaultlabel = QLabel(QApplication.translate("Label", "Default", None))
        self.defaultcombobox = QComboBox()
        self.defaultcombobox.addItems([
            "", "Artisan", "SCCA", "CQI", "SweetMarias", "C", "E",
            "CoffeeGeek", "Intelligentsia", "IIAC", "WCRC", "*CUSTOM*"
        ])
        self.defaultcombobox.setCurrentIndex(0)
        self.lastcomboboxIndex = 0
        self.defaultcombobox.currentIndexChanged.connect(self.setdefault)
        self.flavortable = QTableWidget()
        self.flavortable.setTabKeyNavigation(True)
        self.createFlavorTable()
        leftButton = QPushButton("<")
        leftButton.setFocusPolicy(Qt.NoFocus)
        leftButton.clicked.connect(self.moveLeft)
        rightButton = QPushButton(">")
        rightButton.setFocusPolicy(Qt.NoFocus)
        rightButton.clicked.connect(self.moveRight)
        addButton = QPushButton(QApplication.translate("Button", "Add", None))
        addButton.setFocusPolicy(Qt.NoFocus)
        addButton.clicked.connect(self.addlabel)
        delButton = QPushButton(QApplication.translate("Button", "Del", None))
        delButton.setFocusPolicy(Qt.NoFocus)
        delButton.clicked.connect(self.poplabel)
        saveImgButton = QPushButton(
            QApplication.translate("Button", "Save Image", None))
        saveImgButton.setFocusPolicy(Qt.NoFocus)
        #saveImgButton.clicked.connect(self.aw.resizeImg_0_1) # save as PNG (raster)
        saveImgButton.clicked.connect(
            self.aw.saveVectorGraph_PDF)  # save as PDF (vector)

        # connect the ArtisanDialog standard OK/Cancel buttons
        self.dialogbuttons.accepted.connect(self.close)
        self.dialogbuttons.removeButton(
            self.dialogbuttons.button(QDialogButtonBox.Cancel))

        self.backgroundCheck = QCheckBox(
            QApplication.translate("CheckBox", "Background", None))
        if self.aw.qmc.flavorbackgroundflag:
            self.backgroundCheck.setChecked(True)
        self.backgroundCheck.clicked.connect(self.showbackground)
        aspectlabel = QLabel(
            QApplication.translate("Label", "Aspect Ratio", None))
        self.aspectSpinBox = QDoubleSpinBox()
        self.aspectSpinBox.setToolTip(
            QApplication.translate("Tooltip", "Aspect Ratio", None))
        self.aspectSpinBox.setRange(0., 2.)
        self.aspectSpinBox.setSingleStep(.1)
        self.aspectSpinBox.setValue(self.aw.qmc.flavoraspect)
        self.aspectSpinBox.valueChanged.connect(self.setaspect)
        flavorLayout = QHBoxLayout()
        flavorLayout.addWidget(self.flavortable)
        comboLayout = QHBoxLayout()
        comboLayout.addWidget(defaultlabel)
        comboLayout.addWidget(self.defaultcombobox)
        comboLayout.addStretch()
        aspectLayout = QHBoxLayout()
        aspectLayout.addWidget(self.backgroundCheck)
        aspectLayout.addWidget(aspectlabel)
        aspectLayout.addWidget(self.aspectSpinBox)
        aspectLayout.addStretch()
        blayout1 = QHBoxLayout()
        blayout1.addStretch()
        blayout1.addWidget(addButton)
        blayout1.addWidget(delButton)
        blayout1.addStretch()
        extralayout = QVBoxLayout()
        extralayout.addLayout(comboLayout)
        extralayout.addLayout(aspectLayout)
        extraGroupLayout = QGroupBox()
        extraGroupLayout.setLayout(extralayout)
        blayout = QHBoxLayout()
        blayout.addStretch()
        blayout.addWidget(leftButton)
        blayout.addWidget(rightButton)
        blayout.addStretch()
        mainButtonsLayout = QHBoxLayout()
        mainButtonsLayout.addWidget(saveImgButton)
        mainButtonsLayout.addStretch()
        mainButtonsLayout.addWidget(self.dialogbuttons)
        mainLayout = QVBoxLayout()
        mainLayout.addLayout(flavorLayout)
        mainLayout.addLayout(blayout1)
        mainLayout.addWidget(extraGroupLayout)
        mainLayout.addLayout(blayout)
        #        mainLayout.addStretch()
        mainLayout.addLayout(mainButtonsLayout)
        self.setLayout(mainLayout)
        self.aw.qmc.flavorchart()
        self.dialogbuttons.button(QDialogButtonBox.Ok).setFocus()

    @pyqtSlot(float)
    def setaspect(self, _):
        self.aw.qmc.flavoraspect = self.aspectSpinBox.value()
        self.aw.qmc.flavorchart()

    def createFlavorTable(self):
        nflavors = len(self.aw.qmc.flavorlabels)

        # self.flavortable.clear() # this crashes Ubuntu 16.04
        #        if ndata != 0:
        #            self.flavortable.clearContents() # this crashes Ubuntu 16.04 if device table is empty and also sometimes else
        self.flavortable.clearSelection(
        )  # this seems to work also for Ubuntu 16.04

        if nflavors:
            self.flavortable.setRowCount(nflavors)
            self.flavortable.setColumnCount(3)
            self.flavortable.setHorizontalHeaderLabels([
                QApplication.translate("Table", "Label", None),
                QApplication.translate("Table", "Value", None), ""
            ])
            self.flavortable.setAlternatingRowColors(True)
            self.flavortable.setEditTriggers(QTableWidget.NoEditTriggers)
            self.flavortable.setSelectionBehavior(QTableWidget.SelectRows)
            self.flavortable.setSelectionMode(QTableWidget.SingleSelection)
            self.flavortable.setShowGrid(True)
            #self.flavortable.verticalHeader().setSectionResizeMode(2)
            #populate table
            for i in range(nflavors):
                labeledit = QLineEdit(self.aw.qmc.flavorlabels[i])
                labeledit.textChanged.connect(self.setlabel)
                valueSpinBox = MyQDoubleSpinBox()
                valueSpinBox.setRange(0., 10.)
                valueSpinBox.setSingleStep(.25)
                valueSpinBox.setAlignment(Qt.AlignRight)
                val = self.aw.qmc.flavors[i]
                if self.aw.qmc.flavors[0] < 1. and self.aw.qmc.flavors[
                        -1] < 1.:  # < 0.5.0 version style compatibility
                    val *= 10.
                valueSpinBox.setValue(val)
                valueSpinBox.valueChanged.connect(self.setvalue)
                #add widgets to the table
                self.flavortable.setCellWidget(i, 0, labeledit)
                self.flavortable.setCellWidget(i, 1, valueSpinBox)
            self.flavortable.resizeColumnsToContents()
            header = self.flavortable.horizontalHeader()
            header.setSectionResizeMode(0, QHeaderView.Stretch)

    @pyqtSlot(bool)
    def showbackground(self, _):
        if self.backgroundCheck.isChecked():
            if not self.aw.qmc.background:
                message = QApplication.translate(
                    "Message", "Background profile not found", None)
                self.aw.sendmessage(message)
                self.backgroundCheck.setChecked(False)
            else:
                if len(self.aw.qmc.backgroundFlavors) != len(
                        self.aw.qmc.flavors):
                    message = QApplication.translate(
                        "Message",
                        "Background does not match number of labels", None)
                    self.aw.sendmessage(message)
                    self.aw.qmc.flavorbackgroundflag = False
                    self.backgroundCheck.setChecked(False)
                else:
                    self.aw.qmc.flavorbackgroundflag = True
                    self.aw.qmc.flavorchart()
        else:
            self.aw.qmc.flavorbackgroundflag = False
            self.aw.qmc.flavorchart()

    @pyqtSlot(bool)
    def moveLeft(self, _):
        self.aw.qmc.flavorstartangle += 5
        self.aw.qmc.flavorchart()

    @pyqtSlot(bool)
    def moveRight(self, _):
        self.aw.qmc.flavorstartangle -= 5
        self.aw.qmc.flavorchart()

    def savetable(self):
        for i in range(len(self.aw.qmc.flavorlabels)):
            labeledit = self.flavortable.cellWidget(i, 0)
            valueSpinBox = self.flavortable.cellWidget(i, 1)
            label = labeledit.text()
            if "\\n" in label:  #make multiple line text if "\n" found in label string
                parts = label.split("\\n")
                label = chr(10).join(parts)
            self.aw.qmc.flavorlabels[i] = label
            self.aw.qmc.flavors[i] = valueSpinBox.value()
        if self.lastcomboboxIndex == 10:
            # store the current labels as *CUSTOM*
            self.aw.qmc.customflavorlabels = self.aw.qmc.flavorlabels

    @pyqtSlot()
    @pyqtSlot("QString")
    def setlabel(self, _):
        x = self.aw.findWidgetsRow(self.flavortable, self.sender(), 0)
        if x is not None:
            labeledit = self.flavortable.cellWidget(x, 0)
            self.aw.qmc.flavorlabels[x] = labeledit.text()
            self.aw.qmc.updateFlavorchartLabel(x)  # fast incremental redraw

    @pyqtSlot(float)
    def setvalue(self, _):
        x = self.aw.findWidgetsRow(self.flavortable, self.sender(), 1)
        if x is not None:
            valueSpinBox = self.flavortable.cellWidget(x, 1)
            self.aw.qmc.flavors[x] = valueSpinBox.value()
            #            self.aw.qmc.flavorchart() # slow full redraw
            self.aw.qmc.updateFlavorchartValues()  # fast incremental redraw

    @pyqtSlot(int)
    def setdefault(self, _):
        if self.lastcomboboxIndex == 10:
            # store the current labels as *CUSTOM*
            self.aw.qmc.customflavorlabels = self.aw.qmc.flavorlabels
        dindex = self.defaultcombobox.currentIndex()
        #["","Artisan","SCCA","CQI","SweetMarias","C","E","coffeegeek","Intelligentsia","WCRC"]
        if dindex > 0 or dindex < 11:
            self.aw.qmc.flavorstartangle = 90
        if dindex == 1:
            self.aw.qmc.flavorlabels = list(
                self.aw.qmc.artisanflavordefaultlabels)
        elif dindex == 2:
            self.aw.qmc.flavorlabels = list(
                self.aw.qmc.SCCAflavordefaultlabels)
        elif dindex == 3:
            self.aw.qmc.flavorlabels = list(self.aw.qmc.CQIflavordefaultlabels)
        elif dindex == 4:
            self.aw.qmc.flavorlabels = list(
                self.aw.qmc.SweetMariasflavordefaultlabels)
        elif dindex == 5:
            self.aw.qmc.flavorlabels = list(self.aw.qmc.Cflavordefaultlabels)
        elif dindex == 6:
            self.aw.qmc.flavorlabels = list(self.aw.qmc.Eflavordefaultlabels)
        elif dindex == 7:
            self.aw.qmc.flavorlabels = list(
                self.aw.qmc.coffeegeekflavordefaultlabels)
        elif dindex == 8:
            self.aw.qmc.flavorlabels = list(
                self.aw.qmc.Intelligentsiaflavordefaultlabels)
        elif dindex == 9:
            self.aw.qmc.flavorlabels = list(
                self.aw.qmc.IstitutoInternazionaleAssaggiatoriCaffe)
        elif dindex == 10:
            self.aw.qmc.flavorlabels = list(
                self.aw.qmc.WorldCoffeeRoastingChampionship)
        elif dindex == 11:
            self.aw.qmc.flavorlabels = list(self.aw.qmc.customflavorlabels)
        else:
            return
        self.aw.qmc.flavors = [5.] * len(self.aw.qmc.flavorlabels)
        self.createFlavorTable()
        self.aw.qmc.flavorchart()
        self.lastcomboboxIndex = dindex

    @pyqtSlot(bool)
    def addlabel(self, _):
        self.aw.qmc.flavorlabels.append("???")
        self.aw.qmc.flavors.append(5.)
        self.createFlavorTable()
        self.aw.qmc.flavorchart()

    @pyqtSlot(bool)
    def poplabel(self):
        fn = len(self.aw.qmc.flavors)
        self.aw.qmc.flavors = self.aw.qmc.flavors[:(fn - 1)]
        self.aw.qmc.flavorlabels = self.aw.qmc.flavorlabels[:(fn - 1)]
        self.createFlavorTable()
        self.aw.qmc.flavorchart()

    def closeEvent(self, _):
        self.close()

    @pyqtSlot()
    def close(self):
        settings = QSettings()
        #save window geometry
        settings.setValue("FlavorProperties", self.saveGeometry())
        self.savetable()
        self.aw.qmc.fileDirty()
        if self.aw.qmc.ax1 is not None:
            try:
                self.aw.qmc.fig.delaxes(self.aw.qmc.ax1)
            except:
                pass
        self.aw.qmc.fig.clf()
        self.aw.qmc.clearFlavorChart()
        self.aw.redrawOnResize = True
        self.aw.qmc.redraw(recomputeAllDeltas=False)
        self.aw.showControls()
        self.accept()
Ejemplo n.º 14
0
class SettingsWidget(QWidget):
    def __init__(self, parent=None):
        super(SettingsWidget, self).__init__(parent)

        # 软件设置面板
        path_settings_groupbox = QGroupBox()
        path_settings_groupbox.setTitle("本地设置")
        path_settings_groupbox.setFixedHeight(200)
        path_settings_groupbox_layout = QVBoxLayout()
        # 本地客户端路径
        path_widget1_layout = QHBoxLayout()
        local_client_path_label = QLabel()
        local_client_path_label.setText("本地客户端路径:")
        # local_client_path_label.setFixedWidth(105)
        self.local_client_path_lineEdit = QLineEdit()
        self.local_client_path_btn = QPushButton()
        self.local_client_path_btn.setText("浏览")
        path_widget1_layout.addWidget(local_client_path_label)
        path_widget1_layout.addWidget(self.local_client_path_lineEdit)
        path_widget1_layout.addWidget(self.local_client_path_btn)
        # 本地服务端路径
        path_widget2_layout = QHBoxLayout()
        local_server_path_label = QLabel()
        local_server_path_label.setText("本地服务端路径:")
        # local_server_path_label.setFixedWidth(105)
        self.local_server_path_lineEdit = QLineEdit()
        self.local_server_path_lineEdit.setDisabled(True)
        self.local_server_path_btn = QPushButton()
        self.local_server_path_btn.setText("浏览")

        server_betacode_label = QLabel()
        server_betacode_label.setText("测试代码:")
        self.server_betacode_lineEdit = QLineEdit()
        self.server_betacode_lineEdit.setFixedWidth(80)

        path_widget2_layout.addWidget(local_server_path_label)
        path_widget2_layout.addWidget(self.local_server_path_lineEdit)
        path_widget2_layout.addWidget(self.local_server_path_btn)
        path_widget2_layout.addWidget(server_betacode_label)
        path_widget2_layout.addWidget(self.server_betacode_lineEdit)

        # Steamcmd路径
        path_widget4_layout = QHBoxLayout()
        steamcmd_path_label = QLabel()
        steamcmd_path_label.setText("SteamCMD路径:")
        # local_cluster_path_label.setFixedWidth(105)
        self.steamcmd_path_lineEdit = QLineEdit()
        self.steamcmd_path_btn = QPushButton()
        self.steamcmd_path_btn.setText("浏览")

        self.install_server_button = QPushButton()
        self.install_server_button.setText("安装本地服务端")

        self.install_server_button.clicked.connect(self.install_server)

        path_widget4_layout.addWidget(steamcmd_path_label)
        path_widget4_layout.addWidget(self.steamcmd_path_lineEdit)
        path_widget4_layout.addWidget(self.steamcmd_path_btn)
        path_widget4_layout.addWidget(self.install_server_button)

        # 本地存档路径
        path_widget3_layout = QHBoxLayout()
        local_cluster_path_label = QLabel()
        local_cluster_path_label.setText("本地存档路径:")
        # local_cluster_path_label.setFixedWidth(105)
        self.local_cluster_path_lineEdit = QLineEdit()
        self.local_cluster_path_lineEdit.setDisabled(True)
        self.local_cluster_path_btn = QPushButton()
        # self.local_cluster_path_btn.setText("浏览")
        self.local_cluster_path_btn.setText("打开")
        path_widget3_layout.addWidget(local_cluster_path_label)
        path_widget3_layout.addWidget(self.local_cluster_path_lineEdit)
        path_widget3_layout.addWidget(self.local_cluster_path_btn)

        path_settings_groupbox_layout.addLayout(path_widget1_layout)
        path_settings_groupbox_layout.addLayout(path_widget2_layout)

        path_settings_groupbox_layout.addLayout(path_widget4_layout)
        path_settings_groupbox_layout.addLayout(path_widget3_layout)
        path_settings_groupbox.setLayout(path_settings_groupbox_layout)

        sc_settings_groupbox = QGroupBox()
        sc_settings_groupbox.setFixedHeight(75)
        sc_settings_groupbox.setTitle("消息通知设置")
        sc_settings_groupbox_layout = QHBoxLayout()
        self.sc_enable_checkBox = QCheckBox()
        self.sc_enable_checkBox.setText("开启Server酱消息通知")
        sc_key_label = QLabel()
        sc_key_label.setText("Server酱密钥:")
        self.sc_key_lineEdit = QLineEdit()
        sc_settings_groupbox_layout.addWidget(self.sc_enable_checkBox)
        sc_settings_groupbox_layout.addWidget(sc_key_label)
        sc_settings_groupbox_layout.addWidget(self.sc_key_lineEdit)
        sc_settings_groupbox.setLayout(sc_settings_groupbox_layout)

        server_settings_groupbox = QGroupBox()
        server_settings_groupbox.setTitle("云主机设置(截图请注意隐藏IP和密码)")
        server_settings_groupbox_layout = QVBoxLayout()

        token_layout = QHBoxLayout()
        server_token_label = QLabel()
        server_token_label.setText("服务器令牌:")
        self.server_token_lineEdit = QLineEdit()
        token_layout.addWidget(server_token_label)
        token_layout.addWidget(self.server_token_lineEdit)

        server_frame_layout = QHBoxLayout()

        self.server_table = QTableWidget()
        self.server_table.setColumnCount(5)
        # 禁止编辑
        self.server_table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        # 设置标题
        self.server_table.setHorizontalHeaderLabels(
            ['名称', 'IP或域名', '用户名', '密码', '备注'])
        # 设置选择整行
        self.server_table.setSelectionBehavior(QAbstractItemView.SelectRows)
        # 只选中单行
        self.server_table.setSelectionMode(QAbstractItemView.SingleSelection)
        # 自动列宽,随内容
        self.server_table.horizontalHeader().setSectionResizeMode(
            QHeaderView.Stretch)
        self.server_table.horizontalHeader().setSectionResizeMode(
            0, QHeaderView.ResizeToContents)

        server_edit_btn_layout = QVBoxLayout()
        self.add_new_server_btn = QPushButton()
        self.add_new_server_btn.setText("添加新的")
        self.edit_server_btn = QPushButton()
        self.edit_server_btn.setText("修改选中")
        self.delete_server_btn = QPushButton()
        self.delete_server_btn.setText("删除选中")
        self.test_server_btn = QPushButton()
        self.test_server_btn.setText("连接测试")
        server_edit_btn_layout.addWidget(self.add_new_server_btn)
        server_edit_btn_layout.addWidget(self.edit_server_btn)
        server_edit_btn_layout.addWidget(self.delete_server_btn)
        server_edit_btn_layout.addWidget(self.test_server_btn)
        spacerItem = QSpacerItem(20, 20, QSizePolicy.Minimum,
                                 QSizePolicy.Expanding)
        server_edit_btn_layout.addItem(spacerItem)

        server_frame_layout.addWidget(self.server_table)
        server_frame_layout.addLayout(server_edit_btn_layout)

        server_settings_groupbox_layout.addLayout(token_layout)
        server_settings_groupbox_layout.addLayout(server_frame_layout)
        server_settings_groupbox.setLayout(server_settings_groupbox_layout)

        self.save_settings_btn = QPushButton()
        self.save_settings_btn.setText("保存设置(修改完记得保存)")

        settings_layout = QVBoxLayout()
        settings_layout.addWidget(path_settings_groupbox)
        settings_layout.addWidget(sc_settings_groupbox)
        settings_layout.addWidget(server_settings_groupbox)
        settings_layout.addWidget(self.save_settings_btn)
        self.setLayout(settings_layout)

        # 按钮函数绑定
        self.add_new_server_btn.clicked.connect(self.add_new_server)
        self.delete_server_btn.clicked.connect(self.delete_server)
        self.edit_server_btn.clicked.connect(self.edit_server)
        self.test_server_btn.clicked.connect(self.test_server)
        self.save_settings_btn.clicked.connect(self.save_settings_data)
        self.local_server_path_btn.clicked.connect(self.select_server_dir)
        # self.local_cluster_path_btn.clicked.connect(self.select_cluster_dir)
        self.local_cluster_path_btn.clicked.connect(self.open_cluster)
        self.local_client_path_btn.clicked.connect(self.select_client_dir)
        self.steamcmd_path_btn.clicked.connect(self.select_steamcmd_dir)
        self.install_server_button.clicked.connect(self.install_server)

        self.init_settings_data()

    # 添加新服务器
    def add_new_server(self):
        self.server_table.clearSelection()
        self.serverDialog = ServerDialog(self)
        self.serverDialog.setWindowTitle("添加服务器")
        self.serverDialog.serverSignal.connect(self.add_server)
        self.serverDialog.exec()

    def is_server_not_exist(self, ip):
        serverlist = self.get_server_list()
        for server in serverlist:
            if ip == server[1]:
                return False
        return True

    def add_server(self, server):
        flag = True
        server_row_num = self.server_table.currentRow()
        if server_row_num == -1:
            if self.is_server_not_exist(server[1]):
                server_row_num = self.server_table.rowCount()
                self.server_table.setRowCount(server_row_num + 1)
            else:
                QMessageBox.warning(self, "警告", "服务器已存在!", QMessageBox.Yes)
                flag = False
        if flag:
            self.serverDialog.hide()
            for col in range(5):
                self.server_table.setItem(server_row_num, col,
                                          QTableWidgetItem(server[col]))
                self.server_table.item(server_row_num,
                                       col).setTextAlignment(Qt.AlignHCenter
                                                             | Qt.AlignVCenter)

    def edit_server(self):
        row = self.server_table.currentRow()
        if row > -1:
            serverDialog = ServerDialog(self)
            serverDialog.setWindowTitle("修改服务器")
            serverDialog.name_lineEdit.setText(
                self.server_table.item(row, 0).text())
            serverDialog.ip_lineEdit.setText(
                self.server_table.item(row, 1).text())
            serverDialog.user_lineEdit.setText(
                self.server_table.item(row, 2).text())
            serverDialog.passwd_lineEdit.setText(
                self.server_table.item(row, 3).text())
            serverDialog.tips_lineEdit.setText(
                self.server_table.item(row, 4).text())
            serverDialog.serverSignal.connect(self.add_server)
            serverDialog.exec()
        else:
            QMessageBox.warning(self, "警告", "你没有选中服务器!", QMessageBox.Yes)

    def delete_server(self):
        row = self.server_table.currentRow()
        if row > -1:
            self.server_table.removeRow(row)
        else:
            QMessageBox.warning(self, "警告", "你没有选中服务器!", QMessageBox.Yes)

    def test_server(self):
        row = self.server_table.currentRow()
        if row > -1:
            ip = self.server_table.item(row, 1).text()
            if ip == "127.0.0.1":
                QMessageBox.information(self, "无需测试", "本地服请确保本地已安装服务端且已配好路径!",
                                        QMessageBox.Yes)
            else:
                username = self.server_table.item(row, 2).text()
                passwd = self.server_table.item(row, 3).text()
                try:
                    # 创建一个SSH客户端对象
                    ssh = paramiko.SSHClient()
                    # 设置访问策略
                    ssh.load_system_host_keys()
                    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
                    # 与远程主机进行连接
                    ssh.connect(hostname=ip,
                                port=22,
                                username=username,
                                password=passwd)
                    QMessageBox.information(self, "连接正确", "服务器连接测试通过!",
                                            QMessageBox.Yes)
                except Exception as e:
                    QMessageBox.critical(self, "连接错误", str(e), QMessageBox.Yes)
                finally:
                    ssh.close()
        else:
            QMessageBox.warning(self, "警告", "你没有选中服务器!", QMessageBox.Yes)

    def read_json_data(self, filename):
        jsonfile = os.path.join(ROOT_DIR, "settings.json")
        if os.path.exists(jsonfile):
            with open(jsonfile, 'r', encoding="utf-8") as f:
                data = json.load(f)
        else:
            data = {}
        return data

    def write_json_data(self, data):
        jsonfile = os.path.join(ROOT_DIR, 'settings.json')
        with open(jsonfile, 'w', encoding="utf-8") as f:
            json.dump(data, f)

    # 初始化设置
    def init_settings_data(self):
        settings = self.read_json_data('settings.json')
        if settings:
            self.steamcmd_path_lineEdit.setText(settings['steamcmdpath'])
            self.local_client_path_lineEdit.setText(
                settings['localclientpath'])
            self.local_server_path_lineEdit.setText(
                settings['localserverpath'])
            self.local_cluster_path_lineEdit.setText(
                settings['localclusterpath'])
            self.sc_key_lineEdit.setText(settings['sckey'])
            self.sc_enable_checkBox.setChecked(settings['scenable'])
            self.server_token_lineEdit.setText(settings['servertoken'])
            self.set_server_list(settings['servers'])
        else:
            self.local_cluster_path_lineEdit.setText(CLUSTER_DIR)

    def get_server_list(self):
        slist = []
        rowCount = self.server_table.rowCount()
        for row in range(rowCount):
            slist.append([
                self.server_table.item(row, 0).text(),
                self.server_table.item(row, 1).text(),
                self.server_table.item(row, 2).text(),
                self.server_table.item(row, 3).text(),
                self.server_table.item(row, 4).text()
            ])
        return slist

    def set_server_list(self, serverlist):
        row = self.server_table.rowCount()
        flag = False
        for list in serverlist:
            if list[1] == "127.0.0.1":
                flag = True
            self.server_table.setRowCount(row + 1)
            self.server_table.setItem(row, 0, QTableWidgetItem(list[0]))
            self.server_table.setItem(row, 1, QTableWidgetItem(list[1]))
            self.server_table.setItem(row, 2, QTableWidgetItem(list[2]))
            self.server_table.setItem(row, 3, QTableWidgetItem(list[3]))
            self.server_table.setItem(row, 4, QTableWidgetItem(list[4]))
            self.server_table.item(row, 0).setTextAlignment(Qt.AlignHCenter
                                                            | Qt.AlignVCenter)
            self.server_table.item(row, 1).setTextAlignment(Qt.AlignHCenter
                                                            | Qt.AlignVCenter)
            self.server_table.item(row, 2).setTextAlignment(Qt.AlignHCenter
                                                            | Qt.AlignVCenter)
            self.server_table.item(row, 3).setTextAlignment(Qt.AlignHCenter
                                                            | Qt.AlignVCenter)
            self.server_table.item(row, 4).setTextAlignment(Qt.AlignHCenter
                                                            | Qt.AlignVCenter)
            row += 1
            if not flag:
                self.set_server_list(
                    [["本地服务器", "127.0.0.1", "如无必要", "请勿删除", "这个选项"]])
        if 0 == len(serverlist):
            self.set_server_list(
                [["本地服务器", "127.0.0.1", "如无必要", "请勿删除", "这个选项"]])

    # 保存设置
    def save_settings_data(self):
        settings = {}
        settings['steamcmdpath'] = self.steamcmd_path_lineEdit.text()
        settings['localclientpath'] = self.local_client_path_lineEdit.text()
        settings['localserverpath'] = self.local_server_path_lineEdit.text()
        settings['localclusterpath'] = self.local_cluster_path_lineEdit.text()
        settings['sckey'] = self.sc_key_lineEdit.text()
        settings['scenable'] = self.sc_enable_checkBox.isChecked()
        settings['servertoken'] = self.server_token_lineEdit.text()
        settings['servers'] = self.get_server_list()
        self.write_json_data(settings)

    def getServerPath(self):
        return self.local_server_path_lineEdit.text()

    def select_client_dir(self):
        client_dir = self.local_client_path_lineEdit.text()
        root_dir = USER_HOME
        if os.path.exists(client_dir):
            root_dir = client_dir
        if sys.platform == "darwin":
            fileName, _ = QFileDialog.getOpenFileName(
                self, "选择本地客户端路径", root_dir,
                "Mac Applications (*.app);;All Files (*)")
            if fileName:
                client_dir = fileName
        else:
            client_dir = QFileDialog.getExistingDirectory(
                self, "选择本地服务端路径", root_dir)
            if sys.platform == "win32":
                client_dir = client_dir.replace('/', '\\')
        # self.local_server_path_lineEdit.setText(str(server_dir))

        # client_dir = QFileDialog.getExistingDirectory(self, "选择本地客户端路径", USER_HOME)
        if client_dir != "":
            self.local_client_path_lineEdit.setText(str(client_dir))

    def select_cluster_dir(self):
        cluster_dir = QFileDialog.getExistingDirectory(self, "选择本地存档路径",
                                                       USER_HOME)
        # 官方存档路径
        cluster = os.path.join(USER_HOME, 'Documents', 'Klei',
                               'DoNotStarveTogether')
        if cluster_dir != cluster:
            self.local_cluster_path_lineEdit.setText(str(cluster_dir))
        else:
            QMessageBox.warning(self, "警告", "不可选择和官方相同的路径", QMessageBox.Yes)

    def open_cluster(self):
        cluster_path = self.local_cluster_path_lineEdit.text()
        if cluster_path == "":
            cluster_path = CLUSTER_DIR
            self.local_cluster_path_lineEdit.setText(CLUSTER_DIR)
            self.save_settings_data()
        if os.path.exists(cluster_path):
            if sys.platform == "darwin":
                os.system("open %s" % cluster_path)
            elif sys.platform == "win32":
                os.system("start explorer %s" % cluster_path)
            else:
                QMessageBox.warning(self, "警告", "当前系统不支持该操作", QMessageBox.Yes)
        else:
            QMessageBox.warning(self, "警告", "存档文件夹不存在", QMessageBox.Yes)

    def select_server_dir(self):
        server_dir = self.local_server_path_lineEdit.text()
        root_dir = USER_HOME
        if os.path.exists(server_dir):
            root_dir = server_dir
        if sys.platform == "darwin":
            fileName, _ = QFileDialog.getOpenFileName(
                self, "选择本地服务端路径", root_dir,
                "All Files (*);;Mac Applications (*.app)")
            if fileName:
                server_dir = fileName
        else:
            server_dir = QFileDialog.getExistingDirectory(
                self, "选择本地服务端路径", root_dir)
            if sys.platform == "win32":
                server_dir = server_dir.replace('/', '\\')
        if server_dir != "":
            self.local_server_path_lineEdit.setText(str(server_dir))

    def select_steamcmd_dir(self):
        steamcmd_dir = self.steamcmd_path_lineEdit.text()
        root_dir = USER_HOME
        if os.path.exists(steamcmd_dir):
            root_dir = steamcmd_dir
        if sys.platform == "darwin":
            fileName, _ = QFileDialog.getOpenFileName(
                self, "选择SteamCMD路径", root_dir,
                "All Files (*);;Mac Applications (*.app)")
            if fileName:
                steamcmd_dir = fileName
        else:
            steamcmd_dir = QFileDialog.getOpenFileName(
                self, "选择SteamCMD路径", root_dir, "SteamCMD(steamcmd.exe)")
            if sys.platform == "win32":
                steamcmd_dir = steamcmd_dir[0].replace('/', '\\')
        if steamcmd_dir != "":
            self.steamcmd_path_lineEdit.setText(str(steamcmd_dir))
            local_server_path = os.path.join(
                os.path.dirname(steamcmd_dir), "steamapps", "common",
                "Don't Starve Together Dedicated Server")
            if self.local_server_path_lineEdit.text() == "":
                self.local_server_path_lineEdit.setText(local_server_path)

    def install_server(self):
        if sys.platform == "win32":
            steamcmd = self.steamcmd_path_lineEdit.text()
            if steamcmd == "":
                QMessageBox.warning(self, "警告", "请先设置SteamCMD路径!",
                                    QMessageBox.Yes)
                return
            server_dir = self.local_server_path_lineEdit.text()
            if server_dir == "":
                QMessageBox.warning(self, "警告", "请先设置服务端安装路径!",
                                    QMessageBox.Yes)
                return
Ejemplo n.º 15
0
class App(QWidget):
    def __init__(self):
        super().__init__()
        self.title = 'PyQt5 table'
        self.left = 0
        self.top = 0
        self.width = 2700
        self.height = 2500
        self.positionY = -1
        self.positionX = -1
        self.type = -1

        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setStyleSheet('background-color: white')
        self.setGeometry(self.left, self.top, self.width, self.height)

        # mode = input('Auto mode or Manual mode (1-Auto, 2-Manual): ')
        self.mode = '1'

        if self.mode == '1':
            self.auto_input_alg = input(
                'alpha-beta should be activated or not? (1-YES, 2-NO just Mini Max): '
            )
            # auto_input_file = input('should generate a trace of the minimax / alpha-beta or not? (1-YES, 2-NO): ')
            auto_input_sequence = input(
                'Computer Player: play first or second? (1-First, 2-Second): ')

            # auto mode
            if auto_input_sequence == '2':
                self.curPlayer = "Human Player"
            else:
                self.curPlayer = "Computer Player"

            auto_input_choice = input(
                self.curPlayer + ': play color or dot? (1-Color, 2-Dot): ')

            if auto_input_choice == '1':
                self.choice = Choice.COLOR
            elif auto_input_choice == '2':
                self.choice = Choice.DOT
            # if auto_input_choice == '1' and auto_input_sequence == '1':
            #     self.choice = Choice.COLOR
            # elif auto_input_choice == '2' and auto_input_sequence == '2':
            #     self.choice = Choice.DOT
            # elif auto_input_choice == '2' and auto_input_sequence == '1':
            #     self.choice = Choice.DOT
            # elif auto_input_choice == '2' and auto_input_sequence == '2':
            #     self.choice = Choice.COLOR

        else:
            manual_input = input(
                'Player 1: play color or dot? (1-Color, 2-Dot): ')
            # manual mode
            self.curPlayer = "Player 1"
            if manual_input == '1':
                self.choice = Choice.COLOR
            else:
                self.choice = Choice.DOT

        font = QtGui.QFont()
        font.setPixelSize(50)
        font.setBold(True)

        smallfont = QtGui.QFont()
        smallfont.setPixelSize(40)

        self.textLable = QLabel()
        self.countLable = QLabel()
        self.invalidLable = QLabel()
        self.playerLable = QLabel()

        self.textLable.setFont(font)
        self.countLable.setFont(font)
        self.invalidLable.setFont(font)
        self.playerLable.setFont(smallfont)

        self.phase = 'Normal Phase'
        self.textLable.setText(self.phase)
        self.playerLable.setText(self.curPlayer + '(' + str(self.choice) + ')')

        self.game = Game(self.choice)

        self.createTable()
        self.createButton()

        self.editor = QtWidgets.QTextEdit()
        self.editor.setText("hello")

        # Add box layout, add table to box layout and add box layout to widget
        self.tableLayout = QHBoxLayout()
        self.tableLayout.addWidget(self.tableWidget)

        self.lableLayout = QVBoxLayout()
        self.lableLayout.addStretch(0.5)
        self.lableLayout.addWidget(self.textLable)
        self.lableLayout.addStretch(0.7)
        self.lableLayout.addWidget(self.playerLable)
        self.lableLayout.addStretch(0.7)
        self.lableLayout.addWidget(self.countLable)
        self.lableLayout.addStretch(0.7)
        self.lableLayout.addWidget(self.invalidLable)
        self.lableLayout.addStretch(0.5)
        self.lableLayout.addWidget(self.editor)
        self.lableLayout.addStretch(0.6)
        self.lableLayout.addWidget(self.editor_button)

        self.buttonSide1Layout = QVBoxLayout()
        self.buttonSide1Layout.addWidget(self.button1)
        self.buttonSide1Layout.addWidget(self.button2)
        self.buttonSide1Layout.addWidget(self.button3)
        self.buttonSide1Layout.addWidget(self.button4)

        self.buttonSide2Layout = QVBoxLayout()
        self.buttonSide2Layout.addWidget(self.button5)
        self.buttonSide2Layout.addWidget(self.button6)
        self.buttonSide2Layout.addWidget(self.button7)
        self.buttonSide2Layout.addWidget(self.button8)

        self.AnglebuttonSideLayout = QVBoxLayout()
        self.AnglebuttonSideLayout.addWidget(self.RecycleButton)
        self.AnglebuttonSideLayout.addWidget(self.computerPlayerButton)

        self.Operationlayout = QHBoxLayout()
        self.Operationlayout.addStretch(1)
        self.Operationlayout.addLayout(self.lableLayout)
        self.Operationlayout.addStretch(1)
        self.Operationlayout.addLayout(self.buttonSide1Layout)
        self.Operationlayout.addStretch(1)
        self.Operationlayout.addLayout(self.buttonSide2Layout)
        self.Operationlayout.addStretch(1)
        self.Operationlayout.addLayout(self.AnglebuttonSideLayout)

        self.layout = QHBoxLayout()
        self.layout.addLayout(self.tableLayout)
        self.layout.addLayout(self.Operationlayout)

        self.setLayout(self.layout)
        # Show widget
        self.show()

    def createTable(self):
        # Create table
        self.tableWidget = QTableWidget()
        self.tableWidget.setRowCount(12)
        self.tableWidget.setColumnCount(8)
        self.tableWidget.setHorizontalHeaderLabels(
            ('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'))
        self.tableWidget.setVerticalHeaderLabels(
            ('12', '11', '10', '9', '8', '7', '6', '5', '4', '3', '2', '1'))
        self.tableWidget.horizontalHeader().setDefaultSectionSize(130)
        self.tableWidget.verticalHeader().setDefaultSectionSize(130)

        for i in range(self.tableWidget.columnCount()):
            for j in range(self.tableWidget.rowCount()):
                self.tableWidget.setItem(j, i, QTableWidgetItem(""))
        self.tableWidget.move(0, 0)

        # table selection change
        self.tableWidget.clicked.connect(self.table_on_click)

    @pyqtSlot()
    def table_on_click(self):
        for currentQTableWidgetItem in self.tableWidget.selectedItems():
            self.positionX = currentQTableWidgetItem.column()
            self.positionY = currentQTableWidgetItem.row()
            print(12 - self.positionY, str(chr(65 + self.positionX)))
        if self.tableWidget.currentItem().text() != "":
            #    call method return the other segment
            card = self.game.get_card(self.positionX, 11 - self.positionY)
            self.recylePosition1 = [
                card.seg[0].x, card.seg[0].y, card.seg[1].x, card.seg[1].y
            ]
            print(card.seg[0].x, card.seg[0].y, card.seg[1].x, card.seg[1].y)
            self.tableWidget.setRangeSelected(
                #    select the whole card
                QTableWidgetSelectionRange(11 - card.seg[0].y, card.seg[0].x,
                                           11 - card.seg[1].y, card.seg[1].x),
                True)

    def createButton(self):

        self.button1 = QPushButton('', self)
        self.button2 = QPushButton('', self)
        self.button3 = QPushButton('', self)
        self.button4 = QPushButton('', self)
        self.button5 = QPushButton('', self)
        self.button6 = QPushButton('', self)
        self.button7 = QPushButton('', self)
        self.button8 = QPushButton('', self)

        self.createButtonHelper(self.button1, 'Type1.png', 300, 200, 1)
        self.createButtonHelper(self.button2, 'Type2.png', 200, 200, 2)
        self.createButtonHelper(self.button3, 'Type3.png', 300, 200, 3)
        self.createButtonHelper(self.button4, 'Type4.png', 200, 200, 4)

        self.createButtonHelper(self.button5, 'Type5.png', 300, 200, 5)
        self.createButtonHelper(self.button6, 'Type6.png', 200, 200, 6)
        self.createButtonHelper(self.button7, 'Type7.png', 300, 200, 7)
        self.createButtonHelper(self.button8, 'Type8.png', 200, 200, 8)

        self.editor_button = QPushButton('play', self)
        self.editor_button.clicked.connect(self.Editor_button_on_click)
        self.editor_button.setStyleSheet('background: transparent')
        self.editor_button.setIcon(QtGui.QIcon('Play_image.png'))
        self.editor_button.setIconSize(QtCore.QSize(100, 100))

        self.RecycleButton = QPushButton('', self)
        self.RecycleButton.isFlat()
        self.RecycleButton.setStyleSheet('background: transparent')
        self.RecycleButton.setIcon(QtGui.QIcon('Recyle.jpg'))
        self.RecycleButton.setIconSize(QtCore.QSize(200, 200))
        self.RecycleButton.clicked.connect(self.RecycleButton_on_click)

        self.computerPlayerButton = QPushButton('', self)
        self.computerPlayerButton.isFlat()
        self.computerPlayerButton.setStyleSheet('background: transparent')
        self.computerPlayerButton.setIcon(QtGui.QIcon('Play_image.png'))
        self.computerPlayerButton.setIconSize(QtCore.QSize(200, 200))
        self.computerPlayerButton.clicked.connect(
            self.computerPlayerButton_on_click)

    def createButtonHelper(self, button, icon, sizeY, sizeX, number):
        button.isFlat()
        button.setStyleSheet('background: transparent')
        button.setIcon(QtGui.QIcon(icon))
        button.setIconSize(QtCore.QSize(sizeY, sizeX))
        button.clicked.connect(lambda *args: self.buttonType_on_click(number))

    @pyqtSlot()  # send the input to game
    def Editor_button_on_click(self):
        print(self.editor.toPlainText())

    @pyqtSlot()  #send the input to game
    def RecycleButton_on_click(self):
        is_valid, card_removed, card_added, count, win_id = self.game.recycle_card(
            self.recylePosition1[0], self.recylePosition1[1],
            self.recylePosition1[2], self.recylePosition1[3], self.type,
            self.positionX, 11 - self.positionY)
        # print(is_valid, card_removed, card_added, count, win_id)
        if is_valid:
            self.invalidLable.setText("")
            self.playerChange()
            # remove previous card
            self.tableWidget.setItem(11 - card_removed.seg[0].y,
                                     card_removed.seg[0].x,
                                     QTableWidgetItem(""))
            self.tableWidget.item(
                11 - card_removed.seg[0].y,
                card_removed.seg[0].x,
            ).setBackground(QtGui.QColor(255, 255, 255))

            self.tableWidget.setItem(11 - card_removed.seg[1].y,
                                     card_removed.seg[1].x,
                                     QTableWidgetItem(""))
            self.tableWidget.item(
                11 - card_removed.seg[1].y,
                card_removed.seg[1].x,
            ).setBackground(QtGui.QColor(255, 255, 255))

            new_dot0, new_color0 = self.recycleHelper(card_added.seg[0])
            new_dot1, new_color1 = self.recycleHelper(card_added.seg[1])

            self.tableWidget.clearSelection()
            # add new card
            self.tableWidget.setItem(11 - card_added.seg[0].y,
                                     card_added.seg[0].x,
                                     QTableWidgetItem(new_dot0))
            self.tableWidget.item(
                11 - card_added.seg[0].y,
                card_added.seg[0].x,
            ).setBackground(
                QtGui.QColor(new_color0[0], new_color0[1], new_color0[2]))

            self.tableWidget.setItem(11 - card_added.seg[1].y,
                                     card_added.seg[1].x,
                                     QTableWidgetItem(new_dot1))
            self.tableWidget.item(
                11 - card_added.seg[1].y,
                card_added.seg[1].x,
            ).setBackground(
                QtGui.QColor(new_color1[0], new_color1[1], new_color1[2]))
        else:
            self.invalidLable.setText("Invalid Move")
        if win_id == 1:
            self.textLable.setText("Player1 Win!")
        if win_id == 2:
            self.textLable.setText("Player2 Win!")
        if count == 60:
            self.textLable.setText("Draw!")

    def recycleHelper(self, seg):
        new_color = -1
        new_dot = -1
        if seg.color == Color.RED:
            new_color = [255, 0, 0]
        elif seg.color == Color.WHITE:
            new_color = [225, 225, 225]
        if seg.dot == Dot.SOLID:
            new_dot = "      ●"
        elif seg.dot == Dot.EMPTY:
            new_dot = "      O"
        return new_dot, new_color

    @pyqtSlot()  # computer move
    def computerPlayerButton_on_click(self):
        print("computer move")
        if self.curPlayer == "Computer Player":
            card_removed, card_added, count, win_id = self.game.computer_move(
                str(self.choice), self.auto_input_alg, True)

            new_dot0, new_color0 = self.recycleHelper(card_added.seg[0])
            new_dot1, new_color1 = self.recycleHelper(card_added.seg[1])

            self.countLable.setText("count: " + str(count))
            self.playerChange()
            self.playerLable.setText(self.curPlayer + '(' + str(self.choice) +
                                     ')')
            self.invalidLable.setText("")
            if count > 23:
                self.phase = 'Recyle Phase'
            self.tableWidget.clearSelection()
            if card_removed != None:
                # remove previous card
                self.tableWidget.setItem(11 - card_removed.seg[0].y,
                                         card_removed.seg[0].x,
                                         QTableWidgetItem(""))
                self.tableWidget.item(
                    11 - card_removed.seg[0].y,
                    card_removed.seg[0].x,
                ).setBackground(QtGui.QColor(255, 255, 255))

                self.tableWidget.setItem(11 - card_removed.seg[1].y,
                                         card_removed.seg[1].x,
                                         QTableWidgetItem(""))
                self.tableWidget.item(
                    11 - card_removed.seg[1].y,
                    card_removed.seg[1].x,
                ).setBackground(QtGui.QColor(255, 255, 255))
            # add new card
            self.tableWidget.setItem(11 - card_added.seg[0].y,
                                     card_added.seg[0].x,
                                     QTableWidgetItem(new_dot0))
            self.tableWidget.item(
                11 - card_added.seg[0].y,
                card_added.seg[0].x,
            ).setBackground(
                QtGui.QColor(new_color0[0], new_color0[1], new_color0[2]))

            self.tableWidget.setItem(11 - card_added.seg[1].y,
                                     card_added.seg[1].x,
                                     QTableWidgetItem(new_dot1))
            self.tableWidget.item(
                11 - card_added.seg[1].y,
                card_added.seg[1].x,
            ).setBackground(
                QtGui.QColor(new_color1[0], new_color1[1], new_color1[2]))

            if win_id == 1:
                self.textLable.setText("Player1 Win!")
            if win_id == 2:
                self.textLable.setText("Player2 Win!")
            if count == 60:
                self.textLable.setText("Draw!")

        else:
            self.invalidLable.setText("Invalid Player")

    @pyqtSlot()
    def buttonType_on_click(self, buttonNum):
        self.type = buttonNum
        ShowY = 12 - self.positionY
        ShowX = str(chr(65 + self.positionX))
        if self.phase == 'Normal Phase':
            print(self.positionX, ShowY - 1, self.type)
            # auto mode Human player or manual mode
            if (self.mode == '1'
                    and self.curPlayer == "Human Player") or self.mode == '2':
                is_valid, card, count, win_id = self.game.place_card(
                    self.type, self.positionX, ShowY - 1)
                self.tableWidget.clearSelection()
                if is_valid:
                    self.countLable.setText("count: " + str(count))
                    self.playerChange()
                    self.playerLable.setText(self.curPlayer + '(' +
                                             str(self.choice) + ')')
                    self.invalidLable.setText("")
                    # paint the cells
                    if buttonNum == 1:
                        self.tableWidget.setItem(self.positionY,
                                                 self.positionX,
                                                 QTableWidgetItem("      ●"))
                        self.tableWidget.setItem(self.positionY,
                                                 self.positionX + 1,
                                                 QTableWidgetItem("      O"))
                        self.tableWidget.item(self.positionY,
                                              self.positionX).setBackground(
                                                  QtGui.QColor(255, 0, 0))
                        self.tableWidget.item(self.positionY, self.positionX +
                                              1).setBackground(
                                                  QtGui.QColor(225, 225, 225))
                    elif buttonNum == 2:
                        self.tableWidget.setItem(self.positionY - 1,
                                                 self.positionX,
                                                 QTableWidgetItem("      ●"))
                        self.tableWidget.setItem(self.positionY,
                                                 self.positionX,
                                                 QTableWidgetItem("      O"))
                        self.tableWidget.item(self.positionY,
                                              self.positionX).setBackground(
                                                  QtGui.QColor(225, 225, 225))
                        self.tableWidget.item(self.positionY - 1,
                                              self.positionX).setBackground(
                                                  QtGui.QColor(255, 0, 0))
                    elif buttonNum == 3:
                        self.tableWidget.setItem(self.positionY,
                                                 self.positionX,
                                                 QTableWidgetItem("      O"))
                        self.tableWidget.setItem(self.positionY,
                                                 self.positionX + 1,
                                                 QTableWidgetItem("      ●"))
                        self.tableWidget.item(self.positionY,
                                              self.positionX).setBackground(
                                                  QtGui.QColor(225, 225, 225))
                        self.tableWidget.item(self.positionY, self.positionX +
                                              1).setBackground(
                                                  QtGui.QColor(255, 0, 0))
                    elif buttonNum == 4:
                        self.tableWidget.setItem(self.positionY,
                                                 self.positionX,
                                                 QTableWidgetItem("      ●"))
                        self.tableWidget.setItem(self.positionY - 1,
                                                 self.positionX,
                                                 QTableWidgetItem("      O"))
                        self.tableWidget.item(self.positionY,
                                              self.positionX).setBackground(
                                                  QtGui.QColor(255, 0, 0))
                        self.tableWidget.item(self.positionY - 1,
                                              self.positionX).setBackground(
                                                  QtGui.QColor(225, 225, 225))
                    elif buttonNum == 5:
                        self.tableWidget.setItem(self.positionY,
                                                 self.positionX,
                                                 QTableWidgetItem("      O"))
                        self.tableWidget.setItem(self.positionY,
                                                 self.positionX + 1,
                                                 QTableWidgetItem("      ●"))
                        self.tableWidget.item(self.positionY,
                                              self.positionX).setBackground(
                                                  QtGui.QColor(255, 0, 0))
                        self.tableWidget.item(self.positionY, self.positionX +
                                              1).setBackground(
                                                  QtGui.QColor(225, 225, 225))
                    elif buttonNum == 6:
                        self.tableWidget.setItem(self.positionY,
                                                 self.positionX,
                                                 QTableWidgetItem("      ●"))
                        self.tableWidget.setItem(self.positionY - 1,
                                                 self.positionX,
                                                 QTableWidgetItem("      O"))
                        self.tableWidget.item(self.positionY - 1,
                                              self.positionX).setBackground(
                                                  QtGui.QColor(255, 0, 0))
                        self.tableWidget.item(self.positionY,
                                              self.positionX).setBackground(
                                                  QtGui.QColor(225, 225, 225))
                    elif buttonNum == 7:
                        self.tableWidget.setItem(self.positionY,
                                                 self.positionX,
                                                 QTableWidgetItem("      ●"))
                        self.tableWidget.setItem(self.positionY,
                                                 self.positionX + 1,
                                                 QTableWidgetItem("      O"))
                        self.tableWidget.item(self.positionY,
                                              self.positionX).setBackground(
                                                  QtGui.QColor(225, 225, 225))
                        self.tableWidget.item(self.positionY, self.positionX +
                                              1).setBackground(
                                                  QtGui.QColor(255, 0, 0))
                    elif buttonNum == 8:
                        self.tableWidget.setItem(self.positionY - 1,
                                                 self.positionX,
                                                 QTableWidgetItem("      ●"))
                        self.tableWidget.setItem(self.positionY,
                                                 self.positionX,
                                                 QTableWidgetItem("      O"))
                        self.tableWidget.item(self.positionY,
                                              self.positionX).setBackground(
                                                  QtGui.QColor(255, 0, 0))
                        self.tableWidget.item(self.positionY - 1,
                                              self.positionX).setBackground(
                                                  QtGui.QColor(225, 225, 225))
                else:
                    self.invalidLable.setText("Invalid Move")
                if count > 24:
                    self.phase = 'Recyle Phase'
                    self.textLable.setText(self.phase)
                if win_id == 1:
                    self.textLable.setText("Player1 Win!")
                if win_id == 2:
                    self.textLable.setText("Player2 Win!")
                if count == 60:
                    self.textLable.setText("Draw!")
            else:
                self.invalidLable.setText("Invalid Player")

    @pyqtSlot()
    def playerChange(self):
        if self.curPlayer == "Player 1":
            self.curPlayer = "Player 2"
        elif self.curPlayer == "Player 2":
            self.curPlayer = "Player 1"
        elif self.curPlayer == "Human Player":
            self.curPlayer = "Computer Player"
        elif self.curPlayer == "Computer Player":
            self.curPlayer = "Human Player"
        if self.choice == Choice.DOT:
            self.choice = Choice.COLOR
        elif self.choice == Choice.COLOR:
            self.choice = Choice.DOT
Ejemplo n.º 16
0
class WheelDlg(ArtisanDialog):
    def __init__(self, parent=None, aw=None):
        super(WheelDlg, self).__init__(parent, aw)
        self.setAttribute(
            Qt.WA_DeleteOnClose,
            False)  # overwrite the ArtisanDialog class default here!!

        rcParams['path.effects'] = []

        self.setModal(True)
        self.setWindowTitle(
            QApplication.translate("Form Caption", "Wheel Graph Editor", None))
        #table
        self.datatable = QTableWidget()
        self.createdatatable()
        #table for labels
        self.labeltable = QTableWidget()

        self.subdialogbuttons = QDialogButtonBox(
            QDialogButtonBox.Close | QDialogButtonBox.RestoreDefaults,
            Qt.Horizontal)
        self.setButtonTranslations(
            self.subdialogbuttons.button(QDialogButtonBox.RestoreDefaults),
            "Restore Defaults",
            QApplication.translate("Button", "Restore Defaults", None))
        self.setButtonTranslations(
            self.subdialogbuttons.button(QDialogButtonBox.Close), "Close",
            QApplication.translate("Button", "Close", None))

        self.subdialogbuttons.rejected.connect(self.closelabels)
        self.subdialogbuttons.button(
            QDialogButtonBox.RestoreDefaults).clicked.connect(
                self.resetlabelparents)

        self.labelwheelx = 0  #index of wheel being edited on labeltable
        #        self.hierarchyButton = QPushButton(QApplication.translate("Button","Reverse Hierarchy",None))
        #        self.hierarchyButton.setToolTip(QApplication.translate("Tooltip","Sets graph hierarchy child->parent instead of parent->child",None))
        #        self.hierarchyButton.clicked.connect(self.aw.qmc.setWheelHierarchy)
        self.labeltable.setVisible(False)
        self.subdialogbuttons.setVisible(False)
        aspectlabel = QLabel(QApplication.translate("Label", "Ratio", None))
        self.aspectSpinBox = QDoubleSpinBox()
        self.aspectSpinBox.setToolTip(
            QApplication.translate("Tooltip", "Aspect Ratio", None))
        self.aspectSpinBox.setRange(0., 2.)
        self.aspectSpinBox.setSingleStep(.1)
        self.aspectSpinBox.setValue(self.aw.qmc.wheelaspect)
        self.aspectSpinBox.valueChanged.connect(self.setaspect)
        txtlabel = QLabel(QApplication.translate("Label", "Text", None))
        txtButtonplus = QPushButton(QApplication.translate(
            "Button", "+", None))
        txtButtonplus.setToolTip(
            QApplication.translate("Tooltip",
                                   "Increase size of text in all the graph",
                                   None))
        txtButtonplus.clicked.connect(self.changetext1)
        txtButtonminus = QPushButton(
            QApplication.translate("Button", "-", None))
        txtButtonminus.setToolTip(
            QApplication.translate("Tooltip",
                                   "Decrease size of text in all the graph",
                                   None))
        txtButtonminus.clicked.connect(self.changetext0)
        edgelabel = QLabel(QApplication.translate("Label", "Edge", None))
        self.edgeSpinBox = QSpinBox()
        self.edgeSpinBox.setToolTip(
            QApplication.translate("Tooltip", "Decorative edge beween wheels",
                                   None))
        self.edgeSpinBox.setRange(0, 5)
        self.edgeSpinBox.setValue(int(self.aw.qmc.wheeledge * 100))
        self.edgeSpinBox.valueChanged.connect(self.setedge)
        linewidthlabel = QLabel(QApplication.translate("Label", "Line", None))
        self.linewidthSpinBox = QSpinBox()
        self.linewidthSpinBox.setToolTip(
            QApplication.translate("Tooltip", "Line thickness", None))
        self.linewidthSpinBox.setRange(0, 20)
        self.linewidthSpinBox.setValue(self.aw.qmc.wheellinewidth)
        self.linewidthSpinBox.valueChanged.connect(self.setlinewidth)
        linecolor = QPushButton(
            QApplication.translate("Button", "Line Color", None))
        linecolor.setToolTip(
            QApplication.translate("Tooltip", "Line color", None))
        linecolor.clicked.connect(self.setlinecolor)
        textcolor = QPushButton(
            QApplication.translate("Button", "Text Color", None))
        textcolor.setToolTip(
            QApplication.translate("Tooltip", "Text color", None))
        textcolor.clicked.connect(self.settextcolor)
        colorlabel = QLabel(
            QApplication.translate("Label", "Color pattern", None))
        self.colorSpinBox = QSpinBox()
        self.colorSpinBox.setToolTip(
            QApplication.translate("Tooltip",
                                   "Apply color pattern to whole graph", None))
        self.colorSpinBox.setRange(0, 255)
        self.colorSpinBox.setValue(self.aw.qmc.wheelcolorpattern)
        self.colorSpinBox.setWrapping(True)
        self.colorSpinBox.valueChanged.connect(self.setcolorpattern)
        addButton = QPushButton(QApplication.translate("Button", "Add", None))
        addButton.setToolTip(
            QApplication.translate("Tooltip", "Add new wheel", None))
        addButton.clicked.connect(self.insertwheel)
        rotateLeftButton = QPushButton(
            QApplication.translate("Button", "<", None))
        rotateLeftButton.setToolTip(
            QApplication.translate("Tooltip",
                                   "Rotate graph 1 degree counter clockwise",
                                   None))
        rotateLeftButton.clicked.connect(self.rotatewheels1)
        rotateRightButton = QPushButton(
            QApplication.translate("Button", ">", None))
        rotateRightButton.setToolTip(
            QApplication.translate("Tooltip",
                                   "Rotate graph 1 degree clockwise", None))
        rotateRightButton.clicked.connect(self.rotatewheels0)

        self.main_buttons = QDialogButtonBox()

        saveButton = QPushButton(
            QApplication.translate("Button", "Save File", None))
        saveButton.clicked.connect(self.fileSave)
        saveButton.setToolTip(
            QApplication.translate("Tooltip", "Save graph to a text file.wg",
                                   None))
        self.main_buttons.addButton(saveButton, QDialogButtonBox.ActionRole)

        saveImgButton = QPushButton(
            QApplication.translate("Button", "Save Img", None))
        saveImgButton.setToolTip(
            QApplication.translate(
                "Tooltip",
                "Save image using current graph size to a png format", None))
        #saveImgButton.clicked.connect(self.aw.resizeImg_0_1) # save as PNG (raster)
        saveImgButton.clicked.connect(
            self.aw.saveVectorGraph_PDF)  # save as PDF (vector)
        self.main_buttons.addButton(saveImgButton, QDialogButtonBox.ActionRole)

        openButton = self.main_buttons.addButton(QDialogButtonBox.Open)
        openButton.setToolTip(
            QApplication.translate("Tooltip", "open wheel graph file", None))
        openButton.clicked.connect(self.loadWheel)

        viewModeButton = self.main_buttons.addButton(QDialogButtonBox.Close)
        viewModeButton.setToolTip(
            QApplication.translate("Tooltip", "Sets Wheel graph to view mode",
                                   None))
        viewModeButton.clicked.connect(self.viewmode)

        if self.aw.locale not in self.aw.qtbase_locales:
            self.main_buttons.button(QDialogButtonBox.Close).setText(
                QApplication.translate("Button", "Close", None))
            self.main_buttons.button(QDialogButtonBox.Open).setText(
                QApplication.translate("Button", "Open", None))

        self.aw.qmc.drawWheel()
        label1layout = QVBoxLayout()
        label2layout = QHBoxLayout()
        label1layout.addWidget(self.labeltable)
        label2layout.addWidget(self.subdialogbuttons)
        label1layout.addLayout(label2layout)
        self.labelGroupLayout = QGroupBox(
            QApplication.translate("GroupBox", "Label Properties", None))
        self.labelGroupLayout.setLayout(label1layout)
        self.labelGroupLayout.setVisible(False)
        buttonlayout = QHBoxLayout()
        buttonlayout.addWidget(self.main_buttons)
        configlayout = QHBoxLayout()
        configlayout.addWidget(colorlabel)
        configlayout.addWidget(self.colorSpinBox)
        configlayout.addWidget(aspectlabel)
        configlayout.addWidget(self.aspectSpinBox)
        configlayout.addWidget(edgelabel)
        configlayout.addWidget(self.edgeSpinBox)
        configlayout.addWidget(linewidthlabel)
        configlayout.addWidget(self.linewidthSpinBox)
        configlayout.addWidget(linecolor)
        configlayout.addWidget(textcolor)
        configlayout.addWidget(txtlabel)
        configlayout.addWidget(txtButtonplus)
        configlayout.addWidget(txtButtonminus)
        controlLayout = QHBoxLayout()
        controlLayout.addWidget(addButton)
        controlLayout.addWidget(rotateLeftButton)
        controlLayout.addWidget(rotateRightButton)
        #        controlLayout.addWidget(self.hierarchyButton)
        mainlayout = QVBoxLayout()
        mainlayout.addWidget(self.datatable)
        mainlayout.addWidget(self.labelGroupLayout)
        mainlayout.addLayout(controlLayout)
        mainlayout.addLayout(configlayout)
        mainlayout.addLayout(buttonlayout)
        self.setLayout(mainlayout)

    def close(self):
        self.accept()

    #creates config table for wheel with index x
    @pyqtSlot(bool)
    def createlabeltable(self, _):
        x = self.aw.findWidgetsRow(self.datatable, self.sender(), 3)
        if x is not None:
            self.createlabeltablex(x)

    def createlabeltablex(self, x):
        self.labelwheelx = x  #wheel being edited
        self.labelGroupLayout.setVisible(True)
        self.labeltable.setVisible(True)
        self.subdialogbuttons.setVisible(True)

        nlabels = len(self.aw.qmc.wheelnames[x])
        # self.labeltable.clear() # this crashes Ubuntu 16.04
        self.labeltable.clearSelection(
        )  # this seems to work also for Ubuntu 16.04

        if nlabels:
            self.labeltable.setRowCount(nlabels)
            self.labeltable.setColumnCount(5)
            self.labeltable.setHorizontalHeaderLabels([
                QApplication.translate("Table", "Label", None),
                QApplication.translate("Table", "Parent", None),
                QApplication.translate("Table", "Width", None),
                QApplication.translate("Table", "Color", None),
                QApplication.translate("Table", "Opaqueness", None)
            ])
            self.labeltable.setAlternatingRowColors(True)
            self.labeltable.setEditTriggers(QTableWidget.NoEditTriggers)
            self.labeltable.setSelectionBehavior(QTableWidget.SelectRows)
            self.labeltable.setSelectionMode(QTableWidget.SingleSelection)
            self.labeltable.setShowGrid(True)
            self.labeltable.verticalHeader().setSectionResizeMode(2)
            #populate table
            for i in range(nlabels):
                label = QTableWidgetItem(self.aw.qmc.wheelnames[x][i])
                parentComboBox = QComboBox()
                if x > 0:
                    items = self.aw.qmc.wheelnames[x - 1][:]
                    items.insert(0, "")
                    parentComboBox.addItems(items)
                    if self.aw.qmc.wheellabelparent[x][i]:
                        parentComboBox.setCurrentIndex(
                            self.aw.qmc.wheellabelparent[x][i])
                else:
                    parentComboBox.addItems([])
                parentComboBox.currentIndexChanged.connect(self.setwheelchild)
                labelwidthSpinBox = QDoubleSpinBox()
                labelwidthSpinBox.setRange(1., 100.)
                labelwidthSpinBox.setValue(self.aw.qmc.segmentlengths[x][i])
                labelwidthSpinBox.setSuffix("%")
                labelwidthSpinBox.valueChanged.connect(self.setlabelwidth)
                colorButton = QPushButton("Set Color")
                colorButton.clicked.connect(self.setsegmentcolor)
                alphaSpinBox = QSpinBox()
                alphaSpinBox.setRange(0, 10)
                alphaSpinBox.setValue(int(self.aw.qmc.segmentsalpha[x][i] *
                                          10))
                alphaSpinBox.valueChanged.connect(self.setsegmentalpha)
                #add widgets to the table
                self.labeltable.setItem(i, 0, label)
                self.labeltable.setCellWidget(i, 1, parentComboBox)
                self.labeltable.setCellWidget(i, 2, labelwidthSpinBox)
                self.labeltable.setCellWidget(i, 3, colorButton)
                self.labeltable.setCellWidget(i, 4, alphaSpinBox)

    @pyqtSlot(bool)
    def setsegmentcolor(self, _):
        i = self.aw.findWidgetsRow(self.labeltable, self.sender(), 3)
        if i is not None:
            x = self.labelwheelx
            colorf = self.aw.colordialog(QColor(self.aw.qmc.wheelcolor[x][i]))
            if colorf.isValid():
                colorname = str(colorf.name())
                self.aw.qmc.wheelcolor[x][
                    i] = colorname  #add new color to label
                self.createdatatable(
                )  #update main table with label names (label::color)
                self.aw.qmc.drawWheel()

    #sets a uniform color in wheel
    @pyqtSlot(bool)
    def setwheelcolor(self, _):
        x = self.aw.findWidgetsRow(self.datatable, self.sender(), 8)
        if x is not None:
            colorf = self.aw.colordialog(QColor(self.aw.qmc.wheelcolor[x][0]))
            if colorf.isValid():
                colorname = str(colorf.name())
                for i in range(len(self.aw.qmc.wheelcolor[x])):
                    self.aw.qmc.wheelcolor[x][i] = colorname
            self.createdatatable()
            self.aw.qmc.drawWheel()

    #sets color pattern (many colors) in wheel
    @pyqtSlot(int)
    def setwheelcolorpattern(self, _):
        x = self.aw.findWidgetsRow(self.datatable, self.sender(), 9)
        if x is not None:
            wsb = self.datatable.cellWidget(x, 9)
            wpattern = wsb.value()
            wlen = len(self.aw.qmc.wheelcolor[x])
            for i in range(wlen):
                color = QColor()
                color.setHsv((360 / wlen) * i * wpattern, 255, 255, 255)
                self.aw.qmc.wheelcolor[x][i] = str(color.name())
            self.aw.qmc.drawWheel()

    #sets color pattern (many colors) for whole graph
    @pyqtSlot(int)
    def setcolorpattern(self, _):
        self.aw.qmc.wheelcolorpattern = self.colorSpinBox.value()
        if self.aw.qmc.wheelcolorpattern:
            for x in range(len(self.aw.qmc.wheelcolor)):
                wlen = len(self.aw.qmc.wheelcolor[x])
                for i in range(wlen):
                    color = QColor()
                    color.setHsv(
                        (360 / wlen) * i * self.aw.qmc.wheelcolorpattern, 255,
                        255, 255)
                    self.aw.qmc.wheelcolor[x][i] = str(color.name())
            self.aw.qmc.drawWheel()

    @pyqtSlot(int)
    def setsegmentalpha(self, z):
        u = self.aw.findWidgetsRow(self.labeltable, self.sender(), 4)
        if u is not None:
            x = self.labelwheelx
            self.aw.qmc.segmentsalpha[x][u] = float(z / 10.)
            self.aw.qmc.drawWheel()

    #rotate whole graph
    @pyqtSlot(bool)
    def rotatewheels1(self, _):
        for i in range(len(self.aw.qmc.startangle)):
            self.aw.qmc.startangle[i] += 1
        self.aw.qmc.drawWheel()

    @pyqtSlot(bool)
    def rotatewheels0(self, _):
        for i in range(len(self.aw.qmc.startangle)):
            self.aw.qmc.startangle[i] -= 1
        self.aw.qmc.drawWheel()

    #z= new width%, x= wheel number index, u = index of segment in the wheel
    @pyqtSlot(float)
    def setlabelwidth(self, z):
        u = self.aw.findWidgetsRow(self.labeltable, self.sender(), 2)
        if u is not None:
            x = self.labelwheelx
            newwidth = z
            oldwidth = self.aw.qmc.segmentlengths[x][u]
            diff = newwidth - oldwidth
            l = len(self.aw.qmc.segmentlengths[x])
            for i in range(l):
                if i != u:
                    if diff > 0:
                        self.aw.qmc.segmentlengths[x][i] -= abs(
                            float(diff)) / (l - 1)
                    else:
                        self.aw.qmc.segmentlengths[x][i] += abs(
                            float(diff)) / (l - 1)
            self.aw.qmc.segmentlengths[x][u] = newwidth
            self.aw.qmc.drawWheel()

    #input: z = index of parent in previus wheel; x = wheel number; i = index of element in wheel
    @pyqtSlot(int)
    def setwheelchild(self, z):
        i = self.aw.findWidgetsRow(self.labeltable, self.sender(), 1)
        if i is not None:
            self.aw.qmc.setwheelchild(z, self.labelwheelx, i)
            self.aw.qmc.drawWheel()
            self.createdatatable()  #update data table

    #deletes parent-child relation in a wheel. It obtains the wheel index by self.labelwheelx
    @pyqtSlot(bool)
    def resetlabelparents(self, _):
        x = self.labelwheelx
        nsegments = len(self.aw.qmc.wheellabelparent[x])
        for i in range(nsegments):
            self.aw.qmc.wheellabelparent[x][i] = 0
            self.aw.qmc.segmentlengths[x][i] = 100. / nsegments
        self.aw.qmc.drawWheel()
        self.createlabeltablex(x)

    @pyqtSlot(float)
    def setaspect(self, _):
        self.aw.qmc.wheelaspect = self.aspectSpinBox.value()
        self.aw.qmc.drawWheel()

    #adjust decorative edge between wheels
    @pyqtSlot(int)
    def setedge(self):
        self.aw.qmc.wheeledge = float(self.edgeSpinBox.value()) / 100.
        self.aw.qmc.drawWheel()

    #adjusts line thickness
    @pyqtSlot(int)
    def setlinewidth(self, _):
        self.aw.qmc.wheellinewidth = self.linewidthSpinBox.value()
        self.aw.qmc.drawWheel()

    #sets line color
    @pyqtSlot(bool)
    def setlinecolor(self, _):
        colorf = self.aw.colordialog(QColor(self.aw.qmc.wheellinecolor))
        if colorf.isValid():
            colorname = str(colorf.name())
            #self.aw.qmc.wheellinealpha = colorf.alphaF()
            self.aw.qmc.wheellinecolor = colorname  #add new color to label
            self.aw.qmc.drawWheel()

    #sets text color
    @pyqtSlot(bool)
    def settextcolor(self, _):
        colorf = self.aw.colordialog(QColor(self.aw.qmc.wheeltextcolor))
        if colorf.isValid():
            colorname = str(colorf.name())
            #self.aw.qmc.wheeltextalpha = colorf.alphaF()
            self.aw.qmc.wheeltextcolor = colorname  #add new color to label
            self.aw.qmc.drawWheel()

    #makes not visible the wheel config table
    @pyqtSlot()
    def closelabels(self):
        self.labelGroupLayout.setVisible(False)
        self.labeltable.setVisible(False)
        #        self.labelCloseButton.setVisible(False)
        #        self.labelResetButton.setVisible(False)
        self.subdialogbuttons.setVisible(False)

    #creates graph table
    def createdatatable(self):
        ndata = len(self.aw.qmc.wheelnames)

        # self.datatable.clear() # this crashes Ubuntu 16.04
        #        if ndata != 0:
        #            self.datatable.clearContents() # this crashes Ubuntu 16.04 if device table is empty and also sometimes else
        self.datatable.clearSelection(
        )  # this seems to work also for Ubuntu 16.04

        self.datatable.setRowCount(ndata)
        self.datatable.setColumnCount(10)
        self.datatable.setHorizontalHeaderLabels([
            QApplication.translate("Table", "Delete Wheel", None),
            QApplication.translate("Table", "Edit Labels", None),
            QApplication.translate("Table", "Update Labels", None),
            QApplication.translate("Table", "Properties", None),
            QApplication.translate("Table", "Radius", None),
            QApplication.translate("Table", "Starting angle", None),
            QApplication.translate("Table", "Projection", None),
            QApplication.translate("Table", "Text Size", None),
            QApplication.translate("Table", "Color", None),
            QApplication.translate("Table", "Color Pattern", None)
        ])
        self.datatable.setAlternatingRowColors(True)
        self.datatable.setEditTriggers(QTableWidget.NoEditTriggers)
        self.datatable.setSelectionBehavior(QTableWidget.SelectRows)
        self.datatable.setSelectionMode(QTableWidget.SingleSelection)
        self.datatable.setShowGrid(True)
        self.datatable.verticalHeader().setSectionResizeMode(2)
        #populate table
        for i in range(ndata):
            delButton = QPushButton(
                QApplication.translate("Button", "Delete", None))
            delButton.clicked.connect(self.popwheel)
            labelsedit = QLineEdit(str(",".join(self.aw.qmc.wheelnames[i])))
            updateButton = QPushButton(
                QApplication.translate("Button", "Update", None))
            updateButton.clicked.connect(self.updatelabels)
            setButton = QPushButton(
                QApplication.translate("Button", "Select", None))
            setButton.clicked.connect(self.createlabeltable)
            widthSpinBox = QDoubleSpinBox()
            widthSpinBox.setRange(1., 100.)
            widthSpinBox.setValue(self.aw.qmc.wradii[i])
            widthSpinBox.setSuffix("%")
            widthSpinBox.valueChanged.connect(self.setwidth)
            angleSpinBox = QSpinBox()
            angleSpinBox.setSuffix(QApplication.translate(
                "Label", " dg", None))
            angleSpinBox.setRange(0, 359)
            angleSpinBox.setWrapping(True)
            angleSpinBox.setValue(self.aw.qmc.startangle[i])
            angleSpinBox.valueChanged.connect(self.setangle)
            projectionComboBox = QComboBox()
            projectionComboBox.addItems([
                QApplication.translate("ComboBox", "Flat", None),
                QApplication.translate("ComboBox", "Perpendicular", None),
                QApplication.translate("ComboBox", "Radial", None)
            ])
            projectionComboBox.setCurrentIndex(self.aw.qmc.projection[i])
            projectionComboBox.currentIndexChanged.connect(self.setprojection)
            txtSpinBox = QSpinBox()
            txtSpinBox.setRange(1, 30)
            txtSpinBox.setValue(self.aw.qmc.wheeltextsize[i])
            txtSpinBox.valueChanged.connect(self.setTextsizeX)
            colorButton = QPushButton(
                QApplication.translate("Button", "Set Color", None))
            colorButton.clicked.connect(self.setwheelcolor)
            colorSpinBox = QSpinBox()
            colorSpinBox.setRange(0, 255)
            colorSpinBox.setWrapping(True)
            colorSpinBox.valueChanged.connect(self.setwheelcolorpattern)
            #add widgets to the table
            self.datatable.setCellWidget(i, 0, delButton)
            self.datatable.setCellWidget(i, 1, labelsedit)
            self.datatable.setCellWidget(i, 2, updateButton)
            self.datatable.setCellWidget(i, 3, setButton)
            self.datatable.setCellWidget(i, 4, widthSpinBox)
            self.datatable.setCellWidget(i, 5, angleSpinBox)
            self.datatable.setCellWidget(i, 6, projectionComboBox)
            self.datatable.setCellWidget(i, 7, txtSpinBox)
            self.datatable.setCellWidget(i, 8, colorButton)
            self.datatable.setCellWidget(i, 9, colorSpinBox)

    #reads label edit box for wheel with index x, and updates labels
    @pyqtSlot(bool)
    def updatelabels(self, _):
        x = self.aw.findWidgetsRow(self.datatable, self.sender(), 2)
        if x is not None:
            labelsedit = self.datatable.cellWidget(x, 1)
            text = str(labelsedit.text())
            if "\\n" in text:  #make multiple line text if "\n" found in label string
                parts = text.split("\\n")
                text = chr(10).join(parts)
            newwheellabels = text.strip().split(",")
            newnlabels = len(newwheellabels)
            oldnlabels = len(self.aw.qmc.wheelnames[x])
            #adjust segments len and alpha for each wheel if number of labels changed
            if oldnlabels != newnlabels:
                self.aw.qmc.segmentlengths[x] = [100. / newnlabels
                                                 ] * newnlabels
                self.aw.qmc.segmentsalpha[x] = [.3] * newnlabels
                self.aw.qmc.wheellabelparent[x] = [0] * newnlabels
                self.aw.qmc.wheelcolor[x] = [self.aw.qmc.wheelcolor[x][0]
                                             ] * newnlabels
            self.aw.qmc.wheelnames[x] = newwheellabels[:]
            self.aw.qmc.drawWheel()

    #sets radii for a wheel
    @pyqtSlot(float)
    def setwidth(self, _):
        x = self.aw.findWidgetsRow(self.datatable, self.sender(), 4)
        if x is not None:
            widthSpinBox = self.datatable.cellWidget(x, 4)
            newwidth = widthSpinBox.value()
            oldwidth = self.aw.qmc.wradii[x]
            diff = newwidth - oldwidth
            l = len(self.aw.qmc.wradii)
            for i in range(l):
                if i != x:
                    if diff > 0:
                        self.aw.qmc.wradii[i] -= abs(float(diff)) / (l - 1)
                    else:
                        self.aw.qmc.wradii[i] += abs(float(diff)) / (l - 1)
            self.aw.qmc.wradii[x] = newwidth
            #Need 100.0% coverage. Correct for numerical floating point rounding errors:
            count = 0.
            for i in range(len(self.aw.qmc.wradii)):
                count += self.aw.qmc.wradii[i]
            diff = 100. - count
            if diff != 0.:
                if diff > 0.000:  #if count smaller
                    self.aw.qmc.wradii[x] += abs(diff)
                else:
                    self.aw.qmc.wradii[x] -= abs(diff)
            self.aw.qmc.drawWheel()

    #sets starting angle (rotation) for a wheel with index x
    @pyqtSlot(int)
    def setangle(self, _):
        x = self.aw.findWidgetsRow(self.datatable, self.sender(), 5)
        if x is not None:
            angleSpinBox = self.datatable.cellWidget(x, 5)
            self.aw.qmc.startangle[x] = angleSpinBox.value()
            self.aw.qmc.drawWheel()

    #sets text projection style for a wheel with index x
    @pyqtSlot(int)
    def setprojection(self, _):
        x = self.aw.findWidgetsRow(self.datatable, self.sender(), 6)
        if x is not None:
            projectionComboBox = self.datatable.cellWidget(x, 6)
            self.aw.qmc.projection[x] = projectionComboBox.currentIndex()
            self.aw.qmc.drawWheel()

    #chages text size in wheel with index x
    @pyqtSlot(int)
    def setTextsizeX(self, _):
        x = self.aw.findWidgetsRow(self.datatable, self.sender(), 7)
        if x is not None:
            txtSpinBox = self.datatable.cellWidget(x, 7)
            self.aw.qmc.wheeltextsize[x] = txtSpinBox.value()
            self.aw.qmc.drawWheel()

    #changes size of text in whole graph
    @pyqtSlot(bool)
    def changetext1(self, _):
        for i in range(len(self.aw.qmc.wheeltextsize)):
            self.aw.qmc.wheeltextsize[i] += 1
        self.aw.qmc.drawWheel()

    @pyqtSlot(bool)
    def changetext0(self, _):
        for i in range(len(self.aw.qmc.wheeltextsize)):
            self.aw.qmc.wheeltextsize[i] -= 1
        self.aw.qmc.drawWheel()

    #adds new top wheel
    @pyqtSlot(bool)
    def insertwheel(self, _):
        ndata = len(self.aw.qmc.wradii)
        if ndata:
            count = 0.
            for i in range(ndata):
                self.aw.qmc.wradii[i] = 100. / (ndata + 1)
                count += self.aw.qmc.wradii[i]
            self.aw.qmc.wradii.append(100. - count)
        else:
            self.aw.qmc.wradii.append(100.)
        #find number of labels of most outer wheel (last)
        if len(self.aw.qmc.wheelnames):
            nwheels = len(self.aw.qmc.wheelnames[-1])
        else:  #if no wheels
            nwheels = 3
        wn, sl, sa, wlp, co = [], [], [], [], []
        for i in range(nwheels + 1):
            wn.append("W%i %i" % (len(self.aw.qmc.wheelnames) + 1, i + 1))
            sl.append(100. / (nwheels + 1))
            sa.append(.3)
            wlp.append(0)
            color = QColor()
            color.setHsv((360 / (nwheels + 1)) * i, 255, 255, 255)
            co.append(str(color.name()))
        self.aw.qmc.wheelnames.append(wn)
        self.aw.qmc.segmentlengths.append(sl)
        self.aw.qmc.segmentsalpha.append(sa)
        self.aw.qmc.wheellabelparent.append(wlp)
        self.aw.qmc.startangle.append(0)
        self.aw.qmc.projection.append(2)
        self.aw.qmc.wheeltextsize.append(10)
        self.aw.qmc.wheelcolor.append(co)
        self.createdatatable()
        self.aw.qmc.drawWheel()

    #deletes wheel with index x
    @pyqtSlot(bool)
    def popwheel(self, _):
        x = self.aw.findWidgetsRow(self.datatable, self.sender(), 0)
        if x is not None:
            #correct raius of other wheels (to use 100% coverage)
            width = self.aw.qmc.wradii[x]
            l = len(self.aw.qmc.wradii)
            for i in range(l):
                if i != x:
                    self.aw.qmc.wradii[i] += float(width) / (l - 1)
            self.aw.qmc.wheelnames.pop(x)
            self.aw.qmc.wradii.pop(x)
            self.aw.qmc.startangle.pop(x)
            self.aw.qmc.projection.pop(x)
            self.aw.qmc.wheeltextsize.pop(x)
            self.aw.qmc.segmentlengths.pop(x)
            self.aw.qmc.segmentsalpha.pop(x)
            self.aw.qmc.wheellabelparent.pop(x)
            self.aw.qmc.wheelcolor.pop(x)
            self.createdatatable()
            self.aw.qmc.drawWheel()

    @pyqtSlot(bool)
    def fileSave(self, _):
        try:
            filename = self.aw.ArtisanSaveFileDialog(
                msg=QApplication.translate("Message", "Save Wheel graph",
                                           None),
                ext="*.wg")
            if filename:
                #write
                self.aw.serialize(filename, self.aw.getWheelGraph())
                self.aw.sendmessage(
                    QApplication.translate("Message", "Wheel Graph saved",
                                           None))
        except IOError as e:
            self.aw.qmc.adderror(
                (QApplication.translate("Error Message", "IO Error:", None) +
                 " Wheel graph filesave(): {0}").format(str(e)))
            return

    @pyqtSlot(bool)
    def loadWheel(self, _):
        filename = self.aw.ArtisanOpenFileDialog(msg=QApplication.translate(
            "Message", "Open Wheel Graph", None),
                                                 path=self.aw.getDefaultPath(),
                                                 ext="*.wg")
        if filename:
            self.aw.loadWheel(filename)
            self.aw.wheelpath = filename
            self.createdatatable()
            self.aw.qmc.drawWheel()

    def closeEvent(self, _):
        self.viewmode(False)

    @pyqtSlot(bool)
    def viewmode(self, _):
        self.close()
        self.aw.qmc.connectWheel()
        self.aw.qmc.drawWheel()
Ejemplo n.º 17
0
class backgroundDlg(ArtisanResizeablDialog):
    def __init__(self, parent = None, aw = None, activeTab = 0):
        super(backgroundDlg,self).__init__(parent, aw)
        self.setWindowTitle(QApplication.translate("Form Caption","Profile Background", None))
        self.setModal(True)
        
        settings = QSettings()
        if settings.contains("BackgroundGeometry"):
            self.restoreGeometry(settings.value("BackgroundGeometry"))
        
        #TAB 1
        self.pathedit = QLineEdit(self.aw.qmc.backgroundpath)
        self.pathedit.setStyleSheet("background-color:'lightgrey';")
        self.pathedit.setReadOnly(True)
        self.pathedit.setFocusPolicy(Qt.NoFocus)
        self.filename = ""
        self.backgroundCheck = QCheckBox(QApplication.translate("CheckBox","Show", None))
        self.backgroundDetails = QCheckBox(QApplication.translate("CheckBox","Annotations", None))
        self.backgroundeventsflag = QCheckBox(QApplication.translate("CheckBox","Events", None))
        self.backgroundDeltaETflag = QCheckBox()
        backgroundDeltaETflagLabel = QLabel(deltaLabelPrefix + QApplication.translate("Label","ET", None))
        self.backgroundDeltaBTflag = QCheckBox()
        backgroundDeltaBTflagLabel = QLabel(deltaLabelPrefix + QApplication.translate("Label","BT", None))
        self.backgroundETflag = QCheckBox(QApplication.translate("CheckBox","ET", None))
        self.backgroundBTflag = QCheckBox(QApplication.translate("CheckBox","BT", None))
        self.backgroundFullflag = QCheckBox(QApplication.translate("CheckBox","Show Full", None))
        self.backgroundCheck.setChecked(self.aw.qmc.background)
        self.backgroundDetails.setChecked(self.aw.qmc.backgroundDetails)
        self.backgroundeventsflag.setChecked(self.aw.qmc.backgroundeventsflag)
        self.backgroundDeltaETflag.setChecked(self.aw.qmc.DeltaETBflag)
        self.backgroundDeltaBTflag.setChecked(self.aw.qmc.DeltaBTBflag)
        self.backgroundETflag.setChecked(self.aw.qmc.backgroundETcurve)
        self.backgroundBTflag.setChecked(self.aw.qmc.backgroundBTcurve)
        self.backgroundFullflag.setChecked(self.aw.qmc.backgroundShowFullflag)
        loadButton = QPushButton(QApplication.translate("Button","Load", None))
        loadButton.setFocusPolicy(Qt.NoFocus)
        delButton = QPushButton(QApplication.translate("Button","Delete", None))
        delButton.setFocusPolicy(Qt.NoFocus)

        # connect the ArtisanDialog standard OK/Cancel buttons
        self.dialogbuttons.accepted.connect(self.accept)
        self.dialogbuttons.removeButton(self.dialogbuttons.button(QDialogButtonBox.Cancel))
        
        alignButton = QPushButton(QApplication.translate("Button","Align", None))
        alignButton.setFocusPolicy(Qt.NoFocus)
        self.alignComboBox = QComboBox()
        alignnames = [
            QApplication.translate("Label","CHARGE", None),
            QApplication.translate("Label","DRY", None),
            QApplication.translate("Label","FCs", None),
            QApplication.translate("Label","FCe", None),
            QApplication.translate("Label","SCs", None),
            QApplication.translate("Label","SCe", None),
            QApplication.translate("Label","DROP", None),
            QApplication.translate("Label","ALL", None),
            ]
        self.alignComboBox.addItems(alignnames)
        self.alignComboBox.setCurrentIndex(self.aw.qmc.alignEvent)
        self.alignComboBox.currentIndexChanged.connect(self.changeAlignEventidx)
        loadButton.clicked.connect(self.load)
        alignButton.clicked.connect(self.timealign)
        
        self.speedSpinBox = QSpinBox()
        self.speedSpinBox.setAlignment(Qt.AlignRight)
        self.speedSpinBox.setRange(1,90)
        self.speedSpinBox.setSingleStep(5)
        self.speedSpinBox.setValue(self.aw.qmc.backgroundmovespeed)
        
        curvenames = [""] # first entry is the empty one, no extra curve displayed
        for i in range(min(len(self.aw.qmc.extraname1B),len(self.aw.qmc.extraname2B),len(self.aw.qmc.extratimexB))):
            curvenames.append("B" + str(2*i+3) + ": " + self.aw.qmc.extraname1B[i])
            curvenames.append("B" + str(2*i+4) + ": " + self.aw.qmc.extraname2B[i])

        self.xtcurvelabel = QLabel(QApplication.translate("Label", "Extra 1",None))
        self.xtcurveComboBox = QComboBox()
        self.xtcurveComboBox.setToolTip(QApplication.translate("Tooltip","For loaded backgrounds with extra devices only",None))
        self.xtcurveComboBox.setMinimumWidth(120)
        self.xtcurveComboBox.addItems(curvenames)
        if self.aw.qmc.xtcurveidx < len(curvenames):
            self.xtcurveComboBox.setCurrentIndex(self.aw.qmc.xtcurveidx)
        self.xtcurveComboBox.currentIndexChanged.connect(self.changeXTcurveidx)

        self.ytcurvelabel = QLabel(QApplication.translate("Label", "Extra 2",None))
        self.ytcurveComboBox = QComboBox()
        self.ytcurveComboBox.setToolTip(QApplication.translate("Tooltip","For loaded backgrounds with extra devices only",None))
        self.ytcurveComboBox.setMinimumWidth(120)
        self.ytcurveComboBox.addItems(curvenames)
        if self.aw.qmc.ytcurveidx < len(curvenames):
            self.ytcurveComboBox.setCurrentIndex(self.aw.qmc.ytcurveidx)
        self.ytcurveComboBox.currentIndexChanged.connect(self.changeYTcurveidx)
        
        self.upButton = QPushButton(QApplication.translate("Button","Up",None))
        self.upButton.setFocusPolicy(Qt.NoFocus)
        self.downButton = QPushButton(QApplication.translate("Button","Down",None))
        self.downButton.setFocusPolicy(Qt.NoFocus)
        self.leftButton = QPushButton(QApplication.translate("Button","Left",None))
        self.leftButton.setFocusPolicy(Qt.NoFocus)
        self.rightButton = QPushButton(QApplication.translate("Button","Right",None))
        self.rightButton.setFocusPolicy(Qt.NoFocus)
        self.backgroundCheck.clicked.connect(self.readChecks)
        self.backgroundDetails.clicked.connect(self.readChecks)
        self.backgroundeventsflag.clicked.connect(self.readChecks)
        self.backgroundDeltaETflag.clicked.connect(self.readChecks)
        self.backgroundDeltaBTflag.clicked.connect(self.readChecks)
        self.backgroundETflag.clicked.connect(self.readChecks)
        self.backgroundBTflag.clicked.connect(self.readChecks)
        self.backgroundFullflag.clicked.connect(self.readChecks)
        delButton.clicked.connect(self.delete)
        self.upButton.clicked.connect(self.moveUp)
        self.downButton.clicked.connect(self.moveDown)
        self.leftButton.clicked.connect(self.moveLeft)
        self.rightButton.clicked.connect(self.moveRight)
        #TAB 2 EVENTS
        #table for showing events
        self.eventtable = QTableWidget()
        self.eventtable.setTabKeyNavigation(True)
        self.createEventTable()
        self.copyeventTableButton = QPushButton(QApplication.translate("Button", "Copy Table",None))
        self.copyeventTableButton.setToolTip(QApplication.translate("Tooltip","Copy table to clipboard, OPTION or ALT click for tabular text",None))
        self.copyeventTableButton.setFocusPolicy(Qt.NoFocus)
        self.copyeventTableButton.setMaximumSize(self.copyeventTableButton.sizeHint())
        self.copyeventTableButton.setMinimumSize(self.copyeventTableButton.minimumSizeHint())
        self.copyeventTableButton.clicked.connect(self.copyEventTabletoClipboard)
        #TAB 3 DATA
        #table for showing data
        self.datatable = QTableWidget()
        self.datatable.setTabKeyNavigation(True)
        self.createDataTable()
        self.copydataTableButton = QPushButton(QApplication.translate("Button", "Copy Table",None))
        self.copydataTableButton.setToolTip(QApplication.translate("Tooltip","Copy table to clipboard, OPTION or ALT click for tabular text",None))
        self.copydataTableButton.setFocusPolicy(Qt.NoFocus)
        self.copydataTableButton.setMaximumSize(self.copydataTableButton.sizeHint())
        self.copydataTableButton.setMinimumSize(self.copydataTableButton.minimumSizeHint())
        self.copydataTableButton.clicked.connect(self.copyDataTabletoClipboard)
        #TAB 4
        self.replayComboBox = QComboBox()
        replayVariants = [
            QApplication.translate("Label","by time", None),
            QApplication.translate("Label","by BT", None),
            QApplication.translate("Label","by ET", None),
            ]
        self.replayComboBox.addItems(replayVariants)
        self.replayComboBox.setCurrentIndex(self.aw.qmc.replayType)
        self.replayComboBox.currentIndexChanged.connect(self.changeReplayTypeidx)
                
        self.backgroundReproduce = QCheckBox(QApplication.translate("CheckBox","Playback Aid",None))
        self.backgroundReproduce.setChecked(self.aw.qmc.backgroundReproduce)
        self.backgroundReproduce.setFocusPolicy(Qt.NoFocus)
        self.backgroundReproduce.stateChanged.connect(self.setreproduce)
        self.backgroundReproduceBeep = QCheckBox(QApplication.translate("CheckBox","Beep",None))
        self.backgroundReproduceBeep.setChecked(self.aw.qmc.backgroundReproduce)
        self.backgroundReproduceBeep.setFocusPolicy(Qt.NoFocus)
        self.backgroundReproduceBeep.stateChanged.connect(self.setreproduceBeep)
        self.backgroundPlaybackEvents = QCheckBox(QApplication.translate("CheckBox","Playback Events",None))
        self.backgroundPlaybackEvents.setChecked(self.aw.qmc.backgroundPlaybackEvents)
        self.backgroundPlaybackEvents.setFocusPolicy(Qt.NoFocus)
        self.backgroundPlaybackEvents.stateChanged.connect(self.setplaybackevent)
        self.backgroundPlaybackDROP = QCheckBox(QApplication.translate("CheckBox","Playback DROP",None))
        self.backgroundPlaybackDROP.setChecked(self.aw.qmc.backgroundPlaybackDROP)
        self.backgroundPlaybackDROP.setFocusPolicy(Qt.NoFocus)
        self.backgroundPlaybackDROP.stateChanged.connect(self.setplaybackdrop)
        etimelabel =QLabel(QApplication.translate("Label", "Text Warning",None))
        etimeunit =QLabel(QApplication.translate("Label", "sec",None))
        self.etimeSpinBox = QSpinBox()
        self.etimeSpinBox.setRange(1,60)
        self.etimeSpinBox.setValue(self.aw.qmc.detectBackgroundEventTime)
        self.etimeSpinBox.valueChanged.connect(self.setreproduce)
        #LAYOUT MANAGERS
        movelayout = QGridLayout()
        movelayout.addWidget(self.upButton,0,1)
        movelayout.addWidget(self.leftButton,1,0)
        movelayout.addWidget(self.speedSpinBox,1,1)
        movelayout.addWidget(self.rightButton,1,2)
        movelayout.addWidget(self.downButton,2,1)
        movelayout.setSpacing(20)
        checkslayout1 = QHBoxLayout()
        checkslayout1.addStretch()
        checkslayout1.addWidget(self.backgroundCheck)
        checkslayout1.addSpacing(5)
        checkslayout1.addWidget(self.backgroundDetails)
        checkslayout1.addSpacing(5)
        checkslayout1.addWidget(self.backgroundeventsflag)
        checkslayout1.addSpacing(5)
        checkslayout1.addWidget(self.backgroundETflag)
        checkslayout1.addSpacing(5)
        checkslayout1.addWidget(self.backgroundBTflag)
        checkslayout1.addSpacing(5)
        checkslayout1.addWidget(self.backgroundDeltaETflag)
        checkslayout1.addSpacing(3)
        checkslayout1.addWidget(backgroundDeltaETflagLabel)
        checkslayout1.addSpacing(5)
        checkslayout1.addWidget(self.backgroundDeltaBTflag)
        checkslayout1.addSpacing(3)
        checkslayout1.addWidget(backgroundDeltaBTflagLabel)
        checkslayout1.addSpacing(5)
        checkslayout1.addWidget(self.backgroundFullflag)
        checkslayout1.addStretch()
        layout = QGridLayout()
        layoutBoxedH = QHBoxLayout()
        layoutBoxedH.addStretch()
        layoutBoxedH.addLayout(movelayout)
        layoutBoxedH.addLayout(layout)
        layoutBoxedH.addStretch()
        layoutBoxed = QVBoxLayout()
        layoutBoxed.addStretch()
        layoutBoxed.addLayout(checkslayout1)
        layoutBoxed.addStretch()
        layoutBoxed.addLayout(layoutBoxedH)
        layoutBoxed.addStretch()
        alignButtonBoxed = QHBoxLayout()
        alignButtonBoxed.addWidget(self.xtcurvelabel)
        alignButtonBoxed.addWidget(self.xtcurveComboBox)
        alignButtonBoxed.addSpacing(10)
        alignButtonBoxed.addWidget(self.ytcurvelabel)
        alignButtonBoxed.addWidget(self.ytcurveComboBox)
        alignButtonBoxed.addStretch()
        alignButtonBoxed.addWidget(alignButton)
        alignButtonBoxed.addWidget(self.alignComboBox)
        tab4content = QHBoxLayout()
        tab4content.addWidget(self.backgroundReproduce)
        tab4content.addSpacing(10)
        tab4content.addWidget(self.backgroundReproduceBeep)
        tab4content.addSpacing(10)
        tab4content.addWidget(etimelabel)
        tab4content.addWidget(self.etimeSpinBox)
        tab4content.addWidget(etimeunit)
        tab4content.addSpacing(20)
        tab4content.addStretch()
        tab4content.addWidget(self.backgroundPlaybackEvents)
        tab4content.addSpacing(10)
        tab4content.addWidget(self.backgroundPlaybackDROP)
        tab4content.addSpacing(10)
        tab4content.addWidget(self.replayComboBox)
        tab1layout = QVBoxLayout()
        tab1layout.addLayout(layoutBoxed)
#        tab1layout.addStretch()
        tab1layout.addLayout(alignButtonBoxed)
        tab1layout.addLayout(tab4content)
        tab1layout.setContentsMargins(5, 0, 5, 0) # left, top, right, bottom
        eventbuttonLayout = QHBoxLayout()
        eventbuttonLayout.addWidget(self.copyeventTableButton)
        eventbuttonLayout.addStretch()
        tab2layout = QVBoxLayout()
        tab2layout.addWidget(self.eventtable)
        tab2layout.addLayout(eventbuttonLayout)
        tab2layout.setContentsMargins(5, 0, 5, 0) # left, top, right, bottom
        databuttonLayout = QHBoxLayout()
        databuttonLayout.addWidget(self.copydataTableButton)
        databuttonLayout.addStretch()
        tab3layout = QVBoxLayout()
        tab3layout.addWidget(self.datatable)
        tab3layout.addLayout(databuttonLayout)
        tab3layout.setContentsMargins(5, 0, 5, 0) # left, top, right, bottom
        #tab layout
        tab1layout.setSpacing(5)
        self.TabWidget = QTabWidget()
        C1Widget = QWidget()
        C1Widget.setLayout(tab1layout)
        self.TabWidget.addTab(C1Widget,QApplication.translate("Tab","Config",None))
        C2Widget = QWidget()
        C2Widget.setLayout(tab2layout)
        self.TabWidget.addTab(C2Widget,QApplication.translate("Tab","Events",None))
        C3Widget = QWidget()
        C3Widget.setLayout(tab3layout)
        self.TabWidget.addTab(C3Widget,QApplication.translate("Tab","Data",None))
        buttonLayout = QHBoxLayout()
        buttonLayout.addWidget(loadButton)
        buttonLayout.addWidget(delButton)
        buttonLayout.addStretch()
        buttonLayout.addWidget(self.dialogbuttons)
        mainLayout = QVBoxLayout()
        mainLayout.addWidget(self.TabWidget) 
        mainLayout.addWidget(self.pathedit)
        mainLayout.addLayout(buttonLayout)
        mainLayout.setContentsMargins(5, 10, 5, 5) # left, top, right, bottom 
        self.setLayout(mainLayout)
        if platform.system() == 'Windows':
            self.dialogbuttons.button(QDialogButtonBox.Ok)
        else:
            self.dialogbuttons.button(QDialogButtonBox.Ok).setFocus()
        self.TabWidget.setCurrentIndex(activeTab)
    
    @pyqtSlot(bool)
    def timealign(self,_):
        self.aw.qmc.timealign()
    
    #keyboard presses. There must not be widgets (pushbuttons, comboboxes, etc) in focus in order to work 
    def keyPressEvent(self,event):
        if event.matches(QKeySequence.Copy):
            if self.TabWidget.currentIndex() == 2: # datatable
                self.aw.copy_cells_to_clipboard(self.datatable)
                self.aw.sendmessage(QApplication.translate("Message","Data table copied to clipboard",None))
        else:
            super(backgroundDlg,self).keyPressEvent(event)

    @pyqtSlot()
    def accept(self):
        self.aw.qmc.backgroundmovespeed = self.speedSpinBox.value()
        self.close()
        
    def closeEvent(self,_):
        settings = QSettings()
        #save window geometry
        settings.setValue("BackgroundGeometry",self.saveGeometry())
        self.aw.backgroundDlg_activeTab = self.TabWidget.currentIndex()
        
    def getColorIdx(self,c):
        try:
            return self.defaultcolorsmapped.index(c)
        except Exception:
            try:
                return self.colors.index(c) + 5
            except Exception: 
                return 0

    @pyqtSlot(int)
    def setplaybackevent(self,_):
        s = None
        if self.backgroundPlaybackEvents.isChecked():
            self.aw.qmc.backgroundPlaybackEvents = True
            msg = QApplication.translate("Message","Playback Events set ON",None)
        else:
            self.aw.qmc.backgroundPlaybackEvents = False
            msg = QApplication.translate("StatusBar","Playback Events set OFF",None)
            s = "background-color:'transparent';"
        self.aw.sendmessage(msg, style=s)

    @pyqtSlot(int)
    def setplaybackdrop(self,_):
        s = None
        if self.backgroundPlaybackDROP.isChecked():
            self.aw.qmc.backgroundPlaybackDROP = True
            msg = QApplication.translate("Message","Playback DROP set ON",None)
        else:
            self.aw.qmc.backgroundPlaybackDROP = False
            msg = QApplication.translate("StatusBar","Playback DROP set OFF",None)
            s = "background-color:'transparent';"
        self.aw.sendmessage(msg, style=s)
                
    @pyqtSlot(int)
    def setreproduceBeep(self,_):
        if self.backgroundReproduceBeep.isChecked():
            self.aw.qmc.backgroundReproduceBeep = True
        else:
            self.aw.qmc.backgroundReproduceBeep = False

    @pyqtSlot(int)
    def setreproduce(self,_):
        self.aw.qmc.detectBackgroundEventTime = self.etimeSpinBox.value()
        s = None
        if self.backgroundReproduce.isChecked():
            self.aw.qmc.backgroundReproduce = True
            msg = QApplication.translate("Message","Playback Aid set ON at {0} secs",None).format(str(self.aw.qmc.detectBackgroundEventTime))
        else:
            self.aw.qmc.backgroundReproduce = False
            msg = QApplication.translate("StatusBar","Playback Aid set OFF",None)
            s = "background-color:'transparent';"
        self.aw.sendmessage(msg, style=s)

    def adjustcolor(self,curve):
        
        curve = str(curve).lower()

        etcolor = str(self.metcolorComboBox.currentText()).lower()
        btcolor = str(self.btcolorComboBox.currentText()).lower()
        deltabtcolor = str(self.deltabtcolorComboBox.currentText()).lower()
        deltaetcolor = str(self.deltaetcolorComboBox.currentText()).lower()
        xtcolor = str(self.xtcolorComboBox.currentText()).lower()

        defaults =  ["et","bt","deltaet","deltabt"]
        
        if curve == "et":
            if etcolor in defaults:
                self.aw.qmc.backgroundmetcolor = self.aw.qmc.palette[etcolor]
            else:
                self.aw.qmc.backgroundmetcolor = etcolor
                
        elif curve == "bt":
            if btcolor in defaults:
                self.aw.qmc.backgroundbtcolor = self.aw.qmc.palette[btcolor]
            else:
                self.aw.qmc.backgroundbtcolor = btcolor

        elif curve == "deltaet":
            if deltaetcolor in defaults:
                self.aw.qmc.backgrounddeltaetcolor = self.aw.qmc.palette[deltaetcolor]
            else:
                self.aw.qmc.backgrounddeltaetcolor = deltaetcolor
            
        elif curve == "deltabt":
            if deltabtcolor in defaults:
                self.aw.qmc.backgrounddeltabtcolor = self.aw.qmc.palette[deltabtcolor]
            else:
                self.aw.qmc.backgrounddeltabtcolor = deltabtcolor

        elif curve == "xt":
            if xtcolor in defaults:
                self.aw.qmc.backgroundxtcolor = self.aw.qmc.palette[xtcolor]
            else:
                self.aw.qmc.backgroundxtcolor = xtcolor 

        self.aw.qmc.redraw(recomputeAllDeltas=False)

    @pyqtSlot(bool)
    def delete(self,_):
        self.pathedit.setText("")
# we should not overwrite the users app settings here, right:
# but we have to deactivate the show flag
        self.backgroundCheck.setChecked(False)
        self.aw.qmc.background = False
        self.aw.qmc.backgroundprofile = None
        self.xtcurveComboBox.blockSignals(True)
        self.xtcurveComboBox.clear()
        self.aw.deleteBackground()
        self.eventtable.clear()
        self.createEventTable()
        self.createDataTable()
        self.aw.qmc.resetlinecountcaches()
        self.xtcurveComboBox.blockSignals(False)
        self.aw.qmc.redraw(recomputeAllDeltas=False)

    @pyqtSlot(bool)
    def moveUp(self,_):
        self.upButton.setDisabled(True)
        self.move("up")
        self.upButton.setDisabled(False)
    @pyqtSlot(bool)
    def moveDown(self,_):
        self.downButton.setDisabled(True)
        self.move("down")
        self.downButton.setDisabled(False)
    @pyqtSlot(bool)
    def moveLeft(self,_):
        self.leftButton.setDisabled(True)
        self.move("left")
        self.leftButton.setDisabled(False)
    @pyqtSlot(bool)
    def moveRight(self,_):
        self.rightButton.setDisabled(True)
        self.move("right")
        self.rightButton.setDisabled(False)
    
    def move(self,m):
        step = self.speedSpinBox.value()
        self.aw.qmc.movebackground(m,step)
        self.createEventTable()
        self.createDataTable()
        self.aw.qmc.redraw(recomputeAllDeltas=False)

    def readChecks(self):
        self.aw.qmc.background = bool(self.backgroundCheck.isChecked())
        self.aw.qmc.backgroundDetails = bool(self.backgroundDetails.isChecked())
        self.aw.qmc.backgroundeventsflag = bool(self.backgroundeventsflag.isChecked())
        self.aw.qmc.DeltaETBflag = bool(self.backgroundDeltaETflag.isChecked())
        self.aw.qmc.DeltaBTBflag = bool(self.backgroundDeltaBTflag.isChecked())
        self.aw.qmc.backgroundETcurve = bool(self.backgroundETflag.isChecked())
        self.aw.qmc.backgroundBTcurve = bool(self.backgroundBTflag.isChecked())
        self.aw.qmc.backgroundShowFullflag = bool(self.backgroundFullflag.isChecked())
        self.aw.qmc.redraw(recomputeAllDeltas=True)
    
    @pyqtSlot(int)
    def changeAlignEventidx(self,i):
        self.aw.qmc.alignEvent = i
        
    @pyqtSlot(int)
    def changeReplayTypeidx(self,i):
        self.aw.qmc.replayType = i

    @pyqtSlot(int)
    def changeXTcurveidx(self,i):
        self.aw.qmc.xtcurveidx = i
        self.createDataTable()
        self.aw.qmc.redraw(recomputeAllDeltas=False,smooth=True)

    @pyqtSlot(int)
    def changeYTcurveidx(self,i):
        self.aw.qmc.ytcurveidx = i
        self.createDataTable()
        self.aw.qmc.redraw(recomputeAllDeltas=False,smooth=True)

    @pyqtSlot(bool)
    def load(self,_):
        self.filename = self.aw.ArtisanOpenFileDialog(msg=QApplication.translate("Message","Load Background",None),ext_alt=".alog")
        if len(self.filename) == 0:
            return
        self.aw.sendmessage(QApplication.translate("Message","Reading background profile...",None))
        self.aw.qmc.resetlinecountcaches()
        self.aw.loadbackground(self.filename)
        
        # reset XT curve popup
        curvenames = [""] # first entry is the empty one (no extra curve displayed)
        for i in range(min(len(self.aw.qmc.extraname1B),len(self.aw.qmc.extraname2B),len(self.aw.qmc.extratimexB))):
            curvenames.append("B" + str(2*i+3) + ": " + self.aw.qmc.extraname1B[i])
            curvenames.append("B" + str(2*i+4) + ": " + self.aw.qmc.extraname2B[i])
            
        self.xtcurveComboBox.blockSignals(True)
        self.xtcurveComboBox.clear()
        self.xtcurveComboBox.addItems(curvenames)
        if self.aw.qmc.xtcurveidx < len(curvenames):
            self.xtcurveComboBox.setCurrentIndex(self.aw.qmc.xtcurveidx)
        self.xtcurveComboBox.blockSignals(False)

        self.ytcurveComboBox.blockSignals(True)
        self.ytcurveComboBox.clear()
        self.ytcurveComboBox.addItems(curvenames)
        if self.aw.qmc.ytcurveidx < len(curvenames):
            self.ytcurveComboBox.setCurrentIndex(self.aw.qmc.ytcurveidx)
        self.ytcurveComboBox.blockSignals(False)

        self.pathedit.setText(self.filename)
        self.backgroundCheck.setChecked(True)
        self.aw.qmc.timealign(redraw=False)
        self.readChecks()
        self.createEventTable()
        self.createDataTable()

    def createEventTable(self):
        ndata = len(self.aw.qmc.backgroundEvents)
        
        # self.eventtable.clear() # this crashes Ubuntu 16.04
#        if ndata != 0:
#            self.eventtable.clearContents() # this crashes Ubuntu 16.04 if device table is empty and also sometimes else
        self.eventtable.clearSelection() # this seems to work also for Ubuntu 16.04
        
        self.eventtable.setRowCount(ndata)
        self.eventtable.setColumnCount(6)
        self.eventtable.setHorizontalHeaderLabels([QApplication.translate("Table","Time",None),
                                                   QApplication.translate("Table", "ET", None),
                                                   QApplication.translate("Table", "BT", None),
                                                   QApplication.translate("Table","Description",None),
                                                   QApplication.translate("Table","Type",None),
                                                   QApplication.translate("Table","Value",None)])
        self.eventtable.setAlternatingRowColors(True)
        self.eventtable.setEditTriggers(QTableWidget.NoEditTriggers)
        self.eventtable.setSelectionBehavior(QTableWidget.SelectRows)
        self.eventtable.setSelectionMode(QTableWidget.ExtendedSelection)
        self.eventtable.setShowGrid(True)
        self.eventtable.verticalHeader().setSectionResizeMode(2)
        if self.aw.qmc.timeindex[0] != -1:
            start = self.aw.qmc.timex[self.aw.qmc.timeindex[0]]
        else:
            start = 0
        for i in range(ndata):
            timez = QTableWidgetItem(stringfromseconds(self.aw.qmc.timeB[self.aw.qmc.backgroundEvents[i]]-start))
            timez.setTextAlignment(Qt.AlignRight + Qt.AlignVCenter)
    
            if self.aw.qmc.LCDdecimalplaces:
                fmtstr = "%.1f"
            else:
                fmtstr = "%.0f"
            
            etline = QTableWidgetItem(fmtstr%(self.aw.qmc.temp1B[self.aw.qmc.backgroundEvents[i]]) + self.aw.qmc.mode)
            etline.setTextAlignment(Qt.AlignRight + Qt.AlignVCenter)
            
            btline = QTableWidgetItem(fmtstr%(self.aw.qmc.temp2B[self.aw.qmc.backgroundEvents[i]]) + self.aw.qmc.mode)
            btline.setTextAlignment(Qt.AlignRight + Qt.AlignVCenter)
            
            description = QTableWidgetItem(self.aw.qmc.backgroundEStrings[i])
            etype = QTableWidgetItem(self.aw.qmc.Betypesf(self.aw.qmc.backgroundEtypes[i]))
            evalue = QTableWidgetItem(self.aw.qmc.eventsvalues(self.aw.qmc.backgroundEvalues[i]))
            evalue.setTextAlignment(Qt.AlignRight + Qt.AlignVCenter)
            #add widgets to the table
            self.eventtable.setItem(i,0,timez)
            self.eventtable.setItem(i,1,etline)
            self.eventtable.setItem(i,2,btline)
            self.eventtable.setItem(i,3,description)
            self.eventtable.setItem(i,4,etype)
            self.eventtable.setItem(i,5,evalue)
        # improve width of Time column
        self.eventtable.setColumnWidth(1,175)
        header = self.eventtable.horizontalHeader()
        header.setSectionResizeMode(0, QHeaderView.Fixed)
        header.setSectionResizeMode(1, QHeaderView.Fixed)
        header.setSectionResizeMode(2, QHeaderView.Fixed)
        header.setSectionResizeMode(3, QHeaderView.Stretch)
        header.setSectionResizeMode(4, QHeaderView.Fixed)
        header.setSectionResizeMode(5, QHeaderView.Fixed)
        self.eventtable.resizeColumnsToContents()
        self.eventtable.setColumnWidth(1,65)
        self.eventtable.setColumnWidth(2,65)

    def createDataTable(self):
        try:
            #### lock shared resources #####
            self.aw.qmc.samplingsemaphore.acquire(1)
            
            ndata = len(self.aw.qmc.timeB)
            
            self.datatable.clear() # this crashes Ubuntu 16.04
    #        if ndata != 0:
    #            self.datatable.clearContents() # this crashes Ubuntu 16.04 if device table is empty and also sometimes else
            self.datatable.clearSelection() # this seems to work also for Ubuntu 16.04
    
            if self.aw.qmc.timeindexB[0] != -1 and len(self.aw.qmc.timeB) > self.aw.qmc.timeindexB[0]:
                start = self.aw.qmc.timeB[self.aw.qmc.timeindexB[0]]
            else:
                start = 0
            self.datatable.setRowCount(ndata)
            headers = [QApplication.translate("Table","Time",None),
                                                      QApplication.translate("Table","ET",None),
                                                      QApplication.translate("Table","BT",None),
                                                      deltaLabelUTF8 + QApplication.translate("Table","ET",None),
                                                      deltaLabelUTF8 + QApplication.translate("Table","BT",None)]
            xtcurve = False # no XT curve
            if self.aw.qmc.xtcurveidx > 0: # 3rd background curve set?
                idx3 = self.aw.qmc.xtcurveidx - 1
                n3 = idx3 // 2
                if len(self.aw.qmc.temp1BX) > n3 and len(self.aw.qmc.extratimexB) > n3:
                    xtcurve = True
                    if self.aw.qmc.xtcurveidx % 2:
                        headers.append(self.aw.qmc.extraname1B[n3])
                    else:
                        headers.append(self.aw.qmc.extraname2B[n3])

            ytcurve = False # no YT curve
            if self.aw.qmc.ytcurveidx > 0: # 4th background curve set?
                idx4 = self.aw.qmc.ytcurveidx - 1
                n4 = idx4 // 2
                if len(self.aw.qmc.temp1BX) > n4 and len(self.aw.qmc.extratimexB) > n4:
                    ytcurve = True
                    if self.aw.qmc.ytcurveidx % 2:
                        headers.append(self.aw.qmc.extraname1B[n4])
                    else:
                        headers.append(self.aw.qmc.extraname2B[n4])
            
            headers.append("") # dummy column that stretches
            self.datatable.setColumnCount(len(headers))
            self.datatable.setHorizontalHeaderLabels(headers)
            self.datatable.setAlternatingRowColors(True)
            self.datatable.setEditTriggers(QTableWidget.NoEditTriggers)
            self.datatable.setSelectionBehavior(QTableWidget.SelectRows)
            self.datatable.setSelectionMode(QTableWidget.ExtendedSelection) # QTableWidget.SingleSelection, ContiguousSelection, MultiSelection
            self.datatable.setShowGrid(True)
            self.datatable.verticalHeader().setSectionResizeMode(2)
            for i in range(ndata):
                Rtime = QTableWidgetItem(stringfromseconds(self.aw.qmc.timeB[i]-start))
                Rtime.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
                if self.aw.qmc.LCDdecimalplaces:
                    fmtstr = "%.1f"
                else:
                    fmtstr = "%.0f"
                ET = QTableWidgetItem(fmtstr%self.aw.qmc.temp1B[i])
                BT = QTableWidgetItem(fmtstr%self.aw.qmc.temp2B[i])
                ET.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
                BT.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
                if i:
                    d = (self.aw.qmc.timeB[i]-self.aw.qmc.timeB[i-1])
                    if d == 0:
                        dET = 0.
                        dBT = 0.
                    else:
                        dET = (60*(self.aw.qmc.temp1B[i]-self.aw.qmc.temp1B[i-1])/d)
                        dBT = (60*(self.aw.qmc.temp2B[i]-self.aw.qmc.temp2B[i-1])/d)
                    deltaET = QTableWidgetItem("%.1f"%dET)
                    deltaBT = QTableWidgetItem("%.1f"%dBT)
                else:
                    deltaET = QTableWidgetItem("--")
                    deltaBT = QTableWidgetItem("--")
                deltaET.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
                deltaBT.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
                self.datatable.setItem(i,0,Rtime)
                        
                if i:
                    #identify by color and add notation
                    if i == self.aw.qmc.timeindexB[0] != -1:
                        self.datatable.item(i,0).setBackground(QColor('#f07800'))
                        text = QApplication.translate("Table", "CHARGE",None)
                    elif i == self.aw.qmc.timeindexB[1]:
                        self.datatable.item(i,0).setBackground(QColor('orange'))
                        text = QApplication.translate("Table", "DRY END",None)
                    elif i == self.aw.qmc.timeindexB[2]:
                        self.datatable.item(i,0).setBackground(QColor('orange'))
                        text = QApplication.translate("Table", "FC START",None)
                    elif i == self.aw.qmc.timeindexB[3]:
                        self.datatable.item(i,0).setBackground(QColor('orange'))
                        text = QApplication.translate("Table", "FC END",None)
                    elif i == self.aw.qmc.timeindexB[4]:
                        self.datatable.item(i,0).setBackground(QColor('orange'))
                        text = QApplication.translate("Table", "SC START",None)
                    elif i == self.aw.qmc.timeindexB[5]:
                        self.datatable.item(i,0).setBackground(QColor('orange'))
                        text = QApplication.translate("Table", "SC END",None)
                    elif i == self.aw.qmc.timeindexB[6]:
                        self.datatable.item(i,0).setBackground(QColor('#f07800'))
                        text = QApplication.translate("Table", "DROP",None)
                    elif i == self.aw.qmc.timeindexB[7]:
                        self.datatable.item(i,0).setBackground(QColor('orange'))
                        text = QApplication.translate("Table", "COOL",None)
                    elif i in self.aw.qmc.backgroundEvents:
                        self.datatable.item(i,0).setBackground(QColor('yellow'))
                        index = self.aw.qmc.backgroundEvents.index(i)
                        text = QApplication.translate("Table", "#{0} {1}{2}",None).format(str(index+1),self.aw.qmc.Betypesf(self.aw.qmc.backgroundEtypes[index])[0],self.aw.qmc.eventsvalues(self.aw.qmc.backgroundEvalues[index]))
                    else:
                        text = ""
                    Rtime.setText(text + " " + Rtime.text())
                self.datatable.setItem(i,1,ET)
                self.datatable.setItem(i,2,BT)
                self.datatable.setItem(i,3,deltaET)
                self.datatable.setItem(i,4,deltaBT)
                
                if xtcurve and len(self.aw.qmc.temp1BX[n3]) > i: # an XT column is availble, fill it with data
                    if self.aw.qmc.xtcurveidx % 2:
                        XT = QTableWidgetItem("%.0f"%self.aw.qmc.temp1BX[n3][i])
                    else:
                        XT = QTableWidgetItem("%.0f"%self.aw.qmc.temp2BX[n3][i])
                    XT.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
                    self.datatable.setItem(i,5,XT)
                
                if ytcurve and len(self.aw.qmc.temp1BX[n4]) > i: # an YT column is availble, fill it with data
                    if self.aw.qmc.ytcurveidx % 2:
                        YT = QTableWidgetItem("%.0f"%self.aw.qmc.temp1BX[n4][i])
                    else:
                        YT = QTableWidgetItem("%.0f"%self.aw.qmc.temp2BX[n4][i])
                    YT.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
                    if xtcurve:
                        self.datatable.setItem(i,6,YT)
                    else:
                        self.datatable.setItem(i,5,YT)
                    
            header = self.datatable.horizontalHeader()
            header.setSectionResizeMode(0, QHeaderView.Fixed)
            header.setSectionResizeMode(1, QHeaderView.Fixed)
            header.setSectionResizeMode(2, QHeaderView.Fixed)
            header.setSectionResizeMode(3, QHeaderView.Fixed)
            header.setSectionResizeMode(4, QHeaderView.Fixed)
            if (xtcurve and not ytcurve) or (ytcurve and not xtcurve):
                header.setSectionResizeMode(5, QHeaderView.Fixed)
                header.setSectionResizeMode(6, QHeaderView.Stretch)
            elif xtcurve and ytcurve:
                header.setSectionResizeMode(5, QHeaderView.Fixed)
                header.setSectionResizeMode(6, QHeaderView.Fixed)
                header.setSectionResizeMode(7, QHeaderView.Stretch)
            else:
                header.setSectionResizeMode(5, QHeaderView.Stretch)
            self.datatable.resizeColumnsToContents()
        finally:
            if self.aw.qmc.samplingsemaphore.available() < 1:
                self.aw.qmc.samplingsemaphore.release(1)

    @pyqtSlot(bool)
    def copyDataTabletoClipboard(self,_=False):
        self.datatable.selectAll()
        self.aw.copy_cells_to_clipboard(self.datatable,adjustment=7)
        self.datatable.clearSelection()
        self.aw.sendmessage(QApplication.translate("Message","Data table copied to clipboard",None))

    @pyqtSlot(bool)
    def copyEventTabletoClipboard(self,_=False):
        self.aw.copy_cells_to_clipboard(self.eventtable,adjustment=0)
        self.aw.sendmessage(QApplication.translate("Message","Event table copied to clipboard",None))
Ejemplo n.º 18
0
class Widgets(QWidget):
    def __init__(self, parent=None):
        super(Widgets, self).__init__(parent)

        self.initUI()

    def initUI(self):

        fuenteSiacle = self.font()
        fuenteSiacle.setBold(True)
        fuenteSiacle.setPointSize(12)

      # ================= FRAME PANEL DE CONTROL ===================

        paletaBotones = self.palette()
        paletaBotones.setColor(QPalette.Background, QColor("#2EFEC8"))

        frameBotones = QFrame()
        frameBotones.setFrameStyle(QFrame.NoFrame)
        frameBotones.setAutoFillBackground(True)
        frameBotones.setPalette(paletaBotones)
        frameBotones.setFixedWidth(220)

      # ============================================================

        paletaPanel = self.palette()
        paletaPanel.setBrush(QPalette.Background, QBrush(QColor(255, 90, 0), Qt.SolidPattern))
        paletaPanel.setColor(QPalette.Foreground, Qt.white)

        labelSiacle = QLabel("PANEL DE CONTROL", frameBotones)
        labelSiacle.setAlignment(Qt.AlignCenter | Qt.AlignVCenter)
        labelSiacle.setFont(fuenteSiacle)
        labelSiacle.setAutoFillBackground(True)
        labelSiacle.setPalette(paletaPanel)
        labelSiacle.setFixedSize(220, 46)
        labelSiacle.move(0, 0)

      # ============================================================

        tamanioIcono = QSize(30, 30)

        botonNuevo = Boton(frameBotones)
        botonNuevo.setText(" Nuevo")
        botonNuevo.setToolTip("Nuevo cliente")
        botonNuevo.setCursor(Qt.PointingHandCursor)
        botonNuevo.move(-2, 45)

        botonActualizar = Boton(frameBotones)
        botonActualizar.setText(" Actualizar")
        botonActualizar.setToolTip("Actualizar cliente")
        botonActualizar.setCursor(Qt.PointingHandCursor)
        botonActualizar.move(-2, 82)

        botonEliminar = Boton(frameBotones)
        botonEliminar.setText(" Eliminar")
        botonEliminar.setToolTip("Eliminar cliente")
        botonEliminar.setCursor(Qt.PointingHandCursor)
        botonEliminar.move(-2, 119)

        botonLimpiar = Boton(frameBotones)
        botonLimpiar.setText(" Limpiar tabla")
        botonLimpiar.setToolTip("Limpiar tabla")
        botonLimpiar.setCursor(Qt.PointingHandCursor)
        botonLimpiar.move(-2, 156)

      # ============================================================

        paletaSuscribete = self.palette()
        paletaSuscribete.setBrush(QPalette.Background, QBrush(QColor(135, 206, 250),
                                                              Qt.SolidPattern))

        fuenteSuscribete = self.font()
        fuenteSuscribete.setBold(True)
        fuenteSuscribete.setFamily("Arial")
        fuenteSuscribete.setPointSize(11)

        labelSuscribete = QLabel("<a href='https://www.youtube.com/c/AndresNiñoPython?"
                                 "sub_confirmation=1'>SUSCRIBETE.</a>", frameBotones)
        labelSuscribete.setAlignment(Qt.AlignCenter | Qt.AlignVCenter)
        labelSuscribete.setOpenExternalLinks(True)
        labelSuscribete.setFont(fuenteSuscribete)
        labelSuscribete.setAutoFillBackground(True)
        labelSuscribete.setPalette(paletaSuscribete)
        labelSuscribete.setFixedSize(220, 46)
        labelSuscribete.move(0, 210)

      # ============ FRAME BIENVENIDO - CONFIGURACIÓN ==============

        paletaFrame = self.palette()
        paletaFrame.setColor(QPalette.Background, QColor("blue"))

        frameBienvenido = QFrame()
        frameBienvenido.setFrameStyle(QFrame.NoFrame)
        frameBienvenido.setAutoFillBackground(True)
        frameBienvenido.setPalette(paletaFrame)
        frameBienvenido.setFixedHeight(46)

      # ============================================================

        paletaTitulo = self.palette()
        paletaTitulo.setColor(QPalette.Foreground, Qt.yellow)

        labelBienvenido = QLabel("BIENVENIDO A SIACLE")
        labelBienvenido.setAlignment(Qt.AlignCenter)
        labelBienvenido.setFont(fuenteSiacle)
        labelBienvenido.setPalette(paletaTitulo)

        botonConfiguracion = QPushButton()
        botonConfiguracion.setIcon(QIcon("Imagenes/configuracion.png"))
        botonConfiguracion.setIconSize(QSize(24, 24))
        botonConfiguracion.setToolTip("Configurar Siacle")
        botonConfiguracion.setCursor(Qt.PointingHandCursor)
        botonConfiguracion.setFixedWidth(36)

        disenioFrame = QHBoxLayout()
        disenioFrame.addWidget(labelBienvenido, Qt.AlignCenter)
        disenioFrame.addStretch()
        disenioFrame.addWidget(botonConfiguracion)
        disenioFrame.setContentsMargins(0, 0, 5, 0)
        frameBienvenido.setLayout(disenioFrame)

      # ============================================================

        self.buscarLineEdit = QLineEdit()
        self.buscarLineEdit.setObjectName("Enter")
        self.buscarLineEdit.setPlaceholderText("Nombre del cliente")
        self.buscarLineEdit.setMinimumSize(200, 26)

        botonBuscar = QPushButton("Buscar")
        botonBuscar.setObjectName("Buscar")
        botonBuscar.setCursor(Qt.PointingHandCursor)
        botonBuscar.setMinimumSize(60, 26)

        separadorTodos = QFrame()
        separadorTodos.setFrameShape(QFrame.VLine)
        separadorTodos.setFrameShadow(QFrame.Raised)
        separadorTodos.setFixedSize(1, 26)

        botonTodos = QPushButton("Todos")
        botonTodos.setObjectName("Todos")
        botonTodos.setCursor(Qt.PointingHandCursor)
        botonTodos.setMinimumSize(60, 26)

        nombreColumnas = ("Id", "Nombre", "Apellido", "Sexo", "Fecha de nacimiento", "País",
                          "Teléfono o celular")

        menuMostrarOcultar = QMenu()
        for indice, columna in enumerate(nombreColumnas, start=0):
            accion = QAction(columna, menuMostrarOcultar)
            accion.setCheckable(True)
            accion.setChecked(True)
            accion.setData(indice)

            menuMostrarOcultar.addAction(accion)

        botonMostrarOcultar = QPushButton("Motrar/ocultar columnas")
        botonMostrarOcultar.setCursor(Qt.PointingHandCursor)
        botonMostrarOcultar.setMenu(menuMostrarOcultar)
        botonMostrarOcultar.setMinimumSize(180, 26)

        disenioBuscar = QHBoxLayout()
        disenioBuscar.setSpacing(10)
        disenioBuscar.addWidget(self.buscarLineEdit)
        disenioBuscar.addWidget(botonBuscar)
        disenioBuscar.addWidget(separadorTodos)
        disenioBuscar.addWidget(botonTodos)
        disenioBuscar.addWidget(botonMostrarOcultar)

      # =================== WIDGET  QTableWidget ===================
      
        self.tabla = QTableWidget()

        # Deshabilitar edición
        self.tabla.setEditTriggers(QAbstractItemView.NoEditTriggers)

        # Deshabilitar el comportamiento de arrastrar y soltar
        self.tabla.setDragDropOverwriteMode(False)

        # Seleccionar toda la fila
        self.tabla.setSelectionBehavior(QAbstractItemView.SelectRows)

        # Seleccionar una fila a la vez
        self.tabla.setSelectionMode(QAbstractItemView.SingleSelection)

        # Especifica dónde deben aparecer los puntos suspensivos "..." cuando se muestran
        # textos que no encajan
        self.tabla.setTextElideMode(Qt.ElideRight)# Qt.ElideNone

        # Establecer el ajuste de palabras del texto 
        self.tabla.setWordWrap(False)

        # Deshabilitar clasificación
        self.tabla.setSortingEnabled(False)

        # Establecer el número de columnas
        self.tabla.setColumnCount(7)

        # Establecer el número de filas
        self.tabla.setRowCount(0)

        # Alineación del texto del encabezado
        self.tabla.horizontalHeader().setDefaultAlignment(Qt.AlignHCenter|Qt.AlignVCenter|
                                                          Qt.AlignCenter)

        # Deshabilitar resaltado del texto del encabezado al seleccionar una fila
        self.tabla.horizontalHeader().setHighlightSections(False)

        # Hacer que la última sección visible del encabezado ocupa todo el espacio disponible
        self.tabla.horizontalHeader().setStretchLastSection(True)

        # Ocultar encabezado vertical
        self.tabla.verticalHeader().setVisible(False)

        # Dibujar el fondo usando colores alternados
        self.tabla.setAlternatingRowColors(True)

        # Establecer altura de las filas
        self.tabla.verticalHeader().setDefaultSectionSize(20)
        
        # self.tabla.verticalHeader().setHighlightSections(True)

        # Establecer las etiquetas de encabezado horizontal usando etiquetas
        self.tabla.setHorizontalHeaderLabels(nombreColumnas)
        
        # Menú contextual
        self.tabla.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tabla.customContextMenuRequested.connect(self.menuContextual)
        
        # Establecer ancho de las columnas
        for indice, ancho in enumerate((80, 240, 240, 140, 150, 130), start=0):
            self.tabla.setColumnWidth(indice, ancho)

      # ============================================================

        disenioBuscarTabla = QVBoxLayout()
        disenioBuscarTabla.addLayout(disenioBuscar)
        disenioBuscarTabla.addWidget(self.tabla)
        disenioBuscarTabla.setSpacing(8)
        disenioBuscarTabla.setContentsMargins(10, 10, 10, 0)

      # ===================== LAYOUT DERECHO =======================

        disenioDerecho = QVBoxLayout()
        disenioDerecho.addWidget(frameBienvenido)
        disenioDerecho.addLayout(disenioBuscarTabla)
        disenioDerecho.setContentsMargins(0, 0, 0, 0)

      # ====================== LAYOUT FINAL ======================
        
        disenioFinal = QGridLayout()
        disenioFinal.addWidget(frameBotones, 0, 0)
        disenioFinal.addLayout(disenioDerecho, 0, 1)
        disenioFinal.setSpacing(0)
        disenioFinal.setContentsMargins(0, 0, 0, 0)
        
        self.setLayout(disenioFinal)

      # ========= GUARDAR INFORMACIÓN EN EL PORTAPAPELES =========

        self.copiarInformacion = QApplication.clipboard()

      # ======================== EVENTOS =========================

        botonNuevo.clicked.connect(self.Nuevo)
        botonActualizar.clicked.connect(self.Actualizar)
        botonEliminar.clicked.connect(self.Eliminar)
        botonLimpiar.clicked.connect(self.limpiarTabla)

        self.buscarLineEdit.returnPressed.connect(self.Buscar)
        botonBuscar.clicked.connect(self.Buscar)
        botonTodos.clicked.connect(self.Buscar)

        botonConfiguracion.clicked.connect(lambda: Configuracion(self).exec_())

        self.tabla.itemDoubleClicked.connect(self.Suscribete)

        menuMostrarOcultar.triggered.connect(self.mostrarOcultar)

  # ======================= FUNCIONES ============================

    def Nuevo(self):
        nuevoCliente(self).exec_()

    def Actualizar(self):
        fila = self.tabla.selectedItems()

        if fila:
            indice = fila[0].row()
            datos = [self.tabla.item(indice, i).text() for i in range(7)]
            
            actualizarCliente(indice, datos, self).exec_()
        else:
            QMessageBox.critical(self, "Actualizar cliente", "Seleccione un cliente.   ",
                                 QMessageBox.Ok)

    def Eliminar(self):
        fila = self.tabla.selectedItems()

        if fila:
            eliminar = QMessageBox(self)

            eliminar.setWindowTitle("Eliminar cliente")
            eliminar.setIcon(QMessageBox.Question)
            eliminar.setText("¿Esta seguro que desea eliminar el cliente?   ")
            botonSi = eliminar.addButton("Si", QMessageBox.YesRole)
            botonCancelar = eliminar.addButton("Cancelar", QMessageBox.NoRole)
                
            eliminar.exec_()
                
            if eliminar.clickedButton() == botonSi:
                indiceFila = fila[0].row()
                idCliente = self.tabla.item(indiceFila, 0).text()

                if QFile.exists("DB_SIACLE/DB_SIACLE.db"):
                    conexion = sqlite3.connect("DB_SIACLE/DB_SIACLE.db")
                    cursor = conexion.cursor()
                        
                    try:
                        cursor.execute("DELETE FROM CLIENTES WHERE ID = ?", (idCliente,))
                        conexion.commit()

                        conexion.close()

                        self.tabla.removeRow(indiceFila)
                        self.tabla.clearSelection()

                        QMessageBox.information(self, "Eliminar cliente", "Cliente eliminado."
                                                "   ", QMessageBox.Ok)
                    except:
                        conexion.close()
                        QMessageBox.critical(self, "Eliminar cliente", "Error desconocido.   ",
                                             QMessageBox.Ok)
                else:
                    QMessageBox.critical(self, "Buscar clientes", "No se encontro la base de "
                                         "datos.   ", QMessageBox.Ok)
        else:
            QMessageBox.critical(self, "Eliminar cliente", "Seleccione un cliente.   ",
                                 QMessageBox.Ok)

    def Suscribete(self, celda):
        QMessageBox.warning(self, "Suscribirse", "Hola, l@ invito a que se suscriba al "
                            "canal.\nPor cierto hiciste doble clic sobre esta "
                            "celda: {}.   ".format(celda.text()), QMessageBox.Ok)

    def Buscar(self):
        widget = self.sender().objectName()

        if widget in ("Enter", "Buscar"):
            cliente = " ".join(self.buscarLineEdit.text().split()).lower()
            
            if cliente:
                sql = "SELECT * FROM CLIENTES WHERE NOMBRE LIKE ?", ("%"+cliente+"%",)
            else:
                self.buscarLineEdit.setFocus()
                return
        else:
            self.buscarLineEdit.clear()
            sql = "SELECT * FROM CLIENTES"

        if QFile.exists("DB_SIACLE/DB_SIACLE.db"):
            conexion = sqlite3.connect("DB_SIACLE/DB_SIACLE.db")
            cursor = conexion.cursor()
                
            try:
                if widget in ("Enter", "Buscar"):
                    cursor.execute(sql[0], sql[1])
                else:
                    cursor.execute(sql)
                    
                datosDevueltos = cursor.fetchall()
                conexion.close()

                self.tabla.clearContents()
                self.tabla.setRowCount(0)

                if datosDevueltos:
                    fila = 0
                    for datos in datosDevueltos:
                        self.tabla.setRowCount(fila + 1)
            
                        idDato = QTableWidgetItem(str(datos[0]))
                        idDato.setTextAlignment(Qt.AlignCenter)
                        
                        self.tabla.setItem(fila, 0, idDato)
                        self.tabla.setItem(fila, 1, QTableWidgetItem(datos[1]))
                        self.tabla.setItem(fila, 2, QTableWidgetItem(datos[2]))
                        self.tabla.setItem(fila, 3, QTableWidgetItem(datos[3]))
                        self.tabla.setItem(fila, 4, QTableWidgetItem(datos[4]))
                        self.tabla.setItem(fila, 5, QTableWidgetItem(datos[5]))
                        self.tabla.setItem(fila, 6, QTableWidgetItem(datos[6]))

                        fila += 1
                else:   
                    QMessageBox.information(self, "Buscar cliente", "No se encontro "
                                            "información.   ", QMessageBox.Ok)
            except:
                conexion.close()
                QMessageBox.critical(self, "Buscar clientes", "Error desconocido.   ",
                                     QMessageBox.Ok)
        else:
            QMessageBox.critical(self, "Buscar clientes", "No se encontro la base de datos.   ",
                                 QMessageBox.Ok)

        self.buscarLineEdit.setFocus()

    def mostrarOcultar(self, accion):
        columna = accion.data()
        
        if accion.isChecked():
            self.tabla.setColumnHidden(columna, False)
        else:
            self.tabla.setColumnHidden(columna, True)

    def limpiarTabla(self):
        self.tabla.clearContents()
        self.tabla.setRowCount(0)

    def menuContextual(self, posicion):
        indices = self.tabla.selectedIndexes()

        if indices:
            menu = QMenu()

            itemsGrupo = QActionGroup(self)
            itemsGrupo.setExclusive(True)
            
            menu.addAction(QAction("Copiar todo", itemsGrupo))

            columnas = [self.tabla.horizontalHeaderItem(columna).text()
                        for columna in range(self.tabla.columnCount())
                        if not self.tabla.isColumnHidden(columna)]

            copiarIndividual = menu.addMenu("Copiar individual") 
            for indice, item in enumerate(columnas, start=0):
                accion = QAction(item, itemsGrupo)
                accion.setData(indice)
                
                copiarIndividual.addAction(accion)

            itemsGrupo.triggered.connect(self.copiarTableWidgetItem)
            
            menu.exec(self.tabla.viewport().mapToGlobal(posicion))

    def copiarTableWidgetItem(self, accion):
        filaSeleccionada = [dato.text() for dato in self.tabla.selectedItems()]
            
        if accion.text() == "Copiar todo":
            filaSeleccionada = tuple(filaSeleccionada)
        else:
            filaSeleccionada = filaSeleccionada[accion.data()]

        self.copiarInformacion.clear(mode = QClipboard.Clipboard)
        self.copiarInformacion.setText(str(filaSeleccionada), QClipboard.Clipboard)
Ejemplo n.º 19
0
class App(QWidget):
    """Display window for the main game and start the timer.

    Display options to:
        1. Select letters on the table
        2. Pause/Resume the game
        3. Quit the game

    Attributes:
        wordBank: A string of the words to find in the word search.
        wordBankSplit: A list of strings of words to find in the word search.
        wordSelected: A string to hold the current word selected.
        xVisited: A list of integers to hold the current row values of the letters selected.
        yVisited: A list of integers to hold the current column values of the letters selected.
        inRow: An integer to determine if the letters selected are in consecutive fashion.
        progressValue: An integer to keep track of the words found.
        wordsCompleted: A list of strings of the words found.
        timeFlag: A time flag to keep track of the timer if the game has been paused or resumed.
    """
    def __init__(self):
        """Initiate initUI."""
        super().__init__()
        self.wordBank = ""
        self.wordBankSplit = []
        self.wordSelected = ""
        self.xVisited = []
        self.yVisited = []
        self.inRow = 0
        self.progressValue = 0
        self.wordsCompleted = []
        self.timeFlag = 2
        self.initUI()

    def initUI(self):
        """Initiate UI elements."""
        title = 'Word Search Mania'
        self.setWindowTitle(title)

        self.wordBankBox = QTextEdit()
        self.tableWidget = QTableWidget()
        self.progress = QProgressBar()
        self.timer = PyQt5.QtCore.QTimer()

        self.createTable()
        self.createWordBank()
        self.createProgressBar()
        self.createTimer()
        self.mouseTracking()

        wordBankTitle = QLabel()
        wordBankTitle.setText("       Word Bank")
        font = QFont()
        font.setBold(True)
        wordBankTitle.setFont(font)

        buttonClear = QPushButton('Clear', self)
        buttonClear.setToolTip('This clears your word selection.')
        buttonClear.clicked.connect(self.onClickClear)

        buttonQuit = QPushButton('Quit', self)
        buttonQuit.setToolTip(
            'This will buttonQuit your game. You will loose all progress.')
        buttonQuit.clicked.connect(self.onClickQuit)

        self.buttonPause = QPushButton('Pause')
        self.buttonPause.setToolTip('This pauses the game.')
        self.buttonPause.clicked.connect(self.onClickPause)

        vBox = QVBoxLayout()
        vBox.addWidget(wordBankTitle)
        vBox.addWidget(self.wordBankBox)
        vBox.addWidget(buttonClear)
        vBox.addWidget(self.buttonPause)
        vBox.addWidget(buttonQuit)

        self.grid = QGridLayout()
        self.grid.addLayout(vBox, 0, 1)
        self.grid.addWidget(self.tableWidget, 0, 0)
        self.grid.addWidget(self.progress, 1, 0)
        self.grid.addWidget(self.LCD, 1, 1)

        self.setLayout(self.grid)

        self.tableWidget.setSizeAdjustPolicy(
            QAbstractScrollArea.AdjustToContents)

        self.show()

    def createTable(self):
        """Generate the word search table."""
        generateAll = False

        global wordBoxChecked
        global rowBoxChecked
        global columnBoxChecked
        global diagonalBoxChecked

        if wordBoxChecked:
            f = open('custom_word_bank.txt', "r")
            wordBoxChecked = False
        else:
            f = open('words_alpha.txt', "r")
            generateAll = True

        wordFileContent = f.readlines()
        wordFileContent = [x.strip() for x in wordFileContent]

        self.tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.tableWidget.setRowCount(nElements)
        self.tableWidget.setColumnCount(nElements)

        # Populate table with random letters
        for y in range(0, nElements):
            for x in range(0, nElements):
                self.tableWidget.setItem(
                    x, y,
                    QTableWidgetItem(random.choice(string.ascii_uppercase)))
                self.tableWidget.setColumnWidth(x, 20)
                self.tableWidget.setRowHeight(y, 20)

        # Implements words across rows
        def generateRow(self):
            col = 0
            row = 0
            lastColPosition = 0
            wordDuplicate = False
            while row < nElements:
                while col < nElements:
                    col = random.randint(lastColPosition, nElements)
                    word = wordFileContent[random.randint(
                        0,
                        len(wordFileContent) - 1)]
                    while len(word) < 3:
                        word = wordFileContent[random.randint(
                            0,
                            len(wordFileContent) - 1)]
                    for x in self.wordBank.split():
                        if x == word:
                            wordDuplicate = True
                    if not wordDuplicate:
                        if nElements - col > len(word):
                            lastColPosition = len(word) + col
                            self.wordBank += word + "\n"
                            for x in word:
                                self.tableWidget.setItem(
                                    row, col, QTableWidgetItem(x))
                                col += 1
                            col = nElements
                    wordDuplicate = False
                row += 3
                col = 0
                lastColPosition = 0

        # Implements words down each column
        def generateCol(self):
            col = 0
            row = 0
            lastRowPosition = 0
            decide = 0
            wordDuplicate = False
            while col < nElements:
                while row < nElements:
                    row = random.randint(lastRowPosition, nElements)
                    word = wordFileContent[random.randint(
                        0,
                        len(wordFileContent) - 1)]
                    while len(word) < 3:
                        word = wordFileContent[random.randint(
                            0,
                            len(wordFileContent) - 1)]
                    for x in self.wordBank.split():
                        if x == word:
                            wordDuplicate = True
                    if not wordDuplicate:
                        if nElements - row > len(word):
                            for k in range(row, row + len(word)):
                                if self.tableWidget.item(k,
                                                         col).text().islower():
                                    decide += 1
                            if decide == 0:
                                lastRowPosition = len(word) + row
                                self.wordBank += word + "\n"
                                for y in word:
                                    self.tableWidget.setItem(
                                        row, col, QTableWidgetItem(y))
                                    row += 1
                            decide = 0
                    wordDuplicate = False
                col += 3
                row = 0
                lastRowPosition = 0

        # Implements words down each diagonal in forward
        def generateForwardDiag(self):
            col = 0
            row = 0
            wordCount = 0
            decide = 0
            wordDuplicate = False
            while row < nElements:
                while col < nElements:
                    word = wordFileContent[random.randint(
                        0,
                        len(wordFileContent) - 1)]
                    while len(word) < 3:
                        word = wordFileContent[random.randint(
                            0,
                            len(wordFileContent) - 1)]
                    for x in self.wordBank.split():
                        if x == word:
                            wordDuplicate = True
                    if not wordDuplicate:
                        tempRow = row
                        tempCol = col
                        while tempRow < nElements and tempCol < nElements and wordCount < len(
                                word):
                            if self.tableWidget.item(tempRow,
                                                     tempCol).text().islower():
                                decide += 1
                            tempRow += 1
                            tempCol += 1
                            wordCount += 1
                        tempRow = row
                        tempCol = col
                        if decide == 0 and (
                                len(word) + tempCol) < nElements and (
                                    len(word) + tempRow) < nElements:
                            self.wordBank += word + "\n"
                            for y in word:
                                self.tableWidget.setItem(
                                    tempRow, tempCol, QTableWidgetItem(y))
                                tempCol += 1
                                tempRow += 1
                    decide = 0
                    wordCount = 0
                    col += 1
                    wordDuplicate = False
                row += 1
                col = 0

        # Implements words down each diagonal in backward
        def generateBackwardDiag(self):
            col = nElements - 1
            row = 0
            wordCount = 0
            decide = 0
            wordDuplicate = False
            while row < nElements:
                while col >= 0:
                    word = wordFileContent[random.randint(
                        0,
                        len(wordFileContent) - 1)]
                    while len(word) < 3:
                        word = wordFileContent[random.randint(
                            0,
                            len(wordFileContent) - 1)]
                    for x in self.wordBank.split():
                        if x == word:
                            wordDuplicate = True
                    if not wordDuplicate:
                        tempRow = row
                        tempCol = col
                        while tempRow < nElements and tempCol >= 0 and wordCount < len(
                                word):
                            if self.tableWidget.item(tempRow,
                                                     tempCol).text().islower():
                                decide += 1
                            tempRow += 1
                            tempCol -= 1
                            wordCount += 1
                        tempRow = row
                        tempCol = col
                        if decide == 0 and (tempCol - len(word)) > 0 and (
                                len(word) + tempRow) < nElements:
                            self.wordBank += word + "\n"
                            for y in word:
                                self.tableWidget.setItem(
                                    tempRow, tempCol, QTableWidgetItem(y))
                                tempRow += 1
                                tempCol -= 1
                    decide = 0
                    wordCount = 0
                    col -= 1
                    wordDuplicate = False
                row += 1
                col = nElements - 1

        if generateAll:
            generateRow(self)
            generateCol(self)
            generateForwardDiag(self)
            generateBackwardDiag(self)
        else:
            if rowBoxChecked:
                generateRow(self)
                rowBoxChecked = False
            if columnBoxChecked:
                generateCol(self)
                columnBoxChecked = False
            if diagonalBoxChecked:
                generateForwardDiag(self)
                generateBackwardDiag(self)
                diagonalBoxChecked = False

        for y in range(0, nElements):
            for x in range(0, nElements):
                letter = self.tableWidget.item(x, y).text().lower()
                self.tableWidget.setItem(x, y, QTableWidgetItem(letter))
                self.tableWidget.item(x, y).setTextAlignment(
                    PyQt5.QtCore.Qt.AlignCenter)

        self.tableWidget.horizontalHeader().hide()
        self.tableWidget.verticalHeader().hide()
        self.tableWidget.setShowGrid(False)
        self.tableWidget.clicked.connect(self.onClickLetter)

    def createWordBank(self):
        """Generate a word bank of the words to be found."""
        self.wordBankSplit = self.wordBank.split()
        self.wordBankSplit.sort()
        for x in self.wordBankSplit:
            self.wordBankBox.append(x)
        self.wordBankBox.setReadOnly(True)
        self.wordBankBox.setMaximumWidth(120)
        font = QFont()
        font.setFamily('Arial')
        self.wordBankBox.setFont(font)
        self.wordBankBox.moveCursor(QTextCursor.Start)

    def strikeWord(self, word):
        """Strike word with a line if the word is found."""
        newWord = ""
        for x in word:
            newWord += x + '\u0336'
        self.wordBankSplit = [
            newWord if i == word else i for i in self.wordBankSplit
        ]
        self.wordBankBox.setText("")
        for x in self.wordBankSplit:
            self.wordBankBox.append(x)
        self.wordBankBox.show()
        self.wordBankBox.moveCursor(QTextCursor.Start)

    def mouseTracking(self):
        """Track mouse movement of the table."""
        self.currentHover = [0, 0]
        self.tableWidget.setMouseTracking(True)
        self.tableWidget.cellEntered.connect(self.cellHover)

    def cellHover(self, row, column):
        """Highlight letter if mouse is hovering over it."""
        item = self.tableWidget.item(row, column)
        oldItem = self.tableWidget.item(self.currentHover[0],
                                        self.currentHover[1])
        mouseTracker1 = True
        mouseTracker2 = True
        for x in range(len(self.xVisited)):
            if self.xVisited[x] == row and self.yVisited[x] == column:
                mouseTracker1 = False
            if self.currentHover[0] == self.xVisited[x] and self.currentHover[
                    1] == self.yVisited[x]:
                mouseTracker2 = False
        if mouseTracker1:
            if self.currentHover != [row, column]:
                if item.text().islower():
                    item.setBackground(QBrush(QColor('yellow')))
                if oldItem.text().islower() and mouseTracker2:
                    oldItem.setBackground(QBrush(QColor('white')))
        elif mouseTracker2:
            oldItem.setBackground(QBrush(QColor('white')))
        self.currentHover = [row, column]

    def onClickLetter(self):
        """Highlight letters on selection and highlight word green if found on click."""
        self.wordSelected = ""
        wordBankSplitOriginal = self.wordBank.split()
        selectionTracker = True
        selectionCorrectness = 0
        word = ""
        listX = []
        listY = []

        for currentQTableWidgetItem in self.tableWidget.selectedItems():
            if self.tableWidget.item(
                    currentQTableWidgetItem.row(),
                    currentQTableWidgetItem.column()).text().isupper():
                letter = self.tableWidget.item(
                    currentQTableWidgetItem.row(),
                    currentQTableWidgetItem.column()).text().lower()
                self.tableWidget.setItem(currentQTableWidgetItem.row(),
                                         currentQTableWidgetItem.column(),
                                         QTableWidgetItem(letter))
                self.tableWidget.clearSelection()
            else:
                for currentQTableWidgetItem in self.tableWidget.selectedItems(
                ):
                    for x in range(0, len(self.xVisited)):
                        if currentQTableWidgetItem.row() == self.xVisited[x] and currentQTableWidgetItem.column() == \
                                self.yVisited[x]:
                            selectionTracker = False
                    if selectionTracker:
                        letter = self.tableWidget.item(
                            currentQTableWidgetItem.row(),
                            currentQTableWidgetItem.column()).text().upper()
                        self.tableWidget.setItem(
                            currentQTableWidgetItem.row(),
                            currentQTableWidgetItem.column(),
                            QTableWidgetItem(letter))
                for currentQTableWidgetItem in self.tableWidget.selectedItems(
                ):
                    if selectionTracker:
                        self.tableWidget.item(
                            currentQTableWidgetItem.row(),
                            currentQTableWidgetItem.column()).setBackground(
                                QColor(216, 191, 216))
                for currentQTableWidgetItem in self.tableWidget.selectedItems(
                ):
                    if selectionTracker:
                        self.tableWidget.item(
                            currentQTableWidgetItem.row(),
                            currentQTableWidgetItem.column()).setTextAlignment(
                                PyQt5.QtCore.Qt.AlignCenter)
                    self.tableWidget.clearSelection()

        for x in range(0, nElements):
            for y in range(0, nElements):
                if self.tableWidget.item(x, y).text().isupper():
                    self.wordSelected += self.tableWidget.item(x, y).text()
                    listX.append(x)
                    listY.append(y)
        for x in wordBankSplitOriginal:
            if x == self.wordSelected.lower():
                selectionCorrectness += 1
                word = x
        if selectionCorrectness == 1:  # Makes sure the word is in a row
            for i in range(1, len(listY)):
                if listY[i - 1] == listY[i] - 1 and listX[i - 1] == listX[i]:
                    self.inRow += 1
                if self.inRow == len(listY) - 1:
                    selectionCorrectness += 1
                    self.inRow = 0
        if selectionCorrectness == 1:  # Makes sure the word is in a single column
            for i in range(1, len(listY)):
                if listX[i - 1] == listX[i] - 1 and listY[i - 1] == listY[i]:
                    self.inRow += 1
                if self.inRow == len(listY) - 1:
                    selectionCorrectness += 1
                    self.inRow = 0
        if selectionCorrectness == 1:  # Makes sure the word is in a forward diagonal
            for i in range(1, len(listY)):
                if listX[i - 1] == listX[i] - 1 and listY[i -
                                                          1] == listY[i] - 1:
                    self.inRow += 1
                if self.inRow == len(listY) - 1:
                    selectionCorrectness += 1
                    self.inRow = 0
        if selectionCorrectness == 1:  # Makes sure the word is in a backward diagonal
            for i in range(1, len(listY)):
                if listX[i - 1] == listX[i] - 1 and listY[i -
                                                          1] == listY[i] + 1:
                    self.inRow += 1
                if self.inRow == len(listY) - 1:
                    selectionCorrectness += 1
                    self.inRow = 0

        if selectionCorrectness == 2:
            wordIndex = self.wordSelected.find(word)
            self.progressValue += 1
            self.setProgressBar()
            self.strikeWord(word)
            self.wordsCompleted.append(word)
            for i in range(wordIndex, wordIndex + len(word)):
                letterI = self.tableWidget.item(listX[i],
                                                listY[i]).text().lower()
                self.tableWidget.setItem(listX[i], listY[i],
                                         QTableWidgetItem(letterI))
            for i in range(wordIndex, wordIndex + len(word)):
                self.tableWidget.item(listX[i], listY[i]).setBackground(
                    QColor(144, 238, 144))
                self.xVisited.append(listX[i])
                self.yVisited.append(listY[i])
            for i in range(wordIndex, wordIndex + len(word)):
                self.tableWidget.item(listX[i], listY[i]).setTextAlignment(
                    PyQt5.QtCore.Qt.AlignCenter)

    def onClickClear(self):
        """Clear word selection on button click."""
        self.wordSelected = ""
        for x in range(0, nElements):
            for y in range(0, nElements):
                if self.tableWidget.item(x, y).text().isupper():
                    letterI = self.tableWidget.item(x, y).text().lower()
                    self.tableWidget.setItem(x, y, QTableWidgetItem(letterI))
                    self.tableWidget.item(x, y).setTextAlignment(
                        PyQt5.QtCore.Qt.AlignCenter)

    def onClickQuit(self):
        """Display option to quit the app on button click."""
        quitMessage = QMessageBox()
        quitMessage = QMessageBox.question(
            self, "Quit", "Are you sure you would like to buttonQuit?",
            QMessageBox.No | QMessageBox.Yes)
        if quitMessage == QMessageBox.Yes:
            sys.exit()
        else:
            pass

    def createProgressBar(self):
        """Generate progress bar of with the progress of the words found until completion."""
        self.progress.setRange(0, len(self.wordBank.split()))
        self.progress.setToolTip("Shows your word completion progress.")

    def setProgressBar(self):
        """Set value for the progress bar."""
        self.progress.setValue(self.progressValue)

    def createTimer(self):
        """Generate a timer."""
        self.timer.timeout.connect(self.Time)
        self.timer.start(1000)
        self.time = PyQt5.QtCore.QTime(0, 0, 0)

        self.LCD = QLCDNumber()
        self.LCD.display(self.time.toString("hh:mm:ss"))
        self.LCD.setSegmentStyle(QLCDNumber.Flat)

    def Time(self):
        """Increment timer by a second."""
        self.time = self.time.addSecs(1)
        self.LCD.display(self.time.toString("hh:mm:ss"))

        if len(self.wordsCompleted) == len(self.wordBankSplit):
            self.timer.stop()
            self.endTime = self.time.toString("hh:mm:ss")
            self.addHighScore()
            self.close()
            self.openHighscoreMenu = HighScoreMenu()
            self.openHighscoreMenu.show()

    def onClickPause(self):
        """Pause and resume the game on button click."""
        if self.timeFlag % 2 == 0:
            self.timer.stop()
            self.timeFlag += 1
            self.tableWidget.hide()
            self.buttonPause.setText("Unpause")
        else:
            self.timer.start()
            self.timeFlag += 1
            self.tableWidget.show()
            self.tableWidget.clearSelection()
            self.buttonPause.setText("Pause")

    def addHighScore(self):
        """Save highScore to WS_Highscores text file."""
        with open("highscores.txt", "a") as highscoreFile:
            if 10 <= nElements <= 19:
                highscoreFile.write("Easy\n")
            elif 20 <= nElements <= 29:
                highscoreFile.write("Medium\n")
            else:
                highscoreFile.write("Hard\n")
            highscoreFile.write(str(self.endTime) + "\n")
Ejemplo n.º 20
0
class BrowserTags(QDialog):
    def __init__(self, parent=None):
        super(BrowserTags, self).__init__(parent)
        # self.setWindowFlags(Qt.FramelessWindowHint) #|Qt.WindowStaysOnTopHint) #|Qt.WindowTitleHint)
        self.flag = False
        self.resize(1024, 768)
        self.setWindowTitle('Etiquetas')
        masterLayout = QVBoxLayout(self)
        self.tag_list = []
        self.tag_id = -1
        deselect_tags_Btn = QPushButton('Des-seleciona')
        deselect_tags_Btn.clicked.connect(self.deselect_click)

        clean_tranf_Btn = QPushButton('Limpa Transferidas')
        clean_tranf_Btn.clicked.connect(self.clean_transfer)

        add_tag_Btn = QPushButton('Adiciona Tag')
        add_tag_Btn.clicked.connect(self.add_new_tag)

        masterLayout.addLayout(
            qc.addHLayout(
                [deselect_tags_Btn, clean_tranf_Btn, add_tag_Btn, True]))
        self.searchEdit = QLineEdit()
        self.toto = ()
        self.searchEdit.textChanged.connect(self.tag_search_changed)
        masterLayout.addWidget(self.searchEdit)
        self.grid = QTableWidget()
        self.grid.setEditTriggers(QTableWidget.NoEditTriggers)
        self.grid.verticalHeader().setDefaultSectionSize(20)
        self.grid.verticalHeader().setVisible(False)
        self.grid.itemDoubleClicked.connect(self.transfer_click)

        self.lastTags_grid = QTableWidget()
        self.lastTags_grid.setEditTriggers(QTableWidget.NoEditTriggers)
        self.lastTags_grid.verticalHeader().setDefaultSectionSize(20)
        self.lastTags_grid.verticalHeader().setVisible(False)
        self.lastTags_grid.itemDoubleClicked.connect(self.transfer_last_click)

        self.current_tags = QTextBrowser()
        self.current_tags.setMaximumHeight(60)
        self.current_tags.setMinimumHeight(60)

        masterLayout.addLayout(qc.addHLayout([self.grid, self.lastTags_grid]))
        masterLayout.addWidget(self.current_tags)
        exit_btn = QPushButton('Sair')
        exit_btn.clicked.connect(self.exit_click)

        valid_btn = QPushButton('Substitui')
        valid_btn.clicked.connect(self.valid_click)

        add_btn = QPushButton('Adiciona')
        add_btn.clicked.connect(self.add_click)

        masterLayout.addLayout(qc.addHLayout([valid_btn, add_btn, exit_btn]))

        self.tag_refresh()
        self.last_tag_refresh()

    def deselect_click(self):
        self.grid.clearSelection()

    def clean_transfer(self):
        self.current_tags.clear()

    def add_new_tag(self):
        b, ok = QInputDialog.getText(self, self.tr("Nova Etiqueta"),
                                     self.tr("Nova Etiqueta"),
                                     QLineEdit.Normal)
        if ok and not b == '':
            if self.current_tags.toPlainText() == '':
                self.current_tags.setText(b)
            else:
                self.current_tags.setText(self.current_tags.toPlainText() +
                                          ',' + b)
        else:
            print('do nothing')

    def transfer_click(self):
        a = self.grid.item(self.grid.currentRow(), 1).text()
        gl.last_tags.insert(0,
                            self.grid.item(self.grid.currentRow(), 1).text())
        self.tag_list = self.current_tags.toPlainText().split(',')
        self.tag_list.append(a)
        xl = ''
        for n in self.tag_list:
            xl += '<font color="blue"><strong>' + n + ',</font>'
        self.current_tags.setHtml(xl)
        self.searchEdit.clear()
        self.searchEdit.setFocus()

    def transfer_last_click(self):
        a = self.lastTags_grid.item(self.lastTags_grid.currentRow(), 0).text()
        self.tag_list = self.current_tags.toPlainText().split(',')
        self.tag_list.append(a)
        xl = ''
        for n in self.tag_list:
            xl += '<font color="blue"><strong>' + n + ',</font>'
        self.current_tags.setHtml(xl)

    def valid_click(self):
        self.tag_id = 0
        self.tag_list = self.current_tags.toPlainText()
        self.tag_list = self.tag_list.replace(',,', ',')
        self.tag_list = self.tag_list.rstrip(',')
        self.tag_list = self.tag_list.lstrip(',')
        self.flag = True
        self.close()

    def add_click(self):
        self.tag_id = 1
        self.tag_list = self.current_tags.toPlainText()
        self.tag_list = self.tag_list.replace(',,', ',')
        self.tag_list = self.tag_list.rstrip(',')
        self.tag_list = self.tag_list.lstrip(',')
        self.flag = True
        save_last_tags_params()
        self.close()

    def tag_refresh(self):
        self.c_grid = 10
        # sql = '''select ta_id, ta_name from tags order by ta_name'''
        sql = '''select ta_id,ta_name from tags where tag_key is null order by ta_name'''
        dataset = dbmain.query_many(sql)
        ex_grid.ex_grid_update(self.grid, {
            0: ['ID', 'i'],
            1: ['Nome', 's']
        },
                               dataset,
                               hidden=0)
        self.grid.horizontalHeader().setVisible(False)
        self.grid.setColumnWidth(0, 80)
        self.grid.setColumnWidth(1, 350)

    def last_tag_refresh(self):
        self.c_grid = 10
        lin = 0
        self.lastTags_grid.setColumnCount(1)
        self.lastTags_grid.setRowCount(len(gl.last_tags))

        for n in gl.last_tags:
            item = QTableWidgetItem()
            item.setText(n)
            self.lastTags_grid.setItem(lin, 0, item)
            lin += 1
        self.lastTags_grid.horizontalHeader().setVisible(False)
        self.lastTags_grid.setColumnWidth(0, 450)

    def tag_search_changed(self, text):
        if len(text) > 3:
            search = '\'%%' + text + '%%\''
            # print 'search ',text
            sql = '''select ta_id, ta_name from tags where unaccent(ta_name) like unaccent(''' + search + ''') order by ta_name'''
            dataset = dbmain.query_many(sql)
            ex_grid.ex_grid_update(self.grid, {
                0: ['ID', 'i'],
                1: ['Nome', 's']
            },
                                   dataset,
                                   hidden=0)
            self.grid.horizontalHeader().setVisible(False)
            self.grid.setColumnWidth(0, 80)
            self.grid.setColumnWidth(1, 350)

    def exit_click(self):
        self.tag_list = ''
        self.tag_id = -1
        self.close()
Ejemplo n.º 21
0
class MainWindow(QMainWindow):
    """Главное окно программы. Управляет интерфейсом и событиями."""
    def __init__(self, core):
        """Инициализация главного окна.

        core - ядро программы, содержащее логику."""
        super().__init__()
        self.core = core
        self.core.logged.connect(self.onLogged)
        self.initUI()
        self.command()

    def initUI(self):
        """Инициализировать графический интерфейс."""
        self.textEdit = QTextEdit()

        self.actionFileStart = QAction('&Start', self)
        self.actionFileStart.triggered.connect(self.onActionFileStartTriggered)
        self.actionFileStop = QAction('&Stop', self)
        self.actionFileStop.triggered.connect(self.onActionFileStopTriggered)
        self.actionFileStop.setDisabled(True)

        actionFileSave = QAction('&Save config', self)
        actionFileSave.triggered.connect(self.core.save)
        actionFileDraw = QAction('&Save chart', self)
        actionFileDraw.triggered.connect(self.core.draw)

        actionFileLogClear = QAction('&Clear', self)
        actionFileLogClear.triggered.connect(self.textEdit.clear)

        actionFileExit = QAction('&Exit', self)
        actionFileExit.triggered.connect(self.close)

        self.actionViewInfo = QAction('&Extended', self)
        self.actionViewInfo.setCheckable(True)
        self.actionViewInfo.setChecked(True)
        self.actionViewInfo.changed.connect(self.changeRow)

        actionConfigPeriod = QAction('&Period...', self)
        actionConfigPeriod.triggered.connect(self.actionConfigPeriodTriggered)

        actionConfigSensorsAdd = QAction('&Add...', self)
        actionConfigSensorsAdd.triggered.connect(
            self.actionConfigSensorsAddTriggered)

        actionConfigSensorsDel = QAction('&Delete...', self)
        actionConfigSensorsDel.triggered.connect(
            self.actionConfigSensorsDelTriggered)

        actionConfigPathAddresses = QAction('&Adressess...', self)
        actionConfigPathAddresses.triggered.connect(
            self.actionConfigPathAddressesTriggered)

        actionConfigPathSensors = QAction('&Sensors...', self)
        actionConfigPathSensors.triggered.connect(
            self.actionConfigPathSensorsTriggered)

        actionConfigPathData = QAction('&Data...', self)
        actionConfigPathData.triggered.connect(
            self.actionConfigPathDataTriggered)

        actionHelpHelp = QAction('&Help...', self)
        actionHelpHelp.triggered.connect(self.actionHelpHelpTriggered)
        actionHelpAbout = QAction('&About...', self)
        actionHelpAbout.triggered.connect(self.onAbout)

        menuFile = self.menuBar().addMenu('&File')
        menuFile.addAction(self.actionFileStart)
        menuFile.addAction(self.actionFileStop)
        menuFile.addSeparator()

        menuFileOpen = menuFile.addMenu('&Open')
        menuFileSave = menuFile.addMenu('&Save')
        menuFileSave.addAction(actionFileSave)
        menuFileSave.addAction(actionFileDraw)
        menuFile.addSeparator()

        menuFile.addAction(actionFileLogClear)
        menuFile.addSeparator()
        menuFile.addAction(actionFileExit)

        menuView = self.menuBar().addMenu('&View')
        menuView.addAction(self.actionViewInfo)

        menuConfig = self.menuBar().addMenu('&Settings')
        menuConfig.addAction(actionConfigPeriod)
        menuConfigSensors = menuConfig.addMenu('&Sensors')
        menuConfigSensors.addAction(actionConfigSensorsAdd)
        menuConfigSensors.addAction(actionConfigSensorsDel)
        menuConfigPath = menuConfig.addMenu('&Path')
        menuConfigPath.addAction(actionConfigPathAddresses)
        menuConfigPath.addAction(actionConfigPathSensors)
        menuConfigPath.addAction(actionConfigPathData)

        menuHelp = self.menuBar().addMenu('&Help')
        menuHelp.addAction(actionHelpHelp)
        menuHelp.addAction(actionHelpAbout)

        self.textEditList = deque(maxlen=100)
        self.textEdit.setVerticalScrollBarPolicy(2)
        self.textEdit.setToolTip("Action log.")
        self.textEdit.setReadOnly(True)

        self.isItemSave = False
        self.table = QTableWidget(0, 3)
        self.table.setToolTip("Temperature sensors.")
        self.table.setFixedWidth(342)
        self.table.setVerticalScrollBarPolicy(1)
        self.table.setHorizontalScrollBarPolicy(1)
        self.table.setColumnWidth(0, 50)
        self.table.setColumnWidth(1, 150)
        self.table.setColumnWidth(2, 120)
        self.table.setAlternatingRowColors(True)
        self.table.setSelectionMode(QTableWidget.SingleSelection)
        self.table.setSelectionBehavior(QTableWidget.SelectRows)
        self.table.setHorizontalHeaderLabels(['Val', 'Name', 'Address'])
        self.table.verticalHeader().setFixedWidth(20)
        self.table.verticalHeader().setDefaultAlignment(Qt.AlignRight)
        self.table.setEditTriggers(self.table.NoEditTriggers)

        grid = QGridLayout()
        grid.setSpacing(3)
        grid.setContentsMargins(3, 3, 3, 3)
        grid.addWidget(self.textEdit, 0, 0, 1, 1)
        grid.addWidget(self.table, 0, 1, 1, 1)
        widget = QWidget()
        widget.setLayout(grid)
        self.setCentralWidget(widget)

        self.setGeometry(300, 200, 600, 400)
        self.setWindowFlags(Qt.MSWindowsFixedSizeDialogHint)
        self.statusBar().setSizeGripEnabled(False)
        self.setWindowTitle('Observer')
        self.show()
        self.core.dataAdded.connect(self.onDataAdded)
        self.statusBar().showMessage('Application is runnig.')

    def command(self):
        """Обработка командой строки при запуске."""
        if len(sys.argv) > 1:
            if sys.argv[1] == '-s':
                if len(sys.argv) > 2:
                    if sys.argv[2].isdigit():
                        self.core.period = sys.argv[2]
                    self.actionFileStart.trigger()

    def closeEvent(self, event):
        """Событие закрытия программы."""
        self.core.stop()
        super().closeEvent(event)

    def onActionFileStartTriggered(self):
        """Действие нажатия Файл -> Старт.
        Запускает мониторинг."""
        self.actionFileStop.setEnabled(True)
        self.actionFileStart.setDisabled(True)
        self.core.start()

    def onActionFileStopTriggered(self):
        """Действие нажатия Файл -> Стоп.
        Остановить мониторинг."""
        self.actionFileStart.setEnabled(True)
        self.actionFileStop.setDisabled(True)
        self.core.stop()

    def actionConfigSensorsAddTriggered(self):
        """Действие нажатия Настройки -> Сенсоры -> Добавить.
        Открыть файл с настройками датчиков."""
        if os.path.exists(self.core.pathSensors):
            answer = QMessageBox.question(
                self, 'Add sensors',
                'Open file "{}/{}" to add sensors in external editor?'.format(
                    self.core.pathSensors, 'temperature'))
            if answer == QMessageBox.Yes:
                try:
                    os.startfile('{}\\{}'.format(self.core.pathSensors,
                                                 'temperature'))
                except Exception:
                    QMessageBox.warning(
                        self, 'Add sensors', 'File "{}/{}" don`t open!'.format(
                            self.core.pathSensors, 'temperature'))
        else:
            QMessageBox.warning(
                self, 'Add sensors',
                '"{}" path does not exist'.format(self.core.pathSensors))

    def actionConfigSensorsDelTriggered(self):
        """Действие нажатия Настройки -> Сенсоры -> Удалить.
        Открыть файл с настройками датчиков."""
        if os.path.exists(self.core.pathSensors):
            answer = QMessageBox.question(
                self, 'Delete sensors',
                'Open "{}/{}" to delete sensors in external editor?'.format(
                    self.core.pathSensors, 'temperature'))
            if answer == QMessageBox.Yes:
                try:
                    os.startfile('{}\\{}'.format(self.core.pathSensors,
                                                 'temperature'))
                except Exception:
                    QMessageBox.warning(
                        self, 'Delete sensors',
                        'File "{}/{}" don`t open!'.format(
                            self.core.pathSensors, 'temperature'))
        else:
            QMessageBox.warning(
                self, 'Delete sensors',
                '"{}" path does not exist'.format(self.core.pathSensors))

    def actionConfigPeriodTriggered(self):
        """Действие нажатия Настройки -> Период.
        Открыть окно настройки периода опроса датчиков."""
        period, ok = QInputDialog.getInt(self, 'Request period',
                                         'Enter request period:',
                                         int(self.core.period), 10, 3600)
        if ok:
            self.core.period = str(period)
            self.core.configSave()

    def actionConfigPathAddressesTriggered(self):
        """Действие нажатия Настройки -> Путь -> Адреса.
        Открывает окно выбора пути к файлу настройки адресов."""
        path = QFileDialog.getOpenFileName(self, 'Addresses path',
                                           self.core.pathAddresses, '')
        if path[0] != '':
            self.core.pathAddresses = path[0]
            self.core.configSave()

    def actionConfigPathSensorsTriggered(self):
        """Действие нажатия Настройки -> Путь -> Датчики.
        Открывает окно выбора пути к файлу настройки датчиков."""
        path = QFileDialog.getExistingDirectory(self, 'Sensors directory',
                                                self.core.pathSensors)
        if path != '':
            self.core.pathSensors = path
            self.core.configSave()

    def actionConfigPathDataTriggered(self):
        """Действие нажатия Настройки -> Путь -> Данные.
        Открывает окно выбора пути к папке, содержащей данные."""
        path = QFileDialog.getExistingDirectory(self, 'Data directory',
                                                self.core.pathData)
        if path != '':
            self.core.pathData = path
            self.core.configSave()

    def changeRow(self):
        """Изменение отображения информации в колонках."""
        if self.actionViewInfo.isChecked():
            self.table.setColumnHidden(1, False)
            self.table.setColumnHidden(2, False)
            self.table.setFixedWidth(self.table.width() + 270)
            self.setFixedWidth(self.width() + 270)
        else:
            self.table.setColumnHidden(1, True)
            self.table.setColumnHidden(2, True)
            self.table.setFixedWidth(self.table.width() - 270)
            self.setFixedWidth(self.width() - 270)

    def checkItemSave(self, item):
        """Проверка изменения ячейки имени датчика."""
        if item.column() == 1:
            self.isItemSave = True
        else:
            self.isItemSave = False

    def itemSave(self, item):
        """Сохранение имени в списке."""
        if self.isItemSave:
            if item.column() == 1:
                if item.tableWidget() == self.table:
                    self.isItemSave = False
                    self.statusBar().showMessage(item.text() + " save")
                    temp = self.table.item(item.row(), 2)
                    key = temp.text()
                    self.core.sensors[key].name = item.text()
        self.table.clearSelection()

    def onLogged(self, log, modes):
        """Событие логирования.
        
        log - передаваемое сообщение;
        
        modes - содержит один или несколько режимов отображения лога:
        
        l - вывод в текстовое поле;

        s - вывод в статус бар;

        f - запись в файл."""
        if 'l' in modes:
            self.textEditList.appendleft(log)
            self.textEdit.clear()
            self.textEdit.setText('\n'.join(self.textEditList))

        if 's' in modes:
            self.statusBar().showMessage(log)

        if 'f' in modes:
            directory = '{0}\\{1}\\{2}\\{3}'.format(
                self.core.pathData, self.core.currentDate.strftime('%Y'),
                self.core.currentDate.strftime('%m'),
                self.core.currentDate.strftime('%d'))
            os.makedirs(directory, 0o777, True)
            with open(
                    '{0}\\{1}.log'.format(
                        directory, self.core.currentDate.strftime('%Y.%m.%d')),
                    'a') as file:
                file.write(log + '\n')

    def onDataAdded(self):
        """Событие добавления данных."""
        self.table.setRowCount(len(self.core.sensors))
        if self.table.rowCount() <= 20:
            self.table.setMinimumHeight(25 + self.table.rowCount() * 23)
        i = 0
        for key in self.core.sensors.keys():
            if self.core.sensors[key].value is not None:
                self.table.setRowHeight(i, 23)
                self.table.setItem(
                    i, 0, QTableWidgetItem(self.core.sensors[key].value))
                self.table.setItem(
                    i, 1, QTableWidgetItem(self.core.sensors[key].name))
                self.table.setItem(i, 2, QTableWidgetItem(key))
                i += 1
        self.table.setRowCount(i)
        self.table.sortItems(1)

    def onAbout(self):
        """Действие нажатия Помощь -> О программе."""
        text = '<h2>{0}</h2>'\
               '<p>Client program for monitoring the condition<br>'\
               'of the premises of the Kharkov Radar.<br>'\
               'Source code is available on '\
               '<a href="https://github.com/StanislavMain/ObserverClient">'\
               'GitHub</a>.</p><p><b>Stanislav Hnatiuk</b><br>'\
               'Institute of Ionosphere\n<br>Ukraine, Kharkiv.<br><br>'\
               'Contacts with me:<br>'\
               '<a href="https://t.me/stanmain">Telegram</a><br>'\
               '<a href="https://github.com/StanislavMain">GitHub</a><br>'\
               '<br><b>All rights reserved.</b></p>'.format(self.windowTitle())
        QMessageBox.about(self, 'About the program', text)

    def actionHelpHelpTriggered(self):
        """Действие нажатия Помощь -> Помощь."""
        text = '<p><b>Console parametrs</b><br>'\
               'usage: main [options]<br>'\
               'where options have next key:<br>'\
               '-s [seconds]: start monitoring with a period of [seconds]</p>'\
               '<p><b>Code and name</b><br>'\
               'Write your address and sensors in the appropriate files:<br>'\
               '{}<br>{}/*</p>'\
               '<p><b>Data</b><br>'\
               'Data is located in "{}"<br>'\
               '"/Year/Month/Day/Y.M.D.csv" : data file<br>'\
               '"/Year/Month/Day/Y.M.D.png" : chart file<br>'\
               '"/Year/Month/Day/Y.M.D.log" : log file<br>'\
               '</p>'.format(
                   self.core.pathAddresses,
                   self.core.pathSensors,
                   self.core.pathData
                )
        QMessageBox.information(self, 'Help', text)
Ejemplo n.º 22
0
class Widgets(QWidget):
    def __init__(self, parent=None):
        super(Widgets, self).__init__(parent)

        self.initUI()

    def initUI(self):

        fuenteSiacle = self.font()
        fuenteSiacle.setBold(True)
        fuenteSiacle.setPointSize(12)

        paletaBotones = self.palette()
        paletaBotones.setColor(QPalette.Background, QColor("#2EFEC8"))

        frameBotones = QFrame()
        frameBotones.setFrameStyle(QFrame.NoFrame)
        frameBotones.setAutoFillBackground(True)
        frameBotones.setPalette(paletaBotones)
        frameBotones.setFixedWidth(220)

        paletaPanel = self.palette()
        paletaPanel.setBrush(QPalette.Background, QBrush(QColor(255, 90, 0), Qt.SolidPattern))
        paletaPanel.setColor(QPalette.Foreground, Qt.white)

        labelSiacle = QLabel("ПАНЕЛЬ УПРАВЛЕНИЯ", frameBotones)
        labelSiacle.setAlignment(Qt.AlignCenter | Qt.AlignVCenter)
        labelSiacle.setFont(fuenteSiacle)
        labelSiacle.setAutoFillBackground(True)
        labelSiacle.setPalette(paletaPanel)
        labelSiacle.setFixedSize(220, 46)
        labelSiacle.move(0, 0)

        # ============================================================

        tamanioIcono = QSize(30, 30)

        botonNuevo = Boton(frameBotones)
        botonNuevo.setText(" Новый")
        botonNuevo.setToolTip("Новый клиент")
        botonNuevo.setCursor(Qt.PointingHandCursor)
        botonNuevo.move(-2, 45)

        botonActualizar = Boton(frameBotones)
        botonActualizar.setText(" Обновление")
        botonActualizar.setToolTip("Обновление клиента ")
        botonActualizar.setCursor(Qt.PointingHandCursor)
        botonActualizar.move(-2, 82)

        botonEliminar = Boton(frameBotones)
        botonEliminar.setText(" Удалить")
        botonEliminar.setToolTip("Удалить клиента")
        botonEliminar.setCursor(Qt.PointingHandCursor)
        botonEliminar.move(-2, 119)

        botonLimpiar = Boton(frameBotones)
        botonLimpiar.setText(" Закрыть")
        botonLimpiar.setToolTip("Закрыть бд")
        botonLimpiar.setCursor(Qt.PointingHandCursor)
        botonLimpiar.move(-2, 156)

        # ============================================================

        paletaSuscribete = self.palette()
        paletaSuscribete.setBrush(QPalette.Background, QBrush(QColor(135, 206, 250),
                                                              Qt.SolidPattern))

        fuenteSuscribete = self.font()
        fuenteSuscribete.setBold(True)
        fuenteSuscribete.setFamily("Arial")
        fuenteSuscribete.setPointSize(11)

        labelSuscribete = QLabel("<a href='https://t.me/yarosla_0v'>АВТОР</a>", frameBotones)

        labelSuscribete.setAlignment(Qt.AlignCenter | Qt.AlignVCenter)
        labelSuscribete.setOpenExternalLinks(True)
        labelSuscribete.setFont(fuenteSuscribete)
        labelSuscribete.setAutoFillBackground(True)
        labelSuscribete.setPalette(paletaSuscribete)
        labelSuscribete.setFixedSize(220, 46)
        labelSuscribete.move(0, 210)

        paletaFrame = self.palette()
        paletaFrame.setColor(QPalette.Background, QColor("blue"))

        frameBienvenido = QFrame()
        frameBienvenido.setFrameStyle(QFrame.NoFrame)
        frameBienvenido.setAutoFillBackground(True)
        frameBienvenido.setPalette(paletaFrame)
        frameBienvenido.setFixedHeight(46)

        # ============================================================

        paletaTitulo = self.palette()
        paletaTitulo.setColor(QPalette.Foreground, Qt.yellow)

        labelBienvenido = QLabel("Клиенты")
        labelBienvenido.setAlignment(Qt.AlignCenter)
        labelBienvenido.setFont(fuenteSiacle)
        labelBienvenido.setPalette(paletaTitulo)

        botonConfiguracion = QPushButton()
        botonConfiguracion.setIcon(QIcon("Imagenes/configuracion.png"))
        botonConfiguracion.setIconSize(QSize(24, 24))
        botonConfiguracion.setToolTip("Конфигурация")
        botonConfiguracion.setCursor(Qt.PointingHandCursor)
        botonConfiguracion.setFixedWidth(36)

        disenioFrame = QHBoxLayout()
        disenioFrame.addWidget(labelBienvenido, Qt.AlignCenter)
        disenioFrame.addStretch()
        disenioFrame.addWidget(botonConfiguracion)
        disenioFrame.setContentsMargins(0, 0, 5, 0)
        frameBienvenido.setLayout(disenioFrame)

        # ============================================================

        self.buscarLineEdit = QLineEdit()
        self.buscarLineEdit.setObjectName("Enter")
        self.buscarLineEdit.setPlaceholderText("Имя клента")
        self.buscarLineEdit.setMinimumSize(200, 26)

        botonBuscar = QPushButton("Поиск")
        botonBuscar.setObjectName("Поиск")
        botonBuscar.setCursor(Qt.PointingHandCursor)
        botonBuscar.setMinimumSize(60, 26)

        separadorTodos = QFrame()
        separadorTodos.setFrameShape(QFrame.VLine)
        separadorTodos.setFrameShadow(QFrame.Raised)
        separadorTodos.setFixedSize(1, 26)

        botonTodos = QPushButton("Все записи")
        botonTodos.setObjectName("Все записи")
        botonTodos.setCursor(Qt.PointingHandCursor)
        botonTodos.setMinimumSize(60, 26)

        nombreColumnas = ("Id", "Имя", "Фамилия", "Пол", "Дата рождения", "Страна",
                          "Телефон")

        menuMostrarOcultar = QMenu()
        for indice, columna in enumerate(nombreColumnas, start=0):
            accion = QAction(columna, menuMostrarOcultar)
            accion.setCheckable(True)
            accion.setChecked(True)
            accion.setData(indice)

            menuMostrarOcultar.addAction(accion)

        botonMostrarOcultar = QPushButton("Скрыть столбцы")
        botonMostrarOcultar.setCursor(Qt.PointingHandCursor)
        botonMostrarOcultar.setMenu(menuMostrarOcultar)
        botonMostrarOcultar.setMinimumSize(180, 26)

        disenioBuscar = QHBoxLayout()
        disenioBuscar.setSpacing(10)
        disenioBuscar.addWidget(self.buscarLineEdit)
        disenioBuscar.addWidget(botonBuscar)
        disenioBuscar.addWidget(separadorTodos)
        disenioBuscar.addWidget(botonTodos)
        disenioBuscar.addWidget(botonMostrarOcultar)

        self.tabla = QTableWidget()

        self.tabla.setEditTriggers(QAbstractItemView.NoEditTriggers)

        self.tabla.setDragDropOverwriteMode(False)

        self.tabla.setSelectionBehavior(QAbstractItemView.SelectRows)

        self.tabla.setSelectionMode(QAbstractItemView.SingleSelection)

        self.tabla.setTextElideMode(Qt.ElideRight)  # Qt.ElideNone

        self.tabla.setWordWrap(False)

        self.tabla.setSortingEnabled(False)

        self.tabla.setColumnCount(7)

        self.tabla.setRowCount(0)

        self.tabla.horizontalHeader().setDefaultAlignment(Qt.AlignHCenter | Qt.AlignVCenter |
                                                          Qt.AlignCenter)

        self.tabla.horizontalHeader().setHighlightSections(False)

        self.tabla.horizontalHeader().setStretchLastSection(True)

        self.tabla.verticalHeader().setVisible(False)

        self.tabla.setAlternatingRowColors(True)

        self.tabla.verticalHeader().setDefaultSectionSize(20)

        # self.tabla.verticalHeader().setHighlightSections(True)

        self.tabla.setHorizontalHeaderLabels(nombreColumnas)

        self.tabla.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tabla.customContextMenuRequested.connect(self.menuContextual)

        for indice, ancho in enumerate((80, 240, 240, 140, 150, 130), start=0):
            self.tabla.setColumnWidth(indice, ancho)

        # ============================================================

        disenioBuscarTabla = QVBoxLayout()
        disenioBuscarTabla.addLayout(disenioBuscar)
        disenioBuscarTabla.addWidget(self.tabla)
        disenioBuscarTabla.setSpacing(8)
        disenioBuscarTabla.setContentsMargins(10, 10, 10, 0)

        disenioDerecho = QVBoxLayout()
        disenioDerecho.addWidget(frameBienvenido)
        disenioDerecho.addLayout(disenioBuscarTabla)
        disenioDerecho.setContentsMargins(0, 0, 0, 0)

        disenioFinal = QGridLayout()
        disenioFinal.addWidget(frameBotones, 0, 0)
        disenioFinal.addLayout(disenioDerecho, 0, 1)
        disenioFinal.setSpacing(0)
        disenioFinal.setContentsMargins(0, 0, 0, 0)

        self.setLayout(disenioFinal)

        self.copiarInformacion = QApplication.clipboard()

        botonNuevo.clicked.connect(self.Nuevo)
        botonActualizar.clicked.connect(self.Actualizar)
        botonEliminar.clicked.connect(self.Eliminar)
        botonLimpiar.clicked.connect(self.limpiarTabla)

        self.buscarLineEdit.returnPressed.connect(self.Buscar)
        botonBuscar.clicked.connect(self.Buscar)
        botonTodos.clicked.connect(self.Buscar)

        botonConfiguracion.clicked.connect(lambda: Configuracion(self).exec_())

        self.tabla.itemDoubleClicked.connect(self.Suscribete)

        menuMostrarOcultar.triggered.connect(self.mostrarOcultar)

    def Nuevo(self):
        nuevoCliente(self).exec_()

    def Actualizar(self):
        fila = self.tabla.selectedItems()

        if fila:
            indice = fila[0].row()
            datos = [self.tabla.item(indice, i).text() for i in range(7)]

            actualizarCliente(indice, datos, self).exec_()
        else:
            QMessageBox.critical(self, "Обновление клиента", "Выберите клиента.   ",
                                 QMessageBox.Ok)

    def Eliminar(self):
        fila = self.tabla.selectedItems()

        if fila:
            eliminar = QMessageBox(self)

            eliminar.setWindowTitle("Удалить клиента")
            eliminar.setIcon(QMessageBox.Question)
            eliminar.setText("Вы уверены, что хотите удалить клиента?   ")
            botonSi = eliminar.addButton("Да", QMessageBox.YesRole)
            botonCancelar = eliminar.addButton("Отмена", QMessageBox.NoRole)

            eliminar.exec_()

            if eliminar.clickedButton() == botonSi:
                indiceFila = fila[0].row()
                idCliente = self.tabla.item(indiceFila, 0).text()

                if QFile.exists("DB_SIACLE/DB_SIACLE.db"):
                    conexion = sqlite3.connect("DB_SIACLE/DB_SIACLE.db")
                    cursor = conexion.cursor()

                    try:
                        cursor.execute("DELETE FROM CLIENTES WHERE ID = ?", (idCliente,))
                        conexion.commit()

                        conexion.close()

                        self.tabla.removeRow(indiceFila)
                        self.tabla.clearSelection()

                        QMessageBox.information(self, "Удалить клиента.", "Клиент удален."
                                                                          "   ", QMessageBox.Ok)
                    except:
                        conexion.close()
                        QMessageBox.critical(self, "Удалить клиента.", "Неизвестная ошибка.   ",
                                             QMessageBox.Ok)
                else:
                    QMessageBox.critical(self, "Поиск клиентов", "База не найдена. "
                                                                 "datos.   ", QMessageBox.Ok)
        else:
            QMessageBox.critical(self, "Удалить клиента ", "Выберите клиента.   ",
                                 QMessageBox.Ok)

    def Suscribete(self, celda):
        QMessageBox.warning(self, "", " "
                                      "\n "
                                      "   ".format(celda.text()), QMessageBox.Ok)

    def Buscar(self):
        widget = self.sender().objectName()

        if widget in ("Enter", "Поиск"):
            cliente = " ".join(self.buscarLineEdit.text().split()).lower()

            if cliente:
                sql = "SELECT * FROM CLIENTES WHERE NOMBRE LIKE ?", ("%" + cliente + "%",)
            else:
                self.buscarLineEdit.setFocus()
                return
        else:
            self.buscarLineEdit.clear()
            sql = "SELECT * FROM CLIENTES"

        if QFile.exists("DB_SIACLE/DB_SIACLE.db"):
            conexion = sqlite3.connect("DB_SIACLE/DB_SIACLE.db")
            cursor = conexion.cursor()

            try:
                if widget in ("Enter", "Поиск"):
                    cursor.execute(sql[0], sql[1])
                else:
                    cursor.execute(sql)

                datosDevueltos = cursor.fetchall()
                conexion.close()

                self.tabla.clearContents()
                self.tabla.setRowCount(0)

                if datosDevueltos:
                    fila = 0
                    for datos in datosDevueltos:
                        self.tabla.setRowCount(fila + 1)

                        idDato = QTableWidgetItem(str(datos[0]))
                        idDato.setTextAlignment(Qt.AlignCenter)

                        self.tabla.setItem(fila, 0, idDato)
                        self.tabla.setItem(fila, 1, QTableWidgetItem(datos[1]))
                        self.tabla.setItem(fila, 2, QTableWidgetItem(datos[2]))
                        self.tabla.setItem(fila, 3, QTableWidgetItem(datos[3]))
                        self.tabla.setItem(fila, 4, QTableWidgetItem(datos[4]))
                        self.tabla.setItem(fila, 5, QTableWidgetItem(datos[5]))
                        self.tabla.setItem(fila, 6, QTableWidgetItem(datos[6]))

                        fila += 1
                else:
                    QMessageBox.information(self, "Поиск клиента ", "Не найдено "
                                                                    "информации.   ", QMessageBox.Ok)
            except:
                conexion.close()
                QMessageBox.critical(self, "Поиск клиента", "Неизвестная ошибка.   ",
                                     QMessageBox.Ok)
        else:
            QMessageBox.critical(self, "Buscar clientes", "База данных не найдена.   ",
                                 QMessageBox.Ok)

        self.buscarLineEdit.setFocus()

    def mostrarOcultar(self, accion):
        columna = accion.data()

        if accion.isChecked():
            self.tabla.setColumnHidden(columna, False)
        else:
            self.tabla.setColumnHidden(columna, True)

    def limpiarTabla(self):
        self.tabla.clearContents()
        self.tabla.setRowCount(0)

    def menuContextual(self, posicion):
        indices = self.tabla.selectedIndexes()

        if indices:
            menu = QMenu()

            itemsGrupo = QActionGroup(self)
            itemsGrupo.setExclusive(True)

            menu.addAction(QAction("Скопировать все ", itemsGrupo))

            columnas = [self.tabla.horizontalHeaderItem(columna).text()
                        for columna in range(self.tabla.columnCount())
                        if not self.tabla.isColumnHidden(columna)]

            copiarIndividual = menu.addMenu("Копировать поле")
            for indice, item in enumerate(columnas, start=0):
                accion = QAction(item, itemsGrupo)
                accion.setData(indice)

                copiarIndividual.addAction(accion)

            itemsGrupo.triggered.connect(self.copiarTableWidgetItem)

            menu.exec(self.tabla.viewport().mapToGlobal(posicion))

    def copiarTableWidgetItem(self, accion):
        filaSeleccionada = [dato.text() for dato in self.tabla.selectedItems()]

        if accion.text() == "Скопировать все":
            filaSeleccionada = tuple(filaSeleccionada)
        else:
            filaSeleccionada = filaSeleccionada[accion.data()]

        self.copiarInformacion.clear(mode=QClipboard.Clipboard)
        self.copiarInformacion.setText(str(filaSeleccionada), QClipboard.Clipboard)
Ejemplo n.º 23
0
class App(QDialog):
    def __init__(self):
        super().__init__()

        self.title = 'SEQUENTIAL'
        self.left = 100
        self.top = 100
        self.width = 320
        self.height = 320
        self.initUI()

    def initUI(self):

        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, 1500, 1500)
        global inpSize  # cardinal variables d'entrées dans notre cas rf0 rf1  pr1 pr2 pr3
        global outpSize  # cardinal variables de sorties pr1 pr2 pr3
        global inlabels  # labels des variables
        global outlabels  #
        global pblties  # 2^(inpsize)

        self.textboxou = QLineEdit(self)
        self.textboxou.setPlaceholderText("Out")

        self.textboxou.move(442, 600)
        self.textboxou.resize(30, 30)

        self.textboxin = QLineEdit(self)
        self.textboxin.setText("")
        self.textboxin.setPlaceholderText("In")
        self.textboxin.move(410, 600)
        self.textboxin.resize(30, 30)

        inlabels = []
        outlabels = []
        global horiz

        self.buttonSet = QPushButton('OK', self)
        self.buttonSet.move(410, 630)
        self.buttonSet.resize(60, 40)
        self.buttonSet.clicked.connect(self.on_lickvarou)

        self.show()

    def on_lickvarou(self):

        global inpSize
        global outpSize
        global inlabels
        global outlabels
        global pblties

        inlabels = []
        outlabels = []
        outpSize = int(self.textboxou.text())

        inpSize = int(self.textboxin.text())
        self.textboxou.hide()
        self.textboxin.hide()
        self.buttonSet.hide()
        horiz = []
        pblties = 2**inpSize
        ii = 0
        while (ii < inpSize):
            inlabels.append("in" + str(ii))
            horiz.append("in" + str(ii))
            ii = ii + 1
        ii = 0
        while (ii < outpSize):
            outlabels.append("out" + str(ii))
            horiz.append("out" + str(ii))
            ii = ii + 1

        self.datatable = QTableWidget(parent=self)
        self.datatable.setColumnCount(inpSize + outpSize)
        self.datatable.setRowCount(pblties)
        self.datatable.setHorizontalHeaderLabels(horiz)
        self.datatable.show()
        QTableWidget.resize(self.datatable, 1250, 600)

        self.textbox = QTextEdit(self)
        self.textbox.setText("")
        self.textbox.move(900, 630)
        self.textbox.resize(280, 40)
        self.textbox.show()

        lik = list(itertools.product([0, 1], repeat=inpSize))
        i = 0
        while (i < pblties):
            j = 0
            while (j < (inpSize + outpSize)):
                if (j > inpSize - 1):

                    self.datatable.setItem(i, j, QTableWidgetItem('x'))
                else:
                    self.datatable.setItem(
                        i, j,
                        QTableWidgetItem(str(
                            lik.__getitem__(i).__getitem__(j))))
                j = j + 1
            i = i + 1

        buttonEnv = QPushButton('ENVOYER', self)
        buttonEnv.setToolTip('This is an example button')
        buttonEnv.move(700, 650)
        buttonEnv.clicked.connect(self.on_lick)
        buttonEnv.show()

    def on_lick(self):
        global inpSize
        global outpSize
        global inlabels
        global outlabels
        global pblties
        print("hala")
        self.datatable.clearSelection()
        self.datatable.selectAll()
        strsin = ["" for x in range(pblties)]
        strsout = ["" for x in range(pblties)]

        z = 0
        for currentQTableWidgetItem in self.datatable.selectedItems():
            if (currentQTableWidgetItem.column() > inpSize - 1):
                strsout[currentQTableWidgetItem.row(
                )] = strsout[currentQTableWidgetItem.row(
                )] + currentQTableWidgetItem.text()
            else:
                strsin[currentQTableWidgetItem.row(
                )] = strsin[currentQTableWidgetItem.row(
                )] + currentQTableWidgetItem.text()

        k = 0
        t = logicmin.TT(inpSize, outpSize)
        while (k < pblties):
            t.add(strsin[k], strsout[k])
            k = k + 1
        sols = t.solve()
        self.textbox.setText(
            sols.printN(xnames=inlabels, ynames=outlabels, info=False))
Ejemplo n.º 24
0
class MainWindow(QMainWindow):
    ''' A class used to represent main window

    Attributes
    ----------
    mydatabase : mydatabase
        instance of the class mydatabase
    table : QTableWidget
        table for displaying data from database

    Methods
    -------
    initUI
        Initializes user interface
    loaddb(grid_layout)
        Loads database and display it in table
    createdb(grid_layout,colnumber,valuelist)
        Creates new database and display it in table
    displaytable(grid_layout,colnumber,rownumber,data)
        Displays data in table
    savefile
        Saves data in csv file
    requesteditrow(grid_layout)
        Asks user to input data for editing cell
    requaestdelrow(grid_layout)
        Asks user to input data for deleting row
    requestaddrow(grid_layout)
        Asks user to input data for adding row
    askforsearch
        Asks user to input data for finding row
    openfilename
        Asks user to select file for opening
    savefilepath
        Asks user to select file for saving
    requestcolnumber(grid_layout)
        Asks user to input data for creating new database
    showabout
        Shows message with information about developer
    on_cell_item_clicked(item)
        Allows user to edit cell by double clicking on cell's item
    showmessage(title,text)
        Shows  message box with given title and text
    '''

    def __init__(self):
        super().__init__()
        self.table = QTableWidget()  # Создаём таблицу
        self.table.itemDoubleClicked.connect(self.on_cell_item_clicked)
        self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.initUI()


    def initUI(self):
        '''Initializes user interface
        '''

        central_widget = QWidget(self)                  # Создаём центральный виджет
        self.setMinimumWidth(500)
        self.setMinimumHeight(500)
        self.setCentralWidget(central_widget)           # Устанавливаем центральный виджет

        grid_layout = QGridLayout()             # Создаём QGridLayout
        central_widget.setLayout(grid_layout)   # Устанавливаем данное размещение в центральный виджет
        
         

        exitAction = QAction('Exit', self)
        exitAction.setShortcut('Ctrl+Q')
        exitAction.setStatusTip('Exit from application')
        exitAction.setIcon(QIcon('exit.svg'))
        exitAction.triggered.connect(self.close)

        loadAction = QAction('Load',self)
        loadAction.setShortcut('Ctrl+O')
        loadAction.setStatusTip('Load database from cvs file')
        loadAction.setIcon(QIcon('load.svg'))
        loadAction.triggered.connect(lambda: self.loaddb(grid_layout))

        saveAction = QAction('Save', self)
        saveAction.setShortcut('Ctrl+S')
        saveAction.setStatusTip('Save database into cvs file')
        saveAction.setIcon(QIcon('save.svg'))
        saveAction.triggered.connect(self.savefile)

        createAction = QAction('Create', self)
        createAction.setShortcut('Ctrl+N')
        createAction.setStatusTip('Create new database')
        createAction.setIcon(QIcon("new.svg"))
        createAction.triggered.connect(lambda: self.requestcolnumber(grid_layout))


        deleterowAction = QAction('Delete row',self)
        deleterowAction.setStatusTip('Delete row from database')
        deleterowAction.setIcon(QIcon('delete.svg'))
        deleterowAction.triggered.connect(lambda: self.requaestdelrow(grid_layout))

        addrowAction = QAction('Add row', self)
        addrowAction.setStatusTip('Add row to database')
        addrowAction.setIcon(QIcon('add.svg'))
        addrowAction.triggered.connect(lambda: self.requestaddrow(grid_layout)) 

        editrowAction = QAction('Edit row',self)
        editrowAction.setStatusTip('Edit row in database')
        editrowAction.setIcon(QIcon('edit.svg'))
        editrowAction.triggered.connect(lambda: self.requesteditrow(grid_layout))

        searchAction = QAction('Find row',self)
        searchAction.setShortcut('Ctrl+F')
        searchAction.setStatusTip('Find row in database')
        searchAction.setIcon(QIcon('find.svg'))
        searchAction.triggered.connect(self.askforsearch)

        aboutAction = QAction('About us', self)
        aboutAction.setStatusTip('About us')
        aboutAction.setIcon(QIcon('about.svg'))
        aboutAction.triggered.connect(self.showabout)


        self.statusBar()

        menubar = self.menuBar()


        fileMenu = menubar.addMenu('&File')
        editMenu = menubar.addMenu('&Edit')
        moreMenu = menubar.addMenu('&More')
        helpMenu = menubar.addMenu('&Help')
        

        fileMenu.addAction(loadAction)
        fileMenu.addAction(saveAction)
        fileMenu.addAction(createAction)
        fileMenu.addAction(exitAction)

        editMenu.addAction(deleterowAction)
        editMenu.addAction(addrowAction)
        editMenu.addAction(editrowAction)

        moreMenu.addAction(searchAction)

        helpMenu.addAction(aboutAction)
        
        self.setWindowTitle('База данных') # название окна
        self.setWindowIcon(QIcon('icon.jpg'))
        self.show()

    def loaddb(self,grid_layout):
        '''Loads database and display it in table
        Parameters
        ----------
        :param grid_layout: QGridLayout
        '''
        filename = self.openfilename()
        if os.path.exists(filename):
            self.mydatabase = mydatabase(filename)
            rownumber,colnumber,data = self.mydatabase.readdatafromcsv(filename)
            self.displaytable(grid_layout,colnumber,rownumber,data)

    def createdb(self,grid_layout,colnumber,valuelist):
        ''' Creates new database and display it in table
        Parameters
        ----------
        :param grid_layout: QGridLayout
        :param colnumber: number of columns
        :param valuelist: list of values
        '''
        self.mydatabase = mydatabase('')
        colnumber=colnumber+1
        newdb = self.mydatabase.create(colnumber,valuelist[0:colnumber])
        self.mydatabase.add(valuelist[colnumber:len(valuelist)])
        rownumber = 2
        data=[valuelist[0:colnumber]]
        data.append(valuelist[colnumber:len(valuelist)])
        self.displaytable(grid_layout,colnumber,rownumber,data)

    def displaytable(self,grid_layout,colnumber,rownumber,data):
        '''Displays data in table
        Parameters
        ----------
        :param grid_layout: QGridLayout
        :param colnumber: number of columns
        :param rownumber: number of rows
        :param data: data
        '''
        self.table.setColumnCount(colnumber)
        self.table.setRowCount(rownumber-1)  
        if type(data[0]) == list:
            headerlist=data[0]
            self.table.setHorizontalHeaderLabels(headerlist)
            data=data[1:]
            for i in range(rownumber-1):
                for j in range(colnumber):
                    # print('i, j, data[i][j]',i,j,data[i][j])
                    self.table.setItem(i, j, QTableWidgetItem(str(data[i][j])))
        else:
            headerlist = ['столбец '+str(i) for i in range(1,colnumber+1)]
            self.table.setHorizontalHeaderLabels(headerlist)
            for j in range(colnumber):
                    self.table.setItem(0, j, QTableWidgetItem(str(data[j])))
        grid_layout.addWidget(self.table, 0, 0)   # Добавляем таблицу в сетку 
 
    def savefile(self):
        ''' Saves data in csv file
        '''
        savepath = self.savefilepath()
        print('savepath',savepath)
        if len(savepath) < 4:
            print('length',len(savepath))
            savepath=savepath+".csv"
        else:
            if savepath[-4:] !=".csv":
                print('1',savepath[-4:])
                savepath=savepath+".csv"
                print('2',savepath)
        try:            
            self.mydatabase.dumpdb(savepath)
        except Exception as e:
            pass

    def requesteditrow(self,grid_layout):
        ''' Asks user to input data for editing cell
        Parameters
        ----------
        :param grid_layout: QGridLayout
        '''
        try:
            row, ok = QInputDialog.getInt(self, 'Редактировать ячейку', 'Введите номер строки \n(Вы также можете редактировать ячейку дважды кликнув по ней)',min=1,max=len(self.mydatabase.db.keys())-1)
            col, ok = QInputDialog.getInt(self, 'Редактировать ячейку', 'Введите номер столбца',min=1,max=len(self.mydatabase.db[0])-1)
            value, ok = QInputDialog.getText(self, 'Редактировать ячейку', 'Введите значение ячейки')
            is_successful = self.mydatabase.set(row,col,value)
            if is_successful == True:
                colnumber = len(self.mydatabase.db[0])
                rownumber = len(self.mydatabase.db.keys())
                data = []
                for key in self.mydatabase.db:
                    data.append(self.mydatabase.db[key])
                print('data',data)
                self.displaytable(grid_layout,colnumber,rownumber,data)
        except Exception as e:
            self.showmessage("Внимание","Чтобы редактировать строку, нужно сначала загрузить из файла или создать базу данных")
   

    def requaestdelrow(self,grid_layout):
        ''' Asks user to input data for deleting row
        Parameters
        ----------
        :param grid_layout: QGridLayout
        '''
        try:
            # key, ok = QInputDialog.getInt(self, 'Удалить строку', 'Введите номер строки, которую хотите удалить',min=1,max=len(self.mydatabase.db.keys()))    
            key = int(self.table.selectedItems()[0].text())
            if len(self.table.selectedItems()) == len(self.mydatabase.db[0]):
                is_successful = self.mydatabase.delete(key+1)
                print('key',key,'database',self.mydatabase.db)
                if is_successful == True:
                    colnumber = len(self.mydatabase.db[0])
                    rownumber = len(self.mydatabase.db.keys())
                    data = []
                    for key in self.mydatabase.db:
                        data.append(self.mydatabase.db[key])
                    self.displaytable(grid_layout,colnumber,rownumber,data)
                else:
                    self.showmessage("Внимание","Вы пытаетесь удалить несуществующую строку")

            else:
                self.showmessage("Внимание","Вы выделили столбец")

        except IndexError:
            self.showmessage("Внимание","Чтобы удалить строку, сначала выделите ее в таблице")

        except Exception as e:
            self.showmessage("Внимание","Чтобы удалить строку, нужно сначала загрузить из файла или создать базу данных")



    def requestaddrow(self,grid_layout):
        ''' Asks user to input data for adding row
        Parameters
        ----------
        :param grid_layout: QGridLayout
        '''
        try:
            colnumber = len(self.mydatabase.db[0])
            valuelist=[str(len(self.mydatabase.db.keys())-1)]
            ok = True
            for i in range(colnumber-1):
                value=''
                while value == '' and ok == True:
                    value, ok = QInputDialog.getText(self, 'Создание БД', 'Введите значение для '+str(i+1)+'-го поля:')
                    if value: 
                        valuelist.append(value)
            self.mydatabase.add(valuelist) #добавили строку в БД
            rownumber = len(self.mydatabase.db.keys())
            data = []
            for key in self.mydatabase.db:
                data.append(self.mydatabase.db[key])
            self.displaytable(grid_layout,colnumber,rownumber,data)
        except IndexError:
            self.showmessage("Внимание","Вы заполнили не все поля")
        
        except Exception as e:
            self.showmessage("Внимание","Чтобы добавить строку, нужно сначала загрузить из файла или создать базу данных")        

    def askforsearch(self):
        ''' Asks user to input data for finding row

        '''
        try:
            colnumber = self.table.currentColumn() 
            print('colnumber',colnumber,len(self.table.selectedItems()),len(self.mydatabase.db.keys())-1)
            print('db',self.mydatabase.db[1][colnumber])
            if len(self.table.selectedItems()) == len(self.mydatabase.db.keys())-1:
                value, ok = QInputDialog.getText(self, 'Поиск по столбцу', 'Введите значение, которое нужно найти: ')
                if value:
                    keylist = self.mydatabase.search(colnumber,value)
                    self.table.clearSelection()
                    for key in keylist:
                        for i in range(len(self.mydatabase.db[0])-1):
                            self.table.item(key-1,i).setSelected(True)
                    print('keys',keylist)
            else:
                self.showmessage("Внимание","Выделите столбец")
                
        except Exception as e:
            self.showmessage("Внимание","Чтобы выполнить поиск, сначала создайте или загрузите базу данных")
            


    def openfilename(self):
        ''' Asks user to select file for opening
        '''
        path = os.getcwd()
        fname = QFileDialog.getOpenFileName(self, 'Open file',path,"*.csv")[0]
        print(fname)
        return fname



    def savefilepath(self):
        '''Asks user to select file for saving
        '''
        path = os.getcwd()
        path = QFileDialog.getSaveFileName(self,'Save file',path,'*.csv')[0]
        print('path',path)
        return path



    def requestcolnumber(self,grid_layout):
        '''Asks user to input data for creating new database
        Parameters
        ----------
        :param grid_layout: QGridLayout
        '''
        colnumber, ok = QInputDialog.getInt(self, 'Создание БД', 'Введите число полей', min = 1)
        if ok == True:
            valuelist=['']
            ok = True
            for i in range(colnumber):
                value=''
                while value == '' and ok == True:
                    value, ok = QInputDialog.getText(self, 'Создание БД', 'Введите название для '+str(i+1)+'-го поля:')
                    if value: 
                        valuelist.append(value)
            valuelist.append(0)
            for i in range(colnumber):
                value=''
                while value == '' and ok == True:
                    value, ok = QInputDialog.getText(self, 'Создание БД', 'Введите значение для '+str(i+1)+'-го поля:')
                    if value: 
                        valuelist.append(value)
            if ok == True:
                self.createdb(grid_layout,colnumber,valuelist)


    def showabout(self):
        ''' Shows message with information about developer
        '''
        self.showmessage("О разработчике","Студент Роман Забаровский")
     


    def on_cell_item_clicked(self, item):
        ''' Allows user to edit cell by double clicking on cell's item
        Parameters
        ----------
        :param item: QTableWidget::item
        '''
        print(item, item.column())
        if item.column() != 0:
            new_text, ok = QInputDialog.getText(self, 'Редактирование ячейки', 'Введите новое значение поля', text=item.text())
            row=item.row()+1
            is_successful = self.mydatabase.set(row,item.column(),new_text)
            print('is_successful',is_successful, 'db',self.mydatabase.db[row])
            if ok:
                item.setText(new_text)


    def showmessage(self,title,text):
        ''' Shows  message box with given title and text
        Parameters
        ----------
        :param title: the title of message box
        :param text: the text in message box
        '''
        msg = QMessageBox()
        msg.setWindowTitle(title)
        msg.setText(text)
        x = msg.exec_()