Example #1
0
class WatchersWidget(QWidget):
    """ WatchersWidget

        Signals:
            onItemSelected(addr_str) - item dblclicked
            onItemAddClick

        Constants:
            MEMORY_ACCESS_READ = 1
            MEMORY_ACCESS_WRITE = 2
            MEMORY_ACCESS_EXECUTE = 4
            MEMORY_WATCH_SINGLESHOT = 8
    """
    MEMORY_ACCESS_READ = 1
    MEMORY_ACCESS_WRITE = 2
    MEMORY_ACCESS_EXECUTE = 4
    MEMORY_WATCH_SINGLESHOT = 8

    onItemDoubleClicked = pyqtSignal(int, name='onItemDoubleClicked')
    onItemAdded = pyqtSignal(int, name='onItemAdded')
    onItemRemoved = pyqtSignal(int, name='onItemRemoved')

    def __init__(self, parent=None):  # pylint: disable=too-many-statements
        super(WatchersWidget, self).__init__(parent=parent)
        self._app_window = parent

        if self._app_window.dwarf is None:
            print('WatchersWidget created before Dwarf exists')
            return

        self._uppercase_hex = True
        self.setAutoFillBackground(True)

        # connect to dwarf
        self._app_window.dwarf.onWatcherAdded.connect(self._on_watcher_added)
        self._app_window.dwarf.onWatcherRemoved.connect(
            self._on_watcher_removed)

        # setup our model
        self._watchers_model = QStandardItemModel(0, 5)
        self._watchers_model.setHeaderData(0, Qt.Horizontal, 'Address')
        self._watchers_model.setHeaderData(1, Qt.Horizontal, 'R')
        self._watchers_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter,
                                           Qt.TextAlignmentRole)
        self._watchers_model.setHeaderData(2, Qt.Horizontal, 'W')
        self._watchers_model.setHeaderData(2, Qt.Horizontal, Qt.AlignCenter,
                                           Qt.TextAlignmentRole)
        self._watchers_model.setHeaderData(3, Qt.Horizontal, 'X')
        self._watchers_model.setHeaderData(3, Qt.Horizontal, Qt.AlignCenter,
                                           Qt.TextAlignmentRole)
        self._watchers_model.setHeaderData(4, Qt.Horizontal, 'S')
        self._watchers_model.setHeaderData(4, Qt.Horizontal, Qt.AlignCenter,
                                           Qt.TextAlignmentRole)

        # setup ui
        v_box = QVBoxLayout(self)
        v_box.setContentsMargins(0, 0, 0, 0)
        self.list_view = DwarfListView()
        self.list_view.setModel(self._watchers_model)
        self.list_view.header().setSectionResizeMode(0, QHeaderView.Stretch)
        self.list_view.header().setSectionResizeMode(
            1, QHeaderView.ResizeToContents | QHeaderView.Fixed)
        self.list_view.header().setSectionResizeMode(
            2, QHeaderView.ResizeToContents | QHeaderView.Fixed)
        self.list_view.header().setSectionResizeMode(
            3, QHeaderView.ResizeToContents | QHeaderView.Fixed)
        self.list_view.header().setSectionResizeMode(
            4, QHeaderView.ResizeToContents | QHeaderView.Fixed)
        self.list_view.header().setStretchLastSection(False)
        self.list_view.doubleClicked.connect(self._on_item_dblclick)
        self.list_view.setContextMenuPolicy(Qt.CustomContextMenu)
        self.list_view.customContextMenuRequested.connect(self._on_contextmenu)

        v_box.addWidget(self.list_view)
        #header = QHeaderView(Qt.Horizontal, self)

        h_box = QHBoxLayout()
        h_box.setContentsMargins(5, 2, 5, 5)
        btn1 = QPushButton(QIcon(utils.resource_path('assets/icons/plus.svg')),
                           '')
        btn1.setFixedSize(20, 20)
        btn1.clicked.connect(self._on_additem_clicked)
        btn2 = QPushButton(QIcon(utils.resource_path('assets/icons/dash.svg')),
                           '')
        btn2.setFixedSize(20, 20)
        btn2.clicked.connect(self.delete_items)
        btn3 = QPushButton(
            QIcon(utils.resource_path('assets/icons/trashcan.svg')), '')
        btn3.setFixedSize(20, 20)
        btn3.clicked.connect(self.clear_list)
        h_box.addWidget(btn1)
        h_box.addWidget(btn2)
        h_box.addSpacerItem(
            QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Preferred))
        h_box.addWidget(btn3)
        # header.setLayout(h_box)
        # header.setFixedHeight(25)
        # v_box.addWidget(header)
        v_box.addLayout(h_box)

        # create a centered dot icon
        _section_width = self.list_view.header().sectionSize(2)
        self._new_pixmap = QPixmap(_section_width, 20)
        self._new_pixmap.fill(Qt.transparent)
        painter = QPainter(self._new_pixmap)
        rect = QRect((_section_width * 0.5), 0, 20, 20)
        painter.setBrush(QColor('#666'))
        painter.setPen(QColor('#666'))
        painter.drawEllipse(rect)
        self._dot_icon = QIcon(self._new_pixmap)

        # shortcuts
        shortcut_add = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_W),
                                 self._app_window, self._on_additem_clicked)
        shortcut_add.setAutoRepeat(False)

        self.setLayout(v_box)

    # ************************************************************************
    # **************************** Properties ********************************
    # ************************************************************************
    @property
    def uppercase_hex(self):
        """ Addresses displayed lower/upper-case
        """
        return self._uppercase_hex

    @uppercase_hex.setter
    def uppercase_hex(self, value):
        """ Addresses displayed lower/upper-case
            value - bool or str
                    'upper', 'lower'
        """
        if isinstance(value, bool):
            self._uppercase_hex = value
        elif isinstance(value, str):
            self._uppercase_hex = (value == 'upper')

    # ************************************************************************
    # **************************** Functions *********************************
    # ************************************************************************
    def do_addwatcher_dlg(self, ptr=None):  # pylint: disable=too-many-branches
        """ Shows AddWatcherDialog
        """
        watcher_dlg = AddWatcherDialog(self, ptr)
        if watcher_dlg.exec_() == QDialog.Accepted:
            mem_r = watcher_dlg.acc_read.isChecked()
            mem_w = watcher_dlg.acc_write.isChecked()
            mem_x = watcher_dlg.acc_execute.isChecked()
            mem_s = watcher_dlg.singleshot.isChecked()

            ptr = watcher_dlg.text_field.toPlainText()

            if ptr:
                if isinstance(ptr, str):
                    if ptr.startswith('0x') or ptr.startswith('#'):
                        ptr = utils.parse_ptr(ptr)
                    else:
                        try:
                            ptr = int(ptr, 10)
                        except ValueError:
                            pass

                    # int now?
                    if not isinstance(ptr, int):
                        try:
                            ptr = int(
                                self._app_window.dwarf.dwarf_api(
                                    'evaluatePtr', ptr), 16)
                        except ValueError:
                            ptr = 0

                        if ptr == 0:
                            return

                        if not self._app_window.dwarf.dwarf_api(
                                'isValidPointer', ptr):
                            return
                else:
                    return

                mem_val = 0
                if mem_r:
                    mem_val |= self.MEMORY_ACCESS_READ
                if mem_w:
                    mem_val |= self.MEMORY_ACCESS_WRITE
                if mem_x:
                    mem_val |= self.MEMORY_ACCESS_EXECUTE
                if mem_s:
                    mem_val |= self.MEMORY_WATCH_SINGLESHOT

                self.add_address(ptr, mem_val, from_api=False)

                # return [ptr, mem_val]

    def add_address(self, ptr, flags, from_api=False):
        """ Adds Address to display

            ptr - str or int
            flags - int
        """
        if isinstance(ptr, str):
            ptr = utils.parse_ptr(ptr)

        if not isinstance(flags, int):
            try:
                flags = int(flags, 10)
            except ValueError:
                flags = 3

        if not from_api:
            # function was called directly so add it to dwarf
            if not self._app_window.dwarf.is_address_watched(ptr):
                self._app_window.dwarf.dwarf_api('addWatcher', [ptr, flags])
                return

        # show header
        self.list_view.setHeaderHidden(False)

        # create items to add
        if self._uppercase_hex:
            str_frmt = '0x{0:X}'
        else:
            str_frmt = '0x{0:x}'

        addr = QStandardItem()
        addr.setText(str_frmt.format(ptr))

        read = QStandardItem()
        write = QStandardItem()
        execute = QStandardItem()
        singleshot = QStandardItem()

        if flags & self.MEMORY_ACCESS_READ:
            read.setIcon(self._dot_icon)
        if flags & self.MEMORY_ACCESS_WRITE:
            write.setIcon(self._dot_icon)
        if flags & self.MEMORY_ACCESS_EXECUTE:
            execute.setIcon(self._dot_icon)
        if flags & self.MEMORY_WATCH_SINGLESHOT:
            singleshot.setIcon(self._dot_icon)

        # add items as new row on top
        self._watchers_model.insertRow(
            0, [addr, read, write, execute, singleshot])

    def remove_address(self, ptr, from_api=False):
        """ Remove Address from List
        """
        if isinstance(ptr, str):
            ptr = utils.parse_ptr(ptr)

        if not from_api:
            # called somewhere so remove watcher in dwarf too
            self._app_window.dwarf.dwarf_api('removeWatcher', ptr)
            return

        str_frmt = ''
        if self._uppercase_hex:
            str_frmt = '0x{0:X}'.format(ptr)
        else:
            str_frmt = '0x{0:x}'.format(ptr)

        model = self.list_view.model()
        for item in range(model.rowCount()):
            if str_frmt == model.item(item).text():
                model.removeRow(item)

    def delete_items(self):
        """ Delete selected Items
        """
        model = self.list_view.model()

        index = self.list_view.selectionModel().currentIndex().row()
        if index != -1:
            ptr = model.item(index, 0).text()
            self.remove_address(ptr)

    def clear_list(self):
        """ Clear the List
        """
        model = self.list_view.model()

        # go through all items and tell it gets removed
        for item in range(model.rowCount()):
            ptr = model.item(item, 0).text()
            self.remove_address(ptr)

        if model.rowCount() > 0:
            # something was wrong it should be empty
            model.removeRows(0, model.rowCount())

    # ************************************************************************
    # **************************** Handlers **********************************
    # ************************************************************************
    def _on_contextmenu(self, pos):
        index = self.list_view.indexAt(pos).row()
        glbl_pt = self.list_view.mapToGlobal(pos)
        context_menu = QMenu(self)
        context_menu.addAction('Add watcher', self._on_additem_clicked)
        if index != -1:
            context_menu.addSeparator()
            context_menu.addAction(
                'Copy address', lambda: utils.copy_hex_to_clipboard(
                    self._watchers_model.item(index, 0).text()))
            context_menu.addAction(
                'Jump to address', lambda: self._app_window.jump_to_address(
                    self._watchers_model.item(index, 0).text()))
            context_menu.addAction(
                'Delete watcher', lambda: self.remove_address(
                    self._watchers_model.item(index, 0).text()))
            if self.list_view.search_enabled:
                context_menu.addSeparator()
                context_menu.addAction('Search', self.list_view._on_cm_search)
        context_menu.exec_(glbl_pt)

    def _on_item_dblclick(self, model_index):
        row = self._watchers_model.itemFromIndex(model_index).row()
        if row != -1:
            ptr = self._watchers_model.item(row, 0).text()
            self.onItemDoubleClicked.emit(ptr)

    def _on_additem_clicked(self):
        if self._app_window.dwarf.pid == 0:
            return

        self.do_addwatcher_dlg()

    def _on_watcher_added(self, ptr, flags):
        """ Callback from Dwarf after Watcher is added
        """
        ptr = utils.parse_ptr(ptr)
        # add to watcherslist
        self.add_address(ptr, flags, from_api=True)
        self.onItemAdded.emit(ptr)

    def _on_watcher_removed(self, ptr):
        """ Callback from Dwarf after watcher is removed
        """
        ptr = utils.parse_ptr(ptr)
        # remove from list
        self.remove_address(ptr, from_api=True)
        self.onItemRemoved.emit(ptr)
Example #2
0
class AddressList(MyTreeView):

    class Columns(IntEnum):
        TYPE = 0
        ADDRESS = 1
        LABEL = 2
        COIN_BALANCE = 3
        FIAT_BALANCE = 4
        NUM_TXS = 5

    filter_columns = [Columns.TYPE, Columns.ADDRESS, Columns.LABEL, Columns.COIN_BALANCE]

    ROLE_SORT_ORDER = Qt.UserRole + 1000
    ROLE_ADDRESS_STR = Qt.UserRole + 1001

    def __init__(self, parent):
        super().__init__(parent, self.create_menu,
                         stretch_column=self.Columns.LABEL,
                         editable_columns=[self.Columns.LABEL])
        self.wallet = self.parent.wallet
        self.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.setSortingEnabled(True)
        self.show_change = AddressTypeFilter.ALL  # type: AddressTypeFilter
        self.show_used = AddressUsageStateFilter.ALL  # type: AddressUsageStateFilter
        self.change_button = QComboBox(self)
        self.change_button.currentIndexChanged.connect(self.toggle_change)
        for addr_type in AddressTypeFilter.__members__.values():  # type: AddressTypeFilter
            self.change_button.addItem(addr_type.ui_text())
        self.used_button = QComboBox(self)
        self.used_button.currentIndexChanged.connect(self.toggle_used)
        for addr_usage_state in AddressUsageStateFilter.__members__.values():  # type: AddressUsageStateFilter
            self.used_button.addItem(addr_usage_state.ui_text())
        self.std_model = QStandardItemModel(self)
        self.proxy = MySortModel(self, sort_role=self.ROLE_SORT_ORDER)
        self.proxy.setSourceModel(self.std_model)
        self.setModel(self.proxy)
        self.update()
        self.sortByColumn(self.Columns.TYPE, Qt.AscendingOrder)

    def get_toolbar_buttons(self):
        return QLabel(_("Filter:")), self.change_button, self.used_button

    def on_hide_toolbar(self):
        self.show_change = AddressTypeFilter.ALL  # type: AddressTypeFilter
        self.show_used = AddressUsageStateFilter.ALL  # type: AddressUsageStateFilter
        self.update()

    def save_toolbar_state(self, state, config):
        config.set_key('show_toolbar_addresses', state)

    def refresh_headers(self):
        fx = self.parent.fx
        if fx and fx.get_fiat_address_config():
            ccy = fx.get_currency()
        else:
            ccy = _('Fiat')
        headers = {
            self.Columns.TYPE: _('Type'),
            self.Columns.ADDRESS: _('Address'),
            self.Columns.LABEL: _('Label'),
            self.Columns.COIN_BALANCE: _('Balance'),
            self.Columns.FIAT_BALANCE: ccy + ' ' + _('Balance'),
            self.Columns.NUM_TXS: _('Tx'),
        }
        self.update_headers(headers)

    def toggle_change(self, state: int):
        if state == self.show_change:
            return
        self.show_change = AddressTypeFilter(state)
        self.update()

    def toggle_used(self, state: int):
        if state == self.show_used:
            return
        self.show_used = AddressUsageStateFilter(state)
        self.update()

    @profiler
    def update(self):
        if self.maybe_defer_update():
            return
        current_address = self.get_role_data_for_current_item(col=self.Columns.LABEL, role=self.ROLE_ADDRESS_STR)
        if self.show_change == AddressTypeFilter.RECEIVING:
            addr_list = self.wallet.get_receiving_addresses()
        elif self.show_change == AddressTypeFilter.CHANGE:
            addr_list = self.wallet.get_change_addresses()
        else:
            addr_list = self.wallet.get_addresses()
        self.proxy.setDynamicSortFilter(False)  # temp. disable re-sorting after every change
        self.std_model.clear()
        self.refresh_headers()
        fx = self.parent.fx
        set_address = None
        addresses_beyond_gap_limit = self.wallet.get_all_known_addresses_beyond_gap_limit()
        for address in addr_list:
            num = self.wallet.get_address_history_len(address)
            label = self.wallet.get_label(address)
            c, u, x = self.wallet.get_addr_balance(address)
            balance = c + u + x
            is_used_and_empty = self.wallet.is_used(address) and balance == 0
            if self.show_used == AddressUsageStateFilter.UNUSED and (balance or is_used_and_empty):
                continue
            if self.show_used == AddressUsageStateFilter.FUNDED and balance == 0:
                continue
            if self.show_used == AddressUsageStateFilter.USED_AND_EMPTY and not is_used_and_empty:
                continue
            if self.show_used == AddressUsageStateFilter.FUNDED_OR_UNUSED and is_used_and_empty:
                continue
            balance_text = self.parent.format_amount(balance, whitespaces=True)
            # create item
            if fx and fx.get_fiat_address_config():
                rate = fx.exchange_rate()
                fiat_balance = fx.value_str(balance, rate)
            else:
                fiat_balance = ''
            labels = ['', address, label, balance_text, fiat_balance, "%d"%num]
            address_item = [QStandardItem(e) for e in labels]
            # align text and set fonts
            for i, item in enumerate(address_item):
                item.setTextAlignment(Qt.AlignVCenter)
                if i not in (self.Columns.TYPE, self.Columns.LABEL):
                    item.setFont(QFont(MONOSPACE_FONT))
            self.set_editability(address_item)
            address_item[self.Columns.FIAT_BALANCE].setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)
            # setup column 0
            if self.wallet.is_change(address):
                address_item[self.Columns.TYPE].setText(_('change'))
                address_item[self.Columns.TYPE].setBackground(ColorScheme.YELLOW.as_color(True))
            else:
                address_item[self.Columns.TYPE].setText(_('receiving'))
                address_item[self.Columns.TYPE].setBackground(ColorScheme.GREEN.as_color(True))
            address_item[self.Columns.LABEL].setData(address, self.ROLE_ADDRESS_STR)
            address_path = self.wallet.get_address_index(address)
            address_item[self.Columns.TYPE].setData(address_path, self.ROLE_SORT_ORDER)
            address_path_str = self.wallet.get_address_path_str(address)
            if address_path_str is not None:
                address_item[self.Columns.TYPE].setToolTip(address_path_str)
            address_item[self.Columns.FIAT_BALANCE].setData(balance, self.ROLE_SORT_ORDER)
            # setup column 1
            if self.wallet.is_frozen_address(address):
                address_item[self.Columns.ADDRESS].setBackground(ColorScheme.BLUE.as_color(True))
            if address in addresses_beyond_gap_limit:
                address_item[self.Columns.ADDRESS].setBackground(ColorScheme.RED.as_color(True))
            # add item
            count = self.std_model.rowCount()
            self.std_model.insertRow(count, address_item)
            address_idx = self.std_model.index(count, self.Columns.LABEL)
            if address == current_address:
                set_address = QPersistentModelIndex(address_idx)
        self.set_current_idx(set_address)
        # show/hide columns
        if fx and fx.get_fiat_address_config():
            self.showColumn(self.Columns.FIAT_BALANCE)
        else:
            self.hideColumn(self.Columns.FIAT_BALANCE)
        self.filter()
        self.proxy.setDynamicSortFilter(True)

    def create_menu(self, position):
        from electrum_mona.wallet import Multisig_Wallet
        is_multisig = isinstance(self.wallet, Multisig_Wallet)
        can_delete = self.wallet.can_delete_address()
        selected = self.selected_in_column(self.Columns.ADDRESS)
        if not selected:
            return
        multi_select = len(selected) > 1
        addrs = [self.item_from_index(item).text() for item in selected]
        menu = QMenu()
        if not multi_select:
            idx = self.indexAt(position)
            if not idx.isValid():
                return
            item = self.item_from_index(idx)
            if not item:
                return
            addr = addrs[0]
            addr_column_title = self.std_model.horizontalHeaderItem(self.Columns.LABEL).text()
            addr_idx = idx.sibling(idx.row(), self.Columns.LABEL)
            self.add_copy_menu(menu, idx)
            menu.addAction(_('Details'), lambda: self.parent.show_address(addr))
            persistent = QPersistentModelIndex(addr_idx)
            menu.addAction(_("Edit {}").format(addr_column_title), lambda p=persistent: self.edit(QModelIndex(p)))
            #menu.addAction(_("Request payment"), lambda: self.parent.receive_at(addr))
            if self.wallet.can_export():
                menu.addAction(_("Private key"), lambda: self.parent.show_private_key(addr))
            if not is_multisig and not self.wallet.is_watching_only():
                menu.addAction(_("Sign/verify message"), lambda: self.parent.sign_verify_message(addr))
                menu.addAction(_("Encrypt/decrypt message"), lambda: self.parent.encrypt_message(addr))
            if can_delete:
                menu.addAction(_("Remove from wallet"), lambda: self.parent.remove_address(addr))
            addr_URL = block_explorer_URL(self.config, 'addr', addr)
            if addr_URL:
                menu.addAction(_("View on block explorer"), lambda: webopen(addr_URL))

            if not self.wallet.is_frozen_address(addr):
                menu.addAction(_("Freeze"), lambda: self.parent.set_frozen_state_of_addresses([addr], True))
            else:
                menu.addAction(_("Unfreeze"), lambda: self.parent.set_frozen_state_of_addresses([addr], False))

        coins = self.wallet.get_spendable_coins(addrs)
        if coins:
            menu.addAction(_("Spend from"), lambda: self.parent.utxo_list.set_spend_list(coins))

        run_hook('receive_menu', menu, addrs, self.wallet)
        menu.exec_(self.viewport().mapToGlobal(position))

    def place_text_on_clipboard(self, text: str, *, title: str = None) -> None:
        if is_address(text):
            try:
                self.wallet.check_address_for_corruption(text)
            except InternalAddressCorruption as e:
                self.parent.show_error(str(e))
                raise
        super().place_text_on_clipboard(text, title=title)

    def get_edit_key_from_coordinate(self, row, col):
        if col != self.Columns.LABEL:
            return None
        return self.get_role_data_from_coordinate(row, col, role=self.ROLE_ADDRESS_STR)

    def on_edited(self, idx, edit_key, *, text):
        self.parent.wallet.set_label(edit_key, text)
        self.parent.history_model.refresh('address label edited')
        self.parent.utxo_list.update()
        self.parent.update_completions()
Example #3
0
class MainWindow(QMainWindow):
    """
    The main window.
    """
    def __init__(self):
        super().__init__()

        self.init_ui()


    def init_ui(self):
        self.setWindowTitle("VenviPy")
        self.resize(1100, 690)
        self.center()
        self.setWindowIcon(QIcon(":/img/profile.png"))

        self.setStyleSheet(
            """
            QMenuBar {
                background-color: rgb(47, 52, 63);
                color: rgb(210, 210, 210)
            }

            QMenuBar::item {
                background-color: rgb(47, 52, 63);
                color: rgb(210, 210, 210)
            }

            QMenuBar::item::selected {
                background-color: rgb(72, 72, 82)
            }

            QMenu {
                background-color: rgb(47, 52, 63);
                color: rgb(210, 210, 210)
            }

            QMenu::item::selected {
                background-color: rgb(72, 72, 82)
            }

            QToolTip {
                background-color: rgb(47, 52, 63);
                border: rgb(47, 52, 63);
                color: rgb(210, 210, 210);
                padding: 2px;
                opacity: 325
            }

            QTableView {
                gridline-color: rgb(230, 230, 230)
            }

            QTableView::item {
                selection-background-color: rgb(120, 120, 130);
                selection-color: rgb(255, 255, 255)
            }
            """
        )

        self.info_about_venvipy = InfoAboutVenviPy()
        self.venv_wizard = wizard.VenvWizard()

        # refresh venv table on wizard close
        self.venv_wizard.refresh.connect(self.pop_venv_table)

        # refresh interpreter table if 'py-installs' changes
        self.venv_wizard.update_table.connect(self.pop_interpreter_table)


        #]===================================================================[#
        #] ICONS [#==========================================================[#
        #]===================================================================[#

        python_icon = QIcon(":/img/python.png")
        find_icon = QIcon.fromTheme("edit-find")
        manage_icon = QIcon.fromTheme("insert-object")
        settings_icon = QIcon.fromTheme("preferences-system")

        new_icon = QIcon(
            self.style().standardIcon(QStyle.SP_FileDialogNewFolder)
        )
        exit_icon = QIcon(
            self.style().standardIcon(QStyle.SP_BrowserStop)
        )
        reload_icon = QIcon(
            self.style().standardIcon(QStyle.SP_BrowserReload)
        )
        delete_icon = QIcon(
            self.style().standardIcon(QStyle.SP_TrashIcon)
        )
        folder_icon = QIcon(
            self.style().standardIcon(QStyle.SP_DirOpenIcon)
        )
        qt_icon = QIcon(
            self.style().standardIcon(QStyle.SP_TitleBarMenuButton)
        )
        info_icon = QIcon(
            self.style().standardIcon(QStyle.SP_FileDialogInfoView)
        )

        #]===================================================================[#
        #] LAYOUTS [#========================================================[#
        #]===================================================================[#

        centralwidget = QWidget(self)
        grid_layout = QGridLayout(centralwidget)

        v_layout_1 = QVBoxLayout()
        v_layout_2 = QVBoxLayout()
        h_layout_1 = QHBoxLayout()

        v_layout_1.setContentsMargins(12, 19, 5, -1)
        v_layout_2.setContentsMargins(-1, 4, 6, -1)

        # python logo
        self.logo = QLabel(centralwidget)
        self.logo.setPixmap(QPixmap(":/img/pypower.png"))
        self.logo.setAlignment(Qt.AlignRight)


        #]===================================================================[#
        #] BUTTONS [#========================================================[#
        #]===================================================================[#

        self.add_interpreter_button = QPushButton(
            "Add &Interpreter",
            centralwidget,
            statusTip="Add an Interpreter",
            clicked=self.add_interpreter
        )
        self.add_interpreter_button.setMinimumSize(QSize(150, 0))

        self.new_venv_button = QPushButton(
            "&New Venv",
            centralwidget,
            statusTip="Create a new virtual environment",
            clicked=self.venv_wizard.exec_
        )
        self.new_venv_button.setMinimumSize(QSize(135, 0))

        #self.search_pypi_button = QPushButton(
            #"&Search PyPI",
            #centralwidget,
            #statusTip="Search the Python Package Index",
            #clicked=self.search_pypi
        #)

        self.exit_button = QPushButton(
            "Quit",
            centralwidget,
            statusTip="Quit Application",
            clicked=self.on_close
        )

        self.active_dir_button = QToolButton(
            icon=folder_icon,
            toolTip="Switch directory",
            statusTip="Select another directory",
            clicked=self.select_active_dir
        )
        self.active_dir_button.setFixedSize(30, 30)

        # use line edit to store the str
        self.directory_line = QLineEdit()

        self.reload_button = QToolButton(
            icon=reload_icon,
            toolTip="Reload",
            statusTip="Reload venv table content",
            clicked=self.pop_venv_table
        )
        self.reload_button.setFixedSize(30, 30)

        #]===================================================================[#
        # spacer between manage button and exit button
        spacer_item_1 = QSpacerItem(
            20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding
        )
        #]===================================================================[#

        v_layout_2.addWidget(self.logo)
        v_layout_2.addWidget(self.add_interpreter_button)
        v_layout_2.addWidget(self.new_venv_button)
        #v_layout_2.addWidget(self.search_pypi_button)
        v_layout_2.addItem(spacer_item_1)
        v_layout_2.addWidget(self.exit_button)

        grid_layout.addLayout(v_layout_2, 0, 1, 1, 1)


        #]===================================================================[#
        #] TABLES [#=========================================================[#
        #]===================================================================[#

        # interpreter table header
        interpreter_table_label = QLabel(
            '<span style="font-size: 13pt;">\
                <b>Available Interpreters</b>\
            </span>',
            centralwidget
        )

        # interpreter table
        self.interpreter_table = InterpreterTable(
            centralwidget,
            selectionBehavior=QAbstractItemView.SelectRows,
            editTriggers=QAbstractItemView.NoEditTriggers,
            alternatingRowColors=True,
            sortingEnabled=True,
            drop_item=self.pop_interpreter_table
        )

        # hide vertical header
        self.interpreter_table.verticalHeader().hide()

        # adjust (horizontal) headers
        h_header_interpreter_table = self.interpreter_table.horizontalHeader()
        h_header_interpreter_table.setDefaultAlignment(Qt.AlignLeft)
        h_header_interpreter_table.setDefaultSectionSize(180)
        h_header_interpreter_table.setStretchLastSection(True)

        # set table view model
        self.model_interpreter_table = QStandardItemModel(0, 2, centralwidget)
        self.model_interpreter_table.setHorizontalHeaderLabels(
            ["Version", "Path"]
        )
        self.interpreter_table.setModel(self.model_interpreter_table)

        #]===================================================================[#
        # spacer between interpreter table and venv table title
        spacer_item_2 = QSpacerItem(
            20, 12, QSizePolicy.Minimum, QSizePolicy.Fixed
        )
        #]===================================================================[#

        # venv table header
        self.venv_table_label = QLabel(centralwidget)

        # venv table
        self.venv_table = VenvTable(
            centralwidget,
            selectionBehavior=QAbstractItemView.SelectRows,
            editTriggers=QAbstractItemView.NoEditTriggers,
            alternatingRowColors=True,
            sortingEnabled=True,
            refresh=self.pop_venv_table
        )

        # hide vertical header
        self.venv_table.verticalHeader().hide()

        # adjust horizontal headers
        h_header_venv_table = self.venv_table.horizontalHeader()
        h_header_venv_table.setDefaultAlignment(Qt.AlignLeft)
        h_header_venv_table.setStretchLastSection(True)

        # set table view model
        self.model_venv_table = QStandardItemModel(0, 3, centralwidget)
        self.model_venv_table.setHorizontalHeaderLabels(
            ["Venv", "Version", "Packages", "installed"]
        )
        self.venv_table.setModel(self.model_venv_table)

        # adjust column width
        self.venv_table.setColumnWidth(0, 225)
        self.venv_table.setColumnWidth(1, 120)
        self.venv_table.setColumnWidth(2, 100)
        self.venv_table.setColumnWidth(3, 80)

        # add widgets to layout
        v_layout_1.addWidget(interpreter_table_label)
        v_layout_1.addWidget(self.interpreter_table)
        v_layout_1.addItem(spacer_item_2)
        v_layout_1.addLayout(h_layout_1)
        h_layout_1.addWidget(self.venv_table_label)
        h_layout_1.addWidget(self.reload_button)
        h_layout_1.addWidget(self.active_dir_button)
        v_layout_1.addWidget(self.venv_table)

        grid_layout.addLayout(v_layout_1, 0, 0, 1, 1)

        self.setCentralWidget(centralwidget)


        #]===================================================================[#
        #] ACTIONS [#========================================================[#
        #]===================================================================[#

        # create actions
        self.action_add_interpreter = QAction(
            find_icon,
            "Add &Interpreter",
            self,
            statusTip="Add an Interpreter",
            shortcut="Ctrl+I",
            triggered=self.add_interpreter
        )

        self.action_new_venv = QAction(
            new_icon,
            "&New Venv",
            self,
            statusTip="Create a new virtual environment",
            shortcut="Ctrl+N",
            triggered=self.venv_wizard.exec_
        )

        #self.action_search_pypi = QAction(
            #manage_icon,
            #"&Search PyPI",
            #self,
            #statusTip="Search the Python Package Index",
            #shortcut="Ctrl+S",
            #triggered=self.search_pypi
        #)

        self.action_select_active_dir = QAction(
            folder_icon,
            "Change active &directory",
            self,
            statusTip="Change active directory",
            shortcut="Ctrl+D",
            triggered=self.select_active_dir
        )

        self.action_exit = QAction(
            exit_icon,
            "&Quit",
            self,
            statusTip="Quit application",
            shortcut="Ctrl+Q",
            triggered=self.on_close
        )

        self.action_about_venvipy = QAction(
            info_icon,
            "&About VenviPy",
            self,
            statusTip="About VenviPy",
            shortcut="Ctrl+A",
            triggered=self.info_about_venvipy.exec_
        )

        self.action_about_qt = QAction(
            qt_icon,
            "About &Qt",
            self,
            statusTip="About Qt",
            shortcut="Ctrl+Q",
            triggered=self.info_about_qt
        )

        #]===================================================================[#
        #] MENUS [#==========================================================[#
        #]===================================================================[#

        status_bar = QStatusBar(self)
        self.setStatusBar(status_bar)

        menu_bar = QMenuBar(self)
        menu_bar.setGeometry(QRect(0, 0, 740, 24))
        self.setMenuBar(menu_bar)

        menu_venv = QMenu("&Venv", menu_bar)
        menu_venv.addAction(self.action_add_interpreter)
        menu_venv.addSeparator()
        menu_venv.addAction(self.action_new_venv)
        menu_venv.addAction(self.action_select_active_dir)
        menu_venv.addSeparator()
        menu_venv.addAction(self.action_exit)
        menu_bar.addAction(menu_venv.menuAction())

        #menu_extras = QMenu("&Extras", menu_bar)
        #menu_extras.addAction(self.action_search_pypi)
        #menu_bar.addAction(menu_extras.menuAction())

        menu_help = QMenu("&Help", menu_bar)
        menu_help.addAction(self.action_about_venvipy)
        menu_help.addAction(self.action_about_qt)

        menu_bar.addAction(menu_help.menuAction())

        msg_txt = (
            "No suitable Python installation found!\n\n"
            "Please specify the path to a Python (>=3.3) \n"
            "installation or click 'Continue' to go on anyway.\n\n"
        )
        self.msg_box = QMessageBox(
            QMessageBox.Critical,
            "VenviPy",
            msg_txt, QMessageBox.NoButton,
            self
        )

        # check if any Python is installed
        if os.path.exists(get_data.DB_FILE):
            with open(get_data.DB_FILE, "r") as f:
                lines = f.readlines()
            if len(lines) < 2:
                self.launching_without_python()


    def launching_without_python(self):
        """If no Python was found run with features disabled.
        """
        logger.warning("No suitable Python installation found")
        self.msg_box.addButton("&Select", QMessageBox.AcceptRole)
        self.msg_box.addButton("&Continue", QMessageBox.RejectRole)
        if self.msg_box.exec_() == QMessageBox.AcceptRole:
            # let user specify path to an interpreter
            self.add_interpreter()
        else:
            self.enable_features(False)


    def center(self):
        """Center window.
        """
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())


    def on_close(self):
        """Stop all threads, then close the application.
        """
        self.venv_wizard.basic_settings.thread.exit()
        self.venv_table.thread.exit()
        self.close()


    def info_about_qt(self):
        """Open the "About Qt" dialog.
        """
        QMessageBox.aboutQt(self)


    def add_interpreter(self):
        """Add a custom interpreter.
        """
        if self.venv_wizard.basic_settings.select_python() != "":
            self.enable_features(True)


    def enable_features(self, state):
        """Enable or disable features.
        """
        self.venv_table.setEnabled(state)
        #self.search_pypi_button.setEnabled(state)
        #self.action_search_pypi.setEnabled(state)


    @pyqtSlot()
    def pop_interpreter_table(self):
        """Populate the interpreter table view.
        """
        get_data.ensure_dbfile()

        with open(get_data.DB_FILE, newline="") as cf:
            reader = csv.DictReader(cf, delimiter=",")
            self.model_interpreter_table.setRowCount(0)
            for info in reader:
                self.model_interpreter_table.insertRow(0)
                for i, text in enumerate(
                        (info["PYTHON_VERSION"], info["PYTHON_PATH"])
                    ):
                    self.model_interpreter_table.setItem(
                        0, i, QStandardItem(text)
                    )
        # also populate the combo box in wizard
        self.venv_wizard.basic_settings.pop_combo_box()


    def pop_venv_table(self):
        """Populate the venv table view.
        """
        self.model_venv_table.setRowCount(0)

        for info in get_data.get_active_dir():
            self.model_venv_table.insertRow(0)
            for i, text in enumerate((
                    info.venv_name,
                    info.venv_version,
                    info.site_packages,
                    info.is_installed
            )):
                self.model_venv_table.setItem(0, i, QStandardItem(text))


    def update_label(self):
        """
        Show the currently selected folder containing
        virtual environments.
        """
        head = (
            '<span style="font-size: 13pt;">\
                    <b>Virtual environments:</b>\
                </span>'
        )
        no_folder = (
            '<span style="font-size: 13pt; color: #ff0000;">\
                <i> --- please select a folder containing virtual environments</i>\
            </span>'
        )
        with_folder = (
            f'<span style="font-size: 13pt; color: #0059ff;">\
                {get_data.get_active_dir_str()}\
            </span>'
        )

        if get_data.get_active_dir_str() != "":
            self.venv_table_label.setText(f"{head}{with_folder}")
        else:
            self.venv_table_label.setText(f"{head}{no_folder}")


    def select_active_dir(self):
        """
        Select the active directory of which the content
        should be shown in venv table.
        """
        directory = QFileDialog.getExistingDirectory(
            self,
            "Open a folder containing virtual environments"
        )
        self.directory_line.setText(directory)

        active_file = os.path.expanduser("~/.venvipy/active")
        active_dir = self.directory_line.text()

        if active_dir != "":
            if os.path.exists(active_file):
                with open(active_file, "w") as f:
                    f.write(active_dir)
                self.pop_venv_table()
                self.update_label()


    def search_pypi(self):
        """Search the Python Package Index.
        """
        pass
Example #4
0
class MainWindow(QMainWindow):
    BASE_DIR = os.path.dirname(os.path.abspath(__file__))
    MAIN_UI_FILE = os.path.join(BASE_DIR, "main.ui")
    NEW_DISH_POPUP_UI_FILE = os.path.join(BASE_DIR, "new_dish_popup.ui")
    NEW_DISH_MULTI_POPUP_UI_FILE = os.path.join(BASE_DIR,
                                                "new_dish_multi_popup.ui")
    NEW_DISH_DATA_POPUP_UI_FILE = os.path.join(BASE_DIR,
                                               "new_dish_data_popup.ui")
    MODIFY_DISH_POPUP_UI_FILE = os.path.join(BASE_DIR, "modify_dish_popup.ui")
    DB_FILE = os.path.join(BASE_DIR, "restaurant.db")

    def __init__(self):
        super(MainWindow, self).__init__()
        # Initialize variable
        self.db_connection = None
        self.new_dish_popup = QWidget()
        self.new_dish_multi_popup = QWidget()
        self.new_dish_data_popup = QWidget()
        self.modify_dish_popup = QWidget()
        self.dish_table_model = QStandardItemModel(0, 6)
        self.dish_table_proxy = TableFilter()
        self.dish_data_table_model = QStandardItemModel(0, 6)
        self.dish_data_table_proxy = TableFilter()
        self.graph_chart = None
        self.graph_series = {}

        # Load UI designs
        uic.loadUi(self.MAIN_UI_FILE, self)
        uic.loadUi(self.NEW_DISH_POPUP_UI_FILE, self.new_dish_popup)
        uic.loadUi(self.NEW_DISH_MULTI_POPUP_UI_FILE,
                   self.new_dish_multi_popup)
        uic.loadUi(self.NEW_DISH_DATA_POPUP_UI_FILE, self.new_dish_data_popup)
        uic.loadUi(self.MODIFY_DISH_POPUP_UI_FILE, self.modify_dish_popup)
        self.init_dish_table()
        self.init_dish_data_table()
        self.init_graph()

        # Connect to database
        self.init_db_connection()

        # MainWindow Bind action triggers
        self.action_new_dish.triggered.connect(self.show_new_dish_popup)
        self.action_new_dish_multi.triggered.connect(
            self.show_new_dish_multi_popup)
        self.action_new_data_multi.triggered.connect(
            lambda: self.modify_new_dish_data_popup_table(show=True))
        self.tabWidget.currentChanged.connect(self.update_graph)

        # Dish Table filter bind
        self.dish_lineEdit.textChanged.connect(
            lambda text, col_idx=1: self.dish_table_proxy.set_col_regex_filter(
                col_idx, text))
        self.lower_price_doubleSpinBox.valueChanged.connect(
            lambda value, col_idx=2: self.dish_table_proxy.
            set_col_number_filter(col_idx, value, -1))
        self.higher_price_doubleSpinBox.valueChanged.connect(
            lambda value, col_idx=2: self.dish_table_proxy.
            set_col_number_filter(col_idx, -1, value))
        self.lower_week_sell_spinBox.valueChanged.connect(
            lambda value, col_idx=3: self.dish_table_proxy.
            set_col_number_filter(col_idx, value, -1))
        self.higher_week_sell_spinBox.valueChanged.connect(
            lambda value, col_idx=3: self.dish_table_proxy.
            set_col_number_filter(col_idx, -1, value))

        # Dish Data Table filter bind
        self.lower_data_dateEdit.dateChanged.connect(
            lambda date, col_idx=1: self.dish_data_table_proxy.
            set_col_date_filter(col_idx, date, -1))
        self.higher_data_dateEdit.dateChanged.connect(
            lambda date, col_idx=1: self.dish_data_table_proxy.
            set_col_date_filter(col_idx, -1, date))
        self.data_lineEdit.textChanged.connect(
            lambda text, col_idx=2: self.dish_data_table_proxy.
            set_col_regex_filter(col_idx, text))
        self.lower_data_doubleSpinBox.valueChanged.connect(
            lambda value, col_idx=3: self.dish_data_table_proxy.
            set_col_number_filter(col_idx, value, -1))
        self.higher_data_doubleSpinBox.valueChanged.connect(
            lambda value, col_idx=3: self.dish_data_table_proxy.
            set_col_number_filter(col_idx, -1, value))
        self.lower_data_spinBox.valueChanged.connect(
            lambda value, col_idx=4: self.dish_data_table_proxy.
            set_col_number_filter(col_idx, value, -1))
        self.higher_data_spinBox.valueChanged.connect(
            lambda value, col_idx=4: self.dish_data_table_proxy.
            set_col_number_filter(col_idx, -1, value))
        self.data_all_check_checkBox.stateChanged.connect(
            lambda state, col_idx=5: self.data_table_check_state(
                state, col_idx))
        self.dish_data_table_model.itemChanged.connect(self.update_series)

        # Popup bind action triggers
        self.new_dish_popup.create_new_dish_btn.clicked.connect(
            self.create_new_dish)
        self.new_dish_multi_popup.pushButton_ok.clicked.connect(
            self.create_new_dish_multi)
        self.new_dish_data_popup.dateEdit.dateChanged.connect(
            self.modify_new_dish_data_popup_table)
        self.new_dish_data_popup.pushButton_ok.clicked.connect(
            self.create_new_dish_data)

        # Get current dishes
        self.load_dish_table()
        self.load_dish_data_table()
        self.new_dish_data_popup.dateEdit.setDate(QtCore.QDate.currentDate())

    def init_dish_table(self):
        self.dish_tableView.horizontalHeader().setSectionResizeMode(
            QHeaderView.Stretch)
        # Set Header data and stretch
        for col, col_name in enumerate(
            ["ID", "菜品", "价格", "近7天总售出", "操作", "备注"]):
            self.dish_table_model.setHeaderData(col, Qt.Horizontal, col_name,
                                                Qt.DisplayRole)
        self.dish_table_proxy.setSourceModel(self.dish_table_model)
        self.dish_tableView.setModel(self.dish_table_proxy)
        self.dish_tableView.setColumnHidden(0, True)
        for (col, method) in [(1, "Regex"), (2, "Number"), (3, "Number"),
                              (5, "Regex")]:
            self.dish_table_proxy.filter_method[col] = method

    def init_dish_data_table(self):
        self.data_tableView.horizontalHeader().setSectionResizeMode(
            QHeaderView.Stretch)
        for col, col_name in enumerate(
            ["Dish_ID", "日期", "菜品", "价格", "售出", "选择"]):
            self.dish_data_table_model.setHeaderData(col, Qt.Horizontal,
                                                     col_name, Qt.DisplayRole)
        self.dish_data_table_proxy.setSourceModel(self.dish_data_table_model)
        self.data_tableView.setModel(self.dish_data_table_proxy)
        self.data_tableView.setColumnHidden(0, True)
        for (col, method) in [(1, "Date"), (2, "Regex"), (3, "Number"),
                              (4, "Number")]:
            self.dish_data_table_proxy.filter_method[col] = method

    def init_graph(self):
        self.graph_chart = QChart(title="售出图")
        self.graph_chart.legend().setVisible(True)
        self.graph_chart.setAcceptHoverEvents(True)

        graph_view = QChartView(self.graph_chart)
        graph_view.setRenderHint(QPainter.Antialiasing)
        self.gridLayout_5.addWidget(graph_view)

    def init_db_connection(self):
        self.db_connection = sqlite3.connect(self.DB_FILE)
        cursor = self.db_connection.cursor()
        # check create table if not exist
        sql_create_dish_table = """ CREATE TABLE IF NOT EXISTS dish (
                                        id integer PRIMARY KEY,
                                        name text NOT NULL,
                                        price numeric Not NULL,
                                        remarks text,
                                        UNIQUE (name, price)
                                    ); """
        sql_create_dish_data_table = """ CREATE TABLE IF NOT EXISTS dish_data (
                                            dish_id integer NOT NULL REFERENCES dish(id) ON DELETE CASCADE,
                                            date date,
                                            sell_num integer DEFAULT 0,
                                            PRIMARY KEY (dish_id, date),
                                            CONSTRAINT dish_fk 
                                                FOREIGN KEY (dish_id) 
                                                REFERENCES dish (id) ON DELETE CASCADE 
                                        ); """
        sql_trigger = """
            CREATE TRIGGER IF NOT EXISTS place_holder_data
            AFTER INSERT ON dish
            BEGIN
                INSERT INTO dish_data (dish_id, date, sell_num) VALUES(new.id, null, 0);
            END;
        """
        cursor.execute(sql_create_dish_table)
        cursor.execute(sql_create_dish_data_table)
        cursor.execute("PRAGMA FOREIGN_KEYS = on")
        cursor.execute(sql_trigger)

        cursor.close()

    def load_dish_table(self):
        today = datetime.today()
        sql_select_query = """
            SELECT dish.id, dish.name, dish.price, COALESCE(SUM(dish_data.sell_num), 0), dish.remarks
            FROM dish LEFT JOIN dish_data 
            ON dish.id = dish_data.dish_id
            WHERE dish_data.date IS NULL OR dish_data.date BETWEEN date('{}') and date('{}')
            GROUP BY dish.id
            ORDER BY dish.name, dish.price;""".format(
            (today - timedelta(days=7)).strftime("%Y-%m-%d"),
            today.strftime("%Y-%m-%d"))
        cursor = self.db_connection.cursor()
        cursor.execute(sql_select_query)
        records = cursor.fetchall()
        for row_idx, record in enumerate(records):
            self.dish_table_model.appendRow(create_dish_table_row(*record))
        cursor.close()
        self.dish_tableView.setItemDelegateForColumn(
            4,
            DishTableDelegateCell(self.show_modify_dish_popup,
                                  self.delete_dish, self.dish_tableView))

    def load_dish_data_table(self):
        sql_select_query = """
            SELECT dish_data.dish_id, dish_data.date, dish.name, dish.price, dish_data.sell_num
            FROM dish_data LEFT JOIN dish  
            ON dish_data.dish_id = dish.id
            WHERE dish_data.date IS NOT NULL
            ORDER BY dish_data.date DESC, dish.name, dish.price, dish_data.sell_num;"""
        cursor = self.db_connection.cursor()
        cursor.execute(sql_select_query)
        records = cursor.fetchall()
        for row_idx, record in enumerate(records):
            self.dish_data_table_model.appendRow(
                create_dish_data_table_row(*record))
        cursor.close()
        self.lower_data_dateEdit.setDate(QDate.currentDate().addDays(-7))
        self.higher_data_dateEdit.setDate(QDate.currentDate())
        self.data_tableView.setItemDelegateForColumn(
            5, DishDataTableDelegateCell(self.data_tableView))

    def data_table_check_state(self, state, col):
        for row in range(self.dish_data_table_proxy.rowCount()):
            index = self.dish_data_table_proxy.mapToSource(
                self.dish_data_table_proxy.index(row, col))
            if index.isValid():
                self.dish_data_table_model.setData(index, str(state),
                                                   Qt.DisplayRole)

    def show_new_dish_popup(self):
        # Move popup to center
        point = self.rect().center()
        global_point = self.mapToGlobal(point)
        self.new_dish_popup.move(
            global_point - QtCore.QPoint(self.new_dish_popup.width() // 2,
                                         self.new_dish_popup.height() // 2))
        self.new_dish_popup.show()

    def show_new_dish_multi_popup(self):
        file_name = QFileDialog().getOpenFileName(None, "选择文件", "",
                                                  self.tr("CSV文件 (*.csv)"))[0]
        self.new_dish_multi_popup.tableWidget.setRowCount(0)
        if file_name:
            with open(file_name, "r") as file:
                csv_reader = csv.reader(file, delimiter=",")
                for idx, row_data in enumerate(csv_reader):
                    if len(row_data) == 2:
                        name, price = row_data
                        remark = ""
                    elif len(row_data) == 3:
                        name, price, remark = row_data
                    else:
                        QMessageBox.warning(
                            self, "格式错误",
                            self.tr('格式为"菜品 价格"或者"菜品 价格 备注"\n第{}行输入有误'.format(
                                idx)))
                        return
                    self.new_dish_multi_popup.tableWidget.insertRow(
                        self.new_dish_multi_popup.tableWidget.rowCount())
                    self.new_dish_multi_popup.tableWidget.setItem(
                        idx, 0, QTableWidgetItem(name))
                    price_type = str_type(price)
                    if price_type == str or (isinstance(
                            price_type, (float, int)) and float(price) < 0):
                        QMessageBox.warning(
                            self, "格式错误",
                            self.tr('第{}行价格输入有误'.format(idx + 1)))
                        return
                    self.new_dish_multi_popup.tableWidget.setItem(
                        idx, 1,
                        QTableWidgetItem("{:.2f}".format(float(price))))
                    self.new_dish_multi_popup.tableWidget.setItem(
                        idx, 2, QTableWidgetItem(remark))
            self.new_dish_multi_popup.show()

    def modify_new_dish_data_popup_table(self, *args, show=False):
        sql_select_query = """
                    SELECT id, name, price, dish_data.sell_num
                    FROM dish LEFT JOIN dish_data
                    ON dish.id=dish_data.dish_id
                    WHERE dish_data.date IS NULL OR dish_data.date = date('{}')
                    GROUP BY id, name, price
                    ORDER BY dish.name, dish.price;""".format(
            self.new_dish_data_popup.dateEdit.date().toString("yyyy-MM-dd"))

        cursor = self.db_connection.cursor()
        cursor.execute(sql_select_query)
        records = cursor.fetchall()
        self.new_dish_data_popup.tableWidget.setRowCount(len(records))
        self.new_dish_data_popup.tableWidget.setColumnHidden(0, True)
        for row_idx, record in enumerate(records):
            dish_id, name, price, sell_num = record
            self.new_dish_data_popup.tableWidget.setItem(
                row_idx, 0, QTableWidgetItem(str(dish_id)))
            self.new_dish_data_popup.tableWidget.setItem(
                row_idx, 1, QTableWidgetItem(name))
            self.new_dish_data_popup.tableWidget.setItem(
                row_idx, 2, QTableWidgetItem("{:.2f}".format(price)))
            spin_box = QSpinBox()
            spin_box.setMaximum(9999)
            spin_box.setValue(sell_num)
            self.new_dish_data_popup.tableWidget.setCellWidget(
                row_idx, 3, spin_box)
        cursor.close()
        if show:
            self.new_dish_data_popup.show()

    def create_new_dish(self):
        cursor = self.db_connection.cursor()
        sql_insert = """ INSERT INTO dish(name, price, remarks)
                         VALUES(?,?,?)"""
        dish_name = self.new_dish_popup.dish_name.text()
        dish_price = self.new_dish_popup.dish_price.value()
        dish_remark = self.new_dish_popup.dish_remark.toPlainText()
        try:
            cursor.execute(sql_insert, (dish_name, dish_price, dish_remark))
            new_dish_id = cursor.lastrowid
            cursor.close()
            self.db_connection.commit()
            # Update dish table and dish comboBox in UI
            self.dish_table_model.appendRow(
                create_dish_table_row(new_dish_id, dish_name, dish_price, 0,
                                      dish_remark))
            self.new_dish_popup.hide()
        except sqlite3.Error:
            cursor.close()
            QMessageBox.warning(self, "菜品价格重复", self.tr('菜品价格组合重复,请检查'))

    def create_new_dish_multi(self):
        cursor = self.db_connection.cursor()
        sql_insert = """ 
            INSERT INTO dish(name, price, remarks)     
            VALUES (?, ?, ?)"""
        for row in range(self.new_dish_multi_popup.tableWidget.rowCount()):
            dish_name = self.new_dish_multi_popup.tableWidget.item(row,
                                                                   0).text()
            dish_price = float(
                self.new_dish_multi_popup.tableWidget.item(row, 1).text())
            dish_remark = self.new_dish_multi_popup.tableWidget.item(row,
                                                                     2).text()
            try:
                cursor.execute(sql_insert,
                               (dish_name, dish_price, dish_remark))
                new_dish_id = cursor.lastrowid
                self.dish_table_model.appendRow(
                    create_dish_table_row(new_dish_id, dish_name, dish_price,
                                          0, dish_remark))
            except sqlite3.Error:
                cursor.close()
                QMessageBox.warning(
                    self, "菜品价格重复",
                    self.tr('前{}行已插入。\n第{}行菜品价格组合重复,请检查'.format(row, row + 1)))
                return
        cursor.close()
        self.db_connection.commit()
        self.new_dish_multi_popup.hide()

    def create_new_dish_data(self):
        current_date = self.new_dish_data_popup.dateEdit.date().toString(
            "yyyy-MM-dd")
        table_filter = TableFilter()
        table_filter.setSourceModel(self.dish_data_table_model)
        table_filter.set_col_regex_filter(1, current_date)
        for row in range(table_filter.rowCount()):
            index = table_filter.mapToSource(table_filter.index(0, 1))
            if index.isValid():
                self.dish_data_table_model.removeRow(index.row())
        del table_filter
        cursor = self.db_connection.cursor()
        sql_insert = """ 
            INSERT OR REPLACE INTO dish_data(dish_id, date, sell_num)     
            VALUES (?, ?, ?)"""
        for row in range(self.new_dish_data_popup.tableWidget.rowCount()):
            dish_id = int(
                self.new_dish_data_popup.tableWidget.item(row, 0).text())
            name = self.new_dish_data_popup.tableWidget.item(row, 1).text()
            price = float(
                self.new_dish_data_popup.tableWidget.item(row, 2).text())
            sell_num = self.new_dish_data_popup.tableWidget.cellWidget(
                row, 3).value()
            cursor.execute(sql_insert, (dish_id, current_date, sell_num))
            self.dish_data_table_model.appendRow(
                create_dish_data_table_row(dish_id, current_date, name, price,
                                           sell_num))
        cursor.close()
        self.db_connection.commit()
        self.new_dish_data_popup.hide()

    def delete_dish(self, dish_id):
        cursor = self.db_connection.cursor()
        sql_delete = """ DELETE FROM dish WHERE id=?"""
        cursor.execute(sql_delete, tuple([dish_id]))
        cursor.close()
        self.db_connection.commit()

        # Update dish table and dish comboBox in UI
        for row in self.dish_data_table_model.findItems(str(dish_id)):
            index = row.index()
            if index.isValid():
                self.dish_data_table_model.removeRow(index.row())

        for row in self.dish_table_model.findItems(str(dish_id)):
            index = row.index()
            if index.isValid():
                self.dish_table_model.removeRow(index.row())

    def show_modify_dish_popup(self, dish_id):
        point = self.rect().center()
        global_point = self.mapToGlobal(point)
        self.modify_dish_popup.move(
            global_point - QtCore.QPoint(self.modify_dish_popup.width() // 2,
                                         self.modify_dish_popup.height() // 2))
        # Find the row and get necessary info
        index = self.dish_table_model.match(self.dish_table_model.index(0, 0),
                                            Qt.DisplayRole, str(dish_id))
        if index:
            row_idx = index[0]
            dish_name = self.dish_table_model.data(row_idx.siblingAtColumn(1))
            dish_price = self.dish_table_model.data(row_idx.siblingAtColumn(2))
            dish_remark = self.dish_table_model.data(
                row_idx.siblingAtColumn(5))
            self.modify_dish_popup.dish_name.setText(dish_name)
            self.modify_dish_popup.dish_price.setValue(float(dish_price))
            self.modify_dish_popup.dish_remark.setText(dish_remark)

            try:
                self.modify_dish_popup.modify_dish_btn.clicked.disconnect()
            except TypeError:
                pass
            self.modify_dish_popup.modify_dish_btn.clicked.connect(
                lambda: self.modify_dish(row_idx, dish_id))
            self.modify_dish_popup.show()

    def modify_dish(self, row, dish_id):
        cursor = self.db_connection.cursor()
        sql_update = """ UPDATE dish
                         SET name = ?, price = ?, remarks = ?
                         WHERE id=?"""
        dish_name = self.modify_dish_popup.dish_name.text()
        dish_price = self.modify_dish_popup.dish_price.value()
        dish_remark = self.modify_dish_popup.dish_remark.toPlainText()
        cursor.execute(sql_update,
                       (dish_name, dish_price, dish_remark, dish_id))
        cursor.close()
        self.db_connection.commit()
        self.modify_dish_popup.hide()

        # Update dish table and dish comboBox in UI
        old_name = self.dish_table_model.data(row.siblingAtColumn(1))
        old_price = self.dish_table_model.data(row.siblingAtColumn(2))
        sell_num = self.dish_table_model.data(row.siblingAtColumn(3))
        row_idx = row.row()
        self.dish_table_model.removeRow(row_idx)
        self.dish_table_model.insertRow(
            row_idx,
            create_dish_table_row(dish_id, dish_name, dish_price, sell_num,
                                  dish_remark))

        for row in self.dish_data_table_model.findItems(str(dish_id)):
            index = row.index()
            if index.isValid():
                self.dish_data_table_model.setData(index.siblingAtColumn(2),
                                                   dish_name)
                self.dish_data_table_model.setData(index.siblingAtColumn(3),
                                                   "{:.2f}".format(dish_price))
        old_key = old_name + '(' + old_price + ')'
        if old_key in self.graph_line_series:
            self.graph_line_series[dish_name + '(' + str(dish_price) +
                                   ')'] = self.graph_line_series[old_key]
            del self.graph_line_series[old_key]

    def update_series(self, item: QStandardItem):
        if item.column() == 5:  # check for checkbox column
            item_idx = item.index()
            date = self.dish_data_table_model.data(item_idx.siblingAtColumn(1))
            dish_name = self.dish_data_table_model.data(
                item_idx.siblingAtColumn(2))
            dish_price = self.dish_data_table_model.data(
                item_idx.siblingAtColumn(3))
            sell_num = self.dish_data_table_model.data(
                item_idx.siblingAtColumn(4))
            set_name = dish_name + "(" + dish_price + ")"
            key = str(
                QDateTime(QDate.fromString(date,
                                           "yyyy-MM-dd")).toSecsSinceEpoch())
            if key not in self.graph_series:
                self.graph_series[key] = {}

            if int(item.text()) == 0:
                if set_name in self.graph_series[key]:
                    del self.graph_series[key][set_name]
                if not self.graph_series[key]:
                    del self.graph_series[key]
            else:
                self.graph_series[key][set_name] = int(sell_num)

    def update_graph(self, index):
        if index == 2:
            self.graph_chart.removeAllSeries()

            axis_x = QBarCategoryAxis()
            axis_x.setTitleText("日期")
            if self.graph_chart.axisX():
                self.graph_chart.removeAxis(self.graph_chart.axisX())
            self.graph_chart.addAxis(axis_x, Qt.AlignBottom)

            axis_y = QValueAxis()
            axis_y.setLabelFormat("%i")
            axis_y.setTitleText("售出量")
            if self.graph_chart.axisY():
                self.graph_chart.removeAxis(self.graph_chart.axisY())
            self.graph_chart.addAxis(axis_y, Qt.AlignLeft)

            max_num = 0
            total_date = 0
            set_dict = {}
            for key, data in sorted(self.graph_series.items(),
                                    key=lambda i: int(i[0])):
                axis_x.append(
                    QDateTime.fromSecsSinceEpoch(
                        int(key)).toString("yyyy年MM月dd日"))
                for set_name, value in data.items():
                    if set_name not in set_dict:
                        set_dict[set_name] = QBarSet(set_name)
                        for _ in range(total_date):
                            set_dict[set_name].append(0)
                    set_dict[set_name].append(value)
                    max_num = max(max_num, value)
                total_date += 1
                for _, bar_set in set_dict.items():
                    if bar_set.count() < total_date:
                        bar_set.append(0)
            bar_series = QBarSeries()
            for _, bar_set in set_dict.items():
                bar_series.append(bar_set)
            bar_series.hovered.connect(self.graph_tooltip)
            axis_y.setMax(max_num + 1)
            axis_y.setMin(0)
            self.graph_chart.addSeries(bar_series)
            bar_series.attachAxis(axis_x)
            bar_series.attachAxis(axis_y)

    def graph_tooltip(self, status, index, bar_set: QBarSet):
        if status:
            QToolTip.showText(
                QCursor.pos(),
                "{}\n日期: {}\n售出: {}".format(bar_set.label(),
                                            self.graph_chart.axisX().at(index),
                                            int(bar_set.at(index))))
Example #5
0
class InvoiceList(MyTreeView):

    class Columns(IntEnum):
        DATE = 0
        TX_TYPE = 1
        DESCRIPTION = 2
        AMOUNT = 3
        IS_PS = 4
        STATUS = 5

    headers = {
        Columns.DATE: _('Date'),
        Columns.TX_TYPE: _('Type'),
        Columns.DESCRIPTION: _('Description'),
        Columns.AMOUNT: _('Amount'),
        Columns.IS_PS: _('PrivateSend'),
        Columns.STATUS: _('Status'),
    }
    filter_columns = [Columns.DATE, Columns.DESCRIPTION, Columns.AMOUNT,
                      Columns.IS_PS, Columns.TX_TYPE]

    def __init__(self, parent):
        super().__init__(parent, self.create_menu,
                         stretch_column=self.Columns.DESCRIPTION,
                         editable_columns=[])
        self.std_model = QStandardItemModel(self)
        self.proxy = MySortModel(self, sort_role=ROLE_SORT_ORDER)
        self.proxy.setSourceModel(self.std_model)
        self.setModel(self.proxy)
        self.setSortingEnabled(True)
        self.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.update()

    def update_item(self, key, invoice: Invoice):
        model = self.std_model
        for row in range(0, model.rowCount()):
            item = model.item(row, 0)
            if item.data(ROLE_REQUEST_ID) == key:
                break
        else:
            return
        status_item = model.item(row, self.Columns.STATUS)
        status = self.parent.wallet.get_invoice_status(invoice)
        status_str = invoice.get_status_str(status)
        status_item.setText(status_str)
        status_item.setIcon(read_QIcon(pr_icons.get(status)))

    def update(self):
        # not calling maybe_defer_update() as it interferes with conditional-visibility
        self.proxy.setDynamicSortFilter(False)  # temp. disable re-sorting after every change
        self.std_model.clear()
        self.update_headers(self.__class__.headers)
        for idx, item in enumerate(self.parent.wallet.get_invoices()):
            key = item.id
            invoice_ext = self.parent.wallet.get_invoice_ext(key)
            icon_name = 'dashcoin.png'
            if item.bip70:
                icon_name = 'seal.png'
            status = self.parent.wallet.get_invoice_status(item)
            status_str = item.get_status_str(status)
            message = item.message
            amount = item.get_amount_sat()
            timestamp = item.time or 0
            ps_str = _('PrivateSend') if invoice_ext.is_ps else _('Regular')
            tx_type = invoice_ext.tx_type
            type_str = SPEC_TX_NAMES[tx_type]
            date_str = format_time(timestamp) if timestamp else _('Unknown')
            amount_str = self.parent.format_amount(amount, whitespaces=True)
            labels = [date_str, type_str, message, amount_str, ps_str,
                      status_str]
            items = [QStandardItem(e) for e in labels]
            self.set_editability(items)
            items[self.Columns.DATE].setIcon(read_QIcon(icon_name))
            items[self.Columns.STATUS].setIcon(read_QIcon(pr_icons.get(status)))
            items[self.Columns.DATE].setData(key, role=ROLE_REQUEST_ID)
            items[self.Columns.DATE].setData(item.type, role=ROLE_REQUEST_TYPE)
            items[self.Columns.DATE].setData(timestamp, role=ROLE_SORT_ORDER)
            items[self.Columns.TX_TYPE].setData(type_str, role=ROLE_SORT_ORDER)
            items[self.Columns.IS_PS].setData(ps_str, role=ROLE_SORT_ORDER)
            self.std_model.insertRow(idx, items)
        self.filter()
        self.proxy.setDynamicSortFilter(True)
        # sort requests by date
        self.sortByColumn(self.Columns.DATE, Qt.DescendingOrder)
        # hide list if empty
        if self.parent.isVisible():
            b = self.std_model.rowCount() > 0
            self.setVisible(b)
            self.parent.invoices_label.setVisible(b)

    def create_menu(self, position):
        wallet = self.parent.wallet
        items = self.selected_in_column(0)
        if len(items)>1:
            keys = [ item.data(ROLE_REQUEST_ID)  for item in items]
            invoices = [ wallet.invoices.get(key) for key in keys]
            invoices_ext = [ wallet.invoices_ext.get(key) for key in keys]
            can_batch_pay = all([i.type == PR_TYPE_ONCHAIN and wallet.get_invoice_status(i) == PR_UNPAID for i in invoices])
            if can_batch_pay:
                if any([i.is_ps for i in invoices_ext]):
                    can_batch_pay = False
            if can_batch_pay:
                if any([(i.tx_type or i.extra_payload) for i in invoices_ext]):
                    can_batch_pay = False
            menu = QMenu(self)
            if can_batch_pay:
                menu.addAction(_("Batch pay invoices") + "...", lambda: self.parent.pay_multiple_invoices(invoices))
            menu.addAction(_("Delete invoices"), lambda: self.parent.delete_invoices(keys))
            menu.exec_(self.viewport().mapToGlobal(position))
            return
        idx = self.indexAt(position)
        item = self.item_from_index(idx)
        item_col0 = self.item_from_index(idx.sibling(idx.row(), self.Columns.DATE))
        if not item or not item_col0:
            return
        key = item_col0.data(ROLE_REQUEST_ID)
        invoice = self.parent.wallet.get_invoice(key)
        menu = QMenu(self)
        self.add_copy_menu(menu, idx)
        if len(invoice.outputs) == 1:
            menu.addAction(_("Copy Address"), lambda: self.parent.do_copy(invoice.get_address(), title='Dash Address'))
        menu.addAction(_("Details"), lambda: self.parent.show_onchain_invoice(invoice))
        status = wallet.get_invoice_status(invoice)
        if status == PR_UNPAID:
            menu.addAction(_("Pay") + "...", lambda: self.parent.do_pay_invoice(invoice))
        if status == PR_FAILED:
            menu.addAction(_("Retry"), lambda: self.parent.do_pay_invoice(invoice))
        menu.addAction(_("Delete"), lambda: self.parent.delete_invoices([key]))
        menu.exec_(self.viewport().mapToGlobal(position))
class MainWindow(QWidget):
    Id, Password = range(2)
    CONFIG_FILE = 'config'

    def __init__(self):
        super().__init__()
        with open(self.CONFIG_FILE, 'a'):
            pass
        self.init()

    def init(self):
        # ------ initUI
        self.resize(555, 245)
        self.setFixedSize(555, 245)
        self.center()
        self.setWindowTitle('Portal Connector')
        self.setWindowIcon(QIcon('gao.ico'))
        self.backgroundRole()
        palette1 = QPalette()
        palette1.setColor(self.backgroundRole(), QColor(250, 250,
                                                        250))  # 设置背景颜色

        self.setPalette(palette1)

        # ------setLeftWidget

        self.dataGroupBox = QGroupBox("Saved", self)
        self.dataGroupBox.setGeometry(10, 10, 60, 20)
        self.dataGroupBox.setStyleSheet(MyGroupBox)

        self.model = QStandardItemModel(0, 2, self)
        self.model.setHeaderData(self.Id, Qt.Horizontal, "Id")
        self.model.setHeaderData(self.Password, Qt.Horizontal, "Pw")

        self.dataView = QTreeView(self)
        self.dataView.setGeometry(10, 32, 255, 150)
        self.dataView.setRootIsDecorated(False)
        self.dataView.setAlternatingRowColors(True)
        self.dataView.setModel(self.model)
        self.dataView.setStyleSheet(MyTreeView)

        save_btn = QPushButton('Save', self)
        save_btn.setGeometry(15, 195, 100, 35)
        save_btn.setStyleSheet(MyPushButton)

        delete_btn = QPushButton('Delete', self)
        delete_btn.setGeometry(135, 195, 100, 35)
        delete_btn.setStyleSheet(MyPushButton)

        # ------ setRightWidget

        username = QLabel('Id:', self)
        username.setGeometry(300, 45, 50, 30)
        username.setStyleSheet(MyLabel)

        self.username_edit = QLineEdit(self)
        self.username_edit.setGeometry(350, 40, 190, 35)
        self.username_edit.setStyleSheet(MyLineEdit)

        password = QLabel('Pw:', self)
        password.setGeometry(300, 100, 50, 30)
        password.setStyleSheet(MyLabel)

        self.password_edit = QLineEdit(self)
        self.password_edit.setGeometry(350, 95, 190, 35)
        self.password_edit.setStyleSheet(MyLineEdit)

        status_label = QLabel('Result:', self)
        status_label.setGeometry(295, 150, 70, 30)
        status_label.setStyleSheet(UnderLabel)

        self.status = QLabel('Disconnect', self)
        self.status.setGeometry(360, 150, 190, 30)
        self.status.setStyleSheet(UnderLabel)

        connect_btn = QPushButton('Connect', self)
        connect_btn.setGeometry(320, 195, 100, 35)
        connect_btn.setStyleSheet(MyPushButton)

        test_btn = QPushButton('Test', self)
        test_btn.setGeometry(440, 195, 100, 35)
        test_btn.setStyleSheet(MyPushButton)

        # ------setTabOrder

        self.setTabOrder(self.username_edit, self.password_edit)
        self.setTabOrder(self.password_edit, connect_btn)
        self.setTabOrder(connect_btn, test_btn)

        # ------setEvent

        self.dataView.mouseDoubleClickEvent = self.set_text
        self.dataView.mousePressEvent = self.set_focus
        delete_btn.clicked.connect(self.removeItem)
        connect_btn.clicked.connect(self.connect_clicked)
        save_btn.clicked.connect(self.save_infomation)
        test_btn.clicked.connect(self.test_network)

        self.readItem(self.CONFIG_FILE)
        self.connect_clicked()
        self.show()

    def connect_clicked(self):
        result = connect_portal(self.username_edit.text(),
                                self.password_edit.text())
        self.status.setText(result)

    def save_infomation(self):
        if self.username_edit.text() and self.password_edit.text():
            try:
                selected = self.dataView.selectedIndexes()[0].row()
                self.modifyItem(selected)
            except IndexError:
                self.addItem(self.username_edit.text(),
                             self.password_edit.text())

    def test_network(self):
        result = test_public()
        self.status.setText(result)

    def set_text(self, event=None):
        try:
            self.username_edit.setText(
                self.dataView.selectedIndexes()[0].data())
            self.password_edit.setText(
                self.dataView.selectedIndexes()[1].data())
        except IndexError:
            pass

    def set_focus(self, event):
        index = self.dataView.indexAt(event.pos())
        if not index.isValid():
            self.dataView.clearSelection()
        else:
            self.dataView.setCurrentIndex(index)

    def readItem(self, filename):
        with open(filename, 'r') as f:
            for line in f.readlines():
                self.addItem(*(line.split()))

        self.dataView.setCurrentIndex(self.dataView.indexAt(QPoint(1, 1)))
        self.set_text()

    def addItem(self, username, password):
        self.model.insertRow(0)
        self.model.setData(self.model.index(0, self.Id), username)
        self.model.setData(self.model.index(0, self.Password), password)
        self.save_to_file()

    def modifyItem(self, row):
        self.model.setData(self.model.index(row, self.Id),
                           self.username_edit.text())
        self.model.setData(self.model.index(row, self.Password),
                           self.password_edit.text())
        self.save_to_file()

    def removeItem(self):
        try:
            self.model.removeRow(self.dataView.selectedIndexes()[0].row())
            self.save_to_file()
        except IndexError:
            pass

    def save_to_file(self):
        with open(self.CONFIG_FILE, 'w') as f:
            for x in range(self.model.rowCount()):
                for y in range(self.model.columnCount()):
                    f.write(self.model.data(self.model.index(x, y)) + " ")
                f.write("\n")

    def center(self):
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())
class DisplaySongs(QWidget):
    def __init__(self):
        super().__init__()
        self.initializeUI()
        self.pb_search.clicked.connect(self.pb_search_clicked)
        self.pb_reload.clicked.connect(self.pb_reload_clicked)
        self.table_view.clicked.connect(self.select_song)

    def initializeUI(self):
        """
        Initialize the window and display its contents to the screen.
        """
        self.setWindowIcon(QIcon('icon.ico'))
        self.setGeometry(100, 100, 1200, 800)
        self.setWindowTitle('Songer-book')

        self.table_view = QTableView()
        self.table_view.setAlternatingRowColors(True)
        self.table_view.setSelectionMode(1)
        self.table_view.setSelectionBehavior(1)
        self.table_view.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.table_view.horizontalHeader().setSectionResizeMode(1)

        self.setupModelView()
        self.le_search = QLineEdit()
        self.le_search.setPlaceholderText('Ведите название песни')
        self.pb_search = QPushButton('Найти')
        self.pb_reload = QPushButton('Загрузить заново')
        self.text_edit = QTextEdit()
        self.text_edit.setFont(QFont("Times", 17))

        vbox1 = QVBoxLayout()
        hbox_mini = QHBoxLayout()
        hbox_mini.addWidget(self.le_search)
        hbox_mini.addWidget(self.pb_search)
        vbox1.addLayout(hbox_mini)
        vbox1.addWidget(self.table_view)
        vbox1.addWidget(self.pb_reload)

        vbox2 = QVBoxLayout()
        vbox2.addWidget(self.text_edit)

        hbox = QHBoxLayout()
        hbox.addLayout(vbox1)
        hbox.addLayout(vbox2)

        self.setLayout(hbox)

        self.show()

    def setupModelView(self):
        """
        Set up standard item model and table view.
        """
        self.model = QStandardItemModel()
        self.table_view.setModel(self.model)
        self.model.setRowCount(0)
        self.model.setColumnCount(2)

        self.loadDataFromDB()

    def loadDataFromDB(self, text=None):

        headers = ['Название композиции', 'Исполнитель(Автор)']
        self.model.clear()
        self.model.setHorizontalHeaderLabels(headers)
        if text:
            data = get_data(text)
        else:
            data = get_data()
        for i, row in enumerate(data):
            items = [QStandardItem(item) for item in row[1:3]]
            self.model.insertRow(i, items)
        self.table_view.resizeColumnsToContents()
        self.table_view.resizeRowsToContents()

    def pb_search_clicked(self):
        text = self.le_search.text()
        self.loadDataFromDB(text)

    def pb_reload_clicked(self):
        self.le_search.clear()
        self.loadDataFromDB()

    def select_song(self):
        indexes = self.table_view.selectedIndexes()
        if indexes:
            index = indexes[0]
            title = self.table_view.model().data(index, Qt.DisplayRole)
            data = get_data(title)[0]
            self.text_edit.setText(data[3])
class GtoQgisSettingsDialog(QDialog):
    def __init__(self, gtomain, parent=None):
        super(GtoQgisSettingsDialog, self).__init__(parent)
        # gto
        self.gtomain = gtomain
        self.info = self.gtomain.info
        self.helper = self.gtomain.helper
        self.debug = self.gtomain.debug
        self.iface = self.gtomain.iface
        try:
            # references
            self.undoList = []
            self.setWindowTitle('QGIS settings')
            self.setSizeGripEnabled(True)

            self.model = QStandardItemModel(self)
            self.model.setColumnCount(2)
            self.model.setHeaderData(0, Qt.Horizontal, "key")
            self.model.setHeaderData(1, Qt.Horizontal, "value")

            s = QSettings()
            for key in s.allKeys():
                val = s.value(key)
                items = []
                itKey = QStandardItem(key)
                itKey.setEditable(False)
                items.append(itKey)
                try:
                    items.append(QStandardItem(val))
                    self.model.appendRow(items)
                except Exception as e:
                    pass
                    # if self.debug: self.info.err(e)

            self._proxy = MyFilter(self)
            self._proxy.setSourceModel(self.model)

            self.model.itemChanged.connect(self.dataChanged)  # QstandardItem

            # create gui
            self.tableview = QTableView()
            self.tableview.horizontalHeader().setSectionResizeMode(
                QHeaderView.Stretch)
            self.tableview.horizontalHeader().setSectionsMovable(False)
            self.tableview.setSelectionBehavior(
                QAbstractItemView.SelectRows)  # SelectItems
            self.tableview.setSelectionMode(QAbstractItemView.SingleSelection)
            self.tableview.setModel(self._proxy)

            self.search = QLineEdit()
            self.search.textChanged.connect(self.on_text_changed)
            self.btnDelete = QPushButton('Delete')
            self.btnDelete.clicked.connect(self.delete)
            self.btnAddRandowKey = QPushButton('add key')
            self.btnAddRandowKey.clicked.connect(self.addRandomKey)
            self.btnAddRandowKey.setHidden(not self.debug)
            # self.btnDelete.setEnabled(self.debug)
            self.btnUndo = QPushButton("Undo")
            self.btnUndo.setEnabled(False)
            self.btnUndo.clicked.connect(self.undo)
            self.btnCopy = QPushButton('Copy')
            self.btnCopy.clicked.connect(self.copy)
            self.chkPureJson = QCheckBox('Pure json')
            # layout search
            laySearch = QHBoxLayout()
            laySearch.addWidget(QLabel('Suche:'))
            laySearch.addWidget(self.search)
            # layout buttons
            layBtns = QHBoxLayout()
            layBtns.addWidget(self.btnAddRandowKey)
            layBtns.addWidget(self.btnDelete)
            layBtns.addWidget(self.btnUndo)
            hspacer = QSpacerItem(0, 0, QSizePolicy.Expanding,
                                  QSizePolicy.Minimum)
            layBtns.addItem(hspacer)
            layBtns.addWidget(self.btnCopy)
            layBtns.addWidget(self.chkPureJson)
            # layout dialog
            self.layout = QVBoxLayout(self.iface.mainWindow())
            self.layout.addLayout(laySearch)
            self.layout.addWidget(self.tableview)
            self.layout.addLayout(layBtns)

            self.setLayout(self.layout)
            self.resize(640, 480)

            self.tableview.sortByColumn(0, Qt.AscendingOrder)
            self.tableview.setSortingEnabled(True)
            self.tableview.selectRow(0)
        except Exception as e:
            self.info.err(e)

    def addRandomKey(self):
        try:
            if self.debug:
                val = str(random.random() * 100)
                key = val[0:1] + "/" + val[3:5]
                self.setQvalue(key, float(val))
                items = []
                it = QStandardItem(key)
                it.setEditable(False)
                items.append(it)
                items.append(QStandardItem(val))
                self.model.appendRow(items)
        except Exception as e:
            self.info.err(e)

    def copy(self):
        try:
            index = self.tableview.currentIndex()
            key = self._proxy.index(index.row(), 0).data(0)
            val = self._proxy.index(index.row(), 1).data(0)
            s = QSettings()
            val = s.value(key)
            if self.debug: self.info.log("copy key:", key)
            if self.debug: self.info.log("copy val", val)
            if self.debug: self.info.log("copy Qval", val)
            if self.chkPureJson.isChecked():
                val = json.dumps(val, ensure_ascii=False)
            else:
                val = self.getValue(val)
            text = '"{0}":{1},\n'.format(key, val)
            if self.debug: self.info.log("copy:", text)
            self.helper.copyToClipboard(text)
        except Exception as e:
            self.info.err(e)

    def getValue(self, val):
        try:  # readable json expression: true instead of "true" or 9.99 instead of "9.99"
            if val is not None:
                try:  # bool :S
                    if val == "true":
                        return json.dumps(True, ensure_ascii=False)
                    if val == "false":
                        return json.dumps(False, ensure_ascii=False)
                    if val.lower() == "true":
                        return json.dumps(True, ensure_ascii=False)
                    if val.lower() == "false":
                        return json.dumps(False, ensure_ascii=False)
                except:
                    pass
                try:  # integer
                    return int(val)
                except:
                    pass
                try:  # float
                    return float(val)
                except:
                    pass
                if val is not None:
                    if isinstance(val, str):
                        return json.dumps(val, ensure_ascii=False)
                    if not (isinstance(val, list) or isinstance(val, dict)):
                        val = [val]
                        lst = json.dumps(val, ensure_ascii=False)
                        val = lst[1:-1]
                if val == "": val = None
            return json.dumps(val, ensure_ascii=False)
        except Exception as e:
            if self.debug: self.info.err(e)
            return val

    def delete(self, *args):
        try:
            index = self._proxy.mapSelectionToSource(
                self.tableview.selectionModel().selection()).indexes()[0]
            row = index.row()
            items = self.model.takeRow(row)  # QList<QStandardItem>
            key = items[0].data(0)
            val = items[1].data(0)
            if self.debug: self.info.log("delete key:", key)
            if self.debug: self.info.log("delte val", val)
            s = QSettings()
            s.remove(key)

            self.undoList.append((index, items))
            self.btnUndo.setEnabled(True)
        except Exception as e:
            self.info.err(e)

    def undo(self):
        try:
            if len(self.undoList) > 0:
                self.undoList.reverse()
                index, items = self.undoList[0]

                key = items[0].data(0)
                val = items[1].data(0)
                if self.debug: self.info.log("undo key:", key)
                if self.debug: self.info.log("undo val", val)
                self.setQvalue(key, val)

                self.model.insertRow(index.row(), items)

                tabindex = self._proxy.mapFromSource(index)
                self.tableview.selectRow(tabindex.row())

                del self.undoList[0]
                self.undoList.reverse()
            if len(self.undoList) == 0: self.btnUndo.setEnabled(False)
        except Exception as e:
            self.info.err(e)

    def dataChanged(self, item):
        try:
            val = item.data(0)
            key = self.model.item(item.row(), 0).data(0)
            if self.debug: self.info.log("datachanged key:", key)
            if self.debug: self.info.log("datachanged val", val)
            self.setQvalue(key, val)
        except Exception as e:
            self.info.err(e)

    def setQvalue(self, key, val):
        try:
            s = QSettings()
            s.setValue(key, val)
        except Exception as e:
            self.info.err(e)

    @pyqtSlot(str)
    def on_text_changed(self, text):
        try:
            regExp = QRegExp(text, Qt.CaseInsensitive, QRegExp.Wildcard)
            self._proxy.setFilterRegExp(regExp)
        except Exception as e:
            self.info.err(e)
Example #9
0
class FriendVeiw(Ui_Form):

    #分组信息存储
    grouplist = []
    #用户信息存储
    userlist = []

    def __init__(self, parent=None):
        super(FriendVeiw, self).__init__(parent)
        print('sss')
        self.setupUi()
        # self.show()
        self.Ui_init()

    def Ui_init(self):
        # 设置好友图标大小等
        # print('3', self, '4', self.form)
        self.treeWidget.setColumnCount(1)
        self.treeWidget.setColumnWidth(0, 50)
        self.treeWidget.setHeaderLabels(['好友'])
        self.treeWidget.setIconSize(QSize(50, 50))

        # 搜索时自动填充,创建一个缓存空间, 0行1列
        self.add_model = QStandardItemModel(0, 1, self)
        add_completer = QCompleter(self.add_model, self)
        self.lineEdit.setCompleter(add_completer)
        add_completer.activated[str].connect(self.onUsernameChoosed)

        self.treeWidget.setSelectionMode(QAbstractItemView.MultiSelection)
        # print('t1')
        self.treeWidget.itemSelectionChanged.connect(self.getListitems)
        self.treeWidget.itemDoubleClicked.connect(self.open_chatview)
        # print('t2')
        # self.treeWidget.currentItemChanged.connect(self.restatistic)
        # self.treeWidget.itemClicked.connect(self.isclick)

        # 样式的设置
        # with codecs.open('./qss/treeWidget.qss', 'r', 'utf-8') as f:
        #     style = f.read()
        #     print(style)
        # self.treeWidget.setStyleSheet(style)

        # 添加好友分组
        root = self.createGroup('我的好友')
        # root1 = self.createGroup('我的群组')
        root.setExpanded(True)
        # root1.setExpanded(True)

    # 创建好友分组
    def createGroup(self, groupname):
        onlinenum = 0
        group = QTreeWidgetItem(self.treeWidget)
        groupdic = {
            'group': group,
            'groupname': groupname,
            'childcount': 0,
            'childstatus': 0
        }

        # 给分组设置小图标
        icon = self.searchicon(groupname)
        group.setIcon(0, icon)
        #
        #     # with codecs.open('friend_info', 'r', 'utf-8') as f:
        #     #     fre_info = f.read()
        #     # print(fre_info.split('\r\n'))
        fre_info = [['小李', '1001', '0', '../images/user/0.jpg'],
                    ['小强', '1002', '1', '../images/user/0.jpg'],
                    ['小明', '1003', '1', '../images/user/0.jpg']]
        for item in fre_info:
            child = QTreeWidgetItem()
            uname = item[0]
            chatID = item[1]
            status = item[2]
            icon_path = QIcon(item[3])
            name = uname + '(%s)' % chatID
            # name, chatID, icon_path, font, status = self.createUser(item)
            font = QFont()
            font.setPointSize(9)

            userdic = {
                'user': child,
                'username': name,
                'userID': chatID,
                'status': status
            }
            self.userlist.append(userdic)
            child.setFont(0, font)
            child.setIcon(0, icon_path)
            # 离线、在线判断
            onlinenum, name = self.judge_online(status, onlinenum, name, child)
            group.addChild(child)

        # 判断在线、总人数
        childnum = group.childCount()
        print('childnum:', childnum, 'online:', onlinenum)
        off_line_num = childnum - onlinenum
        groupdic['childcount'] = childnum
        groupdic['childstatus'] = onlinenum
        groupname += ' ' + str(onlinenum) + '/' + str(childnum)
        group.setText(0, groupname)
        self.grouplist.append(groupdic)
        # print('grouplist:', self.grouplist)
        return group

    # 在线、离线判断
    def judge_online(self, status, onlinenum, name, child):
        if status == '1':
            onlinenum += 1
            name += ' 在线'
            child.setText(0, name)
        else:
            name += ' 离线'
            child.setText(0, name)
        return onlinenum, name

    # 设置菜单
    def contextMenuEvent(self, event):
        hititem = self.treeWidget.currentItem()
        print('event', event, 'hititem', hititem)
        if hititem:
            # 当root是 None 时,此时节点在分组上
            root = hititem.parent()
            if root is None:
                pgroupmenu = QMenu(self)
                pAddgroupAct = QAction('添加分组', self.treeWidget)
                pRenameAct = QAction('重命名', self.treeWidget)
                pDeleteAct = QAction('删除该组', self.treeWidget)
                pgroupmenu.addAction(pAddgroupAct)
                pgroupmenu.addAction(pRenameAct)
                pgroupmenu.addAction(pDeleteAct)
                pAddgroupAct.triggered.connect(self.addgroup)
                pRenameAct.triggered.connect(self.renamegroup)
                if self.treeWidget.itemAbove(hititem) is None:
                    pDeleteAct.setEnabled(False)
                else:
                    pDeleteAct.triggered.connect(self.deletegroup)
                pgroupmenu.popup(self.mapToGlobal(event.pos()))
            # 此时节点在联系人上
            elif root.childCount() > 0:
                pItemmenu = QMenu(self)
                pDeleteItemAct = QAction('删除联系人', pItemmenu)
                pRenameItemAct = QAction('添加备注', pItemmenu)
                pItemmenu.addAction(pDeleteItemAct)
                pItemmenu.addAction(pRenameItemAct)
                pDeleteItemAct.triggered.connect(self.delete)
                pRenameItemAct.triggered.connect(self.renameItem)
                print('font', hititem.text(0))
                # 左键点击事件

                # self.treeWidget.itemDoubleClicked(hititem).connect(self.click_event)
                # 当联系人大于 1时,可以转移
                if len(self.grouplist) > 1:
                    pSubMenu = QMenu('转移联系人至', pItemmenu)
                    pItemmenu.addMenu(pSubMenu)
                    for item_dic in self.grouplist:
                        if item_dic['group'] is not root:
                            pMoveAct = QAction(item_dic['groupname'],
                                               pItemmenu)
                            pSubMenu.addAction(pMoveAct)
                            pMoveAct.triggered.connect(self.moveItem)
                pItemmenu.popup(self.mapToGlobal(event.pos()))

    # 添加分组
    def addgroup(self):
        gname, ok = QInputDialog.getText(self, '提示信息', '请输入分组名称')
        if ok:
            if len(gname) == 0:
                QMessageBox.information(self, '提示', '分组名称不能为空哦')
            else:
                self.createGroup(gname)

    # 重命名
    def renamegroup(self):
        hitgroup = self.treeWidget.currentItem()
        gnewname, ok = QInputDialog.getText(self, '提示信息', '请输入分组的新名称')
        if ok:
            if len(gnewname) == 0:
                QMessageBox.information(self, '提示', '分组名称不能为空哦')
            else:
                hitgroup.setText(0, gnewname)
                newicon = self.searchicon(hitgroup.text(0))
                hitgroup.setIcon(0, newicon)
                gindex = self.searchgroup(hitgroup)
                self.grouplist[gindex]['groupname'] = gnewname
                self.treeWidget.setCurrentItem(hitgroup.child(0))

    # 给联系人添加备注
    def renameItem(self):
        hituser = self.treeWidget.currentItem()
        uindex = self.searchuser(hituser)
        unewname, ok = QInputDialog.getText(self, '提示信息', '请输入备注名称')
        if ok:
            if len(unewname) == 0:
                QMessageBox.information(self, '提示', '备注名称不能为空哦')
            else:
                hituser.setText(0, unewname)
                self.userslist[uindex]['username'] = unewname

    # 删除分组
    def deletegroup(self):
        hitgroup = self.treeWidget.currentItem()
        gindex = self.searchgroup(hitgroup)
        reply = QMessageBox.question(self, '警告', '确定要删除这个分组及其联系人吗?',
                                     QMessageBox.Yes | QMessageBox.No,
                                     QMessageBox.No)

        if reply == QMessageBox.Yes:
            self.treeWidget.takeTopLevelItem(gindex)
            del self.grouplist[gindex]

    # 移动联系人
    def moveItem(self):
        movelist = self.getListitems(self.menuflag)
        togroupname = self.sender().text()
        mindex = self.searchgroup(togroupname)
        togroup = self.grouplist[mindex]['group']
        self.deleteItems(movelist, flag=0)
        self.add(togroup, movelist)
        self.tmpuseritem.clear()

    def delete(self):
        delitems = self.getListitems(self.menuflag)
        self.deleteItems(delitems)
        self.tmpuseritem.clear()

    def deleteItems(self, items, flag=1):
        for delitem in items:
            delitem.setData(0, Qt.CheckStateRole, QVariant())  #取消删除item的复选框
            pindex = delitem.parent().indexOfChild(delitem)
            dindex = self.searchuser(delitem)
            ishide = self.userslist[dindex]['ishide']
            if flag == 1:
                del self.userslist[dindex]
            fathergroup = delitem.parent()
            findex = self.searchgroup(fathergroup)
            if ishide == 1:
                self.grouplist[findex]['childishide'] -= 1
                self.grouplist[findex]['childcount'] -= 1
            else:
                self.grouplist[findex]['childcount'] -= 1

            delitem.parent().takeChild(pindex)

    def add(self, group, items):
        gindex = self.searchgroup(group)
        for item in items:
            aindex = self.searchuser(item)
            ishide = self.userslist[aindex]['ishide']
            if ishide == 1:
                self.grouplist[gindex]['childishide'] += 1
                self.grouplist[gindex]['childcount'] += 1
            else:
                self.grouplist[gindex]['childcount'] += 1
            group.addChild(item)
            self.treeWidget.setCurrentItem(item)

    def Batchoperation(self):
        self.menuflag *= -1

        group = self.getListitems()[0].parent()
        childnum = group.childCount()
        for c in range(childnum):
            child = group.child(c)
            child.setCheckState(0, Qt.Unchecked)

    def CancelBatchoperation(self):
        self.menuflag *= -1
        group = self.getListitems()[0].parent()
        childnum = group.childCount()
        for c in range(childnum):
            child = group.child(c)
            child.setData(0, Qt.CheckStateRole, QVariant())

    def isclick(self, item):
        if item.checkState(0) == Qt.Checked:
            if self.tmpuseritem.count(item) == 0:
                self.tmpuseritem.append(item)
        else:
            if len(self.tmpuseritem) > 0:
                if self.tmpuseritem.count(item) != 0:
                    i = self.tmpuseritem.index(item)
                    del self.tmpuseritem[i]

    # 查找分组
    def searchgroup(self, hitgroup):
        if isinstance(hitgroup, str):
            for i, g in enumerate(self.grouplist):
                if g['groupname'] == hitgroup:
                    return i
        else:
            for i, g in enumerate(self.grouplist):
                if g['group'] == hitgroup:
                    return i

    def searchuser(self, hituser):
        if isinstance(hituser, str):
            for i, u in enumerate(self.userlist):
                if u['userID'] == hituser:
                    return i
        else:
            for i, u in enumerate(self.userslist):
                if u['user'] == hituser:
                    return i

    def searchicon(self, gpname2):
        if gpname2.find('好友') >= 0:
            return QIcon('../iamges/list_images/buddy.ico')
        elif gpname2.find('同事') >= 0:
            return QIcon('../images/list_images/partner.ico')
        elif gpname2.find('黑名单') >= 0:
            return QIcon('../images/list_images/blacklist.ico')
        else:
            return QIcon('../images/list_images/buddy_default.ico')

    # 返回当前对象
    def getListitems(self, flag=1):
        if flag > 0:
            return self.treeWidget.selectedItems()

    def restatistic(self, item, preitem):
        if item:
            fathergroup = item.parent()
            if fathergroup:
                self.restatistic_op(fathergroup)
            else:
                self.restatistic_op(item)
        elif preitem.parent().childCount() == 1:
            lastgroupname = preitem.parent().text(0).split()[0] + ' 0/0'
            preitem.parent().setText(0, lastgroupname)
            self.menuflag = 1

    def restatistic_op(self, itemorgroup):
        gindex = self.searchgroup(itemorgroup)
        totalcount = self.grouplist[gindex]['childcount']
        hidecount = self.grouplist[gindex]['childishide']
        fathergroupname = self.grouplist[gindex]['groupname']
        fathergroupname += ' ' + str(totalcount -
                                     hidecount) + '/' + str(totalcount)
        itemorgroup.setText(0, fathergroupname)

    def open_chatview(self):
        t = Thread()
        print('2222')

        user_id, user_name = self.handle_info()

        try:
            # app = QApplication(sys.argv)
            self.hide()
            ch = ChatForm(user_id, user_name)
            ch.show()
            ch.exec_()
            # sys.exit(app.exec_())
        except Exception as e:
            print(e)

        t.start()
        t.join()

    # 双击时获取好友信息
    def handle_info(self):
        hititem = self.treeWidget.currentItem()
        text = hititem.text(0)

        partern = '\d+'
        user_id = re.findall(partern, text)

        partern1 = '^\w+'
        user_name = re.findall(partern1, text)
        print('11', user_id[0], user_name[0])
        return user_id[0], user_name[0]

    # 添加好友
    @pyqtSlot()
    def on_bt_adduser_clicked(self):
        addUser = AddFriend()
        for gro in self.grouplist:
            addUser.comboBox.addItem(gro['groupname'])
        r = addUser.exec_()
        if r > 0:
            newItem = QTreeWidgetItem()
            newId = addUser.lineEdit_add.text()
            print('newId', newId)
            # 设置一个接口 获取 id 对应的信息
            newUser = ['小李', '1006', '1', '../images/user/7.jpg']
            newName = newUser[0]
            newStatus = newUser[2]
            newPath = QIcon(newUser[3])

            name = newName + '(%s)' % newId
            font = QFont()
            font.setPointSize(9)

            userdic = {
                'user': newItem,
                'username': name,
                'userID': newId,
                'status': newStatus
            }
            self.userlist.append(userdic)
            newItem.setFont(0, font)
            newItem.setIcon(0, newPath)
            newItem.setText(0, name)

            comboInfo = addUser.comboBox.currentText()
            conboIndex = self.searchgroup(comboInfo)
            group = self.grouplist[conboIndex]['group']
            self.grouplist[conboIndex]['childcount'] += 1

            group.addChild(newItem)
            self.treeWidget.setCurrentItem(newItem)

    # 获取lineEdit的输入信息
    def onUsernameChoosed(self, name):
        self.lineEdit.setText(name)

    # 查找好友
    @pyqtSlot()
    def on_bt_search_clicked(self):
        userId = self.lineEdit.text()
        if len(userId) > 0:
            user_index = self.searchuser(userId)
            print('user', user_index)
            userItem = self.userlist[user_index]['user']
            self.treeWidget.setCurrentItem(userItem)

    @pyqtSlot(str)
    def on_lineEdit_textChanged(self, text):
        unameList = []
        for i in self.userlist:
            userName = i['username']
            if userName.find(text) > 0:
                unameList.append(userName)
            self.add_model.removeRows(0, self.add_model.rowCount())

            for n in range(0, len(unameList)):
                self.add_model.insertRow(0)
                self.add_model.setData(self.add_model.index(0, 0),
                                       unameList[n])
Example #10
0
class WelcomeDialog(QDialog):
    onSessionSelected = pyqtSignal(str, name='onSessionSelected')
    onSessionRestore = pyqtSignal(dict, name='onSessionRestore')
    onUpdateComplete = pyqtSignal(name='onUpdateComplete')
    onIsNewerVersion = pyqtSignal(name='onIsNewerVersion')

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

        self._prefs = parent.prefs

        self._sub_titles = [
            ['duck', 'dumb', 'doctor', 'dutch', 'dark', 'dirty'],
            ['warriors', 'wardrobes', 'waffles', 'wishes'],
            ['are', 'aren\'t', 'ain\'t', 'appears to be'],
            ['rich', 'real', 'riffle', 'retarded', 'rock'],
            ['as f**k', 'fancy', 'f****d', 'front-ended', 'falafel', 'french fries'],
        ]

        self._recent_list_model = QStandardItemModel(0, 6)
        self._recent_list_model.setHeaderData(0, Qt.Horizontal, 'Path')
        self._recent_list_model.setHeaderData(1, Qt.Horizontal, 'Session')
        self._recent_list_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole)
        self._recent_list_model.setHeaderData(2, Qt.Horizontal, 'Hooks')
        self._recent_list_model.setHeaderData(2, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole)
        self._recent_list_model.setHeaderData(3, Qt.Horizontal, 'Watchers')
        self._recent_list_model.setHeaderData(3, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole)
        self._recent_list_model.setHeaderData(4, Qt.Horizontal, 'OnLoads')
        self._recent_list_model.setHeaderData(4, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole)
        self._recent_list_model.setHeaderData(5, Qt.Horizontal, 'Bookmarks')
        self._recent_list_model.setHeaderData(5, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole)
        #self._recent_list_model.setHeaderData(6, Qt.Horizontal, 'Custom script')
        #self._recent_list_model.setHeaderData(6, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole)

        self._recent_list = DwarfListView(self)
        self._recent_list.setModel(self._recent_list_model)

        self._recent_list.header().setSectionResizeMode(0, QHeaderView.ResizeToContents | QHeaderView.Interactive)
        self._recent_list.header().setSectionResizeMode(1, QHeaderView.Stretch)
        self._recent_list.header().setSectionResizeMode(2, QHeaderView.Stretch)
        self._recent_list.header().setSectionResizeMode(3, QHeaderView.Stretch)
        self._recent_list.header().setSectionResizeMode(4, QHeaderView.Stretch)
        self._recent_list.header().setSectionResizeMode(5, QHeaderView.Stretch)
        #self._recent_list.header().setSectionResizeMode(6, QHeaderView.Stretch)

        self._recent_list.setContextMenuPolicy(Qt.CustomContextMenu)
        self._recent_list.customContextMenuRequested.connect(self._on_recent_sessions_context_menu)
        self._recent_list.doubleClicked.connect(self._on_recent_session_double_click)

        # setup size and remove/disable titlebuttons
        self.desktop_geom = qApp.desktop().availableGeometry()
        self.setFixedSize(self.desktop_geom.width() * .45, self.desktop_geom.height() * .38)
        self.setGeometry(QStyle.alignedRect(Qt.LeftToRight, Qt.AlignCenter, self.size(), qApp.desktop().availableGeometry()))
        self.setSizeGripEnabled(False)
        self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.setWindowFlag(Qt.WindowContextHelpButtonHint, False)
        self.setWindowFlag(Qt.WindowCloseButtonHint, True)
        self.setModal(True)

        # setup ui elements
        self.setup_ui()

        self.update_commits_thread = DwarfCommitsThread(parent)
        self.update_commits_thread.on_update_available.connect(self._on_dwarf_isupdate)
        self.update_commits_thread.start()
        # center
        self.setGeometry(
            QStyle.alignedRect(Qt.LeftToRight, Qt.AlignCenter, self.size(), qApp.desktop().availableGeometry()))

    def setup_ui(self):
        """ Setup Ui
        """
        main_wrap = QVBoxLayout()
        main_wrap.setContentsMargins(0, 0, 0, 0)

        # updatebar on top
        self.update_bar = UpdateBar(self)
        self.update_bar.onUpdateNowClicked.connect(self._update_dwarf)
        self.update_bar.setVisible(False)
        main_wrap.addWidget(self.update_bar)

        # main content
        h_box = QHBoxLayout()
        h_box.setContentsMargins(15, 15, 15, 15)
        wrapper = QVBoxLayout()
        # wrapper.setGeometry(QRect(0, 0, 400, 200))
        head = QHBoxLayout()
        head.setContentsMargins(0, 10, 0, 10)
        # dwarf icon
        icon = QLabel()
        icon.setContentsMargins(40, 0, 0, 0)
        dwarf_logo = QPixmap(utils.resource_path('assets/dwarf.svg'))
        icon.setPixmap(dwarf_logo)
        head.addWidget(icon)

        # main title
        v_box = QVBoxLayout()
        title = QLabel('Dwarf')
        title.setContentsMargins(0, 0, 50, 0)
        title.setFont(QFont('Anton', 90, QFont.Bold))
        title.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
        title.setFixedHeight(self.height() * .35)
        title.setAlignment(Qt.AlignCenter)
        v_box.addWidget(title)

        sub_title_text = (self._pick_random_word(0) + ' ' + self._pick_random_word(1) + ' ' +
                          self._pick_random_word(2) + ' ' + self._pick_random_word(3) + ' ' +
                          self._pick_random_word(4))
        sub_title_text = sub_title_text[:1].upper() + sub_title_text[1:]
        sub_title = QLabel(sub_title_text)
        sub_title.setFont(QFont('OpenSans', 14, QFont.Bold))
        sub_title.setFixedHeight(title.height() * .25)
        sub_title.setAlignment(Qt.AlignCenter)
        sub_title.setContentsMargins(0, 0, 50, 0)
        sub_title.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
        v_box.addWidget(sub_title)
        head.addLayout(v_box)

        wrapper.addLayout(head)

        recent = QLabel('Last saved Sessions')
        font = recent.font()
        font.setBold(True)
        #font.setPointSize(10)
        recent.setFont(font)
        wrapper.addWidget(recent)
        wrapper.addWidget(self._recent_list)
        h_box.addLayout(wrapper, stretch=False)
        buttonSpacer = QSpacerItem(15, 100, QSizePolicy.Fixed, QSizePolicy.Minimum)
        h_box.addItem(buttonSpacer)
        wrapper = QVBoxLayout()

        btn = QPushButton()
        ico = QIcon(QPixmap(utils.resource_path('assets/android.svg')))
        btn.setIconSize(QSize(75, 75))
        btn.setIcon(ico)
        btn.setToolTip('New Android Session')
        btn.clicked.connect(self._on_android_button)

        wrapper.addWidget(btn)
        btn = QPushButton()
        ico = QIcon(QPixmap(utils.resource_path('assets/apple.svg')))
        btn.setIconSize(QSize(75, 75))
        btn.setIcon(ico)
        btn.setToolTip('New iOS Session')
        btn.clicked.connect(self._on_ios_button)
        wrapper.addWidget(btn)

        btn = QPushButton()
        ico = QIcon(QPixmap(utils.resource_path('assets/local.svg')))
        btn.setIconSize(QSize(75, 75))
        btn.setIcon(ico)
        btn.setToolTip('New Local Session')
        btn.clicked.connect(self._on_local_button)
        wrapper.addWidget(btn)

        btn = QPushButton()
        ico = QIcon(QPixmap(utils.resource_path('assets/remote.svg')))
        btn.setIconSize(QSize(75, 75))
        btn.setIcon(ico)
        btn.setToolTip('New Remote Session')
        btn.clicked.connect(self._on_remote_button)
        wrapper.addWidget(btn)

        session_history = self._prefs.get(prefs.RECENT_SESSIONS, default=[])
        invalid_session_files = []
        for recent_session_file in session_history:
            if os.path.exists(recent_session_file):
                with open(recent_session_file, 'r') as f:
                    exported_session = json.load(f)
                hooks = '0'
                watchers = '0'
                on_loads = 0
                bookmarks = '0'
                #have_user_script = False
                if 'hooks' in exported_session and exported_session['hooks'] is not None:
                    hooks = str(len(exported_session['hooks']))
                if 'watchers' in exported_session and exported_session['watchers'] is not None:
                    watchers = str(len(exported_session['watchers']))
                if 'nativeOnLoads' in exported_session and exported_session['nativeOnLoads'] is not None:
                    on_loads += len(exported_session['nativeOnLoads'])
                if 'javaOnLoads' in exported_session and exported_session['javaOnLoads'] is not None:
                    on_loads += len(exported_session['javaOnLoads'])
                if 'bookmarks' in exported_session and exported_session['bookmarks'] is not None:
                    bookmarks = str(len(exported_session['bookmarks']))
                if 'user_script' in exported_session and exported_session['user_script']:
                    have_user_script = exported_session['user_script'] != ''

                #user_script_item = QStandardItem()
                #if have_user_script:
                #user_script_item.setIcon(self._dot_icon)

                on_loads = str(on_loads)

                recent_session_file_item = QStandardItem(recent_session_file)
                recent_session_file_item.setData(exported_session, Qt.UserRole + 2)

                item_1 = QStandardItem(exported_session['session'])
                item_1.setTextAlignment(Qt.AlignCenter)
                item_2 = QStandardItem(hooks)
                item_2.setTextAlignment(Qt.AlignCenter)
                item_3 = QStandardItem(watchers)
                item_3.setTextAlignment(Qt.AlignCenter)
                item_4 = QStandardItem(on_loads)
                item_4.setTextAlignment(Qt.AlignCenter)
                item_5 = QStandardItem(bookmarks)
                item_5.setTextAlignment(Qt.AlignCenter)
                #item_6 = QStandardItem(user_script_item)
                #item_6.setTextAlignment(Qt.AlignCenter)

                self._recent_list_model.insertRow(self._recent_list_model.rowCount(), [
                    recent_session_file_item,
                    item_1, item_2, item_3, item_4, item_5
                ])
            else:
                invalid_session_files.append(recent_session_file)
        for invalid in invalid_session_files:
            session_history.pop(session_history.index(invalid))
        self._prefs.put(prefs.RECENT_SESSIONS, session_history)

        h_box.addLayout(wrapper, stretch=False)
        main_wrap.addLayout(h_box)
        self.setLayout(main_wrap)

    def _on_dwarf_isupdate(self):
        self.update_bar.setVisible(True)
        self.onIsNewerVersion.emit()

    def _update_dwarf(self):
        self._update_thread = DwarfUpdateThread(self)
        self._update_thread.on_finished.connect(self._update_finished)
        if not self._update_thread.isRunning():
            self._update_thread.start()

    def _update_finished(self):
        self.onUpdateComplete.emit()

    def _on_android_button(self):
        self.onSessionSelected.emit('Android')
        self.close()

    def _on_local_button(self):
        self.onSessionSelected.emit('Local')
        self.close()

    def _on_ios_button(self):
        self.onSessionSelected.emit('Ios')
        self.close()

    def _on_remote_button(self):
        self.onSessionSelected.emit('Remote')
        self.close()

    def _pick_random_word(self, arr):
        return self._sub_titles[arr][random.randint(0, len(self._sub_titles[arr]) - 1)]

    def _on_recent_sessions_context_menu(self, pos):
        index = self.list_view.indexAt(pos).row()
        glbl_pt = self.list_view.mapToGlobal(pos)
        context_menu = QMenu(self)
        if index != -1:
            context_menu.addAction(
                'Delete recent session', lambda: self._remove_recent_sessions(
                    self._recent_list_model.item(index, 0).text()))

            context_menu.exec_(glbl_pt)

    def _remove_recent_session(self, session_file):
        if os.path.exists(session_file):
            os.remove(session_file)
            session_history = self._prefs.get(prefs.RECENT_SESSIONS, default=[])
            if session_file in session_history:
                session_history.pop(session_history.index(session_file))
                self._prefs.put(prefs.RECENT_SESSIONS, session_history)

    def _on_recent_session_double_click(self, model_index):
        row = self._recent_list_model.itemFromIndex(model_index).row()
        recent_session_file = self._recent_list_model.item(row, 0)
        recent_session_data = recent_session_file.data(Qt.UserRole + 2)
        self.onSessionRestore.emit(recent_session_data)
Example #11
0
class QmyMainWindow(QMainWindow): 
   def __init__(self, parent=None):
      super().__init__(parent)    #调用父类构造函数,创建窗体
      self.ui=Ui_MainWindow()     #创建UI对象
      self.ui.setupUi(self)       #构造UI界面

      self.setCentralWidget(self.ui.splitter)
      self.__buildStatusBar()

      self.COL_COUNT=6  #常数,列数=6
      self.itemModel = QStandardItemModel(5,self.COL_COUNT,self)  # 数据模型,10行6列

##      headerList=["测深(m)","垂深(m)","方位(°)","总位移(m)","固井质量","测井取样"]
##      self.itemModel.setHorizontalHeaderLabels(headerList) #设置表头文字

      self.selectionModel = QItemSelectionModel(self.itemModel) #Item选择模型
      self.selectionModel.currentChanged.connect(self.do_currentChanged)
      self.__lastColumnFlags=(Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
      self.__lastColumnTitle="测井取样"
      
      #为tableView设置数据模型
      self.ui.tableView.setModel(self.itemModel) #设置数据模型
      self.ui.tableView.setSelectionModel(self.selectionModel)    #设置选择模型
      
      oneOrMore=QAbstractItemView.ExtendedSelection
      self.ui.tableView.setSelectionMode(oneOrMore) #可多选

      itemOrRow=QAbstractItemView.SelectItems
      self.ui.tableView.setSelectionBehavior(itemOrRow)   #单元格选择

      
      self.ui.tableView.verticalHeader().setDefaultSectionSize(22)#缺省行高
      self.ui.tableView.setEnabled(False)  #先禁用tableView
##      self.__resetTable(5)

      #创建自定义代理组件并设置
      self.spinCeShen=QmyFloatSpinDelegate(0,10000, 0,self)    #用于 测深
      self.spinLength=QmyFloatSpinDelegate(0,6000,  2,self)    #垂深,总位移
      self.spinDegree=QmyFloatSpinDelegate(0,360,   1,self)    #用于 方位

      self.ui.tableView.setItemDelegateForColumn(0,self.spinCeShen)  #测深
      self.ui.tableView.setItemDelegateForColumn(1,self.spinLength)  #垂深
      self.ui.tableView.setItemDelegateForColumn(3,self.spinLength)  #总位移
      self.ui.tableView.setItemDelegateForColumn(2,self.spinDegree)  #方位角

      qualities=["优","良","合格","不合格"]
      self.comboDelegate=QmyComboBoxDelegate(self)
      self.comboDelegate.setItems(qualities,False) #不可编辑
      self.ui.tableView.setItemDelegateForColumn(4,self.comboDelegate)  #固井质量
        

##  ==============自定义功能函数============
   def __buildStatusBar(self):   ##构建状态栏
      self.LabCellPos = QLabel("当前单元格:",self)
      self.LabCellPos.setMinimumWidth(180)
      self.ui.statusBar.addWidget(self.LabCellPos)

      self.LabCellText = QLabel("单元格内容:",self)
      self.LabCellText.setMinimumWidth(150)
      self.ui.statusBar.addWidget(self.LabCellText)

      self.LabCurFile = QLabel("当前文件:",self)
      self.ui.statusBar.addPermanentWidget(self.LabCurFile)

##   def __resetTable(self,tableRowCount):  #复位数据表,必须为数值设置0,否则代理组件出错
##      self.itemModel.removeRows(0,self.itemModel.rowCount()) #删除所有行
##      self.itemModel.setRowCount(tableRowCount)     #设置新的行数
##
##      for i in range(tableRowCount):  #设置最后一列
##         for j in range(self.COL_COUNT-1):
##            index=self.itemModel.index(i,j) #获取模型索引
##            item=self.itemModel.itemFromIndex(index) #获取item
##            item.setData(0,Qt.DisplayRole) #数值必须初始化为0
##            item.setTextAlignment(Qt.AlignHCenter)
##            
##         index=self.itemModel.index(i,self.COL_COUNT-1) #获取模型索引
##         item=self.itemModel.itemFromIndex(index) #获取item
##         item.setCheckable(True)
##         item.setData(self.__lastColumnTitle,Qt.DisplayRole)
##         item.setEditable(False) #不可编辑
      

   def __iniModelFromStringList(self,allLines):  ##从字符串列表构建模型
      rowCnt=len(allLines) #文本行数,第1行是标题
      self.itemModel.setRowCount(rowCnt-1) #实际数据行数

      headerText=allLines[0].strip() #第1行是表头,去掉末尾的换行符 "\n"
      headerList=headerText.split("\t")
      self.itemModel.setHorizontalHeaderLabels(headerList)

      self.__lastColumnTitle=headerList[len(headerList)-1] # 最后一列表头的标题,即“测井取样”

      lastColNo=self.COL_COUNT-1  #最后一列的列号
      for i in range(rowCnt-1):  
         lineText=allLines[i+1].strip()  #一行的文字,\t分隔
         strList=lineText.split("\t")
         for j in range(self.COL_COUNT-1):  #不含最后一列
             item=QStandardItem(strList[j])
             self.itemModel.setItem(i,j,item)
             
         item=QStandardItem(self.__lastColumnTitle)  #最后一列
         item.setFlags(self.__lastColumnFlags)
         item.setCheckable(True)
         if (strList[lastColNo]=="0"):
             item.setCheckState(Qt.Unchecked)
         else:
             item.setCheckState(Qt.Checked)
         
         self.itemModel.setItem(i,lastColNo,item) #设置最后一列的item
            

   def  __setCellAlignment(self, align=Qt.AlignHCenter):
      if (not self.selectionModel.hasSelection()): #没有选择的项
         return
      selectedIndex=self.selectionModel.selectedIndexes()  #列表类型
      count=len(selectedIndex)
      for i in range(count):
         index=selectedIndex[i]  #获取其中的一个模型索引
         item=self.itemModel.itemFromIndex(index)    #获取一个单元格的项数据对象
         item.setTextAlignment(align) #设置文字对齐方式
    
##  ==========由connectSlotsByName() 自动连接的槽函数==================        
   @pyqtSlot()    ##“打开文件”
   def on_actOpen_triggered(self):  
      curPath=os.getcwd()   #获取当前路径     
      filename,flt=QFileDialog.getOpenFileName(self,"打开一个文件",curPath,
                  "井斜数据文件(*.txt);;所有文件(*.*)")
      if (filename==""):
         return

      self.LabCurFile.setText("当前文件:"+filename)
      self.ui.plainTextEdit.clear()

      aFile=open(filename,'r')
      allLines=aFile.readlines()  #读取所有行,list类型,每行末尾带有 \n
      ##        for eachLine in aFile:  #每次读取一行
      ##            self.ui.plainTextEdit.appendPlainText(eachLine)
      aFile.close()

      for strLine in allLines:
        self.ui.plainTextEdit.appendPlainText(strLine.strip())

      self.__iniModelFromStringList(allLines)  
      self.ui.actAppend.setEnabled(True) #更新Actions的enable属性
      self.ui.actInsert.setEnabled(True)
      self.ui.actDelete.setEnabled(True)
      self.ui.actSave.setEnabled(True)
      self.ui.actModelData.setEnabled(True)
      
      self.ui.tableView.setEnabled(True)  #启用tableView


   @pyqtSlot()    ##保存文件
   def on_actSave_triggered(self):
      curPath=os.getcwd()   #获取当前路径     
      filename,flt=QFileDialog.getSaveFileName(self,"保存文件",curPath,
                  "井斜数据文件(*.txt);;所有文件(*.*)")
      if (filename==""):
         return

      self.on_actModelData_triggered()  #更新数据到plainTextEdit

      aFile=open(filename,'w')  #以写方式打开
      aFile.write(self.ui.plainTextEdit.toPlainText())
      aFile.close()
        

   @pyqtSlot()
   def on_actAppend_triggered(self):    #在最后添加一行
      itemlist=[]  # 列表
      for i in range(self.COL_COUNT-1):
         item=QStandardItem("0")
         itemlist.append(item)
         
      item=QStandardItem(self.__lastColumnTitle) #最后一列
      item.setCheckable(True)
      item.setFlags(self.__lastColumnFlags)
      itemlist.append(item)

      self.itemModel.appendRow(itemlist)
      curIndex=self.itemModel.index(self.itemModel.rowCount()-1,0)
      self.selectionModel.clearSelection()
      self.selectionModel.setCurrentIndex(curIndex,QItemSelectionModel.Select)

   @pyqtSlot()    ##插入一行
   def on_actInsert_triggered(self):   
      itemlist=[]  # 列表
      for i in range(self.COL_COUNT-1):
         item=QStandardItem("0")
         itemlist.append(item)
         
      item=QStandardItem(self.__lastColumnTitle) #最后一列
      item.setFlags(self.__lastColumnFlags)
      item.setCheckable(True)
      item.setCheckState(Qt.Checked)
      itemlist.append(item)

      curIndex=self.selectionModel.currentIndex(); #获取当前选中项的模型索引
      self.itemModel.insertRow(curIndex.row(),itemlist);  #在当前行的前面插入一行
      self.selectionModel.clearSelection()
      self.selectionModel.setCurrentIndex(curIndex,QItemSelectionModel.Select)
        

   @pyqtSlot()    ##删除当前行
   def on_actDelete_triggered(self):  
      curIndex=self.selectionModel.currentIndex()#获取当前选择单元格的模型索引
      self.itemModel.removeRow(curIndex.row())# //删除当前行

   @pyqtSlot()    ##左对齐
   def on_actAlignLeft_triggered(self): 
      self.__setCellAlignment(Qt.AlignLeft | Qt.AlignVCenter)

   @pyqtSlot()    ##中间对齐
   def on_actAlignCenter_triggered(self): 
      self.__setCellAlignment(Qt.AlignHCenter| Qt.AlignVCenter)
        
   @pyqtSlot()    ##右对齐
   def on_actAlignRight_triggered(self):  
      self.__setCellAlignment(Qt.AlignRight | Qt.AlignVCenter)

   @pyqtSlot(bool)      ##字体Bold
   def on_actFontBold_triggered(self,checked): 
      if (not self.selectionModel.hasSelection()): #没有选择的项
         return
        
      selectedIndex=self.selectionModel.selectedIndexes()  #列表类型
      count=len(selectedIndex)
      for i in range(count):
         index=selectedIndex[i]  #获取其中的一个模型索引
         item=self.itemModel.itemFromIndex(index)    #获取一个单元格的项数据对象
         font=item.font()
         font.setBold(checked)
         item.setFont(font)

   @pyqtSlot()    ##模型数据显示到plainTextEdit里
   def on_actModelData_triggered(self):  
      self.ui.plainTextEdit.clear()
      lineStr=""
      for i in range(self.itemModel.columnCount()-1):  #表头
         item=self.itemModel.horizontalHeaderItem(i)
         lineStr=lineStr+item.text()+"\t"
      item=self.itemModel.horizontalHeaderItem(self.COL_COUNT-1)  #最后一列
      lineStr=lineStr+item.text()
      self.ui.plainTextEdit.appendPlainText(lineStr)

      for i in range(self.itemModel.rowCount()):
         lineStr=""
         for j in range(self.itemModel.columnCount()-1):    #不包括最后一列
            item=self.itemModel.item(i,j)
            lineStr=lineStr+item.text()+"\t"
             
         item=self.itemModel.item(i,self.COL_COUNT-1)    #最后一列
         if (item.checkState()==Qt.Checked):
            lineStr=lineStr+"1"
         else:
            lineStr=lineStr+"0"
         self.ui.plainTextEdit.appendPlainText(lineStr)
        
    
##  =============自定义槽函数===============================        
   def do_currentChanged(self,current,previous):
      if (current != None):        #当前模型索引有效
         self.LabCellPos.setText("当前单元格:%d行,%d列"
                               %(current.row(),current.column())) #显示模型索引的行和列号
         item=self.itemModel.itemFromIndex(current)   #从模型索引获得Item
         self.LabCellText.setText("单元格内容:"+item.text())     #显示item的文字内容

         font=item.font() #获取item的字体
         self.ui.actFontBold.setChecked(font.bold())  #更新actFontBold的check状态
Example #12
0
class QtWidgetRegistry(QObject, WidgetRegistry):
    """
    A QObject wrapper for `WidgetRegistry`

    A QStandardItemModel instance containing the widgets in
    a tree (of depth 2). The items in a model can be quaries using standard
    roles (DisplayRole, BackgroundRole, DecorationRole ToolTipRole).
    They also have QtWidgetRegistry.CATEGORY_DESC_ROLE,
    QtWidgetRegistry.WIDGET_DESC_ROLE, which store Category/WidgetDescription
    respectfully. Furthermore QtWidgetRegistry.WIDGET_ACTION_ROLE stores an
    default QAction which can be used for widget creation action.

    """

    CATEGORY_DESC_ROLE = Qt.UserRole + 1
    """Category Description Role"""

    WIDGET_DESC_ROLE = Qt.UserRole + 2
    """Widget Description Role"""

    WIDGET_ACTION_ROLE = Qt.UserRole + 3
    """Widget Action Role"""

    BACKGROUND_ROLE = Qt.UserRole + 4
    """Background color for widget/category in the canvas
    (different from Qt.BackgroundRole)
    """

    category_added = Signal(str, CategoryDescription)
    """signal: category_added(name: str, desc: CategoryDescription)
    """

    widget_added = Signal(str, str, WidgetDescription)
    """signal widget_added(category_name: str, widget_name: str,
                           desc: WidgetDescription)
    """

    reset = Signal()
    """signal: reset()
    """
    def __init__(self, other_or_parent=None, parent=None):
        if isinstance(other_or_parent, QObject) and parent is None:
            parent, other_or_parent = other_or_parent, None
        QObject.__init__(self, parent)
        WidgetRegistry.__init__(self, other_or_parent)

        # Should  the QStandardItemModel be subclassed?
        self.__item_model = QStandardItemModel(self)

        for i, desc in enumerate(self.categories()):
            cat_item = self._cat_desc_to_std_item(desc)
            self.__item_model.insertRow(i, cat_item)

            for j, wdesc in enumerate(self.widgets(desc.name)):
                widget_item = self._widget_desc_to_std_item(wdesc, desc)
                cat_item.insertRow(j, widget_item)

    def model(self):
        """
        Return the widget descriptions in a Qt Item Model instance
        (QStandardItemModel).

        .. note:: The model should not be modified outside of the registry.

        """
        return self.__item_model

    def item_for_widget(self, widget):
        """Return the QStandardItem for the widget.
        """
        if isinstance(widget, six.string_types):
            widget = self.widget(widget)
        cat = self.category(widget.category)
        cat_ind = self.categories().index(cat)
        cat_item = self.model().item(cat_ind)
        widget_ind = self.widgets(cat).index(widget)
        return cat_item.child(widget_ind)

    def action_for_widget(self, widget):
        """
        Return the QAction instance for the widget (can be a string or
        a WidgetDescription instance).

        """
        item = self.item_for_widget(widget)
        return qtcompat.qunwrap(item.data(self.WIDGET_ACTION_ROLE))

    def create_action_for_item(self, item):
        """
        Create a QAction instance for the widget description item.
        """
        name = item.text()
        tooltip = item.toolTip()
        whatsThis = item.whatsThis()
        icon = item.icon()
        if icon:
            action = QAction(icon,
                             name,
                             self,
                             toolTip=tooltip,
                             whatsThis=whatsThis,
                             statusTip=name)
        else:
            action = QAction(name,
                             self,
                             toolTip=tooltip,
                             whatsThis=whatsThis,
                             statusTip=name)

        widget_desc = item.data(self.WIDGET_DESC_ROLE)
        action.setData(widget_desc)
        action.setProperty("item", qtcompat.qwrap(item))
        return action

    def _insert_category(self, desc):
        """
        Override to update the item model and emit the signals.
        """
        priority = desc.priority
        priorities = [c.priority for c, _ in self.registry]
        insertion_i = bisect.bisect_right(priorities, priority)

        WidgetRegistry._insert_category(self, desc)

        cat_item = self._cat_desc_to_std_item(desc)
        self.__item_model.insertRow(insertion_i, cat_item)

        self.category_added.emit(desc.name, desc)

    def _insert_widget(self, category, desc):
        """
        Override to update the item model and emit the signals.
        """
        assert (isinstance(category, CategoryDescription))
        categories = self.categories()
        cat_i = categories.index(category)
        _, widgets = self._categories_dict[category.name]
        priorities = [w.priority for w in widgets]
        insertion_i = bisect.bisect_right(priorities, desc.priority)

        WidgetRegistry._insert_widget(self, category, desc)

        cat_item = self.__item_model.item(cat_i)
        widget_item = self._widget_desc_to_std_item(desc, category)

        cat_item.insertRow(insertion_i, widget_item)

        self.widget_added.emit(category.name, desc.name, desc)

    def _cat_desc_to_std_item(self, desc):
        """
        Create a QStandardItem for the category description.
        """
        item = QStandardItem()
        item.setText(desc.name)

        if desc.icon:
            icon = desc.icon
        else:
            icon = "icons/default-category.svg"

        icon = icon_loader.from_description(desc).get(icon)
        item.setIcon(icon)

        if desc.background:
            background = desc.background
        else:
            background = DEFAULT_COLOR

        background = NAMED_COLORS.get(background, background)

        brush = QBrush(QColor(background))
        item.setData(brush, self.BACKGROUND_ROLE)

        tooltip = desc.description if desc.description else desc.name

        item.setToolTip(tooltip)
        item.setFlags(Qt.ItemIsEnabled)
        item.setData(qtcompat.qwrap(desc), self.CATEGORY_DESC_ROLE)
        return item

    def _widget_desc_to_std_item(self, desc, category):
        """
        Create a QStandardItem for the widget description.
        """
        item = QStandardItem(desc.name)
        item.setText(desc.name)

        if desc.icon:
            icon = desc.icon
        else:
            icon = "icons/default-widget.svg"

        icon = icon_loader.from_description(desc).get(icon)
        item.setIcon(icon)

        # This should be inherited from the category.
        background = None
        if desc.background:
            background = desc.background
        elif category.background:
            background = category.background
        else:
            background = DEFAULT_COLOR

        if background is not None:
            background = NAMED_COLORS.get(background, background)
            brush = QBrush(QColor(background))
            item.setData(brush, self.BACKGROUND_ROLE)

        tooltip = tooltip_helper(desc)
        style = "ul { margin-top: 1px; margin-bottom: 1px; }"
        tooltip = TOOLTIP_TEMPLATE.format(style=style, tooltip=tooltip)
        item.setToolTip(tooltip)
        item.setWhatsThis(whats_this_helper(desc))
        item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
        item.setData(qtcompat.qwrap(desc), self.WIDGET_DESC_ROLE)

        # Create the action for the widget_item
        action = self.create_action_for_item(item)
        item.setData(qtcompat.qwrap(action), self.WIDGET_ACTION_ROLE)
        return item
class WebImageBatchDownloader(QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        self._init_task_list()

    def _init_task_list(self):
        self.model_task_list = QStandardItemModel(1, 3,
                                                  self.ui.tableView_Tasks)
        self.model_task_list.setHorizontalHeaderLabels(["狀態", "網址", "本機儲存目錄"])
        self.model_task_list.removeRow(0)

        self.ui.tableView_Tasks.setModel(self.model_task_list)
        self.ui.tableView_Tasks.horizontalHeader().setSectionResizeMode(
            0, QHeaderView.Fixed)
        self.ui.tableView_Tasks.horizontalHeader().setDefaultSectionSize(60)
        self.ui.tableView_Tasks.horizontalHeader().resizeSection(0, 60)
        self.ui.tableView_Tasks.horizontalHeader().resizeSection(1, 600)
        self.ui.tableView_Tasks.horizontalHeader().resizeSection(2, 250)
        self.ui.tableView_Tasks.verticalHeader().setDefaultSectionSize(20)

    def _model_setItem(self, row, col, data):
        self.model_task_list.setItem(row, col, QStandardItem(data))

    def add_batch_url(self):
        self.ui.comboBox_batch_urls.addItem(
            self.ui.plainTextEdit_BatchUrl.text().rstrip())
        self.ui.comboBox_batch_urls.setCurrentIndex(
            self.ui.comboBox_batch_urls.count() - 1)

        urls = self._analysis_batch_urls()
        self._update_tasks(urls)
        self._update_output_paths()

    def _analysis_batch_urls(self):
        url_interprer = pyddavid.web_image.UrlToComponentsInterpreter()
        batch_urls = [
            self.ui.comboBox_batch_urls.itemText(i)
            for i in range(self.ui.comboBox_batch_urls.count())
        ]
        for batch_url in batch_urls:
            url_interprer.add_urls_from_url_batch(batch_url)
        urls = url_interprer.get_urls()

        return urls

    def _update_tasks(self, urls):
        self.model_task_list.removeRows(0, self.model_task_list.rowCount())

        for url in urls:
            current_row = self.model_task_list.rowCount()
            self.model_task_list.insertRow(current_row)
            self._model_setItem(current_row, 0, "未知")
            self._model_setItem(current_row, 1, url)

    def _adjust_root(self):
        root = self.ui.plainTextEdit_SaveDir.text().replace("\\", "/")
        self.ui.plainTextEdit_SaveDir.setText(root)

    def _update_output_paths(self):
        n_tasks = self.model_task_list.rowCount()

        root = self._get_root()
        level = self._get_level()

        for r in range(n_tasks):
            output_path = pyddavid.web_image.path_from_url_and_root(
                self.model_task_list.item(r, 1).text(), root, level)
            self._model_setItem(r, 2, output_path)

        self.ui.tableView_Tasks.setColumnWidth(2, 280)

    def remove_current_batch_url(self):
        if self.ui.comboBox_batch_urls.count() >= 0:
            self.ui.comboBox_batch_urls.removeItem(
                self.ui.comboBox_batch_urls.currentIndex())

        urls = self._analysis_batch_urls()
        self._update_tasks(urls)
        self._update_output_paths()

    def choose_output_dir(self):
        self.ui.plainTextEdit_SaveDir.setText(
            QFileDialog.getExistingDirectory(
                self, "選擇存檔目錄", self.ui.plainTextEdit_SaveDir.text(),
                QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks))

        self._update_output_paths()

    def _get_root(self):
        root = self.ui.plainTextEdit_SaveDir.text()
        if root == "":
            root = "."

        return root

    def _get_level(self):
        level = int(self.ui.lineEdit_Level.text())

        return level

    def save_img(self, index):
        url = self.model_task_list.item(index.row(), 1).text()
        output_path = self.model_task_list.item(index.row(), 2).text()

        output_dir, output_filename = pyddavid.web_image.split_path_to_dir_and_filename(
            output_path)
        if pyddavid.web_image.save_img_from_url(url, output_dir,
                                                output_filename):
            self._update_process_message("下載完成。")
            imshow(output_path, output_filename)
        else:
            self._update_process_message("下載失敗。")

    def test_urls(self):
        urls = [
            self.model_task_list.item(r, 1).text()
            for r in range(self.model_task_list.rowCount())
        ]

        self.thread_test_urls = TestUrlsThread(urls)
        self.thread_test_urls.start()
        self.thread_test_urls.process_message_updated.connect(
            self._update_process_message)
        self.thread_test_urls.process_task_updated.connect(self._model_setItem)

    def _update_process_message(self, message):
        self.ui.label_ProcessMessage.setText(message)

    def download_imgs(self):
        indexs = []
        urls = []
        output_paths = []
        for r in range(self.model_task_list.rowCount()):
            if (self.model_task_list.item(r, 0).text() == "未知"
                    or self.model_task_list.item(r, 0).text() == "可用"):
                indexs.append(r)
                urls.append(self.model_task_list.item(r, 1).text())
                output_paths.append(self.model_task_list.item(r, 2).text())

        root = self._get_root()

        self.save_image_thread = SaveImageThread(
            indexs,
            urls,
            output_paths,
            root,
        )
        self.save_image_thread.start()
        self.save_image_thread.process_message_updated.connect(
            self._update_process_message)
        self.save_image_thread.process_task_updated.connect(
            self._model_setItem)

    def reset_all(self):
        self.ui.comboBox_batch_urls.clear()
        self.model_task_list.removeRows(0, self.model_task_list.rowCount())
Example #14
0
class TIM(QWidget, Ui_Form):

	grouplist = []
	userslist = []
	tmpuseritem = []

	def __init__(self):
		super().__init__()
		self.setupUi(self)
		self.Ui_init()
		self.menuflag = 1
		self.setWindowFlag(Qt.FramelessWindowHint)
		#self.client = client
		


	def Ui_init(self):
		self.treeWidget.setIndentation(0)
		self.treeWidget.setColumnCount(1)
		self.treeWidget.setColumnWidth(0, 50)
		self.treeWidget.setHeaderLabels(['好友'])
		self.treeWidget.setIconSize(QSize(70, 70))
		self.treeWidget.setSelectionMode(QAbstractItemView.ExtendedSelection)
		self.treeWidget.currentItemChanged.connect(self.restatistic)
		self.treeWidget.itemClicked.connect(self.isclick)
		self.bt_adduser.clicked.connect(self.on_bt_adduser_clicked)
		self.bt_search.clicked.connect(self.on_bt_search_clicked)
		self.m_model = QStandardItemModel(0, 1, self)
		m_completer = QCompleter(self.m_model, self)
		self.lineEdit.setCompleter(m_completer)
		m_completer.activated[str].connect(self.onUsernameChoosed)
		root = self.creategroup('我的好友')
		root.setExpanded(True)
		self.lineEdit.textChanged[str].connect(self.on_lineEdit_textChanged)



	def creategroup(self, groupname):
		hidernum = 0
		group = QTreeWidgetItem(self.treeWidget)
		groupdic = {
			'group' : group,
			'groupname' : groupname,
			'childcount' : 0,
			'childhide' : 0
		}
		icon = self.searchIcon(groupname)
		group.setIcon(0, icon)


		randomnum = random.sample(range(26), 10)
		for i in randomnum:
			child = QTreeWidgetItem()
			randname, randicon, font, isvip, ishider = self.createusers(i)
			userdic = {
			'user' : child,
			'username' : randname,
			'ishide' : 0
			}
			self.userslist.append(userdic)
			child.setText(0, randname)
			child.setFont(0, font)
			child.setIcon(0, randicon)
			child.setTextAlignment(0, Qt.AlignHCenter | Qt.AlignVCenter)
			if isvip == 1:
				child.setForeground(0, QBrush(Qt.red))
				child.setToolTip(0, '会员红名尊享')
			if ishider == 1:
				hidernum += 1
				userdic['ishide'] = 1
			group.addChild(child)
		childnum = group.childCount()
		lastchildnum = childnum - hidernum
		groupdic['childcount'] = childnum
		groupdic['childishide'] = hidernum
		groupname += ' ' + str(lastchildnum) + '/' + str(childnum)
		group.setText(0, groupname)
		self.grouplist.append(groupdic)
		return group


	def createusers(self, num):
		randname = "黑子"
		randicon = QIcon(str(num)+'.jpg')
		font = QFont()
		font.setPointSize(16)
		isvip = random.randint(0, 5)
		ishider = random.randint(0, 5)
		if ishider == 1:
			randicon = QIcon(str(num)+'h.jpg')
		return randname, randicon, font, isvip, ishider

	def searchIcon(self, gpname2):
		if gpname2.find('好友') >= 0:
			return QIcon('buddy.ico')
		elif gpname2.find('同事'):
			return QIcon('partner.ico')
		elif gpname2.find('黑名单'):
			return QIcon('blacklist.ico')
		else:
			return QIcon('defalut.ico')








	def mousePressEvent(self, event):
		if event.button()== Qt.LeftButton:
			self.m_drag=True
			self.m_DragPosition=event.globalPos()-self.pos()
			event.accept()

	def mouseMoveEvent(self, QMouseEvent):
		if QMouseEvent.buttons() and Qt.LeftButton:
			self.move(QMouseEvent.globalPos()-self.m_DragPosition)
			QMouseEvent.accept()

	def mouseReleaseEvent(self, QMouseEvent):
		self.m_drag=False


	def onUsernameChoosed(self, name):
		self.lineEdit.setText(name)


	def on_lineEdit_textChanged(self, text):
		namelist = []
		for itm in self.userslist:
			username = itm['username']
			if username.find(text) >= 0:
				namelist.append(itm['username'])
		self.m_model.removeRows(0, self.m_model.rowCount())
	    
		for i in range(0, len(namelist)):
			self.m_model.insertRow(0)
			self.m_model.setData(self.m_model.index(0, 0), namelist[i])


	def on_bt_search_clicked(self):
		username = self.lineEdit.text()
		if len(username) > 0:
			useritemindex = self.searchuser(username)
			if useritemindex is not None:
				useritem = self.userslist[useritemindex]['user']
				self.treeWidget.setCurrentItem(useritem)
			else:
				QMessageBox.information(self, '消息', '不存在此好友!')



	def on_bt_adduser_clicked(self):
		adduser = Dialog_additem()
		for g in self.grouplist:
			adduser.comboBox.addItem(g['groupname'])
		r = adduser.exec_()
		if r > 0:
			newitem = QTreeWidgetItem()
			newname = adduser.lineEdit.text()
			newicon = adduser.geticonpath()
			font = QFont()
			font.setPointSize(16)
			newitem.setFont(0, font)
			newitem.setText(0, newname)
			newitem.setTextAlignment(0, Qt.AlignHCenter | Qt.AlignVCenter)
			newitem.setIcon(0, QIcon(newicon))
			comboxinfo = adduser.comboBox.currentText()
			cindex = self.searchgroup(comboxinfo)
			group = self.grouplist[cindex]['group']
			self.grouplist[cindex]['childcount'] += 1
			userdic = {
			'user' : newitem,
			'username' : newname,
			'ishide' : 0
			}
			self.userslist.append(userdic)
			group.addChild(newitem)
			self.treeWidget.setCurrentItem(newitem)









	def contextMenuEvent(self, event):
		hititem = self.treeWidget.currentItem()
		if hititem:
			root = hititem.parent()
			if root is None: #说明是一个分组
				pgroupmenu = QMenu(self)
				pAddgroupAct = QAction('添加分组', self.treeWidget)
				pRenameAct = QAction('重命名', self.treeWidget)
				pDeleteAct = QAction('删除分组', self.treeWidget)
				pgroupmenu.addAction(pAddgroupAct)
				pgroupmenu.addAction(pRenameAct)
				pgroupmenu.addAction(pDeleteAct)
				pAddgroupAct.triggered.connect(self.addgroup)
				pRenameAct.triggered.connect(self.renamegroup)
				if self.treeWidget.itemAbove(hititem) is None:
					pDeleteAct.setEnabled(False)
				else:
					pDeleteAct.setEnabled(True)
					pDeleteAct.triggered.connect(self.deletegroup)
				pgroupmenu.popup(self.mapToGlobal(event.pos()))

			elif root.childCount() > 0:
				pItemmenu = QMenu(self)
				pDeleteItemAct = QAction('删除联系人', pItemmenu)
				pItemmenu.addAction(pDeleteItemAct)
				pDeleteItemAct.triggered.connect(self.delete)
				if len(self.grouplist) > 1:
					pSubMenu = QMenu('转移联系人至', pItemmenu)
					pItemmenu.addMenu(pSubMenu)
					for item_dic in self.grouplist:
						if item_dic['group'] is not root:
							pMoveAct = QAction(item_dic['groupname'], pItemmenu)
							pSubMenu.addAction(pMoveAct)
							pMoveAct.triggered.connect(self.moveItem)
				if len(self.getListitems(self.menuflag)) == 1:
					pRenameItemAct = QAction('设定备注', pItemmenu)
					pItemmenu.addAction(pRenameItemAct)
					pRenameItemAct.triggered.connect(self.renameItem)
				if self.menuflag > 0 and root.childCount() > 1:
					pBatchAct= QAction('分组内批量操作', pItemmenu)
					pItemmenu.addAction(pBatchAct)
					pBatchAct.triggered.connect(self.Batchoperation)
				elif self.menuflag < 0:
					pCancelBatchAct = QAction('取消批量操作', pItemmenu)
					pItemmenu.addAction(pCancelBatchAct)
					pCancelBatchAct.triggered.connect(self.CancelBatchoperation)

				pItemmenu.popup(self.mapToGlobal(event.pos()))

			


	def moveItem(self):
		movelist = self.getListitems(self.menuflag)
		togroupname = self.sender().text()
		mindex = self.searchgroup(togroupname)
		togroup = self.grouplist[mindex]['group']
		self.deleteItems(movelist, flag = 0)
		self.add(togroup, movelist)
		self.tmpuseritem.clear()

	def delete(self):
		delitems = self.getListitems(self.menuflag)
		self.deleteItems(delitems)
		self.tmpuseritem.clear()

	def deleteItems(self, items, flag=1):
		for delitem in items:
			delitem.setData(0, Qt.CheckStateRole, QVariant())
			pindex = delitem.parent().indexOfChild(delitem)
			dindex = self.searchuser(delitem)
			ishide = self.userslist[dindex]['ishide']
			if flag == 1:
				del self.userslist[dindex]
			fathergroup = delitem.parent()
			findex = self.searchgroup(fathergroup)
			if ishide == 1:
				self.grouplist[findex]['childishide'] -= 1
				self.grouplist[findex]['childcount'] -= 1
			else:
				self.grouplist[findex]['childcount'] -= 1

			delitem.parent().takeChild(pindex)


	def add(self, group, items):
		gindex = self.searchgroup(group)
		for item in items:
			aindex = self.searchuser(item)
			ishide = self.userslist[aindex]['ishide']
			if ishide == 1:
				self.grouplist[gindex]['childishide'] += 1
				self.grouplist[gindex]['childcount'] += 1
			else:
				self.grouplist[gindex]['childcount'] += 1
			group.addChild(item)
			self.treeWidget.setCurrentItem(item)


	def Batchoperation(self):
		self.menuflag *= -1
		group = self.getListitems()[0].parent()
		childnum = group.childCount()
		for c in range(childnum):
			child = group.child(c)
			child.setCheckState(0, Qt.Unchecked)

	def CancelBatchoperation(self):
		self.menuflag *= -1
		group = self.getListitems()[0].parent()
		childnum = group.childCount()
		for c in range(childnum):
			child = group.child(c)
			child.setData(0, Qt.CheckStateRole, QVariant())

	def isclick(self, item):
		if item.checkState(0) == Qt.Checked:
			if self.tmpuseritem.count(item) == 0:
				self.tmpuseritem.append(item)
		else:
			if len(self.tmpuseritem) > 0:
				if self.tmpuseritem.count(item) != 0:
					i = self.tmpuseritem.index(item)
					del self.tmpuseritem[i]

	def renameItem(self):
		hituser = self.treeWidget.currentItem()
		uindex = self.searchuser(hituser)
		unewname, ok = QInputDialog.getText(self, '提示信息', '请输入备注名称')
		if ok:
			if len(unewname) == 0:
				QMessageBox.information(self, '提示', '备注名称不能为空')
			else:
				hituser.setText(0, unewname)
				self.userslist[uindex]['username'] = unewname

	def searchuser(self, hituser):
		if isinstance(hituser, str):
			for i, u in enumerate(self.userslist):
				if u['username'] == hituser:
					return i 
		else:
			for i, u in enumerate(self.userslist):
				if hituser == u['user']:
					return i
		return None



	def getListitems(self, flag=1):
		if flag > 0:
			return self.treeWidget.selectedItems()
		else:
			return self.tmpuseritem


	def addgroup(self):
		gname, ok = QInputDialog.getText(self, '提示信息', '请输入分组名称')
		if ok:
			if len(gname) == 0:
				QMessageBox.information(self, '提示', '分组名称不能为空')
			else:
				self.creategroup(gname)

	def renamegroup(self):
		hitgroup = self.treeWidget.currentItem()
		gnewname, ok = QInputDialog.getText(self, '提示', '请输入新的分组名称')
		if ok:
			if len(gnewname) == 0:
				QMessageBox.information(self, '提示', '分组名称不能为空')
			else:
				hitgroup.setText(0, gnewname)
				newicon = self.searchIcon(hitgroup.text(0))
				hitgroup.setIcon(0, newicon)
				gindex = self.searchgroup(hitgroup)
				self.grouplist[gindex]['groupname'] = gnewname
				self.treeWidget.setCurrentItem(hitgroup.child(0))



	def deletegroup(self):
		hitgroup = self.treeWidget.currentItem()
		gindex = self.searchgroup(hitgroup)
		reply = QMessageBox.question(self, '警告', '确定要删除这个分组吗?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
		if reply == QMessageBox.Yes:
			self.treeWidget.takeTopLevelItem(gindex)
			del self.grouplist[gindex]

	def searchgroup(self, hitgroup):
		if isinstance(hitgroup, str):
			for i, g in enumerate(self.grouplist):
				if g['groupname'] == hitgroup:
					return i
		else:
			for i, g in enumerate(self.grouplist):
				if g['group'] == hitgroup:
					return i



	def restatistic(self, item, preitem):
		if item:
			fathergroup = item.parent()
			if fathergroup:
				self.restatistic_op(fathergroup)
			else:
				self.restatistic_op(item)
		elif preitem.parent().childCount() == 1:
			lastgroupname = preitem.parent().text(0).split()[0] + ' 0/0'
			preitem.parent().setText(0, lastgroupname)
			self.menuflag = 1

	def restatistic_op(self, itemorgroup):
		gindex = self.searchgroup(itemorgroup)
		totalcount = self.grouplist[gindex]['childcount']
		hidecount = self.grouplist[gindex]['childishide']
		fathergroupname = self.grouplist[gindex]['groupname']
		fathergroupname += ' ' + str(totalcount - hidecount) + '/' + str(totalcount)
		itemorgroup.setText(0, fathergroupname)


	def closeEvent(self, event):
		reply = QMessageBox.question(self, '提示', '确定要退出程序吗?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
		if reply == QMessageBox.No:
			event.ignore()
		else:
			self.client.dealQuit()
			event.accept()
Example #15
0
class CustomTable(QTableView):
    """
    CustomTable which inherits the QTableView Class.
    This implementation fixes an apparent issue with the QTableView where if you drag and drop internally
    The dragged item when dropped would overwrite the item it was dropped on and leave a hole in the table
    where the dragged item originates from.
    """
    def __init__(self):
        super(QTableView, self).__init__()

        self.model = QStandardItemModel(1, 2)
        self.setModel(self.model)

        self.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.verticalHeader().hide()

        self.model.setColumnCount(2)
        self.model.setHorizontalHeaderLabels(
            ["Original Files", "New Name - Preview"])
        self.setAlternatingRowColors(True)
        self.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.setMinimumHeight(300)
        self.setDragEnabled(True)
        self.setAcceptDrops(True)
        self.setDropIndicatorShown(True)
        self.setDragDropOverwriteMode(False)
        self.setDefaultDropAction(QtCore.Qt.MoveAction)
        self.setDragDropMode(QAbstractItemView.InternalMove)
        header = self.horizontalHeader()
        header.setSectionResizeMode(QHeaderView.Stretch)

    def dropEvent(self, event):
        """
        overwrite drop event to handle drop events how we need to drop the item.
        """
        # The QTableWidget from which selected rows will be moved
        sender = event.source()
        # GET ROW BEING DROPPED
        drop_row = self.model.itemFromIndex(self.indexAt(event.pos())).row()
        # GET SELECTED ITEMS
        selected_items = sender.get_selected_items()
        # MOVE ITEM
        for data in selected_items:
            if data.text():
                checked = data.checkState()
                new_item = QStandardItem(data.text())
                new_item.setCheckState(checked)
                new_item.setCheckable(True)
                self.model.insertRow(drop_row, new_item)
        event.accept()

    def get_selected_items(self):
        """
        method used to return a list of selected items
        Returns:
            list
        """
        selected_rows = []

        for index in self.selectedIndexes():
            item = self.model.itemFromIndex(index)
            if item not in selected_rows:
                selected_rows.append(item)

        selected_rows.sort()
        return selected_rows
Example #16
0
class BatchWindow(QMainWindow, BATCH_WIDGET):
    """ The batch sir tracker application window """

    NAME, \
        RUN, \
        PARTICLE_COUNT, \
        SCORE_TYPE, \
        FILTER_MODE, \
        UPDATE_INTERVAL, \
        UPDATE_METHOD, \
        HISTORICAL_LENGTH, \
        STATUS = range(9)

    def __init__(self, parent=None):
        super(BatchWindow, self).__init__(parent)
        BATCH_WIDGET.__init__(self)
        self.setupUi(self)

        self.create_run_model(self)
        self.tv_runs.clicked.connect(self.on_tv_runs_clicked)
        self.btn_load.clicked.connect(self.do_load)
        self.btn_start.clicked.connect(self.do_start)
        self.btn_cancel.clicked.connect(self.do_cancel)
        self.options = {}
        self.btn_start.setEnabled(False)
        self.btn_cancel.setEnabled(False)
        self.runs = None
        self.threadpool = QThreadPool()
        self.viewer_index = None
        self.viewer = SIRWindow(self)

    @pyqtSlot()
    def do_load(self):
        """ load batch parameters from a file """
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        filename, _ = QFileDialog.getOpenFileName(
            self,
            "QfileDialog.getOpenFileName()",
            "",
            "Json Files (*.json)",
            options=options)
        if not filename:
            self.btn_start.setEnabled(False)
            return

        with open(filename, 'r') as bo_file:
            self.options = json.load(bo_file)

        batch_details = (f"Source root: {self.options['root_path']}\n"
                         f"Save path: {self.options['save_path']}")
        self.lbl_batch_details.setText(batch_details)

        self.runs = [
            {
                'job_options': {
                    'name': sequence['name'],
                    'start_frame': sequence['start_frame'],
                    'end_frame': sequence['end_frame'],
                    'particle_count': particle_count,
                    'score_type': score_type,
                    'filter_mode': filter_mode,
                    'update_interval': update_interval,
                    'update_method': update_method,
                    'historical_length': historical_length,
                    'run': run,
                    'root_path': self.options['root_path'],
                    'save_path': self.options['save_path'],
                },
                'status': 'Not started'
            } for sequence in self.options['sequences']
            for particle_count in self.options['particle_counts']
            for score_type in self.options['score_types']
            for filter_mode in self.options['filter_modes']
            for update_interval in self.options['update_intervals']
            for update_method in self.options['update_methods']
            for historical_length in self.options['historical_lengths']
            for run in range(self.options['number_runs'])
        ]

        # attach run ids, seed, and tracker objects
        for index, r in enumerate(self.runs):
            r['job_options']['job_id'] = index
            r['job_options']['seed'] = r['job_options']['run']
            r['tracker'] = SIRTracker(r['job_options'])
            r['tracker'].signals.status_changed.connect(self.on_status_change)

        # add to display
        self.clear_runs()
        for ro_idx in range(len(self.runs)):
            run_options = self.runs[ro_idx]['job_options']
            self.add_run(run_options, self.runs[ro_idx]['status'])
        self.btn_start.setEnabled(True)

    @pyqtSlot()
    def do_start(self):
        """ start button callback """
        self.btn_load.setEnabled(False)
        self.btn_start.setEnabled(False)
        self.btn_cancel.setEnabled(True)

        for r in self.runs:
            self.threadpool.start(r['tracker'])

    @pyqtSlot(int, str)
    def on_status_change(self, job_id, status):
        """ a job status has changed """
        self.update_status(job_id, status)

    @pyqtSlot()
    def do_cancel(self):
        """ cancel button callback """
        pass

    def create_run_model(self, parent):
        """ set model for the list(tree) of batch entries """
        self.model = QStandardItemModel(0, 9, parent)
        self.model.setHeaderData(self.NAME, Qt.Horizontal, "Name")
        self.model.setHeaderData(self.RUN, Qt.Horizontal, "Run Index")
        self.model.setHeaderData(self.PARTICLE_COUNT, Qt.Horizontal,
                                 "particles")
        self.model.setHeaderData(self.SCORE_TYPE, Qt.Horizontal, "Score Type")
        self.model.setHeaderData(self.FILTER_MODE, Qt.Horizontal,
                                 "Filter Mode")
        self.model.setHeaderData(self.UPDATE_INTERVAL, Qt.Horizontal,
                                 "Update Interval")
        self.model.setHeaderData(self.UPDATE_METHOD, Qt.Horizontal,
                                 "Update Method")
        self.model.setHeaderData(self.HISTORICAL_LENGTH, Qt.Horizontal,
                                 "History Length")
        self.model.setHeaderData(self.STATUS, Qt.Horizontal, "Status")
        self.tv_runs.setModel(self.model)

    def add_run(self, run_options, status):
        """ add a run to the list """
        row_idx = self.model.rowCount()
        self.model.insertRow(row_idx)
        self.model.setData(self.model.index(row_idx, self.NAME),
                           run_options['name'])
        self.model.setData(self.model.index(row_idx, self.RUN),
                           run_options['run'])
        self.model.setData(self.model.index(row_idx, self.PARTICLE_COUNT),
                           run_options['particle_count'])
        self.model.setData(self.model.index(row_idx, self.SCORE_TYPE),
                           run_options['score_type'])
        self.model.setData(self.model.index(row_idx, self.FILTER_MODE),
                           run_options['filter_mode'])
        self.model.setData(self.model.index(row_idx, self.UPDATE_INTERVAL),
                           run_options['update_interval'])
        self.model.setData(self.model.index(row_idx, self.UPDATE_METHOD),
                           run_options['update_method'])
        self.model.setData(self.model.index(row_idx, self.HISTORICAL_LENGTH),
                           run_options['historical_length'])
        self.model.setData(self.model.index(row_idx, self.STATUS), status)

    def update_status(self, index, status):
        """ update status of a run given its index """
        self.runs[index]['status'] = status
        self.model.setData(self.model.index(index, self.STATUS), status)

    def clear_runs(self):
        """ clear run list """
        self.model.removeRows(0, self.model.rowCount())

    @pyqtSlot(QModelIndex)
    def on_tv_runs_clicked(self, index):
        """ list selection changed """
        row_idx = index.row()
        self.viewer.show()
        self.viewer_index = row_idx
        self.viewer.attach_tracker(self.runs[row_idx]['tracker'])
Example #17
0
class YoutubeDLGui(QMainWindow):
    def __init__(self):
        super(YoutubeDLGui, self).__init__()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        Center(self)
        self.download_model = QStandardItemModel(0, 5, self)
        self.download_model.setHeaderData(0, QtCore.Qt.Horizontal, 'Name')
        self.download_model.setHeaderData(1, QtCore.Qt.Horizontal, 'Progress')
        self.download_model.setHeaderData(2, QtCore.Qt.Horizontal, 'Size')
        self.download_model.setHeaderData(3, QtCore.Qt.Horizontal, 'ETA')
        self.download_model.setHeaderData(4, QtCore.Qt.Horizontal, 'Speed')
        self.ui.downloadView.setModel(self.download_model)
        self.pending_model = QStandardItemModel(0, 2, self)
        self.pending_model.setHeaderData(0, QtCore.Qt.Horizontal, 'Name')
        self.pending_model.setHeaderData(1, QtCore.Qt.Horizontal, 'Quality')
        self.ui.pendingView.setModel(self.pending_model)
        self.ui.pendingView.setItemDelegate(CustomToolTipDelegate(self.ui.pendingView))
        self.init_status_bar()
        self.parsing_worker = WorkerBuilder.build(bool)
        self.pending_list = []

    def init_status_bar(self):
        self.pending_progressbar = QProgressBar()
        self.pending_progressbar.setFixedHeight(20)
        self.pending_progressbar.setFixedWidth(150)
        self.pending_progressbar.setMaximum(0)
        self.pending_progressbar.setMinimum(0)
        self.pending_label = QLabel("")
        self.pending_label.setAlignment(QtCore.Qt.AlignLeading)
        self.pending_label.setFixedWidth(220)
        font = self.pending_label.font()
        font.setPointSize(10)
        self.pending_label.setFont(font)
        self.pending_label.setStyleSheet("padding-left: 5px")
        self.pending_progressbar.setVisible(False)

        self.statusBar().addPermanentWidget(self.pending_progressbar)
        self.statusBar().addWidget(self.pending_label)

    @pyqtSlot()
    def on_addBtn_clicked(self):
        url = CustomInputDialog.get_text("Url", "Enter Url")

        if not url[1]:
            return

        if not validators.url(url[0]):
            QMessageBox.information(self, "Invalid Url", "Please enter a valid url")
            self.on_addBtn_clicked()

        ydl_logger = YDLLogger()
        ydl_logger.debug_message.connect(self.on_debug_message_emitted)
        ydl_opt = {
            'logger': ydl_logger
        }
        self.ui.addBtn.setEnabled(False)
        self.parser = InfoParser(url[0], ydl_opt)
        self.parsing_worker.set_up(self.parser.generate_info, self.on_parsing_done)
        self.parsing_worker.start()
        self.pending_progressbar.setVisible(True)

    @pyqtSlot(int)
    def on_combobox_currentIndexChanged(self, index):
        list_index = self.ui.pendingView.currentIndex().row()
        self.pending_list[list_index].current_format = self.pending_list[list_index].format_info[index]

    @pyqtSlot(str)
    def on_debug_message_emitted(self, msg):
        self.pending_label.setText(msg)

    def add_to_pending(self, ydl_obj):
        if ydl_obj in self.pending_list:
            return

        index = len(self.pending_list)
        self.pending_list.append(ydl_obj)

        self.pending_model.insertRow(index)
        self.pending_model.setData(self.pending_model.index(index, 0), ydl_obj.title)
        model_index = self.pending_model.index(index, 0)
        self.ui.pendingView.setCurrentIndex(model_index)
        self.ui.pendingView.selectionModel().select(model_index, QItemSelectionModel.ClearAndSelect)

        combobox = QComboBox()
        combobox.currentIndexChanged[int].connect(self.on_combobox_currentIndexChanged)
        for ydl_format in ydl_obj.info:
            format_text = "%s, %s, %s" % (ydl_format['extension'], ydl_format['resolution'], ydl_format['filesize'])
            combobox.addItem(format_text)
        self.ui.pendingView.setIndexWidget(self.pending_model.index(index, 1), combobox)

        self.ui.tabWidget.setCurrentIndex(1)

    def on_parsing_done(self, success):
        self.pending_progressbar.setVisible(False)
        self.pending_label.setText("")
        self.ui.addBtn.setEnabled(True)
        if success:
            self.add_to_pending(self.parser.ydl_object)
        else:
            self.parsing_worker.quit()
            self.ui.addBtn.setEnabled(True)
            QMessageBox.information(self, "Invalid Url", "Unable to parse url")
Example #18
0
class QmyMainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        self.setCentralWidget(self.ui.qSplitter)
        self.__ColCount = 6
        self.itemModel = QStandardItemModel(5, self.__ColCount, self)
        self.selectionModel = QItemSelectionModel(self.itemModel)
        self.selectionModel.currentChanged.connect(self.do_curChanged)

        self.__lastColumnTitle = "测井取样"
        self.__lastColumnFlags = (Qt.ItemIsSelectable | Qt.ItemIsUserCheckable
                                  | Qt.ItemIsEnabled)

        self.ui.qTableView.setModel(self.itemModel)
        self.ui.qTableView.setSelectionModel(self.selectionModel)

        oneOrMore = QAbstractItemView.ExtendedSelection
        self.ui.qTableView.setSelectionMode(oneOrMore)

        itemOrRow = QAbstractItemView.SelectItems
        self.ui.qTableView.setSelectionBehavior(itemOrRow)

        self.ui.qTableView.verticalHeader().setDefaultSectionSize(22)
        self.ui.qTableView.setAlternatingRowColors(True)

        self.ui.qTableView.setEnabled(False)

        self.qLabel1 = QLabel("当前单元格:", self)
        self.qLabel1.setMinimumWidth(180)
        self.qLabel2 = QLabel("单元格内容:", self)
        self.qLabel2.setMinimumWidth(150)
        self.qLabel3 = QLabel("当前文件:", self)
        self.ui.qStatusBar.addWidget(self.qLabel1)
        self.ui.qStatusBar.addWidget(self.qLabel2)
        self.ui.qStatusBar.addPermanentWidget(self.qLabel3)

        self.spinCeshen = QmyFloatSpinDelegate(0, 10000, 0, self)
        self.spinLength = QmyFloatSpinDelegate(0, 6000, 2, self)
        self.spinDegree = QmyFloatSpinDelegate(0, 360, 1, self)

        self.ui.qTableView.setItemDelegateForColumn(0, self.spinCeshen)
        self.ui.qTableView.setItemDelegateForColumn(1, self.spinLength)
        self.ui.qTableView.setItemDelegateForColumn(3, self.spinLength)
        self.ui.qTableView.setItemDelegateForColumn(2, self.spinDegree)

        qualities = ["优", "良", "合格", "不合格"]
        self.comboDelegate = QmyComboBoxDelegate(self)
        self.comboDelegate.setItems(qualities, False)
        self.ui.qTableView.setItemDelegateForColumn(4, self.comboDelegate)

    def __iniModelFromStringList(self, allLines):
        rowCnt = len(allLines)
        self.itemModel.setRowCount(rowCnt - 1)
        headerText = allLines[0].strip()
        headerList = headerText.split("\t")
        self.itemModel.setHorizontalHeaderLabels(headerList)
        self.__lastColumnTitle = headerList[len(headerList) - 1]
        lastColNo = self.__ColCount - 1
        for i in range(rowCnt - 1):
            lineText = allLines[i + 1].strip()
            strList = lineText.split("\t")
            for j in range(self.__ColCount - 1):
                item = QStandardItem(strList[j])
                self.itemModel.setItem(i, j, item)

            item = QStandardItem(self.__lastColumnTitle)
            item.setFlags(self.__lastColumnFlags)
            item.setCheckable(True)
            if (strList[lastColNo] == "0"):
                item.setCheckState(Qt.Unchecked)
            else:
                item.setCheckState(Qt.Checked)
            self.itemModel.setItem(i, lastColNo, item)

    def __setCellAlignment(self, align=Qt.AlignHCenter):
        if (not self.selectionModel.hasSelection()):
            return
        selectedIndex = self.selectionModel.selectedIndexes()
        count = len(selectedIndex)
        for i in range(count):
            index = selectedIndex[i]
            item = self.itemModel.itemFromIndex(index)
            item.setTextAlignment(align)

    @pyqtSlot()
    def on_qAction1_triggered(self):  # 打开文件
        curPath = os.getcwd()
        filename, flt = QFileDialog.getOpenFileName(
            self, "打开一个文件", curPath, "井斜数据文件(*.txt);;所有文件(*.*)")
        if (filename == ""):
            return
        self.qLabel3.setText("当前文件:" + filename)
        self.ui.qPlainTextEdit.clear()
        aFile = open(filename, 'r')
        allLines = aFile.readlines()
        aFile.close()

        for strLine in allLines:
            self.ui.qPlainTextEdit.appendPlainText(strLine.strip())

        self.__iniModelFromStringList(allLines)
        self.ui.qTableView.setEnabled(True)
        self.ui.qAction2.setEnabled(True)
        self.ui.qAction3.setEnabled(True)
        self.ui.qAction4.setEnabled(True)
        self.ui.qAction5.setEnabled(True)
        self.ui.qAction6.setEnabled(True)

    @pyqtSlot()
    def on_qAction2_triggered(self):  # 另存文件
        curPath = os.getcwd()
        filename, flt = QFileDialog.getSaveFileName(
            self, "保存文件", curPath, "井斜数据文件(*.txt);;所有文件(*.*)")
        if (filename == ""):
            return
        self.on_qAction3_triggered()
        aFile = open(filename, "w")
        aFile.write(self.ui.qPlainTextEdit.toPlainText())
        aFile.close()

    @pyqtSlot()
    def on_qAction4_triggered(self):  # 添加行
        itemList = []
        for i in range(self.__ColCount - 1):
            item = QStandardItem("0")
            itemList.append(item)

        item = QStandardItem(self.__lastColumnTitle)
        item.setCheckable(True)
        item.setFlags(self.__lastColumnFlags)
        itemList.append(item)

        self.itemModel.appendRow(itemList)
        curIndex = self.itemModel.index(self.itemModel.rowCount() - 1, 0)
        self.selectionModel.clearSelection()
        self.selectionModel.setCurrentIndex(curIndex,
                                            QItemSelectionModel.Select)

    @pyqtSlot()
    def on_qAction5_triggered(self):  # 插入行
        itemlist = []
        for i in range(self.__ColCount - 1):
            item = QStandardItem("0")
            itemlist.append(item)

        item = QStandardItem(self.__lastColumnTitle)
        item.setFlags(self.__lastColumnFlags)
        item.setCheckable(True)
        item.setCheckState(Qt.Checked)
        itemlist.append(item)

        curIndex = self.selectionModel.currentIndex()
        self.itemModel.insertRow(curIndex.row(), itemlist)
        self.selectionModel.clearSelection()
        self.selectionModel.setCurrentIndex(curIndex,
                                            QItemSelectionModel.Select)

    @pyqtSlot()
    def on_qAction6_triggered(self):  # 删除行
        curIndex = self.selectionModel.currentIndex()
        self.itemModel.removeRow(curIndex.row())

    @pyqtSlot()
    def on_qAction7_triggered(self):  # 居左
        self.__setCellAlignment(Qt.AlignLeft | Qt.AlignVCenter)

    @pyqtSlot()
    def on_qAction8_triggered(self):  # 居中
        self.__setCellAlignment(Qt.AlignHCenter | Qt.AlignVCenter)

    @pyqtSlot()
    def on_qAction9_triggered(self):  # 居右
        self.__setCellAlignment(Qt.AlignRight | Qt.AlignVCenter)

    @pyqtSlot(bool)
    def on_qAction10_triggered(self, checked):  # 粗体
        if (not self.selectionModel.hasSelection()):
            return
        selectedIndex = self.selectionModel.selectedIndexes()
        count = len(selectedIndex)
        for i in range(count):
            index = selectedIndex[i]
            item = self.itemModel.itemFromIndex(index)
            font = item.font()
            font.setBold(checked)
            item.setFont(font)

    @pyqtSlot()
    def on_qAction3_triggered(self):  # 模型数据
        self.ui.qPlainTextEdit.clear()
        lineStr = ""
        for i in range(self.itemModel.columnCount() - 1):
            item = self.itemModel.horizontalHeaderItem(i)
            lineStr = lineStr + item.text() + "\t"
        item = self.itemModel.horizontalHeaderItem(self.__ColCount - 1)
        lineStr = lineStr + item.text()
        self.ui.qPlainTextEdit.appendPlainText(lineStr)

        for i in range(self.itemModel.rowCount()):
            lineStr = ""
            for j in range(self.itemModel.columnCount() - 1):
                item = self.itemModel.item(i, j)
                lineStr = lineStr + item.text() + "\t"
            item = self.itemModel.item(i, self.__ColCount - 1)
            if (item.checkState() == Qt.Checked):
                lineStr = lineStr + "1"
            else:
                lineStr = lineStr + "0"
            self.ui.qPlainTextEdit.appendPlainText(lineStr)

    def do_curChanged(self, current, previous):
        if (current != None):
            text = "当前单元格:%d行,%d列" % (current.row(), current.column())
            self.qLabel1.setText(text)
            item = self.itemModel.itemFromIndex(current)
            self.qLabel2.setText("单元格内容:" + item.text())
            font = item.font()
            self.ui.qAction10.setChecked(font.bold())
Example #19
0
class MyWin(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        QtWidgets.QWidget.__init__(self, parent)
        self.ui = MainWindow.Ui_MainWindow()
        self.ui.setupUi(self)
        self.ui.action.triggered.connect(self.action_trigger)
        self.ui.action_5.triggered.connect(self.show_settings)
        self.ui.action_3.triggered.connect(self.action_3_trigger)
        self.ui.action_2.triggered.connect(qApp.quit)

        self.ui.toolButton_2.clicked.connect(self.button_pause)
        self.ui.toolButton.clicked.connect(self.button_play)
        self.ui.toolButton_3.clicked.connect(self.button_stop)

        self.model = QStandardItemModel(0, 2, parent)
        self.model.setHeaderData(0, Qt.Horizontal, "Объект")
        self.model.setHeaderData(1, Qt.Horizontal, "Кол-во совпадений")
        self.ui.treeView.setModel(self.model)
        for i in range(22):
            self.model.insertRow(i)

        self.ui.MplWidget.canvas.axes.clear()
        self.ui.MplWidget.canvas.axes.set_title('Суммарное количество')
        self.ui.MplWidget.canvas.axes.set_facecolor('0.93')
        self.ui.MplWidget.canvas.axes.grid(True, color='1.0', linestyle='-')
        self.ui.MplWidget.canvas.axes.spines['top'].set_color('white')
        self.ui.MplWidget.canvas.axes.spines['bottom'].set_color('white')
        self.ui.MplWidget.canvas.axes.spines['right'].set_color('white')
        self.ui.MplWidget.canvas.axes.spines['left'].set_color('white')
        self.ui.MplWidget.canvas.axes.ticklabel_format(style='plain',
                                                       axis='x',
                                                       useOffset=False)

        for axis in [
                self.ui.MplWidget.canvas.axes.xaxis,
                self.ui.MplWidget.canvas.axes.yaxis
        ]:
            axis.set_major_locator(ticker.MaxNLocator(integer=True))

        self.ui.MplWidget.canvas.draw()

        self.settings = Settings('config/settings.json')
        self.settings.load_json()
        self.accessLabelVideo = True
        self.pathOpen = None
        self.pathSave = None
        self.vebcam = None
        self.isSave = None
        self.stateVideo = VideoState.VIDEO_STOP
        self.prototx = 'config/MobileNetSSD_deploy.prototxt.txt'
        self.caffemodel = 'config/MobileNetSSD_deploy.caffemodel'
        self.action_trigger()

    def button_pause(self):
        self.stateVideo = VideoState.VIDEO_PAUSE

    def button_play(self):
        self.__start_playing_video()

    def button_stop(self):
        self.stateVideo = VideoState.VIDEO_STOP

    @pyqtSlot()
    def clear_image(self):
        self.ui.label.clear()

    def show_settings(self):
        self.myapp = STGWindow(self.settings, self)
        self.myapp.show()

    def __start_playing_video(self):
        if self.stateVideo == VideoState.VIDEO_STOP:
            if not self.pathOpen and not self.vebcam:
                QtWidgets.QMessageBox.about(self, "Ошибка",
                                            "Не указан источник")
                return
            self.stateVideo = VideoState.VIDEO_START

            self.th = Thread(self.prototx, self.caffemodel,
                             self.pathOpen if not self.vebcam else 0,
                             self.pathSave, self.settings, self)
            self.th.changePixmap.connect(self.set_image)
            self.th.printLog.connect(self.print_log)
            self.th.changeStatic.connect(self.set_statistic)
            self.th.clearPixmap.connect(self.clear_image)

            self.th.start()
            self.moveToThread(self.th)

        elif self.stateVideo == VideoState.VIDEO_PAUSE:
            self.stateVideo = VideoState.VIDEO_START
            # QtWidgets.QMessageBox.about(self, "Ошибка", "Сначала завершите текущий сеанс")

    def action_3_trigger(self):
        self.__start_playing_video()

    # Работа с графиком
    @pyqtSlot(dict, int)
    def set_statistic(self, total_visits: dict, count_frames: int):
        self.ui.MplWidget.canvas.axes.clear()
        self.ui.MplWidget.canvas.axes.grid(True)

        for dct in total_visits.values():
            if any(item != 0 for item in dct['counts'][-100:]):
                color = tuple([(1 / 255) * i for i in dct['color']])
                self.ui.MplWidget.canvas.axes.plot(dct['counts'][-100:],
                                                   color=color)
        for axis in [
                self.ui.MplWidget.canvas.axes.xaxis,
                self.ui.MplWidget.canvas.axes.yaxis
        ]:
            axis.set_major_locator(ticker.MaxNLocator(integer=True))
        self.ui.MplWidget.canvas.draw()

        i = 0
        for k, v in total_visits.items():
            self.model.setData(self.model.index(i, 0), k)
            self.model.setData(self.model.index(i, 1), v['counts'][-1])
            i += 1

    @pyqtSlot(QImage)
    def set_image(self, image):
        self.ui.label.setPixmap(QPixmap.fromImage(image))
        self.accessLabelVideo = True

    @pyqtSlot(str, bool)
    def print_log(self, value, is_clear: bool = False):
        self.ui.plainTextEdit.moveCursor(QTextCursor.End)
        if is_clear:
            self.ui.plainTextEdit.clear()
        if type(value) is dict:
            for key, value in value.items():
                self.ui.plainTextEdit.insertPlainText('\n[%s]: %s' %
                                                      (key, value))
        else:
            self.ui.plainTextEdit.insertPlainText('\n' + str(value))

    def action_trigger(self):
        self.myapp = OSWindow(self, self.getvar)
        self.myapp.show()

    def getvar(self, **kwargs):
        self.vebcam = kwargs.get('vebcam', None)
        self.isSave = kwargs.get('save', None)
        self.pathSave = kwargs.get('pathSave', None)
        self.pathOpen = kwargs.get('pathOpen', None)
Example #20
0
class Table(QWidget):
    def __init__(self,
                 name,
                 data,
                 columns=None,
                 index=False,
                 checkable=False,
                 parent=None):
        QWidget.__init__(self, parent)

        self.name = name
        self.index = index
        self.checkable = checkable

        if not any([data, columns]):
            self.columns = []
        else:
            self.columns = columns if columns else list(data[0].keys())

        if checkable:
            self.columns.insert(0, '')

        if index:
            self.columns.insert(0, 'ID')

        self.setData(data)

        self.initUI()

    def initUI(self):
        #  Layout UI elements of table

        mainLayout = QVBoxLayout()

        self.proxyModel = QSortFilterProxyModel()
        self.proxyModel.setDynamicSortFilter(True)

        self.sourceModel = QStandardItemModel(0, len(self.columns), self)

        for i, column in enumerate(self.columns):
            self.sourceModel.setHeaderData(i, Qt.Horizontal, column)

        self.proxyModel.setSourceModel(self.sourceModel)

        self.proxyGroupBox = QGroupBox(self.name)

        self.proxyView = DeselectableTreeView()
        self.proxyView.setRootIsDecorated(False)
        self.proxyView.setAlternatingRowColors(True)
        self.proxyView.setModel(self.proxyModel)

        if not self.checkable:
            self.proxyView.setSortingEnabled(True)
            self.proxyView.sortByColumn(0, Qt.AscendingOrder)

        self.proxyView.setEditTriggers(QAbstractItemView.NoEditTriggers)

        proxyLayout = QGridLayout()
        proxyLayout.addWidget(self.proxyView, 0, 0, 1, 3)
        self.proxyGroupBox.setLayout(proxyLayout)

        mainLayout.addWidget(self.proxyGroupBox)
        self.setLayout(mainLayout)
        self.update(self.data)

    def setSourceModel(self, model):
        self.proxyModel.setSourceModel(model)

    def setData(self, data):
        self.data = []
        for i, item in enumerate(data):
            d = {}
            for col in self.columns:
                if col == 'ID':
                    d[col] = item.get(col, i + 1)
                else:
                    d[col] = item.get(col)
            self.data.append(d)

        #self.data = [{k: item.get(k, i+1) for k in self.columns} for i, item in enumerate(data)]

    def sortBy(self, colName):
        idx = 0
        try:
            idx = self.columns.index(colName)
        except:
            pass

        self.proxyView.sortByColumn(idx, Qt.AscendingOrder)

    def rowCount(self):
        return self.sourceModel.rowCount()

    def columnCount(self):
        return self.sourceModel.columnCount()

    def addRow(self, row_i, rowData):
        self.sourceModel.insertRow(row_i)

        for col_i, data in enumerate(rowData.values()):
            if self.checkable and col_i == 0:
                self.proxyView.setColumnWidth(col_i, 1)
                item = QStandardItem(True)
                item.setCheckable(True)
                item.setCheckState(False)
                self.sourceModel.setItem(row_i, col_i, item)
            else:
                self.sourceModel.setData(self.sourceModel.index(row_i, col_i),
                                         data)

    def update(self, data):
        self.setData(data)
        self.sourceModel.removeRows(0, self.sourceModel.rowCount())

        for i, data in enumerate(self.data):
            self.addRow(i, data)

    def getSelectedRowIndex(self):
        '''
        Returns the index of the selected row from the source model
        '''
        try:
            return self.proxyModel.mapToSource(
                self.proxyView.selectedIndexes()[0]).row()
        except:
            return False

    def getCheckedRowData(self):
        selectedData = []
        for row_i in range(self.sourceModel.rowCount()):
            item = self.sourceModel.item(row_i, 0)
            if item.checkState():
                selectedData.append(self.data[row_i])

        return selectedData
class MessageList(MyTreeView):
    class Columns(IntEnum):
        HEIGHT = 0
        FROM = 1
        DATA = 2

    filter_columns = [Columns.HEIGHT, Columns.FROM, Columns.DATA]

    ROLE_SORT_ORDER = Qt.UserRole + 1000
    ROLE_ASSET_STR = Qt.UserRole + 1001

    def __init__(self, parent):
        super().__init__(parent,
                         self.create_menu,
                         stretch_column=self.Columns.DATA,
                         editable_columns=[])
        self.wallet = self.parent.wallet
        self.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.setSortingEnabled(True)
        self.std_model = QStandardItemModel(self)
        self.proxy = MySortModel(self, sort_role=self.ROLE_SORT_ORDER)
        self.proxy.setSourceModel(self.std_model)
        self.setModel(self.proxy)
        self.update()
        self.sortByColumn(self.Columns.HEIGHT, Qt.AscendingOrder)
        self.messages = {}

    def webopen_safe(self, url):
        show_warn = self.parent.config.get('show_ipfs_warning', True)
        if show_warn:
            cb = QCheckBox(_("Don't show this message again."))
            cb_checked = False

            def on_cb(x):
                nonlocal cb_checked
                cb_checked = x == Qt.Checked

            cb.stateChanged.connect(on_cb)
            goto = self.parent.question(_(
                'You are about to visit:\n\n'
                '{}\n\n'
                'IPFS hashes can link to anything. Please follow '
                'safe practices and common sense. If you are unsure '
                'about what\'s on the other end of an IPFS, don\'t '
                'visit it!\n\n'
                'Are you sure you want to continue?').format(url),
                                        title=_('Warning: External Data'),
                                        checkbox=cb)

            if cb_checked:
                self.parent.config.set_key('show_ipfs_warning', False)
            if goto:
                webopen(url)
        else:
            webopen(url)

    def mouseDoubleClickEvent(self, event: QMouseEvent):
        idx = self.indexAt(event.pos())
        if not idx.isValid():
            return

        # Get the IPFS from 3rd column
        hm_idx = self.model().mapToSource(self.model().index(idx.row(), 2))
        data = self.std_model.data(hm_idx)
        if data[:2] == 'Qm':  # If it starts with Qm, it's an IPFS
            url = ipfs_explorer_URL(self.parent.config, 'ipfs', data)
            self.webopen_safe(url)

    def refresh_headers(self):
        headers = {
            self.Columns.HEIGHT: _('Height'),
            self.Columns.FROM: _('From'),
            self.Columns.DATA: _('Data'),
        }
        self.update_headers(headers)

    @profiler
    def update(self):
        if self.maybe_defer_update():
            return
        self.messages = self.wallet.get_messages()
        self.proxy.setDynamicSortFilter(
            False)  # temp. disable re-sorting after every change
        self.std_model.clear()
        self.refresh_headers()
        set_message = None

        for height, data in self.messages.items():
            for d in data:
                is_from = d[0]
                message_txt = d[1]

                if not self.parent.config.get('get_dev_notifications',
                                              True) and d[2] is None:
                    # The source will only be null if this is a dev notification
                    continue

                # create item
                labels = [height, is_from, message_txt]
                asset_item = [QStandardItem(e) for e in labels]
                # align text and set fonts
                for i, item in enumerate(asset_item):
                    item.setTextAlignment(Qt.AlignVCenter)

                # add item
                count = self.std_model.rowCount()
                self.std_model.insertRow(count, asset_item)

        self.set_current_idx(set_message)
        self.filter()
        self.proxy.setDynamicSortFilter(True)

    def add_copy_menu(self, menu, idx):
        cc = menu.addMenu(_("Copy"))
        for column in self.Columns:
            if self.isColumnHidden(column):
                continue
            column_title = self.model().headerData(column, Qt.Horizontal)
            hm_idx = self.model().mapToSource(self.model().index(
                idx.row(), column))
            column_data = self.std_model.data(hm_idx)
            cc.addAction(column_title,
                         lambda text=column_data, title=column_title: self.
                         place_text_on_clipboard(text, title=title))
        return cc

    def create_menu(self, position):
        org_idx: QModelIndex = self.indexAt(position)

        menu = QMenu()
        self.add_copy_menu(menu, org_idx)

        menu.exec_(self.viewport().mapToGlobal(position))

    def place_text_on_clipboard(self, text: str, *, title: str = None) -> None:
        if is_address(text):
            try:
                self.wallet.check_address_for_corruption(text)
            except InternalAddressCorruption as e:
                self.parent.show_error(str(e))
                raise
        super().place_text_on_clipboard(text, title=title)

    def get_edit_key_from_coordinate(self, row, col):
        return None

    # We don't edit anything here
    def on_edited(self, idx, edit_key, *, text):
        pass
Example #22
0
class gcodeFile(QObject):
    '''
  Gestion d'un fichier GCode dans la QListView de l'interface graphique reservee a cet usage
  Methodes :
  - __init__(QListView) -> Initialise et definit les elements de l'UI qui recevront le contenu du fichier
  - showFileOpen()        -> Affiche la boite de dialogue d'ouverture
  - showFileSave()        -> Affiche la boite de dialogue d'enregistrement
  - readFile(filePath)    -> Charge un fichier dans la QListView
  - saveFile(filePath)    -> Enregistre le contenu de la QListView dans un fichier
  - closeFile()           -> Vide la QListView
  - setGcodeChanged(bool) -> Definit si le contenu de la liste a ete modifie depuis la lecture ou l'enregistrement du fichier
  - bool = gcodeChanged() -> Renvoi vrai si le contenu de la liste a ete modifie depuis la lecture ou l'enregistrement du fichier
  '''

    sig_log = pyqtSignal(int, str)  # Message de fonctionnement du composant

    def __init__(self, gcodeFileUi: QListView):
        super().__init__()
        self.__filePath = ""
        self.__gcodeFileUi = gcodeFileUi
        self.__gcodeFileUiModel = QStandardItemModel(self.__gcodeFileUi)
        self.__gcodeFileUiModel.itemChanged.connect(self.on_gcodeChanged)
        self.__gcodeCharge = False
        self.__gcodeChanged = False

    def showFileOpen(self):
        ''' Affiche la boite de dialogue d'ouverture '''
        '''
    if sys.platform == 'linux':
      # Prépare la boite de dialogue
      dialog = Gtk.FileChooserDialog(
        self.tr("Open a GCode file"),
        self,
        Gtk.FileChooserAction.OPEN,
        (
          Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
          Gtk.STOCK_OPEN, Gtk.ResponseType.OK
        )
      )
      dialog.set_local_only(False) # Permet l'affichage des fichiers réseaux sous Linux GTK+3
      dialog_filter = Gtk.FileFilter()
      dialog_filter.set_name(self.tr("GCode file"))
      dialog_filter.add_pattern("*.gcode")
      dialog_filter.add_pattern("*.ngc")
      dialog_filter.add_pattern("*.nc")
      dialog_filter.add_pattern("*.gc")
      dialog_filter.add_pattern("*.cnc")
      dialog.add_filter(dialog_filter)
      # Affiche la boite de dialogue
      response = dialog.run()
      # Traite la réponse
      if response == Gtk.ResponseType.OK:
          print("Open clicked")
          print("File selected: " + dialog.get_filename())
      elif response == Gtk.ResponseType.CANCEL:
          print("Cancel clicked")
      # Libère les ressources
      dialog.destroy()

    else: # sys.platform == 'linux'
    '''
        opt = QtWidgets.QFileDialog.Options()
        ###opt |= QtWidgets.QFileDialog.DontUseNativeDialog
        fName = QtWidgets.QFileDialog.getOpenFileName(
            None,
            self.tr("Open a GCode file"),
            "",
            self.tr("GCode file (*.gcode *.ngc *.nc *.gc *.cnc)"),
            options=opt)
        return fName

    def readFile(self, filePath: str):
        self.sig_log.emit(logSeverity.info.value,
                          self.tr("Reading file: {}").format(filePath))
        try:
            f = open(filePath, 'r')
            lignes = f.readlines()
            f.close()
            self.sig_log.emit(
                logSeverity.info.value,
                self.tr("{} lines in the file").format(len(lignes)))
            # Envoi du contenu dans la liste
            self.__gcodeFileUiModel.clear()
            for l in lignes:
                item = QStandardItem(l.strip())
                self.__gcodeFileUiModel.appendRow(item)
            self.__gcodeFileUi.setModel(self.__gcodeFileUiModel)
            # Selectionne la premiere ligne du fichier dans la liste
            self.selectGCodeFileLine(0)
            # Selectionne l'onglet du fichier
        except Exception as e:
            self.sig_log.emit(
                logSeverity.error.value,
                self.tr("Reading file error: {}").format(filePath))
            self.sig_log.emit(logSeverity.error.value, str(e))
            self.__gcodeFileUiModel.clear()
            self.__filePath = ""
            self.__gcodeChanged = False
            return False

        # Pas d'erreur
        self.__gcodeCharge = True
        self.__filePath = filePath
        self.__gcodeChanged = False
        return True

    def isFileLoaded(self):
        return self.__gcodeCharge

    def filePath(self):
        return self.__filePath

    def fileName(self):
        return os.path.basename(self.__filePath)

    def selectGCodeFileLine(self, num: int):
        ''' Selectionne un element de la liste du fichier GCode '''
        idx = self.__gcodeFileUiModel.index(num, 0, QModelIndex())
        self.__gcodeFileUi.selectionModel().clearSelection()
        self.__gcodeFileUi.selectionModel().setCurrentIndex(
            idx, QItemSelectionModel.SelectCurrent)

    def getGCodeSelectedLine(self):
        ''' Renvoie le N° (0 base) de la ligne selectionnee dans la liste GCode et les donnees de cette ligne. '''
        idx = self.__gcodeFileUi.selectionModel().selectedIndexes()
        return [idx[0].row(), self.__gcodeFileUiModel.data(idx[0])]

    def saveAs(self):
        fName = self.showFileSave()
        if fName[0] != "":
            self.sig_log.emit(logSeverity.info.value,
                              self.tr("saveAs({})").format(fName[0]))
            self.saveFile(fName[0])
        else:
            self.sig_log.emit(logSeverity.info.value,
                              self.tr("saveAs() canceled!"))

    def showFileSave(self):
        ''' Affiche la boite de dialogue "Save as" '''
        opt = QtWidgets.QFileDialog.Options()
        opt |= QtWidgets.QFileDialog.DontUseNativeDialog
        fName = QtWidgets.QFileDialog.getSaveFileName(
            None,
            self.tr("Save GCode file"),
            "",
            self.tr("GCode file (*.gcode *.ngc *.nc *.gc *.cnc)"),
            options=opt)
        return fName

    def saveFile(self, filePath: str = ""):
        if filePath == "":
            if self.__filePath == "":
                # Le nom du fichier n'est pas definit, il n'y a pas de fichier charge, donc, rien a sauvegarder !
                return
            else:
                filePath = self.__filePath
        self.sig_log.emit(logSeverity.info.value,
                          self.tr("Saving file: {}").format(filePath))
        try:
            f = open(filePath, 'w')
            for I in range(self.__gcodeFileUiModel.rowCount()):
                idx = self.__gcodeFileUiModel.index(I, 0, QModelIndex())
                if self.__gcodeFileUiModel.data(idx) != "":
                    f.write(self.__gcodeFileUiModel.data(idx) + '\n')
            f.close()
            self.__filePath = filePath
        except Exception as e:
            self.sig_log.emit(logSeverity.error.value,
                              self.tr("Save file error: {}").format(filePath))
            self.sig_log.emit(logSeverity.error.value, str(e))
        # Supprime les lignes vides dans la grille d'affichage
        self.delEmptyRow()
        # Reinit du flag fichier change
        self.__gcodeChanged = False

    def enQueue(self, com: grblCom, startLine: int = 0, endLine: int = -1):
        """ Envoi des lignes de startLine a endLine dans la file d'attente du grblCom """
        if endLine == -1:
            endLine = self.__gcodeFileUiModel.rowCount()
        for I in range(startLine, endLine + 1):
            idx = self.__gcodeFileUiModel.index(I, 0, QModelIndex())
            if self.__gcodeFileUiModel.data(idx) != "":
                com.gcodePush(self.__gcodeFileUiModel.data(idx))
                com.gcodePush(CMD_GRBL_GET_GCODE_STATE, COM_FLAG_NO_OK)

    def delEmptyRow(self):
        """ Elimination des lignes GCode vides """
        for I in reversed(range(self.__gcodeFileUiModel.rowCount())):
            # On commence par la fin pour pouvoir supprimer sans tout decaler pour la suite
            idx = self.__gcodeFileUiModel.index(I, 0, QModelIndex())
            if self.__gcodeFileUiModel.data(idx) == "":
                self.__gcodeFileUiModel.removeRow(I)

    def deleteGCodeFileLine(self, num: int):
        self.__gcodeFileUiModel.removeRow(num)
        self.__gcodeChanged = True

    def insertGCodeFileLine(self, num: int):
        item = QStandardItem("")
        self.__gcodeFileUiModel.insertRow(num, item)

    def addGCodeFileLine(self, num: int):
        item = QStandardItem("")
        self.__gcodeFileUiModel.insertRow(num + 1, item)

    def showConfirmChangeLost(self):
        m = msgBox(
            title=self.tr("Save Changes"),
            text=self.tr("Do you want to save the changes before closing?"),
            info=self.
            tr("If you do not save, any changes made since opening or the last save will be lost."
               ),
            icon=msgIconList.Question,
            stdButton=msgButtonList.Save | msgButtonList.Cancel
            | msgButtonList.Discard,
            defButton=msgButtonList.Save,
            escButton=msgButtonList.Cancel)
        return (m.afficheMsg())

    def closeFile(self):
        if self.__gcodeChanged:
            # GCode modifie, on demande confirmation
            Ret = self.showConfirmChangeLost()
            if Ret == msgButtonList.Save:
                if self.__filePath == "":
                    filePath = self.showFileSave()
                    if filePath == "":
                        # Annulation de la boite de dialogue
                        return False
                    else:
                        self.__filePath = filePath
                self.saveFile(self.__filePath)
                return True
            elif Ret == msgButtonList.Discard:
                # Fermer le fichier consiste en vider la fenetre GCode
                self.__gcodeFileUiModel.clear()
                self.__gcodeChanged = False
                self.__gcodeCharge = False
                return True
            else:  # Ret == msgButtonList.Cancel:
                return False
        else:
            # GCode non modifie, on ferme sans confirmation
            # Fermer le fichier consiste en vider la fenetre GCode
            # et a supprimer le status GCode charge.
            self.__gcodeFileUiModel.clear()
            self.__gcodeChanged = False
            self.__gcodeCharge = False
            return True

    @pyqtSlot("QStandardItem*")
    def on_gcodeChanged(self, item):
        self.__gcodeChanged = True

    def gcodeChanged(self):
        return self.__gcodeChanged

    def setGcodeChanged(self, value: bool):
        self.__gcodeChanged = value
Example #23
0
class Application(QMainWindow):
    def __init__(self, version, window=QMainWindow(), player=Player()):
        QMainWindow.__init__(self)
        self.ui = Ui_Main()
        self.window = window
        self.ui.setupUi(window)
        self.player = player
        self.version = version

        # Init Timer
        self.timer = QtCore.QTimer()
        self.timer.start(1000)  # Update every second
        self.timer.timeout.connect(self.track_elapsed)

        # Button icons
        window_icon = QIcon()
        window_icon.addPixmap(QPixmap(os.path.dirname(os.path.realpath(__file__))
                                    + "/images/window/icon.png"), QIcon.Normal, QIcon.Off)
        self.window.setWindowIcon(window_icon)

        self.play_icon = QIcon()
        self.play_icon.addPixmap(QPixmap(os.path.dirname(os.path.realpath(__file__))
                                    + "/images/buttons/play.png"), QIcon.Normal, QIcon.Off)
        self.pause_icon = QIcon()
        self.pause_icon.addPixmap(QPixmap(os.path.dirname(os.path.realpath(__file__))
                                    + "/images/buttons/pause.png"), QIcon.Normal, QIcon.Off)
        self.next_icon = QIcon()
        self.next_icon.addPixmap(QPixmap(os.path.dirname(os.path.realpath(__file__))
                                    + "/images/buttons/next.png"), QIcon.Normal, QIcon.Off)
        self.prev_icon = QIcon()
        self.prev_icon.addPixmap(QPixmap(os.path.dirname(os.path.realpath(__file__))
                                    + "/images/buttons/previous.png"), QIcon.Normal, QIcon.Off)
        self.stop_icon = QIcon()
        self.stop_icon.addPixmap(QPixmap(os.path.dirname(os.path.realpath(__file__))
                                    + "/images/buttons/stop.png"), QIcon.Normal, QIcon.Off)

        # Set buttons
        self.ui.playpauseButton.setIcon(self.play_icon)
        self.ui.nextButton.setIcon(self.next_icon)
        self.ui.previousButton.setIcon(self.prev_icon)
        self.ui.stopButton.setIcon(self.stop_icon)

        # CheckBox for showing / hiding Expanded Lists
        self.ui.expandCheck.stateChanged.connect(self.lists)
        # And for showing / hiding video window
        self.ui.videoCheck.stateChanged.connect(self.video_window)

        # For dragging the slider
        self.was_it_playing = None
        self.ui.TrackSlider.sliderPressed.connect(self.slider_pressed)
        self.ui.TrackSlider.sliderReleased.connect(self.play_when_slider_released)
        self.ui.TrackSlider.sliderMoved.connect(self.player.change_item_pos)

        # Model to hold track list
        self.queueTrackListModel = QStandardItemModel(self.ui.trackList)
        self.ui.trackList.setModel(self.queueTrackListModel)
        self.recentTrackListModel = QStandardItemModel(self.ui.recentTracksList)
        self.ui.recentTracksList.setModel(self.recentTrackListModel)
        self.ui.trackList.doubleClicked.connect(self.choose_track_from_queue)
        self.ui.recentTracksList.doubleClicked.connect(self.choose_track_from_recent)

        self.ui.trackList.hide()  # we start the list hidden
        self.ui.recentTracksList.hide()  # likewise

        # Connect GUI buttons
        self.ui.playpauseButton.clicked.connect(self.play_track)  # Play / Pause button
        self.ui.stopButton.clicked.connect(self.stop_track)  # Stop button
        self.ui.nextButton.clicked.connect(self.next_track)  # Next button
        self.ui.previousButton.clicked.connect(self.prev_track)  # Next button

        self.ui.actionQuit.triggered.connect(sys.exit)  # Quit from menu
        self.ui.actionOpen.triggered.connect(self.choose_track)  # Open single item from menu
        self.ui.actionOpen_Several.triggered.connect(self.choose_tracks)  # Open several items from menu
        self.ui.actionOpen_Directory.triggered.connect(self.choose_directory)  # Open a directory from menu
        self.ui.actionAbout_LiMu.triggered.connect(self.about_dialog)

        # Keyboard shortcuts
        self.shortcut_next_track = QShortcut(QKeySequence("Right"), self.window)
        self.shortcut_next_track.activated.connect(self.next_track)
        self.shortcut_prev_track = QShortcut(QKeySequence("Left"), self.window)
        self.shortcut_prev_track.activated.connect(self.prev_track)
        self.shortcut_play_track = QShortcut(QKeySequence("Up"), self.window)
        self.shortcut_play_track.activated.connect(self.play_track)
        self.shortcut_stop_track = QShortcut(QKeySequence("Down"), self.window)
        self.shortcut_stop_track.activated.connect(self.stop_track)
        self.shortcut_open_folder = QShortcut(QKeySequence("Ctrl+O"), self.window)
        self.shortcut_open_folder.activated.connect(self.choose_directory)
        self.shortcut_open_track = QShortcut(QKeySequence("Ctrl+I"), self.window)
        self.shortcut_open_track.activated.connect(self.choose_track)
        self.shortcut_open_tracks = QShortcut(QKeySequence("Ctrl+L"), self.window)
        self.shortcut_open_tracks.activated.connect(self.choose_tracks)
        self.shortcut_quit = QShortcut(QKeySequence("Ctrl+Q"), self.window)
        self.shortcut_quit.activated.connect(sys.exit)

        # Starts expanded if set in settings.conf
        if config['Expanded'] is True:
            self.ui.expandCheck.nextCheckState()
            self.window.setMaximumSize(QSize(_expX, _expY))
            self.window.setMinimumSize(QSize(_expX, _expY))
            self.window.resize(_expX, _expY)
            self.ui.trackList.show()
            self.ui.recentTracksList.show()

        # Stuck Counter ( A BUG )
        self.stuck_counter = 0

    def lists(self):
        if self.ui.expandCheck.isChecked():
            self.window.setMaximumSize(QSize(_expX, _expY))
            self.window.setMinimumSize(QSize(_expX, _expY))
            self.window.resize(_expX, _expY)
            self.ui.trackList.show()
            self.ui.recentTracksList.show()
        else:
            self.window.setMaximumSize(QSize(_norX, _norY))
            self.window.setMinimumSize(QSize(_norX, _norY))
            self.window.resize(_norX, _norY)
            self.ui.trackList.hide()
            self.ui.recentTracksList.hide()

    def video_window(self):
        self.check_video()
        if self.player.video.isEnabled():
            if self.ui.videoCheck.isChecked():
                self.player.video.show()
            else:
                self.player.video.hide()

    def check_video(self):
        if self.player.get_item() is not None:
            video = False
            for v in video_files:
                if self.player.get_item().lower().endswith(v):
                    self.ui.videoCheck.setEnabled(True)
                    video = True
            if video is False:
                self.ui.videoCheck.setChecked(False)
                self.ui.videoCheck.setEnabled(False)

    def slider_pressed(self):
        if self.player.status == "playing":
            self.play_track()
            self.was_it_playing = True
        else:
            self.was_it_playing = False

    def play_when_slider_released(self):
        if self.was_it_playing is True:
            self.play_track()

    def choose_track_from_queue(self, chosen):
        self.player.stop_item()
        if self.player.get_item() is not None:
            self.current_to_recent()
        location = chosen.data(1)
        self.player.set_item(location)
        print("loaded: " + self.player.get_item())
        location = chosen.data(1)
        self.queueTrackListModel.removeRow(chosen.row())
        self.meta_info(location, active=True)
        self.play_track()

    def choose_track_from_recent(self, chosen):
        self.player.stop_item()
        location = chosen.data(1)
        self.recentTrackListModel.removeRow(chosen.row())
        if self.player.get_item() is not None:
            self.current_to_recent()
        self.player.set_item(location)
        self.play_track()
        self.meta_info(location, active=True)

    @pyqtSlot()
    def play_track(self):
        if self.player.get_item() is not None:
            self.player.play_item()
            self.video_window()
            print(self.player.status)
            if self.player.status == "paused":
                self.ui.playpauseButton.setIcon(self.play_icon)
            elif self.player.status == "playing":
                self.ui.playpauseButton.setIcon(self.pause_icon)
        else:
            print("No track to play")

    @pyqtSlot()
    def stop_track(self):
        if self.player.get_item() is not None:
            self.player.stop_item()
            print(self.player.status)
            self.ui.playpauseButton.setIcon(self.play_icon)

    @pyqtSlot()
    def next_track(self):
        error = "There's no track"
        try:
            self.current_to_recent()
            self.get_next_track()
            self.play_track()
        except AttributeError:
            print(error + " (" + AttributeError.__name__ + ")")
        except TypeError:
            print(error + " (" + TypeError.__name__ + ")")

    @pyqtSlot()
    def prev_track(self):
        previous_track = self.recentTrackListModel.takeItem(0)
        if previous_track is not None or previous_track is not "":
            try:
                location = previous_track.data(1)
                try:
                    self.player.stop_item()
                    print(self.player.get_item())
                    playing_track = self.player.get_item()
                    playing_meta = self.meta_info(playing_track)
                    item = QStandardItem(playing_track)
                    item.setFlags(item.flags() & ~QtCore.Qt.ItemIsDropEnabled)  # This is necessary to drag'n'drop within QueueList
                    item.setText(playing_meta)
                    item.setData(playing_track, 1)
                    self.queueTrackListModel.insertRow(0, item)
                    print("goes back one step..")
                except FileNotFoundError:
                    print("no current track..")
                self.player.set_item(location)
                print("loaded: " + self.player.get_item())
                self.meta_info(location, active=True)
                self.recentTrackListModel.removeRow(0)
                print(previous_track.data(0) + " taken back from recent.")
                self.play_track()
            except AttributeError:
                print("nope")
        elif previous_track is None or previous_track is "":
            print("there's no track - cannot go backwards")

    def current_to_recent(self):
        track = self.player.get_item()
        if track is not "":
            item = QStandardItem(track)
            track_meta = self.meta_info(track)
            item.setText(track_meta)
            item.setData(track, 1)
            self.recentTrackListModel.insertRow(0, item)

    @pyqtSlot()
    def choose_track(self, arg=False):
        if arg is not False:
            chosen = [arg]
        elif arg is False:
            chosen = QFileDialog.getOpenFileName(parent=self.window, filter="Media (*.mp3 *.ogg *.oga *.wav *.flac *.wma *.mkv *.mp4 *.avi *.mpg *.ogv)", directory=os.getenv('HOME'), caption="Open single track")
        if chosen[0] != "":
            if self.player.status != "stopped":
                self.player.stop_item()
            if self.player.get_item() is not None:
                self.current_to_recent()
            location = chosen[0]
            self.player.set_item(location)
            print("loaded: " + self.player.get_item())
            self.meta_info(location, active=True)
            self.play_track()

    @pyqtSlot()
    def choose_tracks(self):
        chosen = QFileDialog.getOpenFileNames(parent=self.window, directory=os.getenv('HOME'), caption="Open one or more tracks")
        tracks = chosen[0]
        count = len(tracks)
        start_all = time.time()
        for track in tracks:
            is_audio = False
            is_video = False
            for a in audio_files:
                if track.lower().endswith(a):
                    is_audio = True
                    break
            for v in video_files:
                if track.lower().endswith(v):
                    is_video = True
                    break
            if is_audio:
                queue.put(track)
            # Adds it directly, bypassing threading (doesn't play nice)
            elif is_video:
                self.process_track(track)
            # The track wasn't a playable track at all!
            else:
                count -= 1
        self.start_working(start_all, count)

    @pyqtSlot()
    def choose_directory(self, arg=False):
        dir_files = ''
        if arg is not False:
            directory = [arg][0]
            dir_files = os.listdir(directory)
        else:
            directory = QFileDialog.getExistingDirectory(directory=os.getenv('HOME'), caption="Open directory with tracks")
            if directory != '':
                dir_files = os.listdir(directory)
        count = len(dir_files)
        start_all = time.time()
        for track in dir_files:
            is_audio = False
            is_video = False
            for a in audio_files:
                if track.lower().endswith(a):
                    is_audio = True
                    break
            for v in video_files:
                if track.lower().endswith(v):
                    is_video = True
                    break
            if is_audio:
                fullpath = os.path.realpath(directory) + "/" + track
                queue.put(fullpath)
            # # Adds it directly, bypassing threading (doesn't play nice)
            elif is_video:
                fullpath = os.path.realpath(directory) + "/" + track
                self.process_track(fullpath)
            # Track was no track at all!
            else:
                count -= 1
        self.start_working(start_all, count)

    def get_next_track(self):
        try:
            next_track = self.queueTrackListModel.takeItem(0)
            print("takes next track from queue..")
            location = next_track.data(1)
            self.player.set_item(location)
            print("loaded: " + self.player.get_item())
            self.meta_info(location, active=True)
            self.queueTrackListModel.removeRow(0)
            print(next_track.data(0) + " removed from queue.")
            self.play_track()
            self.ui.playpauseButton.setIcon(self.pause_icon)
        except AttributeError:
            print("queue's empty.. I'll hang back for now")
            self.player.reset()
            self.ui.playpauseButton.setIcon(self.play_icon)

    def meta_info(self, location, active=False):
        taginfo = os.path.basename(location)
        try:
            tagger = read_tag(location)
            taginfo = tagger.artist + " - " + tagger.title + " (" + tagger.album + ")"# + " (" + tagger.date + ")"
            if active is True:
                if len(taginfo) > 54:
                    taginfo = taginfo[:52]
                    self.ui.TrackInformationText.setText(taginfo + "..")
                else:
                    self.ui.TrackInformationText.setText(taginfo)
        except NameError:  # If NoTagError couldn't import because of lack of stagger
            if active is True:
                self.ui.TrackInformationText.setText(os.path.basename(location))
        except NoTagError:
            if active is True:
                self.ui.TrackInformationText.setText(os.path.basename(location))
        return taginfo

    def track_elapsed(self):
        track = self.player.track_item_pos()
        if self.player.status is "playing":
            # Song finished
            if track[3] >= track[4]:
                if track[4] != 0:  # test-fix for early track switching | booo
                    print("finished playing song")
                    self.current_to_recent()
                    self.player.stop_item()
                    self.get_next_track()
            # -||- but placeholder fix for 1sec left bug
            if track[3] == track[4] - 1:
                stuck = self.is_it()
                if stuck is True:
                    print("finished playing song (IN AN UGLY WAY)")
                    self.current_to_recent()
                    self.player.stop_item()
                    self.get_next_track()
            if track[4] != 0:
                self.ui.TrackElapsedText.setText("+" + track[0])
                self.ui.TrackLengthText.setText(track[1])
                self.ui.TrackLeftText.setText("-" + track[2])
                self.ui.TrackSlider.setMaximum(track[4])
                if self.player.status is not "paused":
                    self.ui.TrackSlider.setValue(track[3])

    def is_it(self):
            self.stuck_counter += 1
            if self.stuck_counter == 3:
                self.stuck_counter = 0
                return True
            else:
                return False

    def about_dialog(self):
        from PyQt5.QtWidgets import QDialog, QLabel, QWidget
        from PyQt5.QtCore import QRect

        d = QDialog(self.window)
        d.setWindowTitle("About LiMu")
        container = QWidget(d)
        container.setGeometry(QRect(0, 0, 200, 80))
        intro = QLabel(container)
        intro.setText("the Liothe Music Player")
        made_by = QLabel(container)
        made_by.setText("\nCreated by: Liothe")
        version = QLabel(container)
        version.setText("\n\nVersion: " + self.version)
        d.show()

    def process_track(self, track):
        with lock:
            start_single = time.time()
            item = QStandardItem(track)
            item.setFlags(item.flags() & ~QtCore.Qt.ItemIsDropEnabled)  # This is necessary to drag'n'drop within QueueList
            track_info = self.meta_info(track)
            item.setText(track_info)
            item.setData(track, 1)
            self.queueTrackListModel.appendRow(item)
            stop_single = time.time() - start_single
            print("queued:", os.path.basename(item.data(0)), "(" + str(stop_single.__round__(5)) + ")" + " --- " + threading.current_thread().name)
            if self.player.status is None:
                self.get_next_track()

    def start_working(self, start_time, count):
        for i in range(os.cpu_count()):
            threading.Thread(target=self.workerbee_do, daemon=True, name="workerbee " + str(i + 1)).start()
        stop_all = time.time() - start_time
        queue.join()
        with lock:
            print("Adding", str(count), "tracks took", str(stop_all.__round__(5)) + "seconds")

    def workerbee_do(self):
        while True:
            item = queue.get()
            self.process_track(item)
            queue.task_done()
Example #24
0
class QmyMainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)  #调用父类构造函数,创建窗体
        self.ui = Ui_MainWindow()  #创建UI对象
        self.ui.setupUi(self)  #构造UI界面
        self.setCentralWidget(self.ui.splitter)

        self.__ColCount = 6  #列数=6
        self.itemModel = QStandardItemModel(5, self.__ColCount,
                                            self)  # 数据模型,10行6列

        self.selectionModel = QItemSelectionModel(self.itemModel)  #Item选择模型
        self.selectionModel.currentChanged.connect(self.do_curChanged)

        self.__lastColumnTitle = "测井取样"
        self.__lastColumnFlags = (Qt.ItemIsSelectable
                                  | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)

        ##tableView设置
        self.ui.tableView.setModel(self.itemModel)  #设置数据模型
        self.ui.tableView.setSelectionModel(self.selectionModel)  #设置选择模型

        oneOrMore = QAbstractItemView.ExtendedSelection
        self.ui.tableView.setSelectionMode(oneOrMore)  #可多选

        itemOrRow = QAbstractItemView.SelectItems
        self.ui.tableView.setSelectionBehavior(itemOrRow)  #单元格选择

        self.ui.tableView.verticalHeader().setDefaultSectionSize(22)  #缺省行高
        self.ui.tableView.setAlternatingRowColors(True)  #交替行颜色

        self.ui.tableView.setEnabled(False)  #先禁用tableView
        self.__buildStatusBar()

##  ==============自定义功能函数============

    def __buildStatusBar(self):  ##构建状态栏
        self.LabCellPos = QLabel("当前单元格:", self)
        self.LabCellPos.setMinimumWidth(180)
        self.ui.statusBar.addWidget(self.LabCellPos)

        self.LabCellText = QLabel("单元格内容:", self)
        self.LabCellText.setMinimumWidth(150)
        self.ui.statusBar.addWidget(self.LabCellText)

        self.LabCurFile = QLabel("当前文件:", self)
        self.ui.statusBar.addPermanentWidget(self.LabCurFile)

    def __iniModelFromStringList(self, allLines):  ##从字符串列表构建模型
        rowCnt = len(allLines)  #文本行数,第1行是标题
        self.itemModel.setRowCount(rowCnt - 1)  #实际数据行数

        headerText = allLines[0].strip()  #第1行是表头,去掉末尾的换行符 "\n"
        headerList = headerText.split("\t")  #转换为字符串列表
        self.itemModel.setHorizontalHeaderLabels(headerList)  #设置表头标题

        self.__lastColumnTitle = headerList[len(headerList) -
                                            1]  # 最后一列表头的标题,即“测井取样”

        lastColNo = self.__ColCount - 1  #最后一列的列号
        for i in range(rowCnt - 1):
            lineText = allLines[i + 1].strip()  #一行的文字,\t分隔
            strList = lineText.split("\t")  #分割为字符串列表
            for j in range(self.__ColCount - 1):  #不含最后一列
                item = QStandardItem(strList[j])
                self.itemModel.setItem(i, j, item)  #设置模型的item

            item = QStandardItem(self.__lastColumnTitle)  #最后一列
            item.setFlags(self.__lastColumnFlags)
            item.setCheckable(True)
            if (strList[lastColNo] == "0"):
                item.setCheckState(Qt.Unchecked)
            else:
                item.setCheckState(Qt.Checked)

            self.itemModel.setItem(i, lastColNo, item)  #设置最后一列的item

    def __setCellAlignment(self, align=Qt.AlignHCenter):
        if (not self.selectionModel.hasSelection()):  #没有选择的项
            return
        selectedIndex = self.selectionModel.selectedIndexes()  #模型索引列表
        count = len(selectedIndex)
        for i in range(count):
            index = selectedIndex[i]  #获取其中的一个模型索引
            item = self.itemModel.itemFromIndex(index)  #获取一个单元格的项数据对象
            item.setTextAlignment(align)  #设置文字对齐方式

##  ==========由connectSlotsByName() 自动连接的槽函数==================

    @pyqtSlot()  ##“打开文件”
    def on_actOpen_triggered(self):
        ##        curPath=QDir.currentPath() #获取当前路径
        curPath = os.getcwd()  #获取当前路径

        filename, flt = QFileDialog.getOpenFileName(
            self, "打开一个文件", curPath, "井斜数据文件(*.txt);;所有文件(*.*)")
        if (filename == ""):
            return

        self.LabCurFile.setText("当前文件:" + filename)
        self.ui.plainTextEdit.clear()

        aFile = open(filename, 'r')
        allLines = aFile.readlines()  #读取所有行,list类型,每行末尾带有 \n
        aFile.close()

        for strLine in allLines:
            self.ui.plainTextEdit.appendPlainText(strLine.strip())

        self.__iniModelFromStringList(allLines)
        self.ui.tableView.setEnabled(True)  #tableView可用
        self.ui.actAppend.setEnabled(True)  #更新Actions的enable属性
        self.ui.actInsert.setEnabled(True)
        self.ui.actDelete.setEnabled(True)
        self.ui.actSave.setEnabled(True)
        self.ui.actModelData.setEnabled(True)

    @pyqtSlot()  ##保存文件
    def on_actSave_triggered(self):
        ##      curPath=QDir.currentPath() #获取当前路径
        curPath = os.getcwd()  #获取当前路径
        filename, flt = QFileDialog.getSaveFileName(
            self, "保存文件", curPath, "井斜数据文件(*.txt);;所有文件(*.*)")
        if (filename == ""):
            return

        self.on_actModelData_triggered()  #更新数据到plainTextEdit

        aFile = open(filename, 'w')  #以写方式打开
        aFile.write(self.ui.plainTextEdit.toPlainText())
        aFile.close()

    @pyqtSlot()  ##在最后添加一行
    def on_actAppend_triggered(self):
        itemlist = []  # QStandardItem 对象列表
        for i in range(self.__ColCount - 1):  #不包括最后一列
            item = QStandardItem("0")
            itemlist.append(item)

        item = QStandardItem(self.__lastColumnTitle)  #最后一列
        item.setCheckable(True)
        item.setFlags(self.__lastColumnFlags)
        itemlist.append(item)

        self.itemModel.appendRow(itemlist)  #添加一行
        curIndex = self.itemModel.index(self.itemModel.rowCount() - 1, 0)
        self.selectionModel.clearSelection()
        self.selectionModel.setCurrentIndex(curIndex,
                                            QItemSelectionModel.Select)

    @pyqtSlot()  ##插入一行
    def on_actInsert_triggered(self):
        itemlist = []  #  QStandardItem 对象列表
        for i in range(self.__ColCount - 1):  #不包括最后一列
            item = QStandardItem("0")
            itemlist.append(item)

        item = QStandardItem(self.__lastColumnTitle)  #最后一列
        item.setFlags(self.__lastColumnFlags)
        item.setCheckable(True)
        item.setCheckState(Qt.Checked)
        itemlist.append(item)

        curIndex = self.selectionModel.currentIndex()
        #获取当前选中项的模型索引
        self.itemModel.insertRow(curIndex.row(), itemlist)
        #在当前行的前面插入一行
        self.selectionModel.clearSelection()
        self.selectionModel.setCurrentIndex(curIndex,
                                            QItemSelectionModel.Select)

    @pyqtSlot()  ##删除当前行
    def on_actDelete_triggered(self):
        curIndex = self.selectionModel.currentIndex()  #获取当前选择单元格的模型索引
        self.itemModel.removeRow(curIndex.row())  #删除当前行

    @pyqtSlot()  ##左对齐
    def on_actAlignLeft_triggered(self):
        self.__setCellAlignment(Qt.AlignLeft | Qt.AlignVCenter)

    @pyqtSlot()  ##中间对齐
    def on_actAlignCenter_triggered(self):
        self.__setCellAlignment(Qt.AlignHCenter | Qt.AlignVCenter)

    @pyqtSlot()  ##右对齐
    def on_actAlignRight_triggered(self):
        self.__setCellAlignment(Qt.AlignRight | Qt.AlignVCenter)

    @pyqtSlot(bool)  ##字体Bold
    def on_actFontBold_triggered(self, checked):
        if (not self.selectionModel.hasSelection()):  #没有选择的项
            return
        selectedIndex = self.selectionModel.selectedIndexes()  #模型索引列表
        count = len(selectedIndex)
        for i in range(count):
            index = selectedIndex[i]  #获取其中的一个模型索引
            item = self.itemModel.itemFromIndex(index)  #获取一个单元格的项数据对象
            font = item.font()
            font.setBold(checked)
            item.setFont(font)

    @pyqtSlot()  ##模型数据显示到plainTextEdit里
    def on_actModelData_triggered(self):
        self.ui.plainTextEdit.clear()
        lineStr = ""
        for i in range(self.itemModel.columnCount() - 1):  #表头,不含最后一列
            item = self.itemModel.horizontalHeaderItem(i)
            lineStr = lineStr + item.text() + "\t"
        item = self.itemModel.horizontalHeaderItem(self.__ColCount - 1)  #最后一列
        lineStr = lineStr + item.text()  #表头文字字符串
        self.ui.plainTextEdit.appendPlainText(lineStr)

        for i in range(self.itemModel.rowCount()):
            lineStr = ""
            for j in range(self.itemModel.columnCount() - 1):  #不包括最后一列
                item = self.itemModel.item(i, j)
                lineStr = lineStr + item.text() + "\t"
            item = self.itemModel.item(i, self.__ColCount - 1)  #最后一列
            if (item.checkState() == Qt.Checked):
                lineStr = lineStr + "1"
            else:
                lineStr = lineStr + "0"
            self.ui.plainTextEdit.appendPlainText(lineStr)

##  =============自定义槽函数===============================

    def do_curChanged(self, current, previous):
        if (current != None):  #当前模型索引有效
            text = "当前单元格:%d行,%d列" % (current.row(), current.column())
            self.LabCellPos.setText(text)
            item = self.itemModel.itemFromIndex(current)  #从模型索引获得Item
            self.LabCellText.setText("单元格内容:" + item.text())  #显示item的文字内容

            font = item.font()  #获取item的字体
            self.ui.actFontBold.setChecked(font.bold())  #更新actFontBold的check状态
Example #25
0
    def addMail2(self, model: QStandardItemModel, mailFrom, subject, date):
        model.insertRow(0)

        model.setData(model.index(1, self.FROM), mailFrom)
        model.setData(model.index(1, self.SUBJECT), subject)
        model.setData(model.index(1, self.DATE), date)
Example #26
0
class App(QWidget):
    global tableWidget

    def __init__(self):
        super().__init__()
        self.title = 'Tensorflow CV Recognition'
        self.left = 10
        self.top = 10
        self.width = 640
        self.height = 480
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)
        button = QPushButton('Open a folder', self)
        button.setToolTip('This is an example button')
        button.move(100, 70)
        button.clicked.connect(self.on_click)
        self.createTable()

        # Add box layout, add table to box layout and add box layout to widget
        self.layout = QVBoxLayout()
        self.layout.addWidget(button)
        self.layout.addWidget(self.tableWidget)
        self.setLayout(self.layout)

        self.show()

    def openFileNameDialog(self):
        #options = QFileDialog.Options()
        #options |= QFileDialog.DontUseNativeDialog
        #fileName = str(QFileDialog.getExistingDirectory(self, "Select Directory"))
        fileName = QFileDialog.getExistingDirectory(None, 'Select a folder:')
        '''fileName, _ = QFileDialog.getOpenFileName(self, "QFileDialog.getOpenFileName()", "",
                                                  "All Files (*);;Python Files (*.py)", options=options)'''
        if fileName:
            print(fileName)
        #fileName = '/'.join(fileName[0].split("/")[:-1])+"/"
        print(fileName)
        main(fileName)

    def openFileNamesDialog(self):
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        files, _ = QFileDialog.getOpenFileNames(
            self,
            "QFileDialog.getOpenFileNames()",
            "",
            "All Files (*);;Python Files (*.py)",
            options=options)
        if files:
            print(files)

    def createTable(self):
        # Create table
        self.tableWidget = QTableView(self)
        self.model = QStandardItemModel(50, 2, self)
        self.model.setHorizontalHeaderLabels(["Document Number", "Decision"])
        self.tableWidget.setModel(self.model)
        self.tableWidget.update()
        #self.model.insertRow(0, [QStandardItem("1"), QStandardItem("2")])

        #self.tableWidget.setColumnCount(2)
        #self.tableWidget.setRowCount(20)
        self.tableWidget.setColumnWidth(0, 295)
        self.tableWidget.setColumnWidth(1, 295)
        self.tableWidget.move(100, 100)
        self.tableWidget.setUpdatesEnabled(True)

    def insert(self, i, row):
        self.model.insertRow(i - 1,
                             [QStandardItem(row[0]),
                              QStandardItem(row[1])])
        self.tableWidget.setModel(self.model)

    @pyqtSlot()
    def on_click(self):
        print('PyQt5 button click')
        self.openFileNameDialog()
Example #27
0
class InvoiceList(MyTreeView):
    class Columns(IntEnum):
        DATE = 0
        DESCRIPTION = 1
        AMOUNT = 2
        STATUS = 3

    headers = {
        Columns.DATE: _('Date'),
        Columns.DESCRIPTION: _('Description'),
        Columns.AMOUNT: _('Amount'),
        Columns.STATUS: _('Status'),
    }
    filter_columns = [Columns.DATE, Columns.DESCRIPTION, Columns.AMOUNT]

    def __init__(self, parent):
        super().__init__(parent,
                         self.create_menu,
                         stretch_column=self.Columns.DESCRIPTION)
        self.std_model = QStandardItemModel(self)
        self.proxy = MySortModel(self, sort_role=ROLE_SORT_ORDER)
        self.proxy.setSourceModel(self.std_model)
        self.setModel(self.proxy)
        self.setSortingEnabled(True)
        self.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.update()

    def update_item(self, key, invoice: Invoice):
        model = self.std_model
        for row in range(0, model.rowCount()):
            item = model.item(row, 0)
            if item.data(ROLE_REQUEST_ID) == key:
                break
        else:
            return
        status_item = model.item(row, self.Columns.STATUS)
        status = self.parent.wallet.get_invoice_status(invoice)
        status_str = invoice.get_status_str(status)
        if self.parent.wallet.lnworker:
            log = self.parent.wallet.lnworker.logs.get(key)
            if log and status == PR_INFLIGHT:
                status_str += '... (%d)' % len(log)
        status_item.setText(status_str)
        status_item.setIcon(read_QIcon(pr_icons.get(status)))

    def update(self):
        # not calling maybe_defer_update() as it interferes with conditional-visibility
        self.proxy.setDynamicSortFilter(
            False)  # temp. disable re-sorting after every change
        self.std_model.clear()
        self.update_headers(self.__class__.headers)
        for idx, item in enumerate(self.parent.wallet.get_unpaid_invoices()):
            key = self.parent.wallet.get_key_for_outgoing_invoice(item)
            if item.is_lightning():
                icon_name = 'lightning.png'
            else:
                icon_name = 'bitcoin.png'
                if item.bip70:
                    icon_name = 'seal.png'
            status = self.parent.wallet.get_invoice_status(item)
            status_str = item.get_status_str(status)
            message = item.message
            amount = item.get_amount_sat()
            timestamp = item.time or 0
            date_str = format_time(timestamp) if timestamp else _('Unknown')
            amount_str = self.parent.format_amount(amount, whitespaces=True)
            labels = [date_str, message, amount_str, status_str]
            items = [QStandardItem(e) for e in labels]
            self.set_editability(items)
            items[self.Columns.DATE].setIcon(read_QIcon(icon_name))
            items[self.Columns.STATUS].setIcon(read_QIcon(
                pr_icons.get(status)))
            items[self.Columns.DATE].setData(key, role=ROLE_REQUEST_ID)
            items[self.Columns.DATE].setData(item.type, role=ROLE_REQUEST_TYPE)
            items[self.Columns.DATE].setData(timestamp, role=ROLE_SORT_ORDER)
            self.std_model.insertRow(idx, items)
        self.filter()
        self.proxy.setDynamicSortFilter(True)
        # sort requests by date
        self.sortByColumn(self.Columns.DATE, Qt.DescendingOrder)
        # hide list if empty
        if self.parent.isVisible():
            b = self.std_model.rowCount() > 0
            self.setVisible(b)
            self.parent.invoices_label.setVisible(b)

    def create_menu(self, position):
        wallet = self.parent.wallet
        items = self.selected_in_column(0)
        if len(items) > 1:
            keys = [item.data(ROLE_REQUEST_ID) for item in items]
            invoices = [wallet.invoices.get(key) for key in keys]
            can_batch_pay = all([
                i.type == PR_TYPE_ONCHAIN
                and wallet.get_invoice_status(i) == PR_UNPAID for i in invoices
            ])
            menu = QMenu(self)
            if can_batch_pay:
                menu.addAction(
                    _("Batch pay invoices") + "...",
                    lambda: self.parent.pay_multiple_invoices(invoices))
            menu.addAction(_("Delete invoices"),
                           lambda: self.parent.delete_invoices(keys))
            menu.exec_(self.viewport().mapToGlobal(position))
            return
        idx = self.indexAt(position)
        item = self.item_from_index(idx)
        item_col0 = self.item_from_index(
            idx.sibling(idx.row(), self.Columns.DATE))
        if not item or not item_col0:
            return
        key = item_col0.data(ROLE_REQUEST_ID)
        invoice = self.parent.wallet.get_invoice(key)
        menu = QMenu(self)
        self.add_copy_menu(menu, idx)
        if invoice.is_lightning():
            menu.addAction(_("Details"),
                           lambda: self.parent.show_lightning_invoice(invoice))
        else:
            if len(invoice.outputs) == 1:
                menu.addAction(
                    _("Copy Address"),
                    lambda: self.parent.do_copy(invoice.get_address(),
                                                title='Garlicoin Address'))
            menu.addAction(_("Details"),
                           lambda: self.parent.show_onchain_invoice(invoice))
        status = wallet.get_invoice_status(invoice)
        if status == PR_UNPAID:
            menu.addAction(
                _("Pay") + "...", lambda: self.parent.do_pay_invoice(invoice))
        if status == PR_FAILED:
            menu.addAction(_("Retry"),
                           lambda: self.parent.do_pay_invoice(invoice))
        if self.parent.wallet.lnworker:
            log = self.parent.wallet.lnworker.logs.get(key)
            if log:
                menu.addAction(_("View log"), lambda: self.show_log(key, log))
        menu.addAction(_("Delete"), lambda: self.parent.delete_invoices([key]))
        menu.exec_(self.viewport().mapToGlobal(position))

    def show_log(self, key, log: Sequence[HtlcLog]):
        d = WindowModalDialog(self, _("Payment log"))
        d.setMinimumWidth(600)
        vbox = QVBoxLayout(d)
        log_w = QTreeWidget()
        log_w.setHeaderLabels([_('Hops'), _('Channel ID'), _('Message')])
        log_w.header().setSectionResizeMode(2, QHeaderView.Stretch)
        log_w.header().setSectionResizeMode(1, QHeaderView.ResizeToContents)
        for payment_attempt_log in log:
            route_str, chan_str, message = payment_attempt_log.formatted_tuple(
            )
            x = QTreeWidgetItem([route_str, chan_str, message])
            log_w.addTopLevelItem(x)
        vbox.addWidget(log_w)
        vbox.addLayout(Buttons(CloseButton(d)))
        d.exec_()
Example #28
0
class SubtitleEditor(SubTab):
    def __init__(self, filePath, subtitleData, parent = None):
        name = os.path.split(filePath)[1]
        super(SubtitleEditor, self).__init__(name, parent)
        self.__initWidgets()
        self.__initContextMenu()

        self._settings = SubSettings()

        self._filePath = filePath
        self._movieFilePath = None
        self._subtitleData = subtitleData

        self.refreshSubtitles()

        # Some signals
        self._subtitleData.fileChanged.connect(self.fileChanged)
        self._subtitleData.subtitlesAdded.connect(self._subtitlesAdded)
        self._subtitleData.subtitlesRemoved.connect(self._subtitlesRemoved)
        self._subtitleData.subtitlesChanged.connect(self._subtitlesChanged)
        self._model.itemChanged.connect(self._subtitleEdited)
        self.customContextMenuRequested.connect(self.showContextMenu)

    def __initWidgets(self):
        minimalSizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)

        # List of subtitles
        subListDelegate = SubListItemDelegate()
        self._model = QStandardItemModel(0, 3, self)
        self._model.setHorizontalHeaderLabels([_("Begin"), _("End"), _("Subtitle")])
        self._subList = QTableView(self)
        self._subList.setModel(self._model)
        self._subList.setItemDelegateForColumn(0, subListDelegate)
        self._subList.setItemDelegateForColumn(1, subListDelegate)
        self._subList.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch)

        self._searchBar = SearchBar(self)
        self._searchBar.hide()

        # Top toolbar
        toolbar = QHBoxLayout()
        toolbar.setAlignment(Qt.AlignLeft)
        #toolbar.addWidget(someWidget....)
        toolbar.addStretch(1)

        # Main layout
        grid = QGridLayout()
        grid.setSpacing(10)
        grid.setContentsMargins(0, 3, 0, 0)
        grid.addLayout(toolbar, 0, 0, 1, 1) # stretch to the right
        grid.addWidget(self._subList, 1, 0)
        grid.addWidget(self._searchBar, 2, 0)
        self.setLayout(grid)

    def __initContextMenu(self):
        self._contextMenu = QMenu(self)
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        af = ActionFactory(self)

        insertSub = af.create(title = _("&Insert subtitle"), icon = "list-add",
            connection = self.insertNewSubtitle)
        self._contextMenu.addAction(insertSub)

        insertSub = af.create(title = _("&Add subtitle"), icon = "list-add",
            connection = self.addNewSubtitle)
        self._contextMenu.addAction(insertSub)

        removeSub = af.create(title = _("&Remove subtitles"), icon = "list-remove",
            connection = self.removeSelectedSubtitles)
        self._contextMenu.addAction(removeSub)

    def _changeRowBackground(self, rowNo, bg):
        with DisableSignalling(self._model.itemChanged, self._subtitleEdited):
            for columnNo in range(self._model.columnCount()):
                item = self._model.item(rowNo, columnNo)
                item.setBackground(bg)

    def _changeItemData(self, item, val, role):
        with DisableSignalling(self._model.itemChanged, self._subtitleEdited):
            item.setData(val, role)

    def _handleIncorrectItem(self, item):
        with DisableSignalling(self._model.itemChanged, self._subtitleEdited):
            item.setData(False, CustomDataRoles.ErrorFlagRole)

        bg = item.background()
        rowNo = item.row()
        self._changeRowBackground(rowNo, Qt.red)
        QTimer.singleShot(600, lambda rowNo=rowNo, bg=bg: self._changeRowBackground(rowNo, bg))

    def _subtitleEdited(self, item):
        modelIndex = item.index()
        column = modelIndex.column()
        subNo = modelIndex.row()

        errorFlag = item.data(CustomDataRoles.ErrorFlagRole)
        if errorFlag is True:
            self._handleIncorrectItem(item)
        else:
            # TODO: timeStart and timeEnd might be displayed in a frame format in a bright future.
            # Check it and create FrameTime properly in that case.
            # TODO: Maybe add column numbers to some kind of enum to avoid magic numbers?
            oldSubtitle = self.subtitles[subNo]
            newSubtitle = oldSubtitle.clone()
            if 0 == column:
                timeStart = item.data(CustomDataRoles.FrameTimeRole)
                newSubtitle.change(start = timeStart)
            elif 1 == column:
                timeEnd = item.data(CustomDataRoles.FrameTimeRole)
                newSubtitle.change(end = timeEnd)
            elif 2 == column:
                newSubtitle.change(text = item.text())
            command = ChangeSubtitle(self.filePath, oldSubtitle, newSubtitle, subNo)
            self._subtitleData.execute(command)

    def _subtitlesAdded(self, path, subNos):
        if path != self.filePath:
            return

        subtitles = self.subtitles
        for subNo in subNos:
            row = createRow(subtitles[subNo])
            self._model.insertRow(subNo, row)

    def _subtitlesRemoved(self, path, subNos):
        if path != self.filePath:
            return

        for subNo in subNos:
            self._model.removeRow(subNo)

    def _subtitlesChanged(self, path, subNos):
        if path != self.filePath:
            return

        for subNo in subNos:
            self.refreshSubtitle(subNo)

    def _createNewSubtitle(self, data, subNo):
        fps = data.fps # data is passed to avoid unnecessary copies
        minFrameTime = FrameTime(fps, frames = 1)

        # calculate correct minimum subtitle start time
        if subNo > 0:
            timeStart = data.subtitles[subNo - 1].end + minFrameTime
        else:
            timeStart = FrameTime(fps, frames = 0)

        # calculate correct maximum subtitle end time
        if subNo < data.subtitles.size():
            try:
                timeEnd = data.subtitles[subNo].start - minFrameTime
            except SubException:
                timeEnd = FrameTime(fps, frames = 0)
        else:
            timeEnd = timeStart + FrameTime(fps, frames = 50)

        # add subtitle to DataModel
        sub = Subtitle(timeStart, timeEnd, "")
        command = AddSubtitle(self.filePath, subNo, sub)
        with DisableSignalling(self._subtitleData.subtitlesAdded, self._subtitlesAdded):
            self._subtitleData.execute(command)

        # create subtitle graphical representation in editor sub list
        row = createRow(sub)
        self._model.insertRow(subNo, row)
        index = self._model.index(subNo, 2)
        self._subList.clearSelection()
        self._subList.setCurrentIndex(index)
        self._subList.edit(index)

    def addNewSubtitle(self):
        data = self.data
        subNo = data.subtitles.size()
        indices = self._subList.selectedIndexes()
        if len(indices) > 0:
            rows = [index.row() for index in indices]
            subNo = max(rows) + 1
        self._createNewSubtitle(data, subNo)

    def insertNewSubtitle(self):
        data = self.data
        subNo = 0
        indices = self._subList.selectedIndexes()
        if len(indices) > 0:
            rows = [index.row() for index in indices]
            subNo = max(rows)
        self._createNewSubtitle(data, subNo)

    def removeSelectedSubtitles(self):
        indices = self._subList.selectedIndexes()
        if len(indices) > 0:
            rows = list(set([index.row() for index in indices]))
            command = RemoveSubtitles(self.filePath, rows)
            self._subtitleData.execute(command)
            if self._model.rowCount() > rows[-1]:
                self._subList.selectRow(rows[-1])
            else:
                self._subList.selectRow(self._model.rowCount() - 1)

    def highlight(self):
        self._searchBar.show()
        self._searchBar.highlight()

    def showContextMenu(self):
        self._contextMenu.exec(QCursor.pos())

    def changeInputEncoding(self, encoding):
        data = self._subtitleData.data(self.filePath)
        if encoding != data.inputEncoding:
            try:
                data.encode(encoding)
            except UnicodeDecodeError:
                message = QMessageBox(
                    QMessageBox.Warning,
                    _("Decoding error"),
                    _("Cannot decode subtitles to '%s' encoding.\nPlease try different encoding.") % encoding,
                    QMessageBox.Ok, self
                )
                message.exec()
            except LookupError:
                message = QMessageBox(QMessageBox.Warning,
                    _("Unknown encoding"), _("Unknown encoding: '%s'") % encoding,
                    QMessageBox.Ok, self
                )
                message.exec()
            else:
                # TODO: outputEncoding
                command = ChangeData(self.filePath, data, _("Input encoding: %s") % encoding)
                self._subtitleData.execute(command)

    def changeOutputEncoding(self, encoding):
        data = self._subtitleData.data(self.filePath)
        if encoding != data.outputEncoding:
            data.outputEncoding = encoding
            command = ChangeData(self.filePath, data, _("Output encoding: %s") % encoding)
            self._subtitleData.execute(command)

    def changeSubFormat(self, fmt):
        data = self._subtitleData.data(self.filePath)
        if data.outputFormat != fmt:
            data.outputFormat = fmt
            command = ChangeData(self.filePath, data)
            self._subtitleData.execute(command)

    def changeFps(self, fps):
        data = self.data
        if data.fps != fps:
            data.subtitles.changeFps(fps)
            data.fps = fps
            command = ChangeData(self.filePath, data, _("FPS: %s") % fps)
            self._subtitleData.execute(command)

    def changeVideoPath(self, path):
        data = self.data
        if data.videoPath != path:
            data.videoPath = path
            command = ChangeData(self.filePath, data, _("Video path: %s") % path)
            self._subtitleData.execute(command)

    def offset(self, seconds):
        data = self.data
        fps = data.subtitles.fps
        if fps is None:
            log.error(_("No FPS for '%s' (empty subtitles)." % self.filePath))
            return
        ft = FrameTime(data.subtitles.fps, seconds=seconds)
        data.subtitles.offset(ft)
        command = ChangeData(self.filePath, data,
                             _("Offset by: %s") % ft.toStr())
        self._subtitleData.execute(command)

    def detectFps(self):
        data = self.data
        if data.videoPath is not None:
            fpsInfo = File.detectFpsFromMovie(data.videoPath)
            if data.videoPath != fpsInfo.videoPath or data.fps != fpsInfo.fps:
                data.videoPath = fpsInfo.videoPath
                data.subtitles.changeFps(fpsInfo.fps)
                data.fps = fpsInfo.fps
                command = ChangeData(self.filePath, data, _("Detected FPS: %s") % data.fps)
                self._subtitleData.execute(command)

    def fileChanged(self, filePath):
        if filePath == self._filePath:
            self.refreshSubtitles()

    def refreshSubtitle(self, subNo):
        sub = self.subtitles[subNo]
        self._model.removeRow(subNo)
        self._model.insertRow(subNo, createRow(sub))

    def refreshSubtitles(self):
        self._model.removeRows(0, self._model.rowCount())
        for sub in self.subtitles:
            self._model.appendRow(createRow(sub))

    def updateTab(self):
        self.refreshSubtitles()

    def selectedSubtitles(self):
        rows = self.selectedRows()
        subtitleList = [self.subtitles[row] for row in rows]
        return subtitleList

    def selectedRows(self):
        indices = self._subList.selectedIndexes()
        # unique list
        rows = list(set([index.row() for index in indices]))
        rows.sort()
        return rows

    def selectRow(self, row):
        self._subList.selectRow(row)

    @property
    def filePath(self):
        return self._filePath

    @property
    def movieFilePath(self):
        return self._movieFilePath

    @property
    def data(self):
        return self._subtitleData.data(self.filePath)

    @property
    def subtitles(self):
        return self.data.subtitles

    @property
    def history(self):
        return self._subtitleData.history(self.filePath)

    @property
    def inputEncoding(self):
        return self.data.inputEncoding

    @property
    def outputEncoding(self):
        return self.data.outputEncoding

    @property
    def outputFormat(self):
        return self.data.outputFormat
Example #29
0
class Interface(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        qApp.setStyle(QStyleFactory.create("Fusion"))
        # Считывание данных из БД, таблицы 'teams'
        con = sqlite3.connect('FootballManager.db')
        cur = con.cursor()
        result = cur.execute("""SELECT * FROM teams""").fetchall()
        con.close()

        # Заполнение класса Team, извлеченными данными
        self.arrayOfTeams = []
        for x in result:
            self.arrayOfTeams.append(Team(x[0], x[1], x[2]))

        # Создание списка сезонов(состоит из игр -> команд -> игроков), каждый прошедший сезон сохраняется в отдельном файле, как архив
        self.globalNumberSeason = 0
        self.ligas = [Liga(self.arrayOfTeams[:16], self.globalNumberSeason)]


        self.model = QStandardItemModel()
        self.listView.setModel(self.model)
        self.listView.clicked.connect(self.onListView)
        self.listView.setEditTriggers(QAbstractItemView.NoEditTriggers)


        # Создание модели для таблицы команд
        self.modelForTableTeams = ModelForTableTeams(self.ligas[-1])

        self.filterModelForTableTeams = QSortFilterProxyModel()
        self.filterModelForTableTeams.setSourceModel(self.modelForTableTeams)
        self.tableViewForTeams.setModel(self.filterModelForTableTeams)

        self.tableViewForTeams.setSortingEnabled(False)
        #self.tableViewForTeams.sortByColumn(0, Qt.AscendingOrder)

        self.tableViewForTeams.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
        self.tableViewForTeams.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
        self.tableViewForTeams.verticalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.tableViewForTeams.setFont(QFont("times", 12))
        self.tableViewForTeams.clicked.connect(self.openGame)

        # Создание модели для таблицы лучших бомбардиров
        self.modelForTablePlayers = ModelForTablePlayers(self.ligas[-1].allPlayers, func=lambda x: (x.goals, x.name))

        self.filterModelForTablePlayers = QSortFilterProxyModel()
        self.filterModelForTablePlayers.setSourceModel(self.modelForTablePlayers)
        self.tableViewForPlayers.setModel(self.filterModelForTablePlayers)

        self.tableViewForPlayers.setSortingEnabled(False)
        #self.tableViewForPlayers.sortByColumn(0, Qt.AscendingOrder)

        self.tableViewForPlayers.setFont(QFont("times", 16))
        self.tableViewForPlayers.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
        self.tableViewForPlayers.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
        self.tableViewForPlayers.verticalHeader().setSectionResizeMode(QHeaderView.Stretch)

        # Создание модели для таблицы лучших распасовщиков
        self.modelForTablePlayersPass = ModelForTablePlayersPass(self.ligas[-1].allPlayers,
                                                            func=lambda x: (x.correctPass / (x.allPass * 100), x.name) if x.skillPass != 1 and x.allPass != 0 else (0, x.name))

        self.filterModelForTablePlayersPass = QSortFilterProxyModel()
        self.filterModelForTablePlayersPass.setSourceModel(self.modelForTablePlayersPass)
        self.tableViewForPlayersPass.setModel(self.filterModelForTablePlayersPass)

        self.tableViewForPlayersPass.setSortingEnabled(False)
        #self.tableViewForPlayers.sortByColumn(0, Qt.AscendingOrder)

        self.tableViewForPlayersPass.setFont(QFont("times", 16))
        self.tableViewForPlayersPass.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
        self.tableViewForPlayersPass.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
        self.tableViewForPlayersPass.verticalHeader().setSectionResizeMode(QHeaderView.Stretch)

        # Обновление таблиц
        self.onlineTables()

        self.pushButton.clicked.connect(self.playOneTour)

    # Проигровка 1 тура матчей лиги
    def playOneTour(self):

        # Если текущий тур не ушёл за границы дозволенного, то продолжить увеличивать туры
        if self.ligas[self.globalNumberSeason].tourNow != (self.ligas[self.globalNumberSeason].countTeams - 1) * 2:

            # Сыграть тур
            self.ligas[self.globalNumberSeason].playTour()

            item = QStandardItem(f'Tур {self.ligas[self.globalNumberSeason].tourNow + 1}\n')
            self.model.appendRow(item)

            #for i in range(self.ligas[self.globalNumberSeason].tourNow *
            #               self.ligas[self.globalNumberSeason].countTeams // 2,
            #               (self.ligas[self.globalNumberSeason].tourNow + 1) *
            #               self.ligas[self.globalNumberSeason].countTeams // 2):
            #    self.textEdit.insertPlainText(self.ligas[self.globalNumberSeason].games[i].teams[0].name + ' ' +
            #                                  str(self.ligas[self.globalNumberSeason].games[i].homeGoal) + ':' +
            #                                  str(self.ligas[self.globalNumberSeason].games[i].guestGoal) + ' ' +
            #                                  self.ligas[self.globalNumberSeason].games[i].teams[1].name + '\n')
            #self.textEdit.insertPlainText('\n')
            # self.textEdit.insertPlainText('-------------------------------------\n')

            # Обновление таблиц
            self.ligas[self.globalNumberSeason].tourNow += 1
            self.onlineTables()
        else:

            with open(f'season{self.globalNumberSeason}.txt', 'w') as f:
                for i in range(self.modelForTableTeams.rowCount()):
                    f.write(self.modelForTableTeams.teams[i].name + ' ' + str(self.modelForTableTeams.teams[i].points) + '\n')

            # Обнуляем все значения для нового сезона
            for i in range(len(self.ligas[self.globalNumberSeason].teams)):
                self.ligas[self.globalNumberSeason].teams[i].zeroingOfNewSeason()

            # Увеличиваем номер сезона на 1
            self.globalNumberSeason += 1

            # Создание нового сезона
            self.ligas.append(Liga(self.arrayOfTeams[:16], self.globalNumberSeason))
            self.modelForTableTeams.newDatas(self.ligas[-1])

            # Обновление таблиц
            self.onlineTables()
            self.model.clear()

    def onlineTables(self):

        # Обновление данных таблиц
        self.modelForTableTeams.oneSort()
        startIndex = self.modelForTableTeams.createIndex(0, 0)
        stopIndex = self.modelForTableTeams.createIndex(self.modelForTableTeams.rowCount(),
                                                        self.modelForTableTeams.columnCount())
        self.tableViewForTeams.dataChanged(startIndex, stopIndex)

        # Обновление данных таблиц
        self.modelForTablePlayers.newData()
        startIndex = self.modelForTablePlayers.createIndex(0, 0)
        stopIndex = self.modelForTablePlayers.createIndex(self.modelForTablePlayers.rowCount(),
                                                          self.modelForTablePlayers.columnCount())

        self.tableViewForPlayers.dataChanged(startIndex, stopIndex)

        # Обновление данных таблиц
        self.modelForTablePlayersPass.newData()
        startIndex = self.modelForTablePlayersPass.createIndex(0, 0)
        stopIndex = self.modelForTablePlayersPass.createIndex(self.modelForTablePlayersPass.rowCount(),
                                                          self.modelForTablePlayersPass.columnCount())

        self.tableViewForPlayersPass.dataChanged(startIndex, stopIndex)

        # Изменение таблицы команд под новые данные
        self.tableViewForTeams.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
        self.tableViewForTeams.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
        self.tableViewForTeams.verticalHeader().setSectionResizeMode(QHeaderView.Stretch)

        # Изменение таблицы бомбардиров под новые данные
        self.tableViewForPlayers.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
        self.tableViewForPlayers.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
        self.tableViewForPlayers.verticalHeader().setSectionResizeMode(QHeaderView.Stretch)

        # Изменение таблицы бомбардиров под новые данные
        self.tableViewForPlayersPass.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
        self.tableViewForPlayersPass.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
        self.tableViewForPlayersPass.verticalHeader().setSectionResizeMode(QHeaderView.Stretch)

    def openGame(self, index):
        row = index.row()
        column = index.column()
        if 2 <= column < 18:
            if column - 2 != row:
                temp = self.modelForTableTeams.table_values.findGameForIds(
                    [self.modelForTableTeams.teams[row].id,
                     self.modelForTableTeams.teams[column - 2].id])
                if temp:
                    print(temp.teams[0].name + ' ' + str(temp.homeGoal) + ' ' + ':' + ' ' + str(temp.guestGoal) + ' ' + temp.teams[1].name)
                    for i in range(2):
                        for x in temp.structures[i]:
                            print(temp.teams[i].players[x].name, temp.teams[i].players[x].physic)
                        print()

    def onListView(self, index):
        row = index.row()
        stTemp2 = str(self.model.item(row).text())
        stTempClick0 = str(stTemp2).split()[0]
        stTempClick1 = stTemp2.split()[1]
        if stTempClick0 == 'Tур':
            if row + 1 == self.model.rowCount():
                for i in range(self.ligas[-1].countTeams // 2):
                    team1 = self.ligas[-1].findGameForIds(self.ligas[-1].games[int(stTempClick1) - 1][i].ids).teams[0].name
                    result = self.ligas[-1].findGameForIds(self.ligas[-1].games[int(stTempClick1) - 1][i].ids).returnResult()
                    team2 = self.ligas[-1].findGameForIds(self.ligas[-1].games[int(stTempClick1) - 1][i].ids).teams[1].name
                    stTemp = f'{team1} {result} {team2}'
                    item = QStandardItem(stTemp)
                    self.model.insertRow(row + 1, item)
            else:
                stTemp3 = str(self.model.item(row + 1).text())
                stTempClick2 = str(stTemp3).split()[0]
                if stTempClick2 == 'Tур':
                    for i in range(self.ligas[-1].countTeams // 2):
                        team1 = self.ligas[-1].findGameForIds(self.ligas[-1].games[int(stTempClick1) - 1][i].ids).teams[0].name
                        result = self.ligas[-1].findGameForIds(self.ligas[-1].games[int(stTempClick1) - 1][i].ids).returnResult()
                        team2 = self.ligas[-1].findGameForIds(self.ligas[-1].games[int(stTempClick1) - 1][i].ids).teams[1].name
                        stTemp = f'{team1} {result} {team2}'
                        item = QStandardItem(stTemp)
                        self.model.insertRow(row + 1, item)
                else:
                    j = 0
                    stTempClick4 = ''
                    print(6)
                    while stTempClick4 != 'Tур' and j + row + 1 < self.model.rowCount():
                        print(stTempClick4, j + row)
                        j += 1
                        stTemp4 = str(self.model.item(j + row).text())
                        stTempClick4 = str(stTemp4).split()[0]
                    if stTempClick4 != 'Tур':
                        for i in range(j):
                            self.model.removeRow(row + 1)
                    else:
                        for i in range(j - 1):
                            self.model.removeRow(row + 1)
        else:
            if ':' in stTemp2:
                if row + 1 != self.model.rowCount():
                    temp1 = str(self.model.item(row + 1).text())
                    if ':' in temp1 or 'Tур' in temp1:
                        temp = stTemp2.split(':')
                        name1 = ' '.join(temp[0].split()[:-1])
                        name2 = ' '.join(temp[1].split()[1:])
                        game = self.ligas[-1].findGameForNames(name1, name2)
                        if game:
                            item = QStandardItem(game.returnSostav())
                            self.model.insertRow(row + 1, item)
                    else:
                        self.model.removeRow(row + 1)
                else:
                    temp = stTemp2.split(':')
                    name1 = ' '.join(temp[0].split()[:-1])
                    name2 = ' '.join(temp[1].split()[1:])
                    game = self.ligas[-1].findGameForNames(name1, name2)
                    if game:
                        item = QStandardItem(game.returnSostav())
                        self.model.insertRow(row + 1, item)
Example #30
0
class Dialog_ui(QDialog, Ui_Dialog):
    """
    Class documentation goes here.
    """
    def __init__(self, parent=None):
        """
        Constructor
        
        @param parent reference to the parent widgets
        @type QWidget
        """
        super(Dialog_ui, self).__init__(parent)
        self.setupUi(self)
        self.ActionStart()

    def ActionStart(self):
        self.lineEdit_2.installEventFilter(self)
        self.lineEdit_3.installEventFilter(self)
        self.lineEdit_2.setContextMenuPolicy(Qt.NoContextMenu)
        self.lineEdit_3.setContextMenuPolicy(Qt.NoContextMenu)
        self.m_model = QStandardItemModel(0, 1, self)
        m_completer = QCompleter(self.m_model, self)
        self.lineEdit_7.setCompleter(m_completer)
        m_completer.activated[str].connect(self.onEmailChoosed)

    def onEmailChoosed(self, email):
        self.lineEdit_7.setText(email)

    def eventFilter(self, object, event):
        if object == self.lineEdit_2:
            if event.type() == QEvent.MouseMove or event.type(
            ) == QEvent.MouseButtonDblClick:
                return True
            elif event.type() == QEvent.KeyPress:
                key = QKeyEvent(event)
                if key.matches(QKeySequence.SelectAll) or key.matches(
                        QKeySequence.Copy) or key.matches(QKeySequence.Paste):
                    return True
        elif object == self.lineEdit_3:
            if event.type() == QEvent.MouseMove or event.type(
            ) == QEvent.MouseButtonDblClick:
                return True
            elif event.type() == QEvent.KeyPress:
                key = QKeyEvent(event)
                if key.matches(QKeySequence.SelectAll) or key.matches(
                        QKeySequence.Copy) or key.matches(QKeySequence.Paste):
                    return True
        return QDialog.eventFilter(self, object, event)

    @pyqtSlot()
    def on_lineEdit_editingFinished(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        regex_user = '******'
        username = self.lineEdit.text()
        if len(username) > 0:
            self.lineEdit_6.clear()
            rruser = re.compile(regex_user)
            if rruser.match(username) is None:
                self.lineEdit_6.setText('用户名不符合要求!')
        else:
            self.lineEdit_6.setText('用户名未填写!')

    @pyqtSlot()
    def on_lineEdit_2_editingFinished(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        # raise NotImplementedError
        regex_pwd = "^([A-Z]|[a-z]|[0-9]|[`~!@#$%^&*()+=|{}':;',\\\\[\\\\].<>/?~!@#¥%……&*()——+|{}【】‘;:”“'。,、?]){6,16}$"
        self.pwd1 = self.lineEdit_2.GetPassword()
        if len(self.pwd1) > 0:
            self.lineEdit_6.clear()
            rrpwd = re.compile(regex_pwd)
            if rrpwd.match(self.pwd1) is None:
                self.lineEdit_6.setText('密码不符合要求!')
        else:
            self.lineEdit_6.setText('密码未填写!')

    @pyqtSlot()
    def on_lineEdit_3_editingFinished(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        # raise NotImplementedError
        self.pwd2 = self.lineEdit_3.GetPassword()
        regex_pwd = "^([A-Z]|[a-z]|[0-9]|[`~!@#$%^&*()+=|{}':;',\\\\[\\\\].<>/?~!@#¥%……&*()——+|{}【】‘;:”“'。,、?]){6,16}$"
        if len(self.pwd2) > 0:
            self.lineEdit_6.clear()
            rrpwd = re.compile(regex_pwd)
            if rrpwd.match(self.pwd2) is None:
                self.lineEdit_6.setText('密码不符合要求!')
            if self.pwd1 != self.pwd2:
                self.lineEdit_6.setText('两次密码不一致!')
        else:
            self.lineEdit_6.setText('密码未填写!')

    @pyqtSlot()
    def on_lineEdit_4_editingFinished(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        # raise NotImplementedError
        regex_phone = '^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0,5-9]))\\d{8}$'
        phone = self.lineEdit_4.text()
        if len(phone) > 0:
            self.lineEdit_6.clear()
            rr1 = re.compile(regex_phone)
            if rr1.match(phone) is None:
                self.lineEdit_6.setText('请填写正确的手机号!')
        else:
            self.lineEdit_6.setText('手机号码未填写!')

    @pyqtSlot()
    def on_lineEdit_7_editingFinished(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        # raise NotImplementedError
        regex_mail = '^[a-z0-9]+([._\\-]*[a-z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$'
        email = self.lineEdit_7.text()
        if len(email) > 0:
            self.lineEdit_6.clear()
            rr1 = re.compile(regex_mail)
            if rr1.match(email) is None:
                self.lineEdit_6.setText('请填写正确的邮箱地址!')
        else:
            self.lineEdit_6.setText('邮箱地址未填写!')

    @pyqtSlot(str)
    def on_lineEdit_7_textChanged(self, text):

        if '@' in self.lineEdit_7.text():
            return

        emaillist = [
            "@163.com", "@qq.com", "@gmail.com", "@live.com", "@126.com",
            "@139.com"
        ]

        self.m_model.removeRows(0, self.m_model.rowCount())

        for i in range(0, len(emaillist)):
            self.m_model.insertRow(0)
            self.m_model.setData(self.m_model.index(0, 0), text + emaillist[i])
class RequestList(MyTreeView):
    class Columns(IntEnum):
        DATE = 0
        DESCRIPTION = 1
        AMOUNT = 2
        STATUS = 3

    headers = {
        Columns.DATE: _('Date'),
        Columns.DESCRIPTION: _('Description'),
        Columns.AMOUNT: _('Amount'),
        Columns.STATUS: _('Status'),
    }
    filter_columns = [Columns.DATE, Columns.DESCRIPTION, Columns.AMOUNT]

    def __init__(self, parent):
        super().__init__(parent,
                         self.create_menu,
                         stretch_column=self.Columns.DESCRIPTION,
                         editable_columns=[])
        self.wallet = self.parent.wallet
        self.std_model = QStandardItemModel(self)
        self.proxy = MySortModel(self, sort_role=ROLE_SORT_ORDER)
        self.proxy.setSourceModel(self.std_model)
        self.setModel(self.proxy)
        self.setSortingEnabled(True)
        self.selectionModel().currentRowChanged.connect(self.item_changed)
        self.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.update()

    def select_key(self, key):
        for i in range(self.model().rowCount()):
            item = self.model().index(i, self.Columns.DATE)
            row_key = item.data(ROLE_KEY)
            if key == row_key:
                self.selectionModel().setCurrentIndex(
                    item, QItemSelectionModel.SelectCurrent
                    | QItemSelectionModel.Rows)
                break

    def item_changed(self, idx: Optional[QModelIndex]):
        if idx is None:
            self.parent.receive_payreq_e.setText('')
            self.parent.receive_address_e.setText('')
            return
        if not idx.isValid():
            return
        # TODO use siblingAtColumn when min Qt version is >=5.11
        item = self.item_from_index(idx.sibling(idx.row(), self.Columns.DATE))
        key = item.data(ROLE_KEY)
        req = self.wallet.get_request(key)
        if req is None:
            self.update()
            return
        self.parent.receive_payreq_e.setText(
            self.parent.wallet.get_request_URI(req))
        self.parent.receive_address_e.setText(req.get_address())
        self.parent.receive_payreq_e.repaint()  # macOS hack (similar to #4777)
        self.parent.receive_address_e.repaint(
        )  # macOS hack (similar to #4777)

    def clearSelection(self):
        super().clearSelection()
        self.selectionModel().clearCurrentIndex()

    def refresh_status(self):
        m = self.std_model
        for r in range(m.rowCount()):
            idx = m.index(r, self.Columns.STATUS)
            date_idx = idx.sibling(idx.row(), self.Columns.DATE)
            date_item = m.itemFromIndex(date_idx)
            status_item = m.itemFromIndex(idx)
            key = date_item.data(ROLE_KEY)
            req = self.wallet.get_request(key)
            if req:
                status = self.parent.wallet.get_request_status(key)
                status_str = req.get_status_str(status)
                status_item.setText(status_str)
                status_item.setIcon(read_QIcon(pr_icons.get(status)))

    def update(self):
        # not calling maybe_defer_update() as it interferes with conditional-visibility
        self.parent.update_receive_address_styling()
        self.proxy.setDynamicSortFilter(
            False)  # temp. disable re-sorting after every change
        self.std_model.clear()
        self.update_headers(self.__class__.headers)
        for req in self.wallet.get_sorted_requests():
            assert isinstance(req, OnchainInvoice)
            key = req.id
            status = self.parent.wallet.get_request_status(key)
            status_str = req.get_status_str(status)
            request_type = req.type
            timestamp = req.time
            amount = req.get_amount_sat()
            message = req.message
            date = format_time(timestamp)
            amount_str = self.parent.format_amount(amount) if amount else ""
            labels = [date, message, amount_str, status_str]
            assert isinstance(req, OnchainInvoice)
            key = req.get_address()
            icon = read_QIcon("firocoin.png")
            tooltip = 'onchain request'
            items = [QStandardItem(e) for e in labels]
            self.set_editability(items)
            items[self.Columns.DATE].setData(request_type, ROLE_REQUEST_TYPE)
            items[self.Columns.DATE].setData(key, ROLE_KEY)
            items[self.Columns.DATE].setData(timestamp, ROLE_SORT_ORDER)
            items[self.Columns.DATE].setIcon(icon)
            items[self.Columns.STATUS].setIcon(read_QIcon(
                pr_icons.get(status)))
            items[self.Columns.DATE].setToolTip(tooltip)
            self.std_model.insertRow(self.std_model.rowCount(), items)
        self.filter()
        self.proxy.setDynamicSortFilter(True)
        # sort requests by date
        self.sortByColumn(self.Columns.DATE, Qt.DescendingOrder)
        # hide list if empty
        if self.parent.isVisible():
            b = self.std_model.rowCount() > 0
            self.setVisible(b)
            self.parent.receive_requests_label.setVisible(b)
            if not b:
                # list got hidden, so selected item should also be cleared:
                self.item_changed(None)

    def create_menu(self, position):
        items = self.selected_in_column(0)
        if len(items) > 1:
            keys = [item.data(ROLE_KEY) for item in items]
            menu = QMenu(self)
            menu.addAction(_("Delete requests"),
                           lambda: self.parent.delete_requests(keys))
            menu.exec_(self.viewport().mapToGlobal(position))
            return
        idx = self.indexAt(position)
        # TODO use siblingAtColumn when min Qt version is >=5.11
        item = self.item_from_index(idx.sibling(idx.row(), self.Columns.DATE))
        if not item:
            return
        key = item.data(ROLE_KEY)
        req = self.wallet.get_request(key)
        if req is None:
            self.update()
            return
        menu = QMenu(self)
        self.add_copy_menu(menu, idx)
        URI = self.wallet.get_request_URI(req)
        menu.addAction(_("Copy Request"),
                       lambda: self.parent.do_copy(URI, title='Dash URI'))
        menu.addAction(
            _("Copy Address"),
            lambda: self.parent.do_copy(req.get_address(),
                                        title='Dash Address'))
        #if 'view_url' in req:
        #    menu.addAction(_("View in web browser"), lambda: webopen(req['view_url']))
        menu.addAction(_("Delete"), lambda: self.parent.delete_requests([key]))
        run_hook('receive_list_menu', menu, key)
        menu.exec_(self.viewport().mapToGlobal(position))
Example #32
0
class ElfInfo(DwarfDialog):
    onShowMemoryRequest = pyqtSignal(str, name='onShowMemoryRequest')

    def __init__(self, parent=None, file_path=None):
        super().__init__(parent=parent)
        h_box = QHBoxLayout(self)
        self._ident_titles = [
            'EI_MAG0', 'EI_MAG1', 'EI_MAG2', 'EI_MAG3', 'EI_CLASS', 'EI_DATA',
            'EI_VERSION', 'EI_OSABI', 'EI_ABIVERSION', 'EI_PAD'
        ]
        self.elf_info = DwarfListView(self)
        self.elf_info.setRootIsDecorated(True)
        self.elf_info.setExpandsOnDoubleClick(True)
        self.elf_info.setContextMenuPolicy(Qt.CustomContextMenu)
        self.elf_info.customContextMenuRequested.connect(self._on_context_menu)
        h_box.addWidget(self.elf_info)
        self._elf_info_mdl = QStandardItemModel(0, 2)
        self._elf_info_mdl.setHeaderData(0, Qt.Horizontal, 'Name')
        self._elf_info_mdl.setHeaderData(1, Qt.Horizontal, 'Value')
        self.elf_info.setModel(self._elf_info_mdl)
        self.elf_info.doubleClicked.connect(self._on_dblclicked)
        self.title = "ELF Info"
        self._elf_file_path = None
        self.setLayout(h_box)
        if file_path:
            self.set_elf_file(file_path)

    def set_elf_file(self, file_path):
        self._elf_file_path = file_path
        self.title = 'ELF Info for ' + file_path
        self._elf_info_mdl.insertRow(
            0, [QStandardItem('File'),
                QStandardItem(file_path)])

    def set_parsed_data(self, parsed_data):
        parent_item = self._elf_info_mdl.item(0)
        if 'endian' in parsed_data:
            parent_item.appendRow([
                QStandardItem('Endian'),
                QStandardItem(parsed_data['endian'])
            ])
        if 'is64bit' in parsed_data:
            txt = 'No'
            if parsed_data['is64bit']:
                txt = 'Yes'
            parent_item.appendRow([QStandardItem('64Bit'), QStandardItem(txt)])

        if 'header' in parsed_data:
            elf_header = QStandardItem('ELF Header')
            parent_item.appendRow([elf_header])
            for d in parsed_data['header']:
                if d == 'e_ident':
                    ident_item = QStandardItem(d)
                    elf_header.appendRow([
                        ident_item,
                        QStandardItem(str(parsed_data['header'][d]))
                    ])
                    a = 0
                    for i in parsed_data['header'][d]:
                        if a >= len(self._ident_titles):
                            a = len(self._ident_titles) - 1
                        ident_item.appendRow([
                            QStandardItem(self._ident_titles[a]),
                            QStandardItem(str(i))
                        ])
                        a += 1
                else:
                    elf_header.appendRow([
                        QStandardItem(d),
                        QStandardItem(hex(parsed_data['header'][d]))
                    ])

        if 'programheaders' in parsed_data:
            prog_headers_item = QStandardItem('Program Headers')
            parent_item.appendRow([prog_headers_item])
            i = 1
            for header in parsed_data['programheaders']:
                header_item = QStandardItem("%d" % i)
                prog_headers_item.appendRow([header_item])
                i += 1
                for d in header:
                    header_item.appendRow(
                        [QStandardItem(d),
                         QStandardItem(hex(header[d]))])

        if 'sectionheaders' in parsed_data:
            sect_headers = QStandardItem('Section Headers')
            parent_item.appendRow([sect_headers])
            i = 1
            for header in parsed_data['sectionheaders']:
                txt = header['name']
                if not txt:
                    txt = 'NULL'
                header_item = QStandardItem(txt)
                sect_headers.appendRow([header_item])
                i += 1
                for d in header:
                    if d == 'name':
                        continue
                    elif d == 'data' and header[d]:
                        data_item = QStandardItem('Data')
                        header_item.appendRow(data_item)
                        base = self.parent().dwarf.dwarf_api(
                            'findModule', self._elf_file_path)['base']
                        for ptr in header[d]:
                            if int(ptr):
                                va = hex(int(base, 16) + int(ptr))
                                fo = hex(int(ptr))
                                if self.elf_info.uppercase_hex:
                                    va = va.upper().replace('0X', '0x')
                                    fo = fo.upper().replace('0X', '0x')
                                data_item.appendRow([
                                    QStandardItem(va),
                                    QStandardItem('FileOffset: ' + fo)
                                ])
                    else:
                        header_item.appendRow(
                            [QStandardItem(d),
                             QStandardItem(hex(header[d]))])

            self.elf_info.expandAll()
            self.elf_info.resizeColumnToContents(0)
            self.elf_info.resizeColumnToContents(1)
            self.setMinimumWidth(
                self.elf_info.columnWidth(0) + self.elf_info.columnWidth(1) +
                50)
            self.setMinimumHeight(400)
            self.elf_info.collapseAll()
            self.elf_info.expandToDepth(1)

    def _on_dblclicked(self, model_index):
        if model_index.column() == 0 and model_index.data():
            if model_index.data().startswith('0x'):
                self.onShowMemoryRequest.emit(model_index.data())

    def _on_context_menu(self, pos):
        model_index = self.elf_info.indexAt(pos)
        if model_index.column() == 0 and model_index.data():
            if model_index.data().startswith('0x'):
                context_menu = QMenu()
                context_menu.addAction(
                    'Add to Bookmarks',
                    lambda: self.parent().bookmarks_panel.insert_bookmark(
                        model_index.data(), 'init_array'))
                context_menu.addAction(
                    'Copy Address',
                    lambda: utils.copy_hex_to_clipboard(model_index.data()))
                # show contextmenu
                glbl_pt = self.elf_info.mapToGlobal(pos)
                context_menu.exec_(glbl_pt)
Example #33
0
class Win3(QWidget):
    def __init__(self):
        super(Win3, self).__init__()
        self.mypdf = MyPdf()
        self.init_ui()
        styleFile = './ui/style2.qss'
        qssStyle = CommonHelper.readQss(styleFile)
        self.setStyleSheet(qssStyle)

    def init_ui(self):
        self.button1 = QPushButton(self)
        self.button1.setText('返回')
        self.button1.setProperty("level", "1")

        # 设置数据层次结构,4行4列
        self.model = QStandardItemModel(0, 2)
        # #设置水平方向四个头标签文本内容
        self.model.setHorizontalHeaderLabels(['序号', '文件名称'])

        # 实例化表格视图,设置模型为自定义的模型
        self.tableView = QTableView(self)
        self.tableView.setModel(self.model)
        self.tableView.horizontalHeader().setSectionResizeMode(
            QHeaderView.Stretch)  # 使表宽度自适应
        self.tableView.horizontalHeader().setSectionResizeMode(
            0, QHeaderView.ResizeToContents)  # 第0列根据文字调节
        self.tableView.verticalHeader().setVisible(False)  # 隐藏列表头
        self.tableView.setSelectionBehavior(
            QAbstractItemView.SelectRows)  # 设置选中模式为选中行
        self.tableView.setStyleSheet(
            "selection-background-color:rgb(91,155,213)")  # 高亮显示选中的行

        self.button11 = QPushButton(self)
        self.button11.setText('+')
        self.button12 = QPushButton(self)
        self.button12.setText('-')
        self.button13 = QPushButton(self)
        self.button13.setText('上移')
        self.button14 = QPushButton(self)
        self.button14.setText('下移')

        self.button11.setProperty("level", "2")
        self.button12.setProperty("level", "2")
        self.button13.setProperty("level", "2")
        self.button14.setProperty("level", "2")

        self.hbox = QHBoxLayout()
        self.hbox.addWidget(self.button11)
        self.hbox.addWidget(self.button12)
        self.hbox.addWidget(self.button13)
        self.hbox.addWidget(self.button14)

        self.button2 = QPushButton(self)
        self.button2.setText('合并PDF')
        self.button2.setProperty("level", "1")

        self.label1 = QLabel(self)
        self.label1.setText('输出文件名:')
        self.lineedit1 = QLineEdit(self)
        self.button3 = QPushButton(self)
        self.button3.setText('选择文件夹')
        self.button3.setProperty("level", "2")
        self.hbox2 = QHBoxLayout()
        self.hbox2.addWidget(self.label1)
        self.hbox2.addWidget(self.lineedit1)
        self.hbox2.addWidget(self.button3)

        self.vbox = QVBoxLayout()
        self.vbox.addWidget(self.tableView)
        self.vbox.addLayout(self.hbox)
        self.vbox.addLayout(self.hbox2)
        self.vbox.addWidget(self.button2)
        self.vbox.addWidget(self.button1)
        self.setLayout(self.vbox)

        self.button11.clicked.connect(self.button11_clicked)
        self.button12.clicked.connect(self.button12_clicked)
        self.button13.clicked.connect(self.button13_clicked)
        self.button14.clicked.connect(self.button14_clicked)
        self.button2.clicked.connect(self.button2_clicked)
        self.button3.clicked.connect(self.button3_clicked)

    def button11_clicked(self):
        '''添加文件'''
        self.mypdf.file_lists = QFileDialog.getOpenFileNames(
            self, "选择文件", "/", "PDF Files (*.pdf)")[0]
        # print(self.mypdf.file_lists)
        # print(range(len(self.mypdf.file_lists)))
        for i in range(len(self.mypdf.file_lists)):
            row = self.model.rowCount()
            self.model.insertRow(row)  #插入一行
            item = QStandardItem(str(row + 1))
            self.model.setItem(row, 0, item)
            item = QStandardItem(self.mypdf.file_lists[i])
            self.model.setItem(row, 1, item)

    def button12_clicked(self):
        '''删除选中的行'''
        row = self.tableView.currentIndex().row()
        self.model.removeRow(int(row))

    def button13_clicked(self):
        '''向上移动行'''
        row = self.tableView.currentIndex().row()
        if row > 0:
            str1 = self.model.item(row, 1).text()
            str2 = self.model.item(row - 1, 1).text()

            self.model.setItem(row, 1, QStandardItem(str2))
            self.model.setItem(row - 1, 1, QStandardItem(str1))
        self.tableView.selectRow(row - 1)

    def button14_clicked(self):
        '''向下移动行'''
        maxrow = self.model.rowCount() - 1
        row = self.tableView.currentIndex().row()
        if row < maxrow:
            str1 = self.model.item(row, 1).text()
            str2 = self.model.item(row + 1, 1).text()

            self.model.setItem(row, 1, QStandardItem(str2))
            self.model.setItem(row + 1, 1, QStandardItem(str1))
        self.tableView.selectRow(row + 1)

    def button2_clicked(self):
        file_lists = []
        maxrow = self.model.rowCount()
        for row in range(maxrow):
            file_lists.append(self.model.item(row, 1).text())
        print(file_lists)
        newfilename = self.lineedit1.text()
        self.mypdf.merge(file_lists=file_lists, new_filename=newfilename)

    def button3_clicked(self):
        path = QFileDialog.getExistingDirectory()
        new_filename = path + '/' + '新合并文件.PDF'
        self.lineedit1.setText(new_filename)
Example #34
0
class CreateModel:

    def createPrologModel(self, prologView):
        listProlog = Prolog.getPrologList()
        for element in listProlog:
            if str(element.fullname).startswith("[pre"):
                listProlog.remove(element)

        self.prologModel = QStandardItemModel()
        self.prologModel.modelReset

        self.prologModel.setHorizontalHeaderItem(0, QStandardItem("Nome Corso"))
        self.prologModel.setHorizontalHeaderItem(1, QStandardItem("Nome Schematico"))
        self.prologModel.setHorizontalHeaderItem(2, QStandardItem("Docente"))
        self.prologModel.setHorizontalHeaderItem(3, QStandardItem("Numero Studenti"))
        self.prologModel.setHorizontalHeaderItem(4, QStandardItem("Corso / Anno"))
        self.prologModel.setHorizontalHeaderItem(5, QStandardItem("Numero Ore"))
        self.prologModel.setHorizontalHeaderItem(6, QStandardItem("Laboratorio"))
        self.prologModel.setHorizontalHeaderItem(7, QStandardItem("Numero Slot"))
        self.prologModel.setHorizontalHeaderItem(8, QStandardItem("Durata Slot"))
        self.prologModel.setHorizontalHeaderItem(9, QStandardItem("Tipo"))
        self.prologModel.setHorizontalHeaderItem(10, QStandardItem("Link"))
        self.prologModel.setHorizontalHeaderItem(11, QStandardItem("Commento"))

        for row in range(0, len(listProlog)):
            listCorsi =  str(listProlog[row].seguitoda).replace("][", "],[")
            nomecorso = QStandardItem(str(listProlog[row].fullname))
            shortName = QStandardItem(str(listProlog[row].nomecorso))
            docente = QStandardItem(str(listProlog[row].docente))
            numstudenti = QStandardItem(str(listProlog[row].numstudenti))
            seguitoda = QStandardItem(str(listCorsi))
            numore = QStandardItem(str(listProlog[row].numore))
            lab = QStandardItem(str(listProlog[row].lab))
            numslot = QStandardItem(str(listProlog[row].numslot))
            if str(listProlog[row].slotdur) != "None":
                slotdur = QStandardItem(str(listProlog[row].slotdur))
            else:
                slotdur = QStandardItem("_")
            type = QStandardItem(str(listProlog[row].type))
            link = QStandardItem(str(listProlog[row].link))

            prologView.setModel(self.prologModel)

            self.prologModel.insertRow(row)

            #imposto il background dei laboratori
            if listProlog[row].fullname == "[]" or "_lab" in str(listProlog[row].nomecorso) or "lab_" in str(listProlog[row].nomecorso):
                nomecorso.setBackground(QBrush(QColor(65, 205, 255, 200)))
                shortName.setBackground(QBrush(QColor(65, 205, 255, 200)))
                docente.setBackground(QBrush(QColor(65, 205, 255, 200)))
                numstudenti.setBackground(QBrush(QColor(65, 205, 255, 200)))
                seguitoda.setBackground(QBrush(QColor(65, 205, 255, 200)))
                numore.setBackground(QBrush(QColor(65, 205, 255, 200)))
                lab.setBackground(QBrush(QColor(65, 205, 255, 200)))
                numslot.setBackground(QBrush(QColor(65, 205, 255, 200)))
                slotdur.setBackground(QBrush(QColor(65, 205, 255, 200)))
                type.setBackground(QBrush(QColor(65, 205, 255, 200)))
                link.setBackground(QBrush(QColor(65, 205, 255, 200)))

            self.prologModel.setItem(row, 0, nomecorso)
            self.prologModel.setItem(row, 1, shortName)
            self.prologModel.setItem(row, 2, docente)
            self.prologModel.setItem(row, 3, numstudenti)
            self.prologModel.setItem(row, 4, seguitoda)
            self.prologModel.setItem(row, 5, numore)
            self.prologModel.setItem(row, 6, lab)
            self.prologModel.setItem(row, 7, numslot)
            self.prologModel.setItem(row, 8, slotdur)
            self.prologModel.setItem(row, 9, type)
            self.prologModel.setItem(row, 10, link)
            self.prologModel.setItem(row, 11, QStandardItem("Inserisci Commento..."))

            prologView.resizeColumnsToContents()

        return self.prologModel

    def createExcelModel(self, excelView):
        listCorsi = Compare.Compare().startCompare()
        listNewCorsi = Compare.Compare().getNewCorsi()
        for element in listNewCorsi:
            listCorsi.append(element)

        #messagebox per controllare i nuovi corsi
        if (len(listNewCorsi) > 0):
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Information)
            msg.resize(400, 400)
            msg.setText("Attenzione")
            msg.setInformativeText("Sono stati aggiunti dei corsi!")
            msg.setWindowTitle("Attenzione")
            toPrint = ""
            for element in listNewCorsi:
                toPrint = str(toPrint) + "*" + str(element.nomecorso) + "\n"
            msg.setDetailedText(toPrint)
            msg.exec_()

        try:
            self.tableModel = QStandardItemModel()
            self.tableModel.setHorizontalHeaderItem(0, QStandardItem("Nome Corso"))
            self.tableModel.setHorizontalHeaderItem(1, QStandardItem("Docente"))
            self.tableModel.setHorizontalHeaderItem(2, QStandardItem("Seguito Da"))
            self.tableModel.setHorizontalHeaderItem(3, QStandardItem("Anno"))
            self.tableModel.setHorizontalHeaderItem(4, QStandardItem("Numero Ore"))
        except AttributeError:
            print("uops")

        excelView.setModel(self.tableModel)

        for row in range(0, len(listCorsi)):

            nomecorso = QStandardItem(str(listCorsi[row].nomecorso))
            docente = QStandardItem(str(listCorsi[row].docente))
            seguitoda = QStandardItem(str(listCorsi[row].seguitoda))
            anno = QStandardItem(str(listCorsi[row].anno))
            numore = QStandardItem(str(listCorsi[row].numore))
            docenteHint = QStandardItem(str(listCorsi[row].docenteHint))
            numoreHint = QStandardItem(str(listCorsi[row].numOreHint))

            self.tableModel.insertRow(row)

            #se sono corsi nuovi li evidenzio in verde
            if listCorsi[row].docente == "" and listCorsi[row].numore == "":
                nomecorso.setBackground(QBrush(QColor(0,255,85,200)))
                docente.setBackground(QBrush(QColor(0, 255, 85, 200)))
                seguitoda.setBackground(QBrush(QColor(0, 255, 85, 200)))
                numore.setBackground(QBrush(QColor(0, 255, 85, 200)))
                anno.setBackground(QBrush(QColor(0, 255, 85, 200)))
                docenteHint.setBackground(QBrush(QColor(0, 255, 85, 200)))
                numoreHint.setBackground(QBrush(QColor(0, 255, 85, 200)))

            self.tableModel.setItem(row, 0, nomecorso)
            if (str(listCorsi[row].docente)) == str(None) or str(listCorsi[row].docente) == "":
                docenteHint.setBackground(QBrush(QColor(255,0,0,100)))
                self.tableModel.setItem(row, 1, docenteHint)
            else:
                self.tableModel.setItem(row, 1, docente)

            self.tableModel.setItem(row, 2, seguitoda)
            self.tableModel.setItem(row, 3, anno)

            if (listCorsi[row].numore == None):
                numoreHint.setBackground(QBrush(QColor(255,0,0,100)))
                self.tableModel.setItem(row, 4, numoreHint)
            else:
                self.tableModel.setItem(row, 4, numore)

        excelView.resizeColumnsToContents()
        return self.tableModel